|
@@ -33,8 +33,7 @@ except ImportError as e:
|
|
|
# 加载环境变量
|
|
|
dotenv.load_dotenv()
|
|
|
|
|
|
-# 全局消息队列
|
|
|
-message_queue: List[Dict[str, Any]] = []
|
|
|
+# 移除消息队列,现在使用直接SSE流
|
|
|
|
|
|
# 全局Agent实例和Memory
|
|
|
global_agent = None
|
|
@@ -423,6 +422,25 @@ async def home():
|
|
|
40% { content: '..'; }
|
|
|
50% { content: '...'; }
|
|
|
}
|
|
|
+
|
|
|
+ /* 打字机光标效果 */
|
|
|
+ .typing-cursor {
|
|
|
+ display: inline-block;
|
|
|
+ background-color: #333;
|
|
|
+ width: 2px;
|
|
|
+ height: 1em;
|
|
|
+ margin-left: 1px;
|
|
|
+ animation: blink 1s infinite;
|
|
|
+ }
|
|
|
+
|
|
|
+ .message.bot .typing-cursor {
|
|
|
+ background-color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes blink {
|
|
|
+ 0%, 50% { opacity: 1; }
|
|
|
+ 51%, 100% { opacity: 0; }
|
|
|
+ }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
@@ -448,7 +466,7 @@ async def home():
|
|
|
type="text"
|
|
|
id="messageInput"
|
|
|
class="message-input"
|
|
|
- placeholder="输入您的消息... (输入 '记忆' 查看我的记忆状态)"
|
|
|
+ placeholder="输入您的消息... (现在支持打字机效果!输入 '记忆' 查看记忆状态)"
|
|
|
maxlength="500"
|
|
|
>
|
|
|
<button id="sendButton" class="send-button">发送</button>
|
|
@@ -456,8 +474,8 @@ async def home():
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
- let eventSource = null;
|
|
|
- let isConnected = false;
|
|
|
+ // 全局变量
|
|
|
+ let currentBotMessageElement = null; // 当前正在构建的机器人消息元素
|
|
|
|
|
|
const messagesContainer = document.getElementById('messagesContainer');
|
|
|
const messageInput = document.getElementById('messageInput');
|
|
@@ -474,61 +492,103 @@ async def home():
|
|
|
sendButton.disabled = false;
|
|
|
messageInput.focus();
|
|
|
|
|
|
- // 显示欢迎消息
|
|
|
- addMessage('🎉 欢迎使用AI实时对话窗口!我是您的智能助手,具有记忆功能,可以记住我们的对话历史。请开始聊天吧~', 'system');
|
|
|
+ // 显示欢迎消息
|
|
|
+ addMessage('🎉 欢迎使用AI实时对话窗口!我是您的智能助手,具有记忆功能和打字机效果。我会一个词一个词地回复您,就像真人打字一样!请开始聊天吧~', 'system');
|
|
|
|
|
|
- // 连接SSE
|
|
|
- connectSSE();
|
|
|
+ // 更新状态
|
|
|
+ statusBar.textContent = '✅ 已就绪 - 请开始对话';
|
|
|
+ statusBar.style.background = '#d4edda';
|
|
|
+ statusBar.style.color = '#155724';
|
|
|
});
|
|
|
|
|
|
- // 连接SSE
|
|
|
- function connectSSE() {
|
|
|
- try {
|
|
|
- console.log('连接SSE...');
|
|
|
- eventSource = new EventSource('/sse/chat');
|
|
|
+ // 创建单次SSE连接用于获取回复
|
|
|
+ function createSSEConnection(message) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const encodedMessage = encodeURIComponent(message);
|
|
|
+ const eventSource = new EventSource(`/api/chat?message=${encodedMessage}`);
|
|
|
|
|
|
eventSource.onopen = function() {
|
|
|
- console.log('SSE连接成功');
|
|
|
- isConnected = true;
|
|
|
- statusBar.textContent = '✅ 已连接 - 消息将实时更新';
|
|
|
- statusBar.style.background = '#d4edda';
|
|
|
- statusBar.style.color = '#155724';
|
|
|
+ console.log('SSE连接已建立');
|
|
|
+ statusBar.textContent = '🔄 正在处理消息...';
|
|
|
+ statusBar.style.background = '#fff3cd';
|
|
|
+ statusBar.style.color = '#856404';
|
|
|
};
|
|
|
|
|
|
eventSource.onmessage = function(event) {
|
|
|
try {
|
|
|
const data = JSON.parse(event.data);
|
|
|
- handleMessage(data);
|
|
|
+ handleSSEMessage(data);
|
|
|
+
|
|
|
+ // 当收到complete消息时关闭连接
|
|
|
+ if (data.type === 'complete') {
|
|
|
+ eventSource.close();
|
|
|
+ resolve();
|
|
|
+ }
|
|
|
} catch (e) {
|
|
|
console.error('消息解析错误:', e);
|
|
|
+ eventSource.close();
|
|
|
+ reject(e);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
eventSource.onerror = function() {
|
|
|
console.log('SSE连接失败');
|
|
|
- isConnected = false;
|
|
|
- statusBar.textContent = '⚠️ 连接失败 - 使用离线模式';
|
|
|
+ eventSource.close();
|
|
|
+ statusBar.textContent = '❌ 连接失败';
|
|
|
statusBar.style.background = '#f8d7da';
|
|
|
statusBar.style.color = '#721c24';
|
|
|
+ reject(new Error('SSE连接失败'));
|
|
|
};
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- console.error('SSE初始化错误:', error);
|
|
|
- statusBar.textContent = '📱 离线模式';
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- // 处理消息
|
|
|
- function handleMessage(data) {
|
|
|
- console.log('收到消息:', data);
|
|
|
+ // 处理SSE消息
|
|
|
+ function handleSSEMessage(data) {
|
|
|
+ console.log('收到SSE消息:', data);
|
|
|
|
|
|
switch(data.type) {
|
|
|
+ case 'status':
|
|
|
+ // 更新状态栏显示处理进度
|
|
|
+ statusBar.textContent = data.message;
|
|
|
+ statusBar.style.background = '#fff3cd';
|
|
|
+ statusBar.style.color = '#856404';
|
|
|
+ break;
|
|
|
+ case 'bot_message_start':
|
|
|
+ // 开始新的机器人回复(打字机效果)
|
|
|
+ hideTypingIndicator();
|
|
|
+ currentBotMessageElement = createEmptyBotMessage();
|
|
|
+ break;
|
|
|
+ case 'bot_message_token':
|
|
|
+ // 添加单个单词到当前机器人回复
|
|
|
+ if (currentBotMessageElement) {
|
|
|
+ appendTokenToBotMessage(currentBotMessageElement, data.token);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'bot_message_end':
|
|
|
+ // 完成机器人回复
|
|
|
+ if (currentBotMessageElement) {
|
|
|
+ removeTypingCursor(currentBotMessageElement);
|
|
|
+ }
|
|
|
+ currentBotMessageElement = null;
|
|
|
+ console.log('✅ 打字机效果回复完成:', data.complete_message);
|
|
|
+ break;
|
|
|
case 'bot_message':
|
|
|
+ // 兼容旧版本的完整消息模式
|
|
|
hideTypingIndicator();
|
|
|
addMessage(data.message, 'bot');
|
|
|
break;
|
|
|
- case 'system_message':
|
|
|
- addMessage(data.message, 'system');
|
|
|
+ case 'complete':
|
|
|
+ // 回复完成,更新状态
|
|
|
+ statusBar.textContent = '✅ 已就绪 - 请开始对话';
|
|
|
+ statusBar.style.background = '#d4edda';
|
|
|
+ statusBar.style.color = '#155724';
|
|
|
+ break;
|
|
|
+ case 'error':
|
|
|
+ hideTypingIndicator();
|
|
|
+ addMessage('❌ 错误: ' + data.message, 'system');
|
|
|
+ statusBar.textContent = '❌ 处理失败';
|
|
|
+ statusBar.style.background = '#f8d7da';
|
|
|
+ statusBar.style.color = '#721c24';
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -555,6 +615,61 @@ async def home():
|
|
|
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
|
}
|
|
|
|
|
|
+ // 创建空的机器人消息元素(用于打字机效果)
|
|
|
+ function createEmptyBotMessage() {
|
|
|
+ console.log('创建空的机器人消息元素');
|
|
|
+
|
|
|
+ const messageDiv = document.createElement('div');
|
|
|
+ messageDiv.className = 'message bot';
|
|
|
+
|
|
|
+ const bubbleDiv = document.createElement('div');
|
|
|
+ bubbleDiv.className = 'message-bubble';
|
|
|
+
|
|
|
+ // 添加打字光标
|
|
|
+ const cursor = document.createElement('span');
|
|
|
+ cursor.className = 'typing-cursor';
|
|
|
+ bubbleDiv.appendChild(cursor);
|
|
|
+
|
|
|
+ const timeDiv = document.createElement('div');
|
|
|
+ timeDiv.className = 'message-time';
|
|
|
+ timeDiv.textContent = new Date().toLocaleTimeString();
|
|
|
+
|
|
|
+ messageDiv.appendChild(bubbleDiv);
|
|
|
+ messageDiv.appendChild(timeDiv);
|
|
|
+
|
|
|
+ messagesContainer.appendChild(messageDiv);
|
|
|
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
|
+
|
|
|
+ return messageDiv;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 向机器人消息添加单词(打字机效果)
|
|
|
+ function appendTokenToBotMessage(messageElement, token) {
|
|
|
+ if (!messageElement) return;
|
|
|
+
|
|
|
+ const bubbleDiv = messageElement.querySelector('.message-bubble');
|
|
|
+ const cursor = bubbleDiv.querySelector('.typing-cursor');
|
|
|
+
|
|
|
+ if (bubbleDiv && cursor) {
|
|
|
+ // 在光标前插入单词
|
|
|
+ const textNode = document.createTextNode(token);
|
|
|
+ bubbleDiv.insertBefore(textNode, cursor);
|
|
|
+
|
|
|
+ // 滚动到底部,保持跟踪打字进度
|
|
|
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 移除打字光标
|
|
|
+ function removeTypingCursor(messageElement) {
|
|
|
+ if (!messageElement) return;
|
|
|
+
|
|
|
+ const cursor = messageElement.querySelector('.typing-cursor');
|
|
|
+ if (cursor) {
|
|
|
+ cursor.remove();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 显示输入指示器
|
|
|
function showTypingIndicator() {
|
|
|
typingIndicator.style.display = 'block';
|
|
@@ -608,59 +723,49 @@ async def home():
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 发送消息
|
|
|
- async function sendMessage() {
|
|
|
- const message = messageInput.value.trim();
|
|
|
- console.log('准备发送消息:', message);
|
|
|
-
|
|
|
- if (!message) {
|
|
|
- console.log('消息为空');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查特殊命令
|
|
|
- if (message === '记忆' || message.toLowerCase() === 'memory') {
|
|
|
- console.log('处理记忆查询命令');
|
|
|
- addMessage(message, 'user');
|
|
|
- messageInput.value = '';
|
|
|
- await showMemoryStatus();
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 立即显示用户消息
|
|
|
- addMessage(message, 'user');
|
|
|
- messageInput.value = '';
|
|
|
-
|
|
|
- // 禁用输入
|
|
|
- messageInput.disabled = true;
|
|
|
- sendButton.disabled = true;
|
|
|
-
|
|
|
- // 显示输入指示器
|
|
|
- showTypingIndicator();
|
|
|
+ // 发送消息
|
|
|
+ async function sendMessage() {
|
|
|
+ const message = messageInput.value.trim();
|
|
|
+ console.log('准备发送消息:', message);
|
|
|
+
|
|
|
+ if (!message) {
|
|
|
+ console.log('消息为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查特殊命令
|
|
|
+ if (message === '记忆' || message.toLowerCase() === 'memory') {
|
|
|
+ console.log('处理记忆查询命令');
|
|
|
+ addMessage(message, 'user');
|
|
|
+ messageInput.value = '';
|
|
|
+ await showMemoryStatus();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 立即显示用户消息
|
|
|
+ addMessage(message, 'user');
|
|
|
+ messageInput.value = '';
|
|
|
+
|
|
|
+ // 禁用输入
|
|
|
+ messageInput.disabled = true;
|
|
|
+ sendButton.disabled = true;
|
|
|
+
|
|
|
+ // 显示输入指示器
|
|
|
+ showTypingIndicator();
|
|
|
|
|
|
try {
|
|
|
- const response = await fetch('/api/chat', {
|
|
|
- method: 'POST',
|
|
|
- headers: {
|
|
|
- 'Content-Type': 'application/json',
|
|
|
- },
|
|
|
- body: JSON.stringify({
|
|
|
- message: message
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- const result = await response.json();
|
|
|
- console.log('发送结果:', result);
|
|
|
-
|
|
|
- if (!result.success) {
|
|
|
- hideTypingIndicator();
|
|
|
- addMessage('❌ 发送失败: ' + result.error, 'system');
|
|
|
- }
|
|
|
+ // 使用SSE获取回复
|
|
|
+ console.log('发送SSE请求...');
|
|
|
+ await createSSEConnection(message);
|
|
|
+ console.log('SSE对话完成');
|
|
|
|
|
|
} catch (error) {
|
|
|
- console.error('发送错误:', error);
|
|
|
+ console.error('SSE对话错误:', error);
|
|
|
hideTypingIndicator();
|
|
|
- addMessage('❌ 网络错误: ' + error.message, 'system');
|
|
|
+ addMessage('❌ 对话失败: ' + error.message, 'system');
|
|
|
+ statusBar.textContent = '❌ 对话失败';
|
|
|
+ statusBar.style.background = '#f8d7da';
|
|
|
+ statusBar.style.color = '#721c24';
|
|
|
} finally {
|
|
|
// 重新启用输入
|
|
|
messageInput.disabled = false;
|
|
@@ -679,11 +784,9 @@ async def home():
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- // 页面关闭时断开连接
|
|
|
+ // 页面关闭时的清理工作
|
|
|
window.addEventListener('beforeunload', function() {
|
|
|
- if (eventSource) {
|
|
|
- eventSource.close();
|
|
|
- }
|
|
|
+ console.log('页面即将关闭');
|
|
|
});
|
|
|
</script>
|
|
|
</body>
|
|
@@ -691,59 +794,19 @@ async def home():
|
|
|
"""
|
|
|
return HTMLResponse(content=html_content)
|
|
|
|
|
|
-# SSE消息流生成器
|
|
|
-async def generate_chat_stream():
|
|
|
- """生成聊天消息流"""
|
|
|
- client_id = f"client_{int(time.time())}"
|
|
|
- last_message_count = 0
|
|
|
-
|
|
|
- try:
|
|
|
- print(f"新的SSE连接: {client_id}")
|
|
|
-
|
|
|
- while True:
|
|
|
- # 检查新消息
|
|
|
- if len(message_queue) > last_message_count:
|
|
|
- for i in range(last_message_count, len(message_queue)):
|
|
|
- message = message_queue[i]
|
|
|
- yield f"data: {json.dumps(message, ensure_ascii=False)}\n\n"
|
|
|
-
|
|
|
- last_message_count = len(message_queue)
|
|
|
-
|
|
|
- await asyncio.sleep(0.1) # 100ms检查间隔
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- print(f"SSE流错误: {e}")
|
|
|
- finally:
|
|
|
- print(f"SSE连接断开: {client_id}")
|
|
|
-
|
|
|
-@app.get("/sse/chat")
|
|
|
-async def sse_chat():
|
|
|
- """SSE聊天端点"""
|
|
|
- return StreamingResponse(
|
|
|
- generate_chat_stream(),
|
|
|
- media_type="text/event-stream",
|
|
|
- headers={
|
|
|
- "Cache-Control": "no-cache",
|
|
|
- "Connection": "keep-alive",
|
|
|
- "Access-Control-Allow-Origin": "*",
|
|
|
- }
|
|
|
- )
|
|
|
+# 旧的SSE接口已被移除,现在使用 /api/chat 直接SSE接口
|
|
|
|
|
|
-@app.post("/api/chat")
|
|
|
-async def chat_api(request: Request):
|
|
|
- """处理聊天消息"""
|
|
|
+async def generate_chat_response(user_message: str):
|
|
|
+ """生成聊天回复的SSE流"""
|
|
|
global global_agent, global_user_id
|
|
|
|
|
|
try:
|
|
|
- data = await request.json()
|
|
|
- user_message = data.get("message", "").strip()
|
|
|
-
|
|
|
- if not user_message:
|
|
|
- return {"success": False, "error": "消息不能为空"}
|
|
|
-
|
|
|
print(f"📨 收到用户消息: {user_message}")
|
|
|
print(f"🤖 Agent可用性: {global_agent is not None}")
|
|
|
|
|
|
+ # 发送开始处理消息
|
|
|
+ yield f"data: {json.dumps({'type': 'status', 'message': '正在处理您的消息...'}, ensure_ascii=False)}\n\n"
|
|
|
+
|
|
|
# 模拟思考时间
|
|
|
await asyncio.sleep(random.uniform(0.5, 1.5))
|
|
|
|
|
@@ -753,6 +816,7 @@ async def chat_api(request: Request):
|
|
|
if global_agent:
|
|
|
try:
|
|
|
print("🤖 调用Memory Agent生成回复...")
|
|
|
+ yield f"data: {json.dumps({'type': 'status', 'message': '🤖 正在生成智能回复...'}, ensure_ascii=False)}\n\n"
|
|
|
|
|
|
# 异步调用Agent处理消息,传入user_id以关联记忆
|
|
|
response = await call_agent_async(global_agent, user_message, global_user_id)
|
|
@@ -779,50 +843,96 @@ async def chat_api(request: Request):
|
|
|
bot_reply = "抱歉,我暂时无法回复。请稍后再试。"
|
|
|
print(f"⚠️ 使用默认回复: {bot_reply}")
|
|
|
|
|
|
- # 添加机器人回复到消息队列
|
|
|
- bot_message = {
|
|
|
- "type": "bot_message",
|
|
|
- "message": bot_reply,
|
|
|
- "timestamp": datetime.now().isoformat()
|
|
|
- }
|
|
|
- message_queue.append(bot_message)
|
|
|
+ # 发送打字机效果的回复
|
|
|
+ print(f"⌨️ 开始打字机效果发送回复...")
|
|
|
|
|
|
- print(f"📤 机器人回复已添加到消息队列: {bot_reply[:50]}...")
|
|
|
+ # 发送开始打字消息
|
|
|
+ yield f"data: {json.dumps({'type': 'bot_message_start', 'timestamp': datetime.now().isoformat()}, ensure_ascii=False)}\n\n"
|
|
|
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": "消息已处理",
|
|
|
+ # 按单词逐个发送,实现打字机效果
|
|
|
+ import re
|
|
|
+ # 使用正则表达式分割文本为单词,包含标点符号
|
|
|
+ words = re.findall(r'\S+|\s+', bot_reply)
|
|
|
+
|
|
|
+ for i, word in enumerate(words):
|
|
|
+ # 发送单个单词
|
|
|
+ word_message = {
|
|
|
+ "type": "bot_message_token",
|
|
|
+ "token": word,
|
|
|
+ "position": i
|
|
|
+ }
|
|
|
+ yield f"data: {json.dumps(word_message, ensure_ascii=False)}\n\n"
|
|
|
+
|
|
|
+ # 控制打字速度:根据单词类型调整停顿时间
|
|
|
+ if word.strip() == '':
|
|
|
+ # 空白字符(空格、换行等)
|
|
|
+ await asyncio.sleep(random.uniform(0.05, 0.1))
|
|
|
+ elif any(punct in word for punct in '。!?'):
|
|
|
+ # 包含句末标点的单词
|
|
|
+ await asyncio.sleep(random.uniform(0.5, 0.8))
|
|
|
+ elif any(punct in word for punct in ',;:'):
|
|
|
+ # 包含句中标点的单词
|
|
|
+ await asyncio.sleep(random.uniform(0.3, 0.5))
|
|
|
+ elif len(word.strip()) > 5:
|
|
|
+ # 长单词
|
|
|
+ await asyncio.sleep(random.uniform(0.2, 0.4))
|
|
|
+ else:
|
|
|
+ # 普通单词
|
|
|
+ await asyncio.sleep(random.uniform(0.1, 0.3))
|
|
|
+
|
|
|
+ # 发送结束消息
|
|
|
+ end_message = {
|
|
|
+ "type": "bot_message_end",
|
|
|
+ "complete_message": bot_reply,
|
|
|
"timestamp": datetime.now().isoformat()
|
|
|
}
|
|
|
+ yield f"data: {json.dumps(end_message, ensure_ascii=False)}\n\n"
|
|
|
+
|
|
|
+ print(f"✅ 打字机效果发送完成")
|
|
|
+
|
|
|
+ # 发送完成状态
|
|
|
+ yield f"data: {json.dumps({'type': 'complete', 'message': '回复完成'}, ensure_ascii=False)}\n\n"
|
|
|
|
|
|
except Exception as e:
|
|
|
print(f"处理消息错误: {e}")
|
|
|
- return {"success": False, "error": f"处理错误: {str(e)}"}
|
|
|
+ error_message = {
|
|
|
+ "type": "error",
|
|
|
+ "message": f"处理错误: {str(e)}"
|
|
|
+ }
|
|
|
+ yield f"data: {json.dumps(error_message, ensure_ascii=False)}\n\n"
|
|
|
+
|
|
|
+@app.get("/api/chat")
|
|
|
+async def chat_api_sse(message: str = ""):
|
|
|
+ """SSE聊天接口"""
|
|
|
+ if not message.strip():
|
|
|
+ return {"error": "消息不能为空"}
|
|
|
+
|
|
|
+ return StreamingResponse(
|
|
|
+ generate_chat_response(message.strip()),
|
|
|
+ media_type="text/event-stream",
|
|
|
+ headers={
|
|
|
+ "Cache-Control": "no-cache",
|
|
|
+ "Connection": "keep-alive",
|
|
|
+ "Access-Control-Allow-Origin": "*",
|
|
|
+ }
|
|
|
+ )
|
|
|
|
|
|
@app.get("/api/status")
|
|
|
async def get_status():
|
|
|
"""获取系统状态"""
|
|
|
return {
|
|
|
"status": "running",
|
|
|
- "messages": len(message_queue),
|
|
|
+ "agent_available": global_agent is not None,
|
|
|
"timestamp": datetime.now().isoformat()
|
|
|
}
|
|
|
|
|
|
@app.post("/api/clear")
|
|
|
async def clear_messages():
|
|
|
- """清空消息历史"""
|
|
|
- global message_queue
|
|
|
- message_queue.clear()
|
|
|
-
|
|
|
- # 添加清空提示消息
|
|
|
- clear_msg = {
|
|
|
- "type": "system_message",
|
|
|
- "message": "💬 消息历史已清空",
|
|
|
- "timestamp": datetime.now().isoformat()
|
|
|
- }
|
|
|
- message_queue.append(clear_msg)
|
|
|
+ """清空消息历史(现在使用直接SSE,无需清空队列)"""
|
|
|
+ # 由于现在使用直接SSE,不再需要清空消息队列
|
|
|
+ # 这个接口保留用于兼容性,但实际不执行任何操作
|
|
|
|
|
|
- return {"success": True, "message": "消息历史已清空"}
|
|
|
+ return {"success": True, "message": "消息历史已清空(使用SSE直接模式)"}
|
|
|
|
|
|
@app.get("/api/memory")
|
|
|
async def get_memory_status():
|