4ff07e3c74
* feat: support fallback image parsing for quoted messages * fix: fallback parse quoted images when reply chain has placeholders * style: format network utils with ruff * test: expand quoted parser coverage and improve fallback diagnostics * fix: fallback to text-only retry when image requests fail * fix: tighten image fallback and resolve nested quoted forwards * refactor: simplify quoted message extraction and dedupe images * fix: harden quoted parsing and openai error candidates * fix: harden quoted image ref normalization * refactor: organize quoted parser settings and logging * fix: cap quoted fallback images and avoid retry loops * refactor: split quoted message parser into focused modules * refactor: share onebot segment parsing logic * refactor: unify quoted message parsing flow * feat: move quoted parser tuning to provider settings * fix: add missing i18n metadata for quoted parser settings * chore: refine forwarded message setting labels
86 lines
2.3 KiB
Python
86 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
_DEFAULT_MAX_COMPONENT_CHAIN_DEPTH = 4
|
|
_DEFAULT_MAX_FORWARD_NODE_DEPTH = 6
|
|
_DEFAULT_MAX_FORWARD_FETCH = 32
|
|
|
|
|
|
def _read_int_mapping(
|
|
mapping: Mapping[str, Any],
|
|
key: str,
|
|
default: int,
|
|
) -> int:
|
|
raw = mapping.get(key)
|
|
if raw is None:
|
|
return default
|
|
try:
|
|
value = int(raw)
|
|
except (TypeError, ValueError):
|
|
return default
|
|
if value <= 0:
|
|
return default
|
|
return value
|
|
|
|
|
|
def _read_bool_mapping(
|
|
mapping: Mapping[str, Any],
|
|
key: str,
|
|
default: bool,
|
|
) -> bool:
|
|
raw = mapping.get(key)
|
|
if raw is None:
|
|
return default
|
|
if isinstance(raw, bool):
|
|
return raw
|
|
if isinstance(raw, str):
|
|
lowered = raw.strip().lower()
|
|
if lowered in {"1", "true", "yes", "on"}:
|
|
return True
|
|
if lowered in {"0", "false", "no", "off"}:
|
|
return False
|
|
return default
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class QuotedMessageParserSettings:
|
|
max_component_chain_depth: int = _DEFAULT_MAX_COMPONENT_CHAIN_DEPTH
|
|
max_forward_node_depth: int = _DEFAULT_MAX_FORWARD_NODE_DEPTH
|
|
max_forward_fetch: int = _DEFAULT_MAX_FORWARD_FETCH
|
|
warn_on_action_failure: bool = False
|
|
|
|
def with_overrides(
|
|
self,
|
|
overrides: Mapping[str, Any] | None = None,
|
|
) -> QuotedMessageParserSettings:
|
|
if not overrides:
|
|
return self
|
|
return QuotedMessageParserSettings(
|
|
max_component_chain_depth=_read_int_mapping(
|
|
overrides,
|
|
"max_component_chain_depth",
|
|
self.max_component_chain_depth,
|
|
),
|
|
max_forward_node_depth=_read_int_mapping(
|
|
overrides,
|
|
"max_forward_node_depth",
|
|
self.max_forward_node_depth,
|
|
),
|
|
max_forward_fetch=_read_int_mapping(
|
|
overrides,
|
|
"max_forward_fetch",
|
|
self.max_forward_fetch,
|
|
),
|
|
warn_on_action_failure=_read_bool_mapping(
|
|
overrides,
|
|
"warn_on_action_failure",
|
|
self.warn_on_action_failure,
|
|
),
|
|
)
|
|
|
|
|
|
SETTINGS = QuotedMessageParserSettings()
|