update pay function
@@ -12,6 +12,7 @@ from typing import List, Dict, Any, Optional, Literal, AsyncGenerator
|
|||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
import logging
|
import logging
|
||||||
import httpx
|
import httpx
|
||||||
|
import time
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import mcp_database as db
|
import mcp_database as db
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
@@ -2474,7 +2475,7 @@ MEETING_ROLES = {
|
|||||||
"nickname": "决策者",
|
"nickname": "决策者",
|
||||||
"role_type": "manager",
|
"role_type": "manager",
|
||||||
"avatar": "/avatars/fund_manager.png",
|
"avatar": "/avatars/fund_manager.png",
|
||||||
"model": "kimi-k2-thinking",
|
"model": "deepseek",
|
||||||
"color": "#8B5CF6",
|
"color": "#8B5CF6",
|
||||||
"description": "综合分析做出最终决策",
|
"description": "综合分析做出最终决策",
|
||||||
"tools": ROLE_TOOLS["fund_manager"],
|
"tools": ROLE_TOOLS["fund_manager"],
|
||||||
@@ -2600,6 +2601,7 @@ async def stream_role_response(
|
|||||||
|
|
||||||
for tool_call in assistant_message.tool_calls:
|
for tool_call in assistant_message.tool_calls:
|
||||||
tool_name = tool_call.function.name
|
tool_name = tool_call.function.name
|
||||||
|
tool_call_id = tool_call.id
|
||||||
try:
|
try:
|
||||||
arguments = json.loads(tool_call.function.arguments)
|
arguments = json.loads(tool_call.function.arguments)
|
||||||
except:
|
except:
|
||||||
@@ -2608,19 +2610,31 @@ async def stream_role_response(
|
|||||||
# 发送工具调用开始事件
|
# 发送工具调用开始事件
|
||||||
yield {
|
yield {
|
||||||
"type": "tool_call_start",
|
"type": "tool_call_start",
|
||||||
"tool": tool_name,
|
"tool_call_id": tool_call_id,
|
||||||
|
"tool_name": tool_name,
|
||||||
"arguments": arguments
|
"arguments": arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
# 执行工具调用
|
# 执行工具调用
|
||||||
|
start_time = time.time()
|
||||||
result = await call_role_tool(role_id, tool_name, arguments)
|
result = await call_role_tool(role_id, tool_name, arguments)
|
||||||
tool_calls_made.append(result)
|
execution_time = time.time() - start_time
|
||||||
|
tool_calls_made.append({
|
||||||
|
"tool_call_id": tool_call_id,
|
||||||
|
"tool_name": tool_name,
|
||||||
|
"arguments": arguments,
|
||||||
|
"result": result,
|
||||||
|
"execution_time": execution_time
|
||||||
|
})
|
||||||
|
|
||||||
# 发送工具调用结果事件
|
# 发送工具调用结果事件
|
||||||
yield {
|
yield {
|
||||||
"type": "tool_call_result",
|
"type": "tool_call_result",
|
||||||
"tool": tool_name,
|
"tool_call_id": tool_call_id,
|
||||||
"result": result
|
"tool_name": tool_name,
|
||||||
|
"result": result,
|
||||||
|
"status": "success" if result.get("success") else "error",
|
||||||
|
"execution_time": execution_time
|
||||||
}
|
}
|
||||||
|
|
||||||
# 添加工具结果到消息
|
# 添加工具结果到消息
|
||||||
@@ -2715,11 +2729,11 @@ async def stream_investment_meeting(request: MeetingRequest):
|
|||||||
|
|
||||||
async for event in stream_role_response(role_id, request.topic, accumulated_context, role_tools):
|
async for event in stream_role_response(role_id, request.topic, accumulated_context, role_tools):
|
||||||
if event["type"] == "tool_call_start":
|
if event["type"] == "tool_call_start":
|
||||||
yield f"data: {json.dumps({'type': 'tool_call_start', 'role_id': role_id, 'tool': event['tool'], 'arguments': event['arguments']}, ensure_ascii=False)}\n\n"
|
yield f"data: {json.dumps({'type': 'tool_call_start', 'role_id': role_id, 'tool_call_id': event['tool_call_id'], 'tool_name': event['tool_name'], 'arguments': event['arguments']}, ensure_ascii=False)}\n\n"
|
||||||
|
|
||||||
elif event["type"] == "tool_call_result":
|
elif event["type"] == "tool_call_result":
|
||||||
yield f"data: {json.dumps({'type': 'tool_call_result', 'role_id': role_id, 'tool': event['tool'], 'result': event['result']}, ensure_ascii=False)}\n\n"
|
yield f"data: {json.dumps({'type': 'tool_call_result', 'role_id': role_id, 'tool_call_id': event['tool_call_id'], 'tool_name': event['tool_name'], 'result': event['result'], 'status': event['status'], 'execution_time': event['execution_time']}, ensure_ascii=False)}\n\n"
|
||||||
tool_calls.append(event["result"])
|
tool_calls.append(event)
|
||||||
|
|
||||||
elif event["type"] == "content_delta":
|
elif event["type"] == "content_delta":
|
||||||
yield f"data: {json.dumps({'type': 'content_delta', 'role_id': role_id, 'content': event['content']}, ensure_ascii=False)}\n\n"
|
yield f"data: {json.dumps({'type': 'content_delta', 'role_id': role_id, 'content': event['content']}, ensure_ascii=False)}\n\n"
|
||||||
@@ -2765,10 +2779,10 @@ async def stream_investment_meeting(request: MeetingRequest):
|
|||||||
|
|
||||||
async for event in stream_role_response("fund_manager", request.topic, accumulated_context, fm_tools):
|
async for event in stream_role_response("fund_manager", request.topic, accumulated_context, fm_tools):
|
||||||
if event["type"] == "tool_call_start":
|
if event["type"] == "tool_call_start":
|
||||||
yield f"data: {json.dumps({'type': 'tool_call_start', 'role_id': 'fund_manager', 'tool': event['tool'], 'arguments': event['arguments']}, ensure_ascii=False)}\n\n"
|
yield f"data: {json.dumps({'type': 'tool_call_start', 'role_id': 'fund_manager', 'tool_call_id': event['tool_call_id'], 'tool_name': event['tool_name'], 'arguments': event['arguments']}, ensure_ascii=False)}\n\n"
|
||||||
elif event["type"] == "tool_call_result":
|
elif event["type"] == "tool_call_result":
|
||||||
yield f"data: {json.dumps({'type': 'tool_call_result', 'role_id': 'fund_manager', 'tool': event['tool'], 'result': event['result']}, ensure_ascii=False)}\n\n"
|
yield f"data: {json.dumps({'type': 'tool_call_result', 'role_id': 'fund_manager', 'tool_call_id': event['tool_call_id'], 'tool_name': event['tool_name'], 'result': event['result'], 'status': event['status'], 'execution_time': event['execution_time']}, ensure_ascii=False)}\n\n"
|
||||||
fm_tool_calls.append(event["result"])
|
fm_tool_calls.append(event)
|
||||||
elif event["type"] == "content_delta":
|
elif event["type"] == "content_delta":
|
||||||
yield f"data: {json.dumps({'type': 'content_delta', 'role_id': 'fund_manager', 'content': event['content']}, ensure_ascii=False)}\n\n"
|
yield f"data: {json.dumps({'type': 'content_delta', 'role_id': 'fund_manager', 'content': event['content']}, ensure_ascii=False)}\n\n"
|
||||||
fm_full_content += event["content"]
|
fm_full_content += event["content"]
|
||||||
|
|||||||
BIN
public/images/agent/simons.png
Normal file
|
After Width: | Height: | Size: 380 KiB |
BIN
public/images/agent/基金经理.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/images/agent/大空头.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
public/images/agent/巴菲特.png
Normal file
|
After Width: | Height: | Size: 562 KiB |
BIN
public/images/agent/牢大.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 918 KiB |
|
Before Width: | Height: | Size: 795 KiB |
|
Before Width: | Height: | Size: 1017 KiB |
|
Before Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 640 KiB |
|
Before Width: | Height: | Size: 315 KiB |
|
Before Width: | Height: | Size: 479 KiB |
|
Before Width: | Height: | Size: 553 KiB |
|
Before Width: | Height: | Size: 556 KiB |
|
Before Width: | Height: | Size: 443 KiB |
|
Before Width: | Height: | Size: 607 KiB |
@@ -519,8 +519,10 @@ export const agentHandlers = [
|
|||||||
await delay(200);
|
await delay(200);
|
||||||
|
|
||||||
// 发送工具调用
|
// 发送工具调用
|
||||||
|
const toolCallResults = [];
|
||||||
for (const tool of role.tools) {
|
for (const tool of role.tools) {
|
||||||
const toolCallId = `tc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
const toolCallId = `tc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||||
|
const execTime = 0.5 + Math.random() * 0.5;
|
||||||
|
|
||||||
// tool_call_start
|
// tool_call_start
|
||||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
||||||
@@ -538,11 +540,20 @@ export const agentHandlers = [
|
|||||||
type: 'tool_call_result',
|
type: 'tool_call_result',
|
||||||
role_id: role.role_id,
|
role_id: role.role_id,
|
||||||
tool_call_id: toolCallId,
|
tool_call_id: toolCallId,
|
||||||
result: tool.result,
|
tool_name: tool.name,
|
||||||
|
result: { success: true, data: tool.result },
|
||||||
status: 'success',
|
status: 'success',
|
||||||
execution_time: 0.5 + Math.random() * 0.5,
|
execution_time: execTime,
|
||||||
})}\n\n`));
|
})}\n\n`));
|
||||||
|
|
||||||
|
toolCallResults.push({
|
||||||
|
tool_call_id: toolCallId,
|
||||||
|
tool_name: tool.name,
|
||||||
|
result: { success: true, data: tool.result },
|
||||||
|
status: 'success',
|
||||||
|
execution_time: execTime,
|
||||||
|
});
|
||||||
|
|
||||||
await delay(200);
|
await delay(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,8 +572,13 @@ export const agentHandlers = [
|
|||||||
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
|
||||||
type: 'message_complete',
|
type: 'message_complete',
|
||||||
role_id: role.role_id,
|
role_id: role.role_id,
|
||||||
|
message: {
|
||||||
|
role_id: role.role_id,
|
||||||
|
role_name: role.role_name,
|
||||||
content: role.content,
|
content: role.content,
|
||||||
|
tool_calls: toolCallResults,
|
||||||
is_conclusion: role.is_conclusion || false,
|
is_conclusion: role.is_conclusion || false,
|
||||||
|
},
|
||||||
})}\n\n`));
|
})}\n\n`));
|
||||||
|
|
||||||
await delay(500);
|
await delay(500);
|
||||||
|
|||||||
@@ -358,7 +358,9 @@ export const useInvestmentMeeting = ({
|
|||||||
|
|
||||||
case 'message_complete':
|
case 'message_complete':
|
||||||
if (data.role_id) {
|
if (data.role_id) {
|
||||||
finishStreamingMessage(data.role_id, data.content);
|
// 后端可能发送 message 对象或直接 content
|
||||||
|
const finalContent = data.message?.content || data.content;
|
||||||
|
finishStreamingMessage(data.role_id, finalContent);
|
||||||
setSpeakingRoleId(null);
|
setSpeakingRoleId(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -561,7 +563,9 @@ export const useInvestmentMeeting = ({
|
|||||||
|
|
||||||
case 'message_complete':
|
case 'message_complete':
|
||||||
if (data.role_id) {
|
if (data.role_id) {
|
||||||
finishStreamingMessage(data.role_id, data.content);
|
// 后端可能发送 message 对象或直接 content
|
||||||
|
const finalContent = data.message?.content || data.content;
|
||||||
|
finishStreamingMessage(data.role_id, finalContent);
|
||||||
setSpeakingRoleId(null);
|
setSpeakingRoleId(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||