from __future__ import annotations import json from collections.abc import Iterator from typing import Any from backend.llm import transport as llm_transport class ReviewAssistantError(RuntimeError): pass def stream_review_assistant( context: dict[str, Any], question: str, history: list[dict[str, str]], api_key: str, base_url: str, model: str, timeout: int = 120, ) -> Iterator[str]: if not api_key or not model: raise ReviewAssistantError("智能解读服务尚未配置。") messages = [{"role": "system", "content": _system_prompt(context)}] messages.extend(history[-12:]) messages.append({"role": "user", "content": question}) try: yield from llm_transport.stream_chat_completion( api_key=api_key, base_url=base_url, model=model, messages=messages, timeout=timeout, user_agent="XiaobaiReviewWeb/1.0", ) except llm_transport.OpenAIEmptyResponseError as exc: raise ReviewAssistantError("智能解读未返回有效内容。") from exc except llm_transport.OpenAIHTTPError as exc: raise ReviewAssistantError(f"智能解读服务暂不可用({exc.code})。") from exc except llm_transport.OpenAITransportError as exc: raise ReviewAssistantError("智能解读连接中断,请稍后重试。") from exc def _system_prompt(context: dict[str, Any]) -> str: context_json = json.dumps(context, ensure_ascii=False, separators=(",", ":")) return f""" 你是“小白复盘”的统一复盘助手。你负责把网页中已经存在的市场统计、策略跟踪、提醒、复盘笔记和手工交易日志连接起来,帮助用户复盘和形成下一步观察计划。 最高优先级规则: 1. 只能使用下方“网页复盘数据”,数据缺失就明确说明,不得补造行情、交易或胜率。 2. 不自动下单,不声称已执行任何操作,不修改策略、提醒、笔记或交易日志。 3. 不承诺收益,不给无条件买卖指令。建议必须写成条件、失效条件和风险边界。 4. 区分市场事实、用户记录和你的推断。引用数字时写明数据日期。 5. 优先结合用户自己的策略跟踪与交易日志寻找可验证的重复模式;样本不足时明确标注。 6. 使用中文,先直接回答,再给数据依据和下一步观察。避免空泛口号,不展示模型、接口或内部工程信息。 7. 控制在 800 个中文字符以内,除非用户明确要求展开。 网页复盘数据: {context_json} """.strip()