落地私聊附件询价:发卡走 H5 收 Excel/PDF,认成口播再复用三线文字流程,避免附件卡在识别或退成纯文本。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,30 +1,106 @@
|
||||
"""
|
||||
千问:附件文本 mode 壳。
|
||||
千问:整理 Excel/PDF 抽出的原文。
|
||||
|
||||
本文件职责:把抽文本结果交给 qwen-plus,只整理看得见的字,不填询价字段。
|
||||
属于 llm 包。单测注入 chat_fn。禁止算最终缺项、禁止发明港口/箱型。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
|
||||
from agent.llm.modes import LlmMode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MODE = LlmMode.ATTACHMENT_TEXT
|
||||
|
||||
ATTACH_SYSTEM = (
|
||||
"下面是从 Excel 或 PDF 抽出来的原文。请整理成一段可读的询价口播:"
|
||||
"只保留材料里已经出现的文字和数字,原样保留港口、机场三字码、箱型、重量。"
|
||||
"看不清或没出现的不要猜,不要补询价缺项,不要发明港口、重量或日期。"
|
||||
"材料完全没有询价信息时输出空。"
|
||||
)
|
||||
|
||||
|
||||
def mode_meta() -> dict[str, Any]:
|
||||
return {
|
||||
"mode": MODE.value,
|
||||
"provider": "qwen",
|
||||
"purpose": "attachment_text",
|
||||
"implemented": False,
|
||||
"implemented": True,
|
||||
}
|
||||
|
||||
|
||||
def _pack_text(text: str, *, stub: bool = False) -> dict[str, Any]:
|
||||
body = (text or "").strip()
|
||||
return {
|
||||
"ok": True,
|
||||
"stub": stub,
|
||||
"mode": MODE.value,
|
||||
"text": body,
|
||||
"empty": not bool(body),
|
||||
"error": "",
|
||||
}
|
||||
|
||||
|
||||
def invoke_shell(*, payload: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
无网/单测入口:优先 assistant_text;否则把 raw_text 当整理结果。
|
||||
"""
|
||||
data = dict(payload or {})
|
||||
if "assistant_text" in data:
|
||||
return _pack_text(str(data.get("assistant_text") or ""), stub=True)
|
||||
if "raw_text" in data:
|
||||
return _pack_text(str(data.get("raw_text") or ""), stub=True)
|
||||
return {
|
||||
"ok": False,
|
||||
"stub": True,
|
||||
"mode": MODE.value,
|
||||
"text": "",
|
||||
"empty": True,
|
||||
"error": "attachment_text_shell_not_implemented",
|
||||
"echo_keys": sorted(payload.keys()),
|
||||
"echo_keys": sorted(data.keys()),
|
||||
}
|
||||
|
||||
|
||||
def invoke_attachment_text(
|
||||
*,
|
||||
payload: dict[str, Any],
|
||||
chat_fn: Optional[Any] = None,
|
||||
allow_network: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
整理一份抽出原文。chat_fn 单测注入;无网走 invoke_shell。
|
||||
"""
|
||||
data = dict(payload or {})
|
||||
raw = str(data.get("raw_text") or "")
|
||||
if chat_fn is None and not allow_network:
|
||||
return invoke_shell(payload=data)
|
||||
if not raw.strip():
|
||||
return _pack_text("", stub=chat_fn is None)
|
||||
if chat_fn is None:
|
||||
from agent.llm.http_client import LlmHttpClient
|
||||
|
||||
client = LlmHttpClient.from_settings()
|
||||
chat_fn = client.chat
|
||||
messages = [
|
||||
{"role": "system", "content": ATTACH_SYSTEM},
|
||||
{"role": "user", "content": raw.strip()},
|
||||
]
|
||||
result = chat_fn(mode=MODE, messages=messages)
|
||||
if not getattr(result, "ok", False):
|
||||
err = str(getattr(result, "error", "") or "attachment_text_failed")
|
||||
logger.info("attachment_text 失败 err=%s", err)
|
||||
return {
|
||||
"ok": False,
|
||||
"stub": False,
|
||||
"mode": MODE.value,
|
||||
"text": "",
|
||||
"empty": True,
|
||||
"error": err,
|
||||
}
|
||||
packed = _pack_text(str(getattr(result, "content", "") or ""))
|
||||
packed["stub"] = False
|
||||
return packed
|
||||
|
||||
Reference in New Issue
Block a user