pipeline-sdlc/wwwroot/api/cockpit_chat.dspy

147 lines
5.2 KiB
Plaintext

# cockpit_chat.dspy - Send message or list conversation
# POST: action=send_message, iteration_id, message_text
# GET: action=list_messages, iteration_id (optional), task_id (optional)
action = (params_kw or {}).get('action', 'list_messages')
dbname = get_module_dbname('pipeline-sdlc')
if action == 'send_message':
iteration_id = (params_kw or {}).get('iteration_id', '')
task_id = (params_kw or {}).get('task_id', '')
message_text = (params_kw or {}).get('message_text', '').strip()
if not iteration_id or not message_text:
return json.dumps({"error": "Missing iteration_id or message_text"}, ensure_ascii=False)
uid = await get_user()
async with DBPools().sqlorContext(dbname) as sor:
# Save user message
msg_id = getID()
await sor.I('sd_conversations', {
'id': msg_id,
'iteration_id': iteration_id,
'task_id': task_id or '',
'step_name': '',
'role': 'user',
'content': message_text,
'attachments': '[]',
'msg_type': 'text',
'org_id': '0',
'created_by': uid
})
# Generate agent response
# 1. Check if there's an active pipeline task for this iteration
if task_id:
agent_reply = f"收到你的消息。当前任务 {task_id} 正在执行中,你的输入已记录。"
else:
# Check for existing iterations
iters = await sor.sqlExe(
"SELECT id, task_id, status FROM sd_iterations WHERE id=${iid}$", {"iid": iteration_id})
if iters:
it = iters[0]
if hasattr(it, 'task_id') and it.task_id:
agent_reply = f"收到。迭代任务 {it.task_id} 状态: {it.status}。"
else:
agent_reply = f"收到你的需求:「{message_text[:50]}...」。请确认是否要为此迭代启动开发产线?"
else:
agent_reply = f"收到你的需求:「{message_text[:50]}...」。建议先在项目管理中创建项目和迭代。"
# Save agent message
agent_msg_id = getID()
await sor.I('sd_conversations', {
'id': agent_msg_id,
'iteration_id': iteration_id,
'task_id': task_id or '',
'step_name': '',
'role': 'agent',
'content': agent_reply,
'attachments': '[]',
'msg_type': 'text',
'org_id': '0',
'created_by': 'system'
})
return json.dumps({"success": True, "message_id": msg_id}, ensure_ascii=False)
else:
# list_messages - return messages as Bricks widget JSON
iteration_id = (params_kw or {}).get('iteration_id', '')
task_id = (params_kw or {}).get('task_id', '')
msgs = []
if iteration_id or task_id:
async with DBPools().sqlorContext(dbname) as sor:
where = []
params = {}
if task_id:
where.append("task_id=${tid}$")
params["tid"] = task_id
if iteration_id:
where.append("iteration_id=${iid}$")
params["iid"] = iteration_id
sql = f"SELECT role, content, msg_type, created_at FROM sd_conversations WHERE {' OR '.join(where)} ORDER BY created_at ASC LIMIT 50"
msgs = await sor.sqlExe(sql, params)
# Build chat messages widget
msg_widgets = []
for m in msgs:
role = m.role if hasattr(m, 'role') else ''
content = m.content if hasattr(m, 'content') else ''
if role == 'agent':
bg = '#e8f0fe'
align = 'flex-start'
label = 'Agent'
label_color = '#3b82f6'
elif role == 'user':
bg = '#dbeafe'
align = 'flex-end'
label = '你'
label_color = '#2563eb'
else:
bg = '#f1f5f9'
align = 'center'
label = '系统'
label_color = '#94a3b8'
msg_widgets.append({
"widgettype": "VBox",
"options": {
"width": "85%",
"alignSelf": align,
"bgcolor": bg,
"borderRadius": "12px",
"padding": "12px 16px",
"marginBottom": "10px",
"gap": "4px"
},
"subwidgets": [
{"widgettype": "Text", "options": {
"text": label, "cfontsize": 0.75,
"color": label_color, "fontWeight": "bold"
}},
{"widgettype": "Text", "options": {
"text": content, "cfontsize": 0.95,
"color": "#1e293b", "whiteSpace": "pre-wrap"
}}
]
})
if not msg_widgets:
msg_widgets.append({
"widgettype": "Text",
"options": {
"text": "暂无对话记录。选择一个迭代后,在下方输入框中开始对话。",
"cfontsize": 0.9, "color": "#94a3b8", "padding": "20px"
}
})
return {
"widgettype": "VBox",
"options": {"width": "100%", "padding": "4px"},
"subwidgets": msg_widgets
}