基本功能完成
This commit is contained in:
196
server/server.js
196
server/server.js
@@ -27,9 +27,7 @@ const TIMEZONE = 'Asia/Shanghai';
|
||||
function timestamp() {
|
||||
return new Date().toLocaleString('zh-CN', { timeZone: TIMEZONE, hour12: false });
|
||||
}
|
||||
function currentTimeStr() {
|
||||
return timestamp();
|
||||
}
|
||||
function currentTimeStr() { return timestamp(); }
|
||||
|
||||
// 初始化用户
|
||||
const insertUser = db.prepare('INSERT OR IGNORE INTO users (username, password, is_admin) VALUES (?, ?, ?)');
|
||||
@@ -94,8 +92,16 @@ app.get('/api/user', auth, (req, res) => {
|
||||
res.json({ username: req.user.username, isAdmin: req.user.isAdmin });
|
||||
});
|
||||
|
||||
// 群聊列表(白名单过滤)
|
||||
app.get('/api/rooms', auth, (req, res) => {
|
||||
const rooms = db.prepare('SELECT * FROM rooms').all();
|
||||
const username = req.user.username;
|
||||
const isAdmin = req.user.isAdmin;
|
||||
let rooms;
|
||||
if (isAdmin) {
|
||||
rooms = db.prepare('SELECT * FROM rooms').all();
|
||||
} else {
|
||||
rooms = db.prepare('SELECT * FROM rooms WHERE white_list = ? OR white_list LIKE ?').all('', `%,${username},%`);
|
||||
}
|
||||
const result = rooms.map(room => {
|
||||
const lastMsg = db.prepare('SELECT text, timestamp FROM messages WHERE room_id = ? ORDER BY timestamp DESC LIMIT 1').get(room.id);
|
||||
return {
|
||||
@@ -151,22 +157,13 @@ app.post('/api/rooms/:roomId/messages', auth, async (req, res) => {
|
||||
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 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 timestamp DESC LIMIT 1').get(roomId);
|
||||
broadcastToRoomExcludeSelf(roomId, username, {
|
||||
type: 'new_message',
|
||||
message: msg,
|
||||
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);
|
||||
|
||||
@@ -182,9 +179,7 @@ app.post('/api/rooms/:roomId/messages', auth, async (req, res) => {
|
||||
if (aiResponse && aiResponse.action !== 'ignore') {
|
||||
handleAIResult(aiResponse, roomId, username, text || '', attachments || []);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('AI 分析失败:', e);
|
||||
}
|
||||
} catch (e) { console.error('AI 分析失败:', e); }
|
||||
});
|
||||
|
||||
app.post('/api/upload', auth, upload.single('file'), (req, res) => {
|
||||
@@ -206,7 +201,15 @@ app.get('/api/purchases/:id', auth, (req, res) => {
|
||||
});
|
||||
|
||||
app.get('/api/summary', auth, (req, res) => {
|
||||
const rooms = db.prepare('SELECT id, name FROM rooms').all();
|
||||
const username = req.user.username;
|
||||
const isAdmin = req.user.isAdmin;
|
||||
let rooms;
|
||||
if (isAdmin) {
|
||||
rooms = db.prepare('SELECT id, name FROM rooms').all();
|
||||
} else {
|
||||
// 使用与群聊列表完全相同的白名单过滤方式
|
||||
rooms = db.prepare('SELECT id, name FROM rooms WHERE white_list = ? OR white_list LIKE ?').all('', `%,${username},%`);
|
||||
}
|
||||
const summary = rooms.map(room => {
|
||||
const stats = db.prepare(`SELECT COUNT(*) as count, SUM(amount) as total FROM purchases WHERE room_id = ?`).get(room.id);
|
||||
return {
|
||||
@@ -230,76 +233,48 @@ app.get('/api/rooms/:roomId/purchases/export', auth, (req, res) => {
|
||||
res.send('\uFEFF' + csv);
|
||||
});
|
||||
|
||||
// WebSocket 管理
|
||||
// WebSocket
|
||||
const clients = new Map();
|
||||
wss.on('connection', (ws, req) => {
|
||||
console.log('✅ WebSocket 客户端已连接');
|
||||
const url = new URL(req.url, 'http://localhost');
|
||||
const token = url.searchParams.get('token');
|
||||
if (!token) return ws.close();
|
||||
|
||||
let username;
|
||||
try {
|
||||
const decoded = jwt.verify(token, JWT_SECRET);
|
||||
username = decoded.username;
|
||||
} catch (e) {
|
||||
return ws.close();
|
||||
}
|
||||
|
||||
try { const decoded = jwt.verify(token, JWT_SECRET); username = decoded.username; }
|
||||
catch (e) { return ws.close(); }
|
||||
ws.username = username;
|
||||
ws.isAdmin = ADMINS.includes(username);
|
||||
clients.set(ws, { username, roomId: null, isAdmin: ws.isAdmin });
|
||||
|
||||
ws.on('message', (data) => {
|
||||
try {
|
||||
const msg = JSON.parse(data);
|
||||
if (msg.type === 'join') {
|
||||
ws.roomId = msg.roomId;
|
||||
clients.set(ws, { username, roomId: msg.roomId, isAdmin: ws.isAdmin });
|
||||
}
|
||||
if (msg.type === 'join') { ws.roomId = msg.roomId; clients.set(ws, { username, roomId: msg.roomId, isAdmin: ws.isAdmin }); }
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
clients.delete(ws);
|
||||
});
|
||||
ws.on('close', () => clients.delete(ws));
|
||||
});
|
||||
|
||||
function broadcastToRoomExcludeSelf(roomId, excludeUsername, data) {
|
||||
const message = JSON.stringify(data);
|
||||
clients.forEach((info, ws) => {
|
||||
if (info.roomId === roomId && info.username !== excludeUsername && ws.readyState === 1) {
|
||||
ws.send(message);
|
||||
}
|
||||
if (info.roomId === roomId && info.username !== excludeUsername && ws.readyState === 1) ws.send(message);
|
||||
});
|
||||
}
|
||||
|
||||
function broadcastToRoom(roomId, data) {
|
||||
const message = JSON.stringify(data);
|
||||
clients.forEach((info, ws) => {
|
||||
if (info.roomId === roomId && ws.readyState === 1) {
|
||||
ws.send(message);
|
||||
}
|
||||
});
|
||||
clients.forEach((info, ws) => { if (info.roomId === roomId && ws.readyState === 1) ws.send(message); });
|
||||
}
|
||||
|
||||
function broadcast(data) {
|
||||
const message = JSON.stringify(data);
|
||||
clients.forEach((ws) => {
|
||||
if (ws.readyState === 1) ws.send(message);
|
||||
});
|
||||
clients.forEach((ws) => { if (ws.readyState === 1) ws.send(message); });
|
||||
}
|
||||
|
||||
function storeAndBroadcastText(roomId, user, text) {
|
||||
const now = timestamp();
|
||||
const result = db.prepare('INSERT INTO messages (room_id, user, text, timestamp) VALUES (?,?,?,?)').run(roomId, user, text, now);
|
||||
const msg = { id: result.lastInsertRowid, room_id: roomId, user, text, attachments: [], timestamp: now };
|
||||
const lastMsg = db.prepare('SELECT text, timestamp FROM messages WHERE room_id = ? ORDER BY timestamp DESC LIMIT 1').get(roomId);
|
||||
broadcastToRoom(roomId, {
|
||||
type: 'new_message',
|
||||
message: msg,
|
||||
room_preview: { room_id: roomId, last_message: lastMsg ? lastMsg.text : '', last_time: lastMsg ? lastMsg.timestamp : '' }
|
||||
});
|
||||
broadcastToRoom(roomId, { type: 'new_message', message: msg, room_preview: { room_id: roomId, last_message: lastMsg ? lastMsg.text : '', last_time: lastMsg ? lastMsg.timestamp : '' } });
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -316,24 +291,22 @@ function executePendingAction(roomId, username) {
|
||||
try {
|
||||
if (action.type === 'delete') {
|
||||
const { itemName, purchaseIds } = action.data;
|
||||
const deleteAttachments = db.prepare('DELETE FROM purchase_attachments WHERE purchase_id = ?');
|
||||
const deleteHistory = db.prepare('DELETE FROM purchase_history WHERE purchase_id = ?');
|
||||
const deletePurchase = db.prepare('DELETE FROM purchases WHERE id = ?');
|
||||
for (const id of purchaseIds) { deleteAttachments.run(id); deleteHistory.run(id); deletePurchase.run(id); }
|
||||
const delA = db.prepare('DELETE FROM purchase_attachments WHERE purchase_id = ?');
|
||||
const delH = db.prepare('DELETE FROM purchase_history WHERE purchase_id = ?');
|
||||
const delP = db.prepare('DELETE FROM purchases WHERE id = ?');
|
||||
for (const id of purchaseIds) { delA.run(id); delH.run(id); delP.run(id); }
|
||||
const reply = `✅ 已删除采购记录:${itemName}(共 ${purchaseIds.length} 条)`;
|
||||
storeAndBroadcastText(roomId, '小财', reply);
|
||||
addToHistory(roomId, 'assistant', reply);
|
||||
storeAndBroadcastText(roomId, '小财', reply); addToHistory(roomId, 'assistant', reply);
|
||||
} else if (action.type === 'clear') {
|
||||
db.prepare('DELETE FROM purchase_attachments WHERE purchase_id IN (SELECT id FROM purchases WHERE room_id = ?)').run(roomId);
|
||||
db.prepare('DELETE FROM purchase_history WHERE purchase_id IN (SELECT id FROM purchases WHERE room_id = ?)').run(roomId);
|
||||
db.prepare('DELETE FROM purchases WHERE room_id = ?').run(roomId);
|
||||
const reply = '✅ 已清空当前房间的所有采购数据。';
|
||||
storeAndBroadcastText(roomId, '小财', reply);
|
||||
addToHistory(roomId, 'assistant', reply);
|
||||
storeAndBroadcastText(roomId, '小财', reply); addToHistory(roomId, 'assistant', reply);
|
||||
}
|
||||
broadcastToRoom(roomId, { type: 'purchase_updated' });
|
||||
return true;
|
||||
} catch (e) { console.error('执行待处理操作失败:', e); storeAndBroadcastText(roomId, '小财', '❌ 操作执行失败,请重试。'); return false; }
|
||||
} catch (e) { storeAndBroadcastText(roomId, '小财', '❌ 操作执行失败,请重试。'); return false; }
|
||||
}
|
||||
|
||||
// 对话历史
|
||||
@@ -341,25 +314,24 @@ const conversationHistory = new Map();
|
||||
function getHistory(roomId) { if (!conversationHistory.has(roomId)) conversationHistory.set(roomId, []); return conversationHistory.get(roomId); }
|
||||
function addToHistory(roomId, role, content) { const history = getHistory(roomId); history.push({ role, content }); if (history.length > 60) conversationHistory.set(roomId, history.slice(-40)); }
|
||||
|
||||
// AI 分析
|
||||
// AI 分析(明确权限不足时返回 chat 而非 ignore)
|
||||
async function analyzeWithDeepSeek(text, historyMessages, username, isAdmin) {
|
||||
const systemPrompt = `你是智能财务助手“小财”。当前服务器时间:${currentTimeStr()}。结合对话历史理解用户意图,只返回JSON。
|
||||
|
||||
意图分类:
|
||||
- 采购/付款/发票相关:action="purchase",提取以下字段(所有字段可选,缺失则不返回):
|
||||
purchase_item (物品名称), quantity (数量,默认1), unit_price (单价,默认0), amount (总金额,默认0),
|
||||
freight (邮费,默认0), payment_method (付款方式:支付宝/微信/对公转账/现金等,淘宝购买默认支付宝),
|
||||
invoice_type (发票类型:增票/普票/无票,默认无票), status (待采购/已采购/发票已收), applicant (申请人),
|
||||
remarks (备注,重要信息如“下次换商家”“缺少配件”等), created_time (如果用户提到具体时间则按yyyy/MM/dd HH:mm:ss格式输出)
|
||||
- 采购/付款/发票相关:action="purchase",提取字段:purchase_item, quantity(默认1), unit_price(默认0), amount(默认0), freight(默认0), payment_method(淘宝默认支付宝), invoice_type(默认无票), status, applicant, remarks, created_time
|
||||
- 查询汇总:action="query"
|
||||
- 聊天:action="chat",reply简短回复
|
||||
- 删除指定物品:action="delete",delete_item为物品名
|
||||
- 清空所有采购数据:action="clear_all"
|
||||
- 忽略:action="ignore"
|
||||
- 忽略(仅当完全无关):action="ignore"
|
||||
|
||||
权限规则:删除和清空仅限管理员。当前用户${username},管理员状态:${isAdmin}。
|
||||
采购规则:用户补充信息时更新已有记录。更新时请返回完整字段值,包括未变化的字段。
|
||||
如果用户要求修改时间,请生成正确的created_time字段。`;
|
||||
⚠️ 重要权限规则:
|
||||
- 如果用户要求删除或清空,但当前用户${username}不是管理员(管理员状态:${isAdmin}),你必须返回 action="chat",reply 说明需要管理员权限。绝对不要返回 action="ignore" 或 action="delete"/"clear_all"。
|
||||
- 如果是管理员,正常返回对应 action。
|
||||
|
||||
采购规则:用户补充信息时更新已有记录。更新时请返回完整字段值,包括未变化的字段。如果用户要求修改时间,请生成正确的created_time字段。
|
||||
⚠️ 总金额(amount)由系统自动按“数量×单价+邮费”计算,你无需提供该字段。`;
|
||||
|
||||
const messages = [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
@@ -381,61 +353,35 @@ async function analyzeWithDeepSeek(text, historyMessages, username, isAdmin) {
|
||||
|
||||
function handleAIResult(aiResult, roomId, username, originalText, attachments) {
|
||||
const now = timestamp();
|
||||
|
||||
if (aiResult.action === 'ask') {
|
||||
storeAndBroadcastText(roomId, '小财', aiResult.question);
|
||||
addToHistory(roomId, 'assistant', aiResult.question);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aiResult.action === 'ask') { storeAndBroadcastText(roomId, '小财', aiResult.question); addToHistory(roomId, 'assistant', aiResult.question); return; }
|
||||
if (aiResult.action === 'delete') {
|
||||
const itemName = aiResult.delete_item;
|
||||
const purchases = db.prepare('SELECT id, item, amount, payment_method, status, applicant, created_at FROM purchases WHERE room_id = ? AND item LIKE ?').all(roomId, `%${itemName}%`);
|
||||
if (purchases.length === 0) {
|
||||
storeAndBroadcastText(roomId, '小财', `没有找到与“${itemName}”相关的采购记录。`);
|
||||
addToHistory(roomId, 'assistant', `没有找到与“${itemName}”相关的采购记录。`);
|
||||
return;
|
||||
}
|
||||
if (purchases.length === 0) { storeAndBroadcastText(roomId, '小财', `没有找到与“${itemName}”相关的采购记录。`); return; }
|
||||
let confirmText = `⚠️ 即将删除以下 ${purchases.length} 条采购记录,请回复“确认”继续:\n\n`;
|
||||
purchases.forEach(p => {
|
||||
confirmText += `• ${p.item} | ¥${p.amount} | ${p.status} | ${p.applicant} | ${p.created_at}\n`;
|
||||
});
|
||||
purchases.forEach(p => confirmText += `• ${p.item} | ¥${p.amount} | ${p.status} | ${p.applicant} | ${p.created_at}\n`);
|
||||
confirmText += `\n如果不删除,请忽略此消息。`;
|
||||
storeAndBroadcastText(roomId, '小财', confirmText);
|
||||
addToHistory(roomId, 'assistant', confirmText);
|
||||
setPendingAction(roomId, username, { type: 'delete', data: { itemName, purchaseIds: purchases.map(p => p.id) } });
|
||||
return;
|
||||
}
|
||||
|
||||
if (aiResult.action === 'clear_all') {
|
||||
const count = db.prepare('SELECT COUNT(*) as count FROM purchases WHERE room_id = ?').get(roomId).count;
|
||||
if (count === 0) {
|
||||
storeAndBroadcastText(roomId, '小财', '当前房间没有采购记录,无需清空。');
|
||||
addToHistory(roomId, 'assistant', '当前房间没有采购记录,无需清空。');
|
||||
return;
|
||||
}
|
||||
const confirmText = `⚠️ 即将清空当前房间的 ${count} 条采购数据,请回复“确认”继续,否则忽略。`;
|
||||
storeAndBroadcastText(roomId, '小财', confirmText);
|
||||
addToHistory(roomId, 'assistant', confirmText);
|
||||
if (count === 0) { storeAndBroadcastText(roomId, '小财', '当前房间没有采购记录,无需清空。'); return; }
|
||||
storeAndBroadcastText(roomId, '小财', `⚠️ 即将清空当前房间的 ${count} 条采购数据,请回复“确认”继续,否则忽略。`);
|
||||
addToHistory(roomId, 'assistant', `请求清空${count}条记录`);
|
||||
setPendingAction(roomId, username, { type: 'clear', data: {} });
|
||||
return;
|
||||
}
|
||||
|
||||
if (aiResult.action === 'purchase') {
|
||||
const createdTime = aiResult.created_time || now;
|
||||
let purchase = db.prepare('SELECT * FROM purchases WHERE room_id = ? AND item LIKE ? AND status != ?').get(roomId, `%${aiResult.purchase_item}%`, '已完成');
|
||||
let replyText = '';
|
||||
|
||||
// 计算总金额:优先使用 AI 提供的 amount,否则根据单价*数量+邮费计算
|
||||
const quantity = aiResult.quantity || 1;
|
||||
const unitPrice = aiResult.unit_price || 0;
|
||||
const freight = aiResult.freight || 0;
|
||||
let amount;
|
||||
if (aiResult.amount !== undefined && aiResult.amount !== null) {
|
||||
amount = aiResult.amount;
|
||||
} else {
|
||||
amount = unitPrice * quantity + freight;
|
||||
}
|
||||
const amount = quantity * unitPrice + freight;
|
||||
|
||||
if (!purchase) {
|
||||
const id = uuidv4();
|
||||
@@ -445,9 +391,7 @@ function handleAIResult(aiResult, roomId, username, originalText, attachments) {
|
||||
const status = aiResult.status || '待处理';
|
||||
const applicant = aiResult.applicant || username;
|
||||
const remarks = aiResult.remarks || '';
|
||||
|
||||
db.prepare(`INSERT INTO purchases (id, room_id, item, quantity, unit_price, amount, freight, payment_method, invoice_type, status, applicant, remarks, created_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(
|
||||
db.prepare(`INSERT INTO purchases (id, room_id, item, quantity, unit_price, amount, freight, payment_method, invoice_type, status, applicant, remarks, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(
|
||||
id, roomId, item, quantity, unitPrice, amount, freight, paymentMethod, invoiceType, status, applicant, remarks, createdTime
|
||||
);
|
||||
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(id, `创建采购:${item},数量${quantity},金额¥${amount},状态${status}`, '小财', now);
|
||||
@@ -455,7 +399,6 @@ function handleAIResult(aiResult, roomId, username, originalText, attachments) {
|
||||
purchase = { id };
|
||||
} else {
|
||||
const old = purchase;
|
||||
// 合并新值
|
||||
const newVals = {
|
||||
quantity: aiResult.quantity ?? old.quantity,
|
||||
unit_price: aiResult.unit_price ?? old.unit_price,
|
||||
@@ -467,9 +410,10 @@ function handleAIResult(aiResult, roomId, username, originalText, attachments) {
|
||||
remarks: aiResult.remarks !== undefined ? aiResult.remarks : old.remarks,
|
||||
created_at: aiResult.created_time || old.created_at
|
||||
};
|
||||
// 重新计算金额,除非 AI 明确给了 amount
|
||||
if (aiResult.amount !== undefined && aiResult.amount !== null) {
|
||||
newVals.amount = aiResult.amount;
|
||||
// 始终根据数量、单价、邮费重新计算总金额,确保准确
|
||||
// newVals.amount = aiResult.amount;
|
||||
newVals.amount = newVals.quantity * newVals.unit_price + newVals.freight;
|
||||
} else {
|
||||
newVals.amount = newVals.unit_price * newVals.quantity + newVals.freight;
|
||||
}
|
||||
@@ -483,7 +427,6 @@ function handleAIResult(aiResult, roomId, username, originalText, attachments) {
|
||||
db.prepare(`UPDATE purchases SET ${field} = ? WHERE id = ?`).run(newVal, purchase.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
db.prepare('UPDATE purchases SET updated_at = ? WHERE id = ?').run(now, purchase.id);
|
||||
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(purchase.id, `更新:${historyChanges.join(';')}`, username, now);
|
||||
@@ -492,35 +435,22 @@ function handleAIResult(aiResult, roomId, username, originalText, attachments) {
|
||||
replyText = `ℹ️ 采购「${aiResult.purchase_item}」的信息没有发生变化。`;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachments?.length) {
|
||||
const insertAttach = db.prepare('INSERT INTO purchase_attachments (purchase_id, file_path, uploaded_by, timestamp) VALUES (?,?,?,?)');
|
||||
attachments.forEach(fp => insertAttach.run(purchase.id, fp, username, now));
|
||||
}
|
||||
|
||||
storeAndBroadcastText(roomId, '小财', replyText);
|
||||
addToHistory(roomId, 'assistant', replyText);
|
||||
broadcastToRoom(roomId, { type: 'purchase_updated' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (aiResult.action === 'query') {
|
||||
const purchaseData = db.prepare('SELECT item, amount, payment_method, status FROM purchases WHERE room_id = ? ORDER BY created_at DESC').all(roomId)
|
||||
.map(p => `${p.item} ¥${p.amount} ${p.payment_method||''} ${p.status}`).join('\n');
|
||||
const purchaseData = db.prepare('SELECT item, amount, payment_method, status FROM purchases WHERE room_id = ? ORDER BY created_at DESC').all(roomId).map(p => `${p.item} ¥${p.amount} ${p.payment_method||''} ${p.status}`).join('\n');
|
||||
const summaryPrompt = `根据以下采购记录,用自然语言回答用户查询“${originalText}”。采购记录:\n${purchaseData || '暂无记录'}`;
|
||||
callDeepSeekForSummary(summaryPrompt).then(reply => {
|
||||
storeAndBroadcastText(roomId, '小财', reply);
|
||||
addToHistory(roomId, 'assistant', reply);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (aiResult.action === 'chat') {
|
||||
const reply = aiResult.reply || '好的,有什么需要帮助的吗?';
|
||||
storeAndBroadcastText(roomId, '小财', reply);
|
||||
addToHistory(roomId, 'assistant', reply);
|
||||
callDeepSeekForSummary(summaryPrompt).then(reply => { storeAndBroadcastText(roomId, '小财', reply); addToHistory(roomId, 'assistant', reply); });
|
||||
return;
|
||||
}
|
||||
if (aiResult.action === 'chat') { storeAndBroadcastText(roomId, '小财', aiResult.reply || '好的。'); addToHistory(roomId, 'assistant', aiResult.reply); return; }
|
||||
}
|
||||
|
||||
async function callDeepSeekForSummary(prompt) {
|
||||
@@ -540,6 +470,4 @@ async function callDeepSeekForSummary(prompt) {
|
||||
return data.choices[0].message.content;
|
||||
}
|
||||
|
||||
server.listen(process.env.PORT || 3000, () => {
|
||||
console.log(`Server running on port ${process.env.PORT || 3000}`);
|
||||
});
|
||||
server.listen(process.env.PORT || 3000, () => console.log(`Server running on port ${process.env.PORT || 3000}`));
|
||||
|
||||
Reference in New Issue
Block a user