| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- 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<void> {
- 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: '未知小区' };
- }
- }
|