pipeline-sdlc/wwwroot/api/task_io.dspy

167 lines
7.0 KiB
Plaintext
Raw 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.

# task_io.dspy - 任务的输入输出ResourceBrowser 右侧面板5 秒自动刷新)
import json
uid = await get_user()
if not uid:
uid = 'user-01'
task_id = (params_kw or {}).get('id', '').strip()
dbname = get_module_dbname('pipeline-sdlc')
_state_colors = {
'completed': '#16a34a',
'approved': '#16a34a',
'running': '#2563eb',
'failed': '#dc2626',
'waiting': '#f0a040',
'submitted': '#64748b',
'review': '#2196f3',
'rejected': '#dc2626',
'paused': '#f0a040',
'cancelled': '#64748b', 'qc_review': '#8b5cf6',
}
if not task_id:
return json.dumps({
"widgettype": "Text",
"options": {"text": "请选择左侧任务查看输入输出", "cfontsize": 0.9, "color": "#94a3b8", "padding": "16px"},
}, ensure_ascii=False)
async with DBPools().sqlorContext(dbname) as sor:
recs = await sor.sqlExe(
"SELECT id, title, role, state, params, last_error, created_at, updated_at "
"FROM pipeline_tasks WHERE id=${t}$", {"t": task_id})
if not recs:
return json.dumps({
"widgettype": "Text",
"options": {"text": "任务不存在", "cfontsize": 0.9, "color": "#94a3b8", "padding": "16px"},
}, ensure_ascii=False)
task = recs[0]
title = getattr(task, 'title', '') or ''
role = getattr(task, 'role', '') or ''
state = getattr(task, 'state', '') or ''
last_error = getattr(task, 'last_error', '') or ''
created_at = str(getattr(task, 'created_at', '') or '')[:16]
updated_at = str(getattr(task, 'updated_at', '') or '')[:16]
# 输入params 里的 description / input_text
params_str = getattr(task, 'params', '') or ''
description = ''
try:
p = json.loads(params_str) if params_str else {}
description = p.get('description', '') or p.get('input_text', '') or p.get('prompt', '') or ''
except Exception:
description = params_str
# 输出:交付件
dels = await sor.sqlExe(
"SELECT deliverable_type, title, content, review_status, quality_score, review_comment "
"FROM pipeline_deliverables WHERE task_id=${t}$ ORDER BY created_at DESC", {"t": task_id})
sc = _state_colors.get(state, '#64748b')
subwidgets = []
# 标题行:任务名 + 状态
subwidgets.append({
"widgettype": "Text",
"options": {"text": title, "halign": "left", "cfontsize": 1.15, "style": {"fontWeight": "bold", "color": "#1e293b"}},
})
subwidgets.append({
"widgettype": "HBox",
"options": {"gap": "12px", "width": "100%"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": state, "cfontsize": 0.75, "color": "#ffffff", "halign": "left", "padding": "1px 10px", "style": {"background": sc, "borderRadius": "12px", "fontWeight": "bold"}}},
{"widgettype": "Text", "options": {"text": "角色: " + role, "cfontsize": 0.8, "color": "#64748b", "halign": "left"}},
{"widgettype": "Text", "options": {"text": "更新: " + updated_at, "cfontsize": 0.75, "color": "#94a3b8", "halign": "left"}},
{"widgettype": "Filler"},
],
})
if last_error:
subwidgets.append({
"widgettype": "Text",
"options": {"text": "错误: " + last_error[:300], "halign": "left", "cfontsize": 0.8, "css": "resp-error", "wrap": True},
})
# 输入
subwidgets.append({
"widgettype": "Text",
"options": {"text": "—— 输入 ——", "halign": "left", "cfontsize": 0.85, "style": {"fontWeight": "bold", "color": "#3b82f6", "marginTop": "8px"}},
})
subwidgets.append({
"widgettype": "Text",
"options": {"text": (description or "(无)")[:4000], "halign": "left", "cfontsize": 0.85, "color": "#334155", "wrap": True, "css": "card"},
})
# 输出
subwidgets.append({
"widgettype": "Text",
"options": {"text": "—— 输出(交付件)——", "halign": "left", "cfontsize": 0.85, "style": {"fontWeight": "bold", "color": "#16a34a", "marginTop": "8px"}},
})
if not dels:
subwidgets.append({
"widgettype": "Text",
"options": {"text": "(暂无交付件)", "halign": "left", "cfontsize": 0.8, "color": "#94a3b8"},
})
else:
for d in dels:
d_type = getattr(d, 'deliverable_type', '') or ''
d_title = getattr(d, 'title', '') or ''
d_content = getattr(d, 'content', '') or ''
d_status = getattr(d, 'review_status', '') or ''
d_score = getattr(d, 'quality_score', '') or ''
d_comment = getattr(d, 'review_comment', '') or ''
card = {
"widgettype": "VBox",
"options": {"css": "card", "gap": "4px", "width": "100%", "padding": "8px"},
"subwidgets": [
{"widgettype": "HBox", "options": {"gap": "8px", "width": "100%"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": d_type, "cfontsize": 0.8, "color": "#3b82f6", "halign": "left"}},
{"widgettype": "Text", "options": {"text": d_title, "cfontsize": 0.8, "color": "#1e293b", "halign": "left"}},
{"widgettype": "Filler"},
{"widgettype": "Text", "options": {"text": d_status, "cfontsize": 0.75, "color": "#94a3b8", "halign": "left"}},
]},
{"widgettype": "Text", "options": {"text": (d_content or "")[:3000], "cfontsize": 0.78, "color": "#475569", "wrap": True, "halign": "left"}},
],
}
if d_comment:
card["subwidgets"].append({
"widgettype": "Text",
"options": {"text": "审核意见: " + d_comment[:300], "cfontsize": 0.75, "color": "#f0a040", "wrap": True, "halign": "left"},
})
subwidgets.append(card)
# 5 秒刷新仅非终态任务刷新。终态completed/approved/failed/rejected/cancelled不再变化
# 切到终态任务时清除定时器非终态任务设置定时器。params.state 由 binds.params 传入 script。
refresh_script = (
"var _term=['completed','approved','failed','rejected','cancelled'];"
"if(_term.indexOf(params.state)>=0){"
"if(window._task_io_timer){clearInterval(window._task_io_timer);window._task_io_timer=null;}"
"}else if(!window._task_io_timer){"
"window._task_io_timer=setInterval(function(){"
"var rb=bricks.getWidgetById('task_rb',bricks.app);"
"if(rb&&rb.current_id){var cid=rb.current_id;rb.current_id=undefined;rb.render_browser(cid);}"
"},5000);}"
)
resp = {
"widgettype": "VBox",
"options": {"width": "100%", "height": "100%", "padding": "12px", "gap": "6px", "overflowY": "auto"},
"subwidgets": subwidgets,
"binds": [{
"wid": "self",
"event": "on_parent",
"actiontype": "script",
"target": "self",
"params": {"state": state},
"script": refresh_script,
}],
}
return json.dumps(resp, ensure_ascii=False)