import type { Request, Response } from 'express'; import { sendSuccess, sendError } from '../http/response.js'; import { checkMessage } from '../services/compliance-check.service.js'; import { analyzeRiskContext } from '../services/ai-analysis.service.js'; import { createRiskEvent, createNotification } from '../services/risk-event.service.js'; import Parse from '../db/parse-client.js'; export async function testCompliance(req: Request, res: Response): Promise { const { roomId, content, senderId, senderName } = req.body as { roomId?: string; content?: string; senderId?: string; senderName?: string; }; if (!content) { sendError(res, 400, 'MISSING_CONTENT', '请提供消息内容'); return; } const rid = roomId || 'test-room'; const sid = senderId || 'test-user'; const sname = senderName || '测试用户'; // Step 1: 关键词初筛 const keywordResult = checkMessage(content); if (!keywordResult.matched) { sendSuccess(res, { keywordMatched: false, keywords: [], keywordDuration: '<1ms', aiTriggered: false, aiResult: null, eventCreated: false, }); return; } // Step 2: 查询当天该用户消息作为上下文 const todayMessages = await getTodayUserMessages(rid, sid); // 把当前测试消息也加入上下文 todayMessages.push({ content, senderName: sname, timestamp: new Date().toISOString(), }); // Step 3: DeepSeek AI 分析 const aiResult = await analyzeRiskContext(todayMessages, keywordResult.keywords[0].word); // Step 4: 创建事件(仅在 AI 判定违规时) let eventCreated = false; if (aiResult?.isRisky) { const groupInfo = await getGroupInfo(rid); const matchedKeywords = keywordResult.keywords.map(k => k.word); await createRiskEvent({ groupId: rid, groupName: groupInfo.groupName, communityName: groupInfo.communityName, type: 'keyword', severity: aiResult.severity, title: aiResult.title, description: aiResult.description, keywords: matchedKeywords, }); await createNotification({ userId: '*', type: 'risk', severity: aiResult.severity, title: `[测试] 风险预警:${groupInfo.groupName}`, description: aiResult.description, groupName: groupInfo.groupName, communityName: groupInfo.communityName, link: '/risk-control', }); eventCreated = true; } sendSuccess(res, { keywordMatched: true, keywords: keywordResult.keywords, keywordDuration: '<1ms', aiTriggered: true, aiResult: aiResult || { isRisky: false, severity: 'low', title: 'AI 未返回结果', description: 'API Key 未配置或调用失败' }, aiDuration: '1-3s', eventCreated, }); } async function getTodayUserMessages(roomId: string, senderId: string): Promise<{ content: string; senderName: string; timestamp: string }[]> { const todayStart = new Date(); todayStart.setHours(0, 0, 0, 0); const q = new Parse.Query('Message'); q.equalTo('roomId', roomId); q.equalTo('senderId', senderId); q.containedIn('msgType', [0, 2]); q.greaterThanOrEqualTo('timestamp', todayStart); q.ascending('timestamp'); q.limit(200); const rows = await q.find({ useMasterKey: true }) as any[]; return rows.map((r: any) => ({ content: (r.get('content') || '') as string, senderName: (r.get('senderName') || '') as string, timestamp: r.get('timestamp') ? new Date(r.get('timestamp') as Date).toISOString() : '', })); } async function getGroupInfo(roomId: string): Promise<{ groupName: string; communityName: string }> { try { const q = new Parse.Query('GroupChat'); q.equalTo('roomId', roomId); q.limit(1); const obj = await q.first({ useMasterKey: true }) as any; return { groupName: obj?.get('roomName') || '未知群', communityName: obj?.get('communityName') || '未知小区', }; } catch { return { groupName: '未知群', communityName: '未知小区' }; } }