Files
ai-xiaocai/server/routes/messages.js
2026-07-29 10:38:19 +08:00

97 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 消息路由 + AI 分析
const express = require('express');
const { authMiddleware } = require('../middleware/auth');
const { broadcastToRoomExcludeSelf, broadcastToRoom } = 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) {
var responses = Array.isArray(aiResponse) ? aiResponse : [aiResponse];
responses.forEach(function(r) {
if (r.action !== 'ignore') handleAIResult(r, roomId, username, text || '', attachments || []);
});
}
} catch (e) {
console.error('AI 分析失败:', e.message);
var errText = '❌ ' + (e.message || 'AI 处理失败,请稍后重试');
var errResult = db.prepare('INSERT INTO messages (room_id, user, text, timestamp) VALUES (?,?,?,?)').run(roomId, '小财', errText, timestamp());
var errMsg = { id: errResult.lastInsertRowid, room_id: roomId, user: '小财', text: errText, attachments: [], timestamp: timestamp() };
broadcastToRoom(roomId, { type: 'new_message', message: errMsg });
}
});
async function analyzeWithDeepSeek(text, historyMessages, username, isAdmin, roomId) {
var systemPrompt = buildSystemPrompt(username, isAdmin);
var messages = [
{ role: 'system', content: systemPrompt }
];
historyMessages.forEach(function(m) { messages.push(m); });
messages.push({ role: 'system', content: '当前服务器时间:' + new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai', hour12: false }) });
const content = await callDeepSeek(messages, username);
console.log('🤖 AI 返回:', content.substring(0, 200));
try {
var cleaned = content.replace(/```json|```/g, '').trim();
if (!cleaned) { console.warn('⚠️ AI 返回空内容'); return { action: 'ignore' }; }
var parsed = JSON.parse(cleaned);
// 支持批量AI 可能返回数组
if (Array.isArray(parsed)) {
parsed.forEach(function(item, i) {
normalize(item);
var v = validate(item);
if (!v.valid) console.warn('⚠️ AI 返回[' + i + ']校验失败:', v.error);
});
} else {
normalize(parsed);
var 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;