fix: 上线检查改为urlwidget子控件模式,每个检查项独立dspy(bug3)
This commit is contained in:
parent
75fe89ac2e
commit
ea2f08e443
@ -57,7 +57,14 @@ PATHS_LOGINED = [
|
|||||||
f"/{MOD}/api_doc.md",
|
f"/{MOD}/api_doc.md",
|
||||||
f"/{MOD}/llm_dialog.ui",
|
f"/{MOD}/llm_dialog.ui",
|
||||||
f"/{MOD}/llm_launch_check.ui",
|
f"/{MOD}/llm_launch_check.ui",
|
||||||
f"/{MOD}/llm_launch_check_page.dspy",
|
f"/{MOD}/check_model_record.dspy",
|
||||||
|
f"/{MOD}/check_date_status.dspy",
|
||||||
|
f"/{MOD}/check_upapp.dspy",
|
||||||
|
f"/{MOD}/check_uapi.dspy",
|
||||||
|
f"/{MOD}/check_uapiio.dspy",
|
||||||
|
f"/{MOD}/check_llm_api_map.dspy",
|
||||||
|
f"/{MOD}/check_pricing_program.dspy",
|
||||||
|
f"/{MOD}/check_pricing_data.dspy",
|
||||||
f"/{MOD}/show_same_catelog_llm.ui",
|
f"/{MOD}/show_same_catelog_llm.ui",
|
||||||
f"/{MOD}/show_llms.ui",
|
f"/{MOD}/show_llms.ui",
|
||||||
f"/{MOD}/show_llms_by_providers.ui",
|
f"/{MOD}/show_llms_by_providers.ui",
|
||||||
|
|||||||
31
wwwroot/check_date_status.dspy
Normal file
31
wwwroot/check_date_status.dspy
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ 日期与状态: 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
recs = await sor.sqlExe(
|
||||||
|
"select * from llm where id=${llmid}$", {'llmid': llmid})
|
||||||
|
|
||||||
|
if not recs:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ 日期与状态: 模型不存在", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
llm = recs[0]
|
||||||
|
date_ok = bool(llm.enabled_date and llm.expired_date)
|
||||||
|
status_ok = llm.status == 'published'
|
||||||
|
|
||||||
|
if date_ok and status_ok:
|
||||||
|
text = f"✅ 日期与状态: 启用:{llm.enabled_date} 失效:{llm.expired_date} 状态:{llm.status}"
|
||||||
|
else:
|
||||||
|
text = f"❌ 日期与状态: 启用:{llm.enabled_date} 失效:{llm.expired_date} 状态:{llm.status}"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
22
wwwroot/check_llm_api_map.dspy
Normal file
22
wwwroot/check_llm_api_map.dspy
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ 能力映射(llm_api_map): 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
maps = await sor.sqlExe(
|
||||||
|
"select * from llm_api_map where llmid=${llmid}$", {'llmid': llmid})
|
||||||
|
|
||||||
|
if maps:
|
||||||
|
ppids = [m.ppid for m in maps if m.ppid]
|
||||||
|
text = f"✅ 能力映射(llm_api_map): {len(maps)}条记录, {len(ppids)}个有定价"
|
||||||
|
else:
|
||||||
|
text = "❌ 能力映射(llm_api_map): 无映射记录"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
22
wwwroot/check_model_record.dspy
Normal file
22
wwwroot/check_model_record.dspy
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ 模型记录: 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
recs = await sor.sqlExe(
|
||||||
|
"select * from llm where id=${llmid}$", {'llmid': llmid})
|
||||||
|
|
||||||
|
if recs:
|
||||||
|
llm = recs[0]
|
||||||
|
text = f"✅ 模型记录: {llm.name} ({llm.model})"
|
||||||
|
else:
|
||||||
|
text = f"❌ 模型记录: llm id={llmid} 不存在"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
36
wwwroot/check_pricing_data.dspy
Normal file
36
wwwroot/check_pricing_data.dspy
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ 定价数据(pricingdata): 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
maps = await sor.sqlExe(
|
||||||
|
"select * from llm_api_map where llmid=${llmid}$", {'llmid': llmid})
|
||||||
|
ppids = [m.ppid for m in maps if m.ppid] if maps else []
|
||||||
|
|
||||||
|
if not ppids:
|
||||||
|
text = "❌ 定价数据(pricingdata): 无定价项目"
|
||||||
|
else:
|
||||||
|
ppid = ppids[0]
|
||||||
|
async with get_sor_context(request._run_ns, 'pricing') as psor:
|
||||||
|
# First check if pricing_program exists
|
||||||
|
pregs = await psor.sqlExe(
|
||||||
|
"select * from pricing_program where id=${ppid}$", {'ppid': ppid})
|
||||||
|
if not pregs:
|
||||||
|
text = "❌ 定价数据(pricingdata): 依赖定价项目未通过"
|
||||||
|
else:
|
||||||
|
datas = await psor.sqlExe(
|
||||||
|
"select count(*) as cnt from pricingdata where ppid=${ppid}$", {'ppid': ppid})
|
||||||
|
cnt = datas[0].cnt if datas else 0
|
||||||
|
if cnt > 0:
|
||||||
|
text = f"✅ 定价数据(pricingdata): {cnt}条记录"
|
||||||
|
else:
|
||||||
|
text = "❌ 定价数据(pricingdata): 无定价数据"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
29
wwwroot/check_pricing_program.dspy
Normal file
29
wwwroot/check_pricing_program.dspy
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ 定价项目(pricing_program): 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
maps = await sor.sqlExe(
|
||||||
|
"select * from llm_api_map where llmid=${llmid}$", {'llmid': llmid})
|
||||||
|
ppids = [m.ppid for m in maps if m.ppid] if maps else []
|
||||||
|
|
||||||
|
if not ppids:
|
||||||
|
text = "❌ 定价项目(pricing_program): llm_api_map中无ppid"
|
||||||
|
else:
|
||||||
|
ppid = ppids[0]
|
||||||
|
async with get_sor_context(request._run_ns, 'pricing') as psor:
|
||||||
|
pregs = await psor.sqlExe(
|
||||||
|
"select * from pricing_program where id=${ppid}$", {'ppid': ppid})
|
||||||
|
if pregs:
|
||||||
|
text = f"✅ 定价项目(pricing_program): {pregs[0].name} (id={ppid})"
|
||||||
|
else:
|
||||||
|
text = f"❌ 定价项目(pricing_program): ppid={ppid} 未找到"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
30
wwwroot/check_uapi.dspy
Normal file
30
wwwroot/check_uapi.dspy
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ API映射(uapi): 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
recs = await sor.sqlExe("""
|
||||||
|
select a.*, e.ioid, e.stream
|
||||||
|
from llm a
|
||||||
|
join llm_api_map m on a.id = m.llmid
|
||||||
|
join upapp c on a.upappid = c.id
|
||||||
|
join uapi e on c.id = e.upappid and m.apiname = e.name
|
||||||
|
where a.id=${llmid}$""", {'llmid': llmid})
|
||||||
|
|
||||||
|
if recs:
|
||||||
|
text = f"✅ API映射(uapi): ioid={recs[0].ioid}, stream={recs[0].stream}"
|
||||||
|
else:
|
||||||
|
# Get apiname from llm
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
llm_recs = await sor.sqlExe("select apiname from llm where id=${llmid}$", {'llmid': llmid})
|
||||||
|
apiname = llm_recs[0].apiname if llm_recs else 'N/A'
|
||||||
|
text = f"❌ API映射(uapi): apiname={apiname} 在upapp中未找到"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
33
wwwroot/check_uapiio.dspy
Normal file
33
wwwroot/check_uapiio.dspy
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ IO定义(uapiio): 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
# First get ioid from uapi
|
||||||
|
recs = await sor.sqlExe("""
|
||||||
|
select e.ioid
|
||||||
|
from llm a
|
||||||
|
join llm_api_map m on a.id = m.llmid
|
||||||
|
join upapp c on a.upappid = c.id
|
||||||
|
join uapi e on c.id = e.upappid and m.apiname = e.name
|
||||||
|
where a.id=${llmid}$""", {'llmid': llmid})
|
||||||
|
|
||||||
|
if not recs:
|
||||||
|
text = "❌ IO定义(uapiio): 依赖 uapi 未通过"
|
||||||
|
else:
|
||||||
|
ioid = recs[0].ioid
|
||||||
|
recs2 = await sor.sqlExe(
|
||||||
|
"select * from uapiio where id=${ioid}$", {'ioid': ioid})
|
||||||
|
if recs2:
|
||||||
|
text = f"✅ IO定义(uapiio): uapiio id={ioid}"
|
||||||
|
else:
|
||||||
|
text = f"❌ IO定义(uapiio): ioid={ioid} 未找到"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
27
wwwroot/check_upapp.dspy
Normal file
27
wwwroot/check_upapp.dspy
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
llmid = params_kw.get('llmid', '')
|
||||||
|
|
||||||
|
if not llmid:
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": "❌ 上位系统(upapp): 缺少llmid参数", "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
||||||
|
recs = await sor.sqlExe(
|
||||||
|
"select a.* from llm a, upapp b where a.id=${llmid}$ and a.upappid=b.id",
|
||||||
|
{'llmid': llmid})
|
||||||
|
|
||||||
|
if recs:
|
||||||
|
llm = recs[0]
|
||||||
|
text = f"✅ 上位系统(upapp): upappid={llm.upappid}"
|
||||||
|
else:
|
||||||
|
# Get llm info to show upappid
|
||||||
|
llm_recs = await sor.sqlExe(
|
||||||
|
"select upappid from llm where id=${llmid}$", {'llmid': llmid})
|
||||||
|
upappid = llm_recs[0].upappid if llm_recs else '未知'
|
||||||
|
text = f"❌ 上位系统(upapp): upappid={upappid} 未找到关联"
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"widgettype": "Text",
|
||||||
|
"options": {"text": text, "i18n": false}
|
||||||
|
}, ensure_ascii=False)
|
||||||
@ -28,15 +28,64 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"name": "checks_list",
|
"name": "checks_list",
|
||||||
"spacing": 5
|
"spacing": 5
|
||||||
|
},
|
||||||
|
"subwidgets": [
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_model_record.dspy')}}?llmid={{llmid}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_date_status.dspy')}}?llmid={{llmid}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_upapp.dspy')}}?llmid={{llmid}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_uapi.dspy')}}?llmid={{llmid}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_uapiio.dspy')}}?llmid={{llmid}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_llm_api_map.dspy')}}?llmid={{llmid}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_pricing_program.dspy')}}?llmid={{llmid}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype": "urlwidget",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./check_pricing_data.dspy')}}?llmid={{llmid}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"widgettype": "Button",
|
"widgettype": "Button",
|
||||||
"options": {
|
"options": {
|
||||||
"name": "test_btn",
|
"name": "test_btn",
|
||||||
"text": "体验一次",
|
"label": "体验一次",
|
||||||
"i18n": false,
|
"i18n": false
|
||||||
"disabled": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -50,16 +99,15 @@
|
|||||||
{
|
{
|
||||||
"widgettype": "Button",
|
"widgettype": "Button",
|
||||||
"options": {
|
"options": {
|
||||||
"name": "check_charging_btn",
|
"name": "charge_btn",
|
||||||
"text": "检查计费",
|
"label": "检查计费",
|
||||||
"i18n": false,
|
"i18n": false
|
||||||
"disabled": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"widgettype": "Text",
|
"widgettype": "Text",
|
||||||
"options": {
|
"options": {
|
||||||
"name": "charging_result",
|
"name": "charge_result",
|
||||||
"text": "",
|
"text": "",
|
||||||
"i18n": false
|
"i18n": false
|
||||||
}
|
}
|
||||||
@ -67,11 +115,22 @@
|
|||||||
],
|
],
|
||||||
"binds": [
|
"binds": [
|
||||||
{
|
{
|
||||||
"wid": "self",
|
"wid": "test_btn",
|
||||||
"event": "load",
|
"event": "click",
|
||||||
"actiontype": "script",
|
"actiontype": "urldata",
|
||||||
"target": "self",
|
"target": "test_result",
|
||||||
"script": "var resp = await fetch('{{entire_url('./api/llm_launch_check_api.dspy')}}?llmid={{llmid}}&action=check'); var data = await resp.json(); var statusEl = this.getWidgetByName('check_status'); var listEl = this.getWidgetByName('checks_list'); if(data.error) { statusEl.set_text('错误: ' + data.error); return; } var html = ''; var allOk = true; (data.checks||[]).forEach(function(c){ var icon = c.passed ? '✅' : '❌'; if(!c.passed) allOk = false; html += '<div style=\"padding:4px 0\">' + icon + ' <b>' + c.name + '</b>: ' + (c.detail||'') + '</div>'; }); if(listEl && listEl.dom_element) listEl.dom_element.innerHTML = html; if(allOk) { statusEl.set_text('全部通过 ✅'); var testBtn = this.getWidgetByName('test_btn'); if(testBtn) { testBtn.dom_element.disabled = false; testBtn.dom_element.onclick = async function(){ var r2 = await fetch('{{entire_url('./api/llm_launch_check_api.dspy')}}?llmid={{llmid}}&action=inference'); var d2 = await r2.json(); var tr = this.getWidgetByName('test_result'); if(d2.success) tr.set_text('回复: ' + d2.response); else tr.set_text('失败: ' + d2.error); }.bind(this); } } else { statusEl.set_text('存在问题 ❌ 请检查下方详情'); }"
|
"options": {
|
||||||
|
"url": "{{entire_url('./api/llm_launch_check_api.dspy')}}?llmid={{llmid}}&action=inference"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wid": "charge_btn",
|
||||||
|
"event": "click",
|
||||||
|
"actiontype": "urldata",
|
||||||
|
"target": "charge_result",
|
||||||
|
"options": {
|
||||||
|
"url": "{{entire_url('./api/llm_launch_check_api.dspy')}}?llmid={{llmid}}&action=check_charging&usages={% raw %}{{"prompt_tokens":1000,"completion_tokens":500}}{% endraw %}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,170 +0,0 @@
|
|||||||
# llm_launch_check_page.dspy
|
|
||||||
# 服务端渲染模型上线检查页面,输出bricks widget JSON
|
|
||||||
# 所有检查在服务端async执行,结果直接嵌入widget
|
|
||||||
|
|
||||||
try:
|
|
||||||
llmid = params_kw.get('id', '')
|
|
||||||
|
|
||||||
if not llmid:
|
|
||||||
return json.dumps({
|
|
||||||
"widgettype": "VBox",
|
|
||||||
"options": {"width": "100%", "height": "100%", "spacing": 10},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Title", "options": {"text": "模型上线检查", "level": 2}},
|
|
||||||
{"widgettype": "Text", "options": {"text": "缺少模型ID参数", "i18n": False}}
|
|
||||||
]
|
|
||||||
}, ensure_ascii=False)
|
|
||||||
|
|
||||||
# --- 服务端执行所有检查 ---
|
|
||||||
checks = []
|
|
||||||
all_passed = True
|
|
||||||
llm_name = ''
|
|
||||||
llm_model = ''
|
|
||||||
|
|
||||||
async def add_check(name, passed, detail=''):
|
|
||||||
global all_passed
|
|
||||||
checks.append({'name': name, 'passed': passed, 'detail': detail})
|
|
||||||
if not passed:
|
|
||||||
all_passed = False
|
|
||||||
|
|
||||||
async with get_sor_context(request._run_ns, 'llmage') as sor:
|
|
||||||
recs = await sor.sqlExe(
|
|
||||||
"select * from llm where id=${llmid}$", {'llmid': llmid})
|
|
||||||
if not recs:
|
|
||||||
await add_check('模型记录', False, f'llm id={llmid} 不存在')
|
|
||||||
else:
|
|
||||||
llm = recs[0]
|
|
||||||
llm_name = llm.name or ''
|
|
||||||
llm_model = llm.model or ''
|
|
||||||
await add_check('模型记录', True, f'{llm_name} ({llm_model})')
|
|
||||||
|
|
||||||
date_ok = bool(llm.enabled_date and llm.expired_date)
|
|
||||||
status_ok = llm.status == 'published'
|
|
||||||
await add_check('日期与状态', date_ok and status_ok,
|
|
||||||
f"启用:{llm.enabled_date} 失效:{llm.expired_date} 状态:{llm.status}")
|
|
||||||
|
|
||||||
recs2 = await sor.sqlExe(
|
|
||||||
"select a.* from llm a, upapp b where a.id=${llmid}$ and a.upappid=b.id",
|
|
||||||
{'llmid': llmid})
|
|
||||||
await add_check('上位系统(upapp)', bool(recs2),
|
|
||||||
f'upappid={llm.upappid}' + ('' if recs2 else ' 未找到关联'))
|
|
||||||
|
|
||||||
recs3 = await sor.sqlExe("""
|
|
||||||
select a.*, e.ioid, e.stream
|
|
||||||
from llm a
|
|
||||||
join llm_api_map m on a.id = m.llmid
|
|
||||||
join upapp c on a.upappid = c.id
|
|
||||||
join uapi e on c.id = e.upappid and m.apiname = e.name
|
|
||||||
where a.id=${llmid}$""", {'llmid': llmid})
|
|
||||||
if recs3:
|
|
||||||
await add_check('API映射(uapi)', True, f'ioid={recs3[0].ioid}, stream={recs3[0].stream}')
|
|
||||||
ioid = recs3[0].ioid
|
|
||||||
recs4 = await sor.sqlExe(
|
|
||||||
"select * from uapiio where id=${ioid}$", {'ioid': ioid})
|
|
||||||
await add_check('IO定义(uapiio)', bool(recs4),
|
|
||||||
f'uapiio id={ioid}' if recs4 else f'ioid={ioid} 未找到')
|
|
||||||
else:
|
|
||||||
await add_check('API映射(uapi)', False, f'apiname={getattr(llm, "apiname", "N/A")} 在upapp中未找到')
|
|
||||||
await add_check('IO定义(uapiio)', False, '依赖 uapi 未通过')
|
|
||||||
|
|
||||||
maps = await sor.sqlExe(
|
|
||||||
"select * from llm_api_map where llmid=${llmid}$", {'llmid': llmid})
|
|
||||||
ppids = []
|
|
||||||
if maps:
|
|
||||||
ppids = [m.ppid for m in maps if m.ppid]
|
|
||||||
await add_check('能力映射(llm_api_map)', True, f'{len(maps)}条记录, {len(ppids)}个有定价')
|
|
||||||
else:
|
|
||||||
await add_check('能力映射(llm_api_map)', False, '无映射记录')
|
|
||||||
|
|
||||||
if ppids:
|
|
||||||
ppid = ppids[0]
|
|
||||||
async with get_sor_context(request._run_ns, 'pricing') as psor:
|
|
||||||
pregs = await psor.sqlExe(
|
|
||||||
"select * from pricing_program where id=${ppid}$", {'ppid': ppid})
|
|
||||||
if pregs:
|
|
||||||
await add_check('定价项目(pricing_program)', True, f'{pregs[0].name} (id={ppid})')
|
|
||||||
datas = await psor.sqlExe(
|
|
||||||
"select count(*) as cnt from pricingdata where ppid=${ppid}$", {'ppid': ppid})
|
|
||||||
cnt = datas[0].cnt if datas else 0
|
|
||||||
await add_check('定价数据(pricingdata)', cnt > 0,
|
|
||||||
f'{cnt}条记录' if cnt > 0 else '无定价数据')
|
|
||||||
else:
|
|
||||||
await add_check('定价项目(pricing_program)', False, f'ppid={ppid} 未找到')
|
|
||||||
await add_check('定价数据(pricingdata)', False, '依赖定价项目未通过')
|
|
||||||
else:
|
|
||||||
await add_check('定价项目(pricing_program)', False, 'llm_api_map中无ppid')
|
|
||||||
await add_check('定价数据(pricingdata)', False, '无定价项目')
|
|
||||||
|
|
||||||
# --- 构建widget JSON ---
|
|
||||||
api_url = entire_url('./api/llm_launch_check_api.dspy')
|
|
||||||
status_text = '全部通过 ✅' if all_passed else '存在问题 ❌ 请检查下方详情'
|
|
||||||
|
|
||||||
# 检查项列表:每项一行Text widget
|
|
||||||
check_widgets = []
|
|
||||||
for c in checks:
|
|
||||||
icon = '✅' if c['passed'] else '❌'
|
|
||||||
text = f"{icon} {c['name']}: {c['detail']}"
|
|
||||||
check_widgets.append({
|
|
||||||
"widgettype": "Text",
|
|
||||||
"options": {"text": text, "i18n": False}
|
|
||||||
})
|
|
||||||
|
|
||||||
# 按钮和结果显示区
|
|
||||||
subwidgets = [
|
|
||||||
{"widgettype": "Title", "options": {"text": f"模型上线检查 — {llm_name}", "level": 2}},
|
|
||||||
{"widgettype": "Text", "options": {"text": status_text, "i18n": False}},
|
|
||||||
] + check_widgets
|
|
||||||
|
|
||||||
if all_passed:
|
|
||||||
subwidgets.append({
|
|
||||||
"widgettype": "Button",
|
|
||||||
"options": {"name": "test_btn", "label": "体验一次", "i18n": False},
|
|
||||||
"binds": [{
|
|
||||||
"wid": "self",
|
|
||||||
"event": "click",
|
|
||||||
"actiontype": "urldata",
|
|
||||||
"target": "test_result",
|
|
||||||
"options": {
|
|
||||||
"url": f"{api_url}?llmid={llmid}&action=inference"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
subwidgets.append({
|
|
||||||
"widgettype": "Text",
|
|
||||||
"options": {"name": "test_result", "text": "", "i18n": False}
|
|
||||||
})
|
|
||||||
subwidgets.append({
|
|
||||||
"widgettype": "Button",
|
|
||||||
"options": {"name": "charge_btn", "label": "检查计费", "i18n": False},
|
|
||||||
"binds": [{
|
|
||||||
"wid": "self",
|
|
||||||
"event": "click",
|
|
||||||
"actiontype": "urldata",
|
|
||||||
"target": "charge_result",
|
|
||||||
"options": {
|
|
||||||
"url": f"{api_url}?llmid={llmid}&action=check_charging&usages=" + json.dumps({"prompt_tokens": 1000, "completion_tokens": 500})
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
subwidgets.append({
|
|
||||||
"widgettype": "Text",
|
|
||||||
"options": {"name": "charge_result", "text": "", "i18n": False}
|
|
||||||
})
|
|
||||||
|
|
||||||
widget = {
|
|
||||||
"widgettype": "VBox",
|
|
||||||
"options": {"width": "100%", "height": "100%", "spacing": 10},
|
|
||||||
"subwidgets": subwidgets
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.dumps(widget, ensure_ascii=False)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return json.dumps({
|
|
||||||
"widgettype": "VBox",
|
|
||||||
"options": {"width": "100%", "height": "100%", "spacing": 10},
|
|
||||||
"subwidgets": [
|
|
||||||
{"widgettype": "Title", "options": {"text": "模型上线检查", "level": 2}},
|
|
||||||
{"widgettype": "Text", "options": {"text": f"执行错误: {format_exc()}", "i18n": False}}
|
|
||||||
]
|
|
||||||
}, ensure_ascii=False)
|
|
||||||
Loading…
x
Reference in New Issue
Block a user