补上丢掉的AI应答

This commit is contained in:
2026-07-22 10:36:53 +08:00
parent 972804edba
commit 4866f29644

View File

@@ -108,12 +108,14 @@ app.get('/api/rooms/:roomId/messages', auth, (req, res) => {
res.json(msgs); res.json(msgs);
}); });
// 发送消息(统一入口) // 发送消息(统一入口,并触发 AI
app.post('/api/rooms/:roomId/messages', auth, (req, res) => { app.post('/api/rooms/:roomId/messages', auth, async (req, res) => {
const { text, attachments } = req.body; const { text, attachments } = req.body;
const roomId = req.params.roomId; const roomId = req.params.roomId;
const username = req.user.username; const username = req.user.username;
const timestamp = new Date().toLocaleString('zh-CN', { hour12: false }); const timestamp = new Date().toLocaleString('zh-CN', { hour12: false });
// 存储消息
const result = db.prepare('INSERT INTO messages (room_id, user, text, attachments, timestamp) VALUES (?,?,?,?,?)').run( const result = db.prepare('INSERT INTO messages (room_id, user, text, attachments, timestamp) VALUES (?,?,?,?,?)').run(
roomId, username, text || '', attachments ? JSON.stringify(attachments) : null, timestamp roomId, username, text || '', attachments ? JSON.stringify(attachments) : null, timestamp
); );
@@ -134,7 +136,7 @@ app.post('/api/rooms/:roomId/messages', auth, (req, res) => {
last_time: lastMsg ? lastMsg.timestamp : '' last_time: lastMsg ? lastMsg.timestamp : ''
}; };
// 广播给房间内其他成员,但不包括发送者自己 // 广播给房间内其他成员(排除自己
broadcastToRoomExcludeSelf(roomId, username, { broadcastToRoomExcludeSelf(roomId, username, {
type: 'new_message', type: 'new_message',
message: msg, message: msg,
@@ -144,8 +146,20 @@ app.post('/api/rooms/:roomId/messages', auth, (req, res) => {
// 加入对话历史 // 加入对话历史
addToHistory(roomId, 'user', `${username}: ${text || '图片'}`); addToHistory(roomId, 'user', `${username}: ${text || '图片'}`);
// 返回消息给发送者 // 先响应客户端
res.json(msg); res.json(msg);
// 异步触发 AI 分析
try {
const history = getHistory(roomId);
const historyMessages = history.map(e => ({ role: e.role, content: e.content }));
const aiResponse = await analyzeWithDeepSeek(text || '', historyMessages, username);
if (aiResponse && aiResponse.action !== 'ignore') {
handleAIResult(aiResponse, roomId, username, text || '', attachments || []);
}
} catch (e) {
console.error('AI 分析失败:', e);
}
}); });
app.post('/api/upload', auth, upload.single('file'), (req, res) => { app.post('/api/upload', auth, upload.single('file'), (req, res) => {
@@ -192,7 +206,7 @@ app.get('/api/rooms/:roomId/purchases/export', auth, (req, res) => {
}); });
// WebSocket 管理 // WebSocket 管理
const clients = new Map(); // ws -> { username, roomId } const clients = new Map();
wss.on('connection', (ws, req) => { wss.on('connection', (ws, req) => {
console.log('✅ WebSocket 客户端已连接'); console.log('✅ WebSocket 客户端已连接');
@@ -218,7 +232,7 @@ wss.on('connection', (ws, req) => {
ws.roomId = msg.roomId; ws.roomId = msg.roomId;
clients.set(ws, { username, roomId: msg.roomId }); clients.set(ws, { username, roomId: msg.roomId });
} }
// 不再处理 message 类型,消息通过 HTTP API 发送 // 不再处理 message 类型
} catch (e) {} } catch (e) {}
}); });
@@ -227,7 +241,6 @@ wss.on('connection', (ws, req) => {
}); });
}); });
// 广播给房间内所有成员,排除指定用户
function broadcastToRoomExcludeSelf(roomId, excludeUsername, data) { function broadcastToRoomExcludeSelf(roomId, excludeUsername, data) {
const message = JSON.stringify(data); const message = JSON.stringify(data);
clients.forEach((info, ws) => { clients.forEach((info, ws) => {
@@ -237,7 +250,6 @@ function broadcastToRoomExcludeSelf(roomId, excludeUsername, data) {
}); });
} }
// 广播给房间内所有人
function broadcastToRoom(roomId, data) { function broadcastToRoom(roomId, data) {
const message = JSON.stringify(data); const message = JSON.stringify(data);
clients.forEach((info, ws) => { clients.forEach((info, ws) => {
@@ -247,7 +259,6 @@ function broadcastToRoom(roomId, data) {
}); });
} }
// 全局广播
function broadcast(data) { function broadcast(data) {
const message = JSON.stringify(data); const message = JSON.stringify(data);
clients.forEach((ws) => { clients.forEach((ws) => {
@@ -255,7 +266,7 @@ function broadcast(data) {
}); });
} }
// 内部消息存储并广播(用于 AI 回复 // 内部消息存储并广播(用于 AI 回复)
function storeAndBroadcastText(roomId, user, text) { function storeAndBroadcastText(roomId, user, text) {
const timestamp = new Date().toLocaleString('zh-CN', { hour12: false }); const timestamp = new Date().toLocaleString('zh-CN', { hour12: false });
const result = db.prepare('INSERT INTO messages (room_id, user, text, timestamp) VALUES (?,?,?,?)').run(roomId, user, text, timestamp); const result = db.prepare('INSERT INTO messages (room_id, user, text, timestamp) VALUES (?,?,?,?)').run(roomId, user, text, timestamp);
@@ -285,7 +296,7 @@ function addToHistory(roomId, role, content) {
if (history.length > 60) conversationHistory.set(roomId, history.slice(-40)); if (history.length > 60) conversationHistory.set(roomId, history.slice(-40));
} }
// AI 处理(保持原逻辑) // AI 分析
async function analyzeWithDeepSeek(text, historyMessages, username) { async function analyzeWithDeepSeek(text, historyMessages, username) {
const systemPrompt = `你是智能财务助手“小财”。结合对话历史理解用户意图。只返回JSON。 const systemPrompt = `你是智能财务助手“小财”。结合对话历史理解用户意图。只返回JSON。
@@ -308,13 +319,16 @@ async function analyzeWithDeepSeek(text, historyMessages, username) {
{ role: 'user', content: `${username}: ${text}` } { role: 'user', content: `${username}: ${text}` }
]; ];
console.log('🤖 调用 DeepSeek...');
const res = await fetch('https://api.deepseek.com/chat/completions', { const res = await fetch('https://api.deepseek.com/chat/completions', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${DEEPSEEK_API_KEY}` }, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${DEEPSEEK_API_KEY}` },
body: JSON.stringify({ model: 'deepseek-v4-flash', messages, temperature: 0.1, stream: false }) body: JSON.stringify({ model: 'deepseek-v4-flash', messages, temperature: 0.1, stream: false })
}); });
const data = await res.json(); const data = await res.json();
return JSON.parse(data.choices[0].message.content.replace(/```json|```/g, '').trim()); const content = data.choices[0].message.content;
console.log('🤖 AI 返回:', content);
return JSON.parse(content.replace(/```json|```/g, '').trim());
} }
function handleAIResult(aiResult, roomId, username, originalText, attachments) { function handleAIResult(aiResult, roomId, username, originalText, attachments) {