f7a3ef2e0b
- 新增内部端点 POST /internal/launch-confirm-sample(X-Internal-Secret 鉴权): pricebot 对没见过文案的启动确认窗用 LLM 兜底放行后,把样本(host 包 / 弹窗树 / LLM plan / 设备 locale 机型)回写落 launch_confirm_sample 表,供研发人工沉淀回 pricebot 规则 yaml - 配套: model LaunchConfirmSample + schema + repo(都上报不去重) + alembic 迁移 launch_confirm_sample_table(down_revision=cps_wx_user) + main 注册 router + models/__init__ 登记 - docs: 后端技术实现.md 加 §6.5 pricebot 回写内部端点说明 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
3.3 KiB
Python
62 lines
3.3 KiB
Python
"""启动确认窗 agent 兜底样本表(launch_confirm_sample)。
|
|
|
|
pricebot 的 launch_confirm_agent 每次"静态 PROFILES 没认出、靠 LLM 兜底放行"一个跨 App
|
|
启动确认窗(繁体 / 英文 / 小语种 / ROM 改版)时,把完整样本 server→server 落这里。研发定期
|
|
**人工**把 exec_success=true 的样本沉淀进 pricebot 的 launch_confirm.PROFILES(静态快路径),
|
|
让以后同款窗不必再调 LLM。
|
|
|
|
设计:
|
|
- 与登录无关、不鉴权(server→server 共享密钥头 X-Internal-Secret)。
|
|
- **都上报、不去重**(by design):同一种窗多台机器上报多条,研发按 host_package / locale
|
|
聚合后人工筛。
|
|
- 大字段(弹窗树快照 + LLM plan + 设备信息)塞 payload(JSONB)兜底,免得加字段就迁移 schema。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import JSON, Boolean, DateTime, Integer, String, func
|
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.db.base import Base
|
|
|
|
# PG 上用 JSONB(可建 GIN 索引),SQLite(本地/测试)退化为通用 JSON(同 price_observation)。
|
|
_JSON = JSON().with_variant(JSONB(), "postgresql")
|
|
|
|
|
|
class LaunchConfirmSample(Base):
|
|
__tablename__ = "launch_confirm_sample"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), index=True, nullable=False
|
|
)
|
|
|
|
# pricebot 侧 trace_id:回指原始 trace,能去 price.shaguabijia.com 查完整上下文。
|
|
trace_id: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True)
|
|
device_id: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True)
|
|
|
|
# 弹窗宿主包(= 触发判据, 也是研发沉淀进 PROFILES.host_packages 的键)。按它聚合人工筛。
|
|
host_package: Mapped[str | None] = mapped_column(String(128), index=True, nullable=True)
|
|
# 被打开的目标 App 包名(标题里"想要打开 X"的 X 是变量, 据此把它从 sign 里挖空)。
|
|
target_app: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
# 系统语言地区(zh-TW / en-US…)—— 多语言问题的核心维度。
|
|
# ⚠️ 前端 AgentStepRequest 暂未上报设备信息 → 现恒 None,待前端加 device_info 字段后回填。
|
|
system_locale: Mapped[str | None] = mapped_column(String(32), index=True, nullable=True)
|
|
|
|
# 这次兜底是否成功放行(弹窗消失=True;放弃 / LLM 没认出=False)。研发只沉淀 True 的。
|
|
exec_success: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
# 弹窗标题全文(研发据此提 launch_sign),如"「傻瓜比价」想要開啟「京東」"。
|
|
dialog_title: Mapped[str | None] = mapped_column(String(256), nullable=True)
|
|
|
|
# 大 JSON:完整样本。{is_launch_confirm, llm_model, llm_reason, plan, dialog_tree,
|
|
# device_info: {screen, locale, brand, model, android_version, rom_version}}
|
|
payload: Mapped[dict | None] = mapped_column(_JSON, nullable=True)
|
|
|
|
def __repr__(self) -> str: # pragma: no cover
|
|
return (
|
|
f"<LaunchConfirmSample id={self.id} host={self.host_package!r} "
|
|
f"locale={self.system_locale!r} success={self.exec_success}>"
|
|
)
|