// 消息路由 + AI 分析 const express = require('express'); const { authMiddleware } = require('../middleware/auth'); const { broadcastToRoomExcludeSelf } = require('../ws'); const { buildSystemPrompt } = require('../ai/prompt'); const { validate, normalize } = require('../ai/validator'); const { callDeepSeek } = require('../ai/client'); const { getHistory, addToHistory, hasPendingAction, handleAIResult, executePendingAction } = require('../handlers'); const db = require('../db'); const { timestamp } = require('../utils'); const router = express.Router(); router.get('/:roomId/messages', authMiddleware, (req, res) => { const msgs = db.prepare('SELECT * FROM messages WHERE room_id = ? ORDER BY id ASC').all(req.params.roomId); res.json(msgs); }); router.post('/:roomId/messages', authMiddleware, async (req, res) => { const { text, attachments } = req.body; console.log('📨 收到消息, text:', (text||'').substring(0,30), 'attachments:', JSON.stringify(attachments)); const roomId = req.params.roomId; const username = req.user.username; const now = timestamp(); const result = db.prepare('INSERT INTO messages (room_id, user, text, attachments, timestamp) VALUES (?,?,?,?,?)').run( roomId, username, text || '', attachments ? JSON.stringify(attachments) : null, now ); const msg = { id: result.lastInsertRowid, room_id: roomId, user: username, text: text || '', attachments: attachments || [], timestamp: now }; const lastMsg = db.prepare('SELECT text, timestamp FROM messages WHERE room_id = ? ORDER BY id DESC LIMIT 1').get(roomId); broadcastToRoomExcludeSelf(roomId, username, { type: 'new_message', message: msg, room_preview: { room_id: roomId, last_message: lastMsg ? lastMsg.text : '', last_time: lastMsg ? lastMsg.timestamp : '' } }); addToHistory(roomId, 'user', `${username}: ${text || '图片'}`); res.json(msg); if (text && text.trim() === '确认' && hasPendingAction(roomId, username)) { executePendingAction(roomId, username); return; } try { const history = getHistory(roomId); const historyMessages = history.map(e => ({ role: e.role, content: e.content })); const aiResponse = await analyzeWithDeepSeek(text || '', historyMessages, username, req.user.isAdmin, roomId); if (aiResponse && aiResponse.action !== 'ignore') { handleAIResult(aiResponse, roomId, username, text || '', attachments || []); } } catch (e) { console.error('AI 分析失败:', e); } }); async function analyzeWithDeepSeek(text, historyMessages, username, isAdmin, roomId) { // 注入当前房间采购清单上下文 const purchases = db.prepare("SELECT item, quantity, amount, status, created_at FROM purchases WHERE room_id = ? ORDER BY created_at DESC LIMIT 10").all(roomId); const purchaseContext = purchases.length ? `\n📋 当前房间采购清单(最近10条):\n${purchases.map(p => `- ${p.item} | ×${p.quantity} | ¥${p.amount} | ${p.status} | ${p.created_at}`).join('\n')}` : ''; const systemPrompt = buildSystemPrompt(username, isAdmin) + purchaseContext; const messages = [ { role: 'system', content: systemPrompt }, ...historyMessages.slice(-30), { role: 'user', content: `${username}: ${text}` } ]; const content = await callDeepSeek(messages, 0.1); console.log('🤖 AI 返回:', content); try { const parsed = JSON.parse(content.replace(/```json|```/g, '').trim()); normalize(parsed); const v = validate(parsed); if (!v.valid) console.warn('⚠️ AI 返回校验失败:', v.error); return parsed; } catch (e) { // AI 返回非 JSON(如纯文本回复图片消息)→ 降级为 chat console.warn('⚠️ AI 返回非 JSON,降级为 chat:', content.substring(0, 50)); return { action: 'chat', reply: content }; } } module.exports = router;