yumoqing 69fe362dde feat(trace): 调用原文追踪「查看IO」前端闭环+按项目费用页(2026-09-10定夺落地)
- json/llm_call_trace_list.json: noedit只读列表;exclouded隐藏id/req_path/resp_path/org_id;
  url/note加宽;kind/method内联枚举(含gen同步生成,此前草稿引用的get_llm_kind_options.dspy不存在);
  删color_mapping(bricks全库0消费的死配置);toolbar查看IO+binds urlwidget→PopupWindow(85%)
  url不带?id=${id}$——生成期ArgsConvert会eval成<built-in function id>垃圾串,
  行数据id经_add_event_data自动并入params(dapi/llmage生产同款)
- api/llm_call_trace_io.dspy: 薄代理(get_user门禁+get_userorgid机构隔离)→env.llm_call_trace_io;
  修草稿4处实锤bug:get_user未await/user.get当dict/sor块外使用/返回PopupWindow套娃
- init.py: llm_call_trace_io读表+同批次+llm_usage上下文(块内读全拷dict)→读文件
  (trace.trace_root realpath前缀校验防穿越)→TabPanel三tab(摘要Html+pre escape防注入/
  请求/响应CodeEditor readonly mode=null);单侧150K截断提示盘上路径;env注册
- api/llm_project_cost_query.dspy: 改{total,rows}契约接Tabular data_url(PageDataLoader);
  wwwroot/llm_project_cost/index.ui: InlineForm(date_from/date_to/status)+Tabular;
  script内getWidgetById起点bricks.app(弹窗DOM挂body下,app.root搜不到)
- card_popup.dspy: titles加llm_call_trace;新增page_targets白名单挂按项目费用页;
  index.ui挂两张卡片(调用原文追踪/按项目费用)
- accounting.py: _maybe_cleanup_traces每日一次接cleanup_expired(trace.py铁律3
  文档承诺worker每日调但循环没接,补齐);放抢锁前(清理幂等多进程同日无害)
- scripts/load_path.py: 注释说明/**通配已覆盖新页面(rbac check_roles_path前缀匹配)
- models/mysql.ddl/README/design-spec: 9张表同步(kind补gen枚举;3.9节;F19/F20)
- scripts/test_llm_call_trace_io.py: stub harness 22断言全过(隔离/穿越/转义/截断/每日门控)
- .gitignore: wwwroot/llm_call_trace/生成目录不入库
2026-09-11 14:58:21 +08:00

374 lines
21 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"widgettype": "VBox",
"options": {
"width": "100%",
"height": "100%",
"padding": "0"
},
"subwidgets": [
{
"widgettype": "HBox",
"options": {
"width": "100%",
"alignItems": "center",
"marginBottom": "24px"
},
"subwidgets": [
{
"widgettype": "Title2",
"options": {
"text": "模型治理"
}
},
{
"widgettype": "Filler"
},
{
"widgettype": "Text",
"options": {
"text": "供应商/账号/模型 · 容错策略 · 限额限流 · 双维度记账 · 点击卡片弹窗处理",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "urlwidget",
"options": {
"url": "{{entire_url('/pipeline-llm/api/llm_dashboard_widget.dspy')}}"
}
},
{
"widgettype": "VScrollPanel",
"options": {
"css": "filler"
},
"subwidgets": [
{
"widgettype": "VBox",
"options": {
"spacing": 24
},
"subwidgets": [
{
"widgettype": "ResponsableBox",
"options": {
"gap": "16px",
"minWidth": "300px"
},
"subwidgets": [
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_vendor');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "供应商与端点",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "供应商协议 + 全球端点目录(国内/国际,配置一次全账号共用)",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_model');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "模型注册",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "能力分类t2t/…、挂定价项目ppid、成本/售价 · 🤖自动配置 · ✅上线检查",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_api_profile');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "适配模板",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "协议×能力形态的请求/响应模板(按形态去重,不按模型开)",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_org_policy');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "组织容错策略",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "组织级主模型 + 备模型链 + 端点偏好prefer/must",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_org_quota');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "组织限额限流",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "组织池充值/余额 + 组织 QPM 上限",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_user_quota');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "个人限额限流",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "个人额度上限 + 个人 QPM共享组织池模式",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_usage');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "用量流水",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "双维度记账:成本侧(账号)+ 消费侧(组织/个人)",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_project_cost');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "按项目费用",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "按项目分组统计调用次数/成本/客户应付/token非项目调用单列一组",
"cfontsize": 1.2
}
}
]
},
{
"widgettype": "VBox",
"options": {
"css": "card",
"cwidth": 25,
"padding": "16px",
"cursor": "pointer"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var old=bricks.getWidgetById('llm_card_pw',bricks.app);if(old&&old.destroy){old.destroy();}var r=await fetch('{{entire_url('/pipeline-llm/api/card_popup.dspy')}}?target=llm_call_trace');var d=await r.json();if(d&&d.widgettype){bricks.widgetBuild(d,bricks.app);}else{bricks.show_message({title:'打开失败',message:'未能加载功能窗口'});}"
}
],
"subwidgets": [
{
"widgettype": "Title4",
"options": {
"text": "调用原文追踪",
"marginBottom": "8px"
}
},
{
"widgettype": "Text",
"options": {
"text": "每次上游往返的上行请求/下行响应原文脱敏落盘保留90天选中行点「查看IO」",
"cfontsize": 1.2
}
}
]
}
]
}
]
}
]
}
]
}