hydro-ai-helper 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/.eslintrc.json +31 -0
  2. package/.github/workflows/sync-releases-to-gitee.yml +119 -0
  3. package/.github/workflows/sync-to-gitee.yml +53 -0
  4. package/.vercelignore +31 -0
  5. package/CONTRIBUTING.md +165 -0
  6. package/README.md +273 -0
  7. package/TROUBLESHOOTING.md +355 -0
  8. package/api/badge-active.ts +88 -0
  9. package/api/badge-installs.ts +75 -0
  10. package/api/report.ts +242 -0
  11. package/assets/screenshots/1.png +0 -0
  12. package/assets/screenshots/2.png +0 -0
  13. package/assets/screenshots/3.png +0 -0
  14. package/assets/screenshots/4.png +0 -0
  15. package/assets/screenshots/5.png +0 -0
  16. package/assets/screenshots/6.png +0 -0
  17. package/assets/screenshots/7.png +0 -0
  18. package/dist/__tests__/__mocks__/hydrooj.js +29 -0
  19. package/dist/__tests__/__mocks__/hydrooj.js.map +1 -0
  20. package/dist/constants/jailbreakRules.js +29 -0
  21. package/dist/constants/jailbreakRules.js.map +1 -0
  22. package/dist/constants/permissions.js +42 -0
  23. package/dist/constants/permissions.js.map +1 -0
  24. package/dist/handlers/adminConfigHandler.js +347 -0
  25. package/dist/handlers/adminConfigHandler.js.map +1 -0
  26. package/dist/handlers/adminHandler.js +378 -0
  27. package/dist/handlers/adminHandler.js.map +1 -0
  28. package/dist/handlers/analyticsHandler.js +433 -0
  29. package/dist/handlers/analyticsHandler.js.map +1 -0
  30. package/dist/handlers/dashboardHandler.js +22 -0
  31. package/dist/handlers/dashboardHandler.js.map +1 -0
  32. package/dist/handlers/exportHandler.js +118 -0
  33. package/dist/handlers/exportHandler.js.map +1 -0
  34. package/dist/handlers/studentHandler.js +430 -0
  35. package/dist/handlers/studentHandler.js.map +1 -0
  36. package/dist/handlers/teacherHandler.js +246 -0
  37. package/dist/handlers/teacherHandler.js.map +1 -0
  38. package/dist/handlers/testHandler.js +27 -0
  39. package/dist/handlers/testHandler.js.map +1 -0
  40. package/dist/handlers/updateHandler.js +84 -0
  41. package/dist/handlers/updateHandler.js.map +1 -0
  42. package/dist/handlers/versionHandler.js +61 -0
  43. package/dist/handlers/versionHandler.js.map +1 -0
  44. package/dist/index.d.ts +22 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +151 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/lib/crypto.js +110 -0
  49. package/dist/lib/crypto.js.map +1 -0
  50. package/dist/lib/httpHelpers.js +61 -0
  51. package/dist/lib/httpHelpers.js.map +1 -0
  52. package/dist/lib/queryHelpers.js +81 -0
  53. package/dist/lib/queryHelpers.js.map +1 -0
  54. package/dist/models/aiConfig.js +255 -0
  55. package/dist/models/aiConfig.js.map +1 -0
  56. package/dist/models/conversation.js +209 -0
  57. package/dist/models/conversation.js.map +1 -0
  58. package/dist/models/jailbreakLog.js +68 -0
  59. package/dist/models/jailbreakLog.js.map +1 -0
  60. package/dist/models/message.js +174 -0
  61. package/dist/models/message.js.map +1 -0
  62. package/dist/models/pluginInstall.js +95 -0
  63. package/dist/models/pluginInstall.js.map +1 -0
  64. package/dist/models/rateLimitRecord.js +54 -0
  65. package/dist/models/rateLimitRecord.js.map +1 -0
  66. package/dist/models/versionCache.js +89 -0
  67. package/dist/models/versionCache.js.map +1 -0
  68. package/dist/services/effectivenessService.js +131 -0
  69. package/dist/services/effectivenessService.js.map +1 -0
  70. package/dist/services/exportService.js +152 -0
  71. package/dist/services/exportService.js.map +1 -0
  72. package/dist/services/migrationService.js +90 -0
  73. package/dist/services/migrationService.js.map +1 -0
  74. package/dist/services/openaiClient.js +412 -0
  75. package/dist/services/openaiClient.js.map +1 -0
  76. package/dist/services/promptService.js +467 -0
  77. package/dist/services/promptService.js.map +1 -0
  78. package/dist/services/rateLimitService.js +108 -0
  79. package/dist/services/rateLimitService.js.map +1 -0
  80. package/dist/services/telemetryService.js +173 -0
  81. package/dist/services/telemetryService.js.map +1 -0
  82. package/dist/services/updateService.js +388 -0
  83. package/dist/services/updateService.js.map +1 -0
  84. package/dist/services/versionService.js +289 -0
  85. package/dist/services/versionService.js.map +1 -0
  86. package/dist/types/hydrooj.js +7 -0
  87. package/dist/types/hydrooj.js.map +1 -0
  88. package/dist/types/mongo.js +7 -0
  89. package/dist/types/mongo.js.map +1 -0
  90. package/dist/utils/domainHelper.js +16 -0
  91. package/dist/utils/domainHelper.js.map +1 -0
  92. package/dist/utils/mongo.js +16 -0
  93. package/dist/utils/mongo.js.map +1 -0
  94. package/frontend/admin/ConfigPanel.tsx +1379 -0
  95. package/frontend/admin/VersionBadge.tsx +655 -0
  96. package/frontend/ai_helper.page.tsx +52 -0
  97. package/frontend/ai_helper_admin_config.page.tsx +47 -0
  98. package/frontend/ai_helper_analytics.page.tsx +52 -0
  99. package/frontend/ai_helper_conversation_detail.page.tsx +55 -0
  100. package/frontend/ai_helper_conversations.page.tsx +56 -0
  101. package/frontend/components/AIHelperDashboard.tsx +125 -0
  102. package/frontend/problem_detail.page.tsx +395 -0
  103. package/frontend/student/AIAssistantPanel.tsx +1839 -0
  104. package/frontend/student/AIChatPanel.tsx +944 -0
  105. package/frontend/student/ThreeColumnLayout.tsx +240 -0
  106. package/frontend/teacher/AnalyticsPage.tsx +614 -0
  107. package/frontend/teacher/ConversationDetail.tsx +504 -0
  108. package/frontend/teacher/ConversationList.tsx +568 -0
  109. package/frontend/teacher/ExportDialog.tsx +291 -0
  110. package/frontend/test.page.ts +88 -0
  111. package/frontend/utils/domainUtils.ts +37 -0
  112. package/index.js +6 -0
  113. package/jest.config.js +17 -0
  114. package/lib/mongodb.ts +60 -0
  115. package/locales/en.yaml +4 -0
  116. package/locales/zh.yaml +77 -0
  117. package/package.json +48 -0
  118. package/public/.gitkeep +0 -0
  119. package/public/README.md +1 -0
  120. package/src/__tests__/__mocks__/hydrooj.ts +27 -0
  121. package/src/__tests__/services/exportService.test.ts +156 -0
  122. package/src/__tests__/services/promptService.test.ts +141 -0
  123. package/src/__tests__/services/rateLimitService.test.ts +145 -0
  124. package/src/__tests__/utils/domainHelper.test.ts +47 -0
  125. package/src/constants/jailbreakRules.ts +28 -0
  126. package/src/constants/permissions.ts +43 -0
  127. package/src/handlers/adminConfigHandler.ts +363 -0
  128. package/src/handlers/adminHandler.ts +427 -0
  129. package/src/handlers/analyticsHandler.ts +517 -0
  130. package/src/handlers/dashboardHandler.ts +20 -0
  131. package/src/handlers/exportHandler.ts +134 -0
  132. package/src/handlers/studentHandler.ts +483 -0
  133. package/src/handlers/teacherHandler.ts +317 -0
  134. package/src/handlers/testHandler.ts +25 -0
  135. package/src/handlers/updateHandler.ts +85 -0
  136. package/src/handlers/versionHandler.ts +62 -0
  137. package/src/index.ts +198 -0
  138. package/src/lib/crypto.ts +125 -0
  139. package/src/lib/httpHelpers.ts +75 -0
  140. package/src/lib/queryHelpers.ts +108 -0
  141. package/src/models/aiConfig.ts +375 -0
  142. package/src/models/conversation.ts +328 -0
  143. package/src/models/jailbreakLog.ts +108 -0
  144. package/src/models/message.ts +246 -0
  145. package/src/models/pluginInstall.ts +138 -0
  146. package/src/models/rateLimitRecord.ts +81 -0
  147. package/src/models/versionCache.ts +127 -0
  148. package/src/services/effectivenessService.ts +161 -0
  149. package/src/services/exportService.ts +191 -0
  150. package/src/services/migrationService.ts +111 -0
  151. package/src/services/openaiClient.ts +548 -0
  152. package/src/services/promptService.ts +573 -0
  153. package/src/services/rateLimitService.ts +122 -0
  154. package/src/services/telemetryService.ts +218 -0
  155. package/src/services/updateService.ts +441 -0
  156. package/src/services/versionService.ts +351 -0
  157. package/src/types/hydrooj-extensions.d.ts +55 -0
  158. package/src/types/hydrooj.ts +38 -0
  159. package/src/types/mongo.ts +23 -0
  160. package/src/utils/domainHelper.ts +16 -0
  161. package/src/utils/mongo.ts +15 -0
  162. package/templates/ai-helper/admin_config.html +8 -0
  163. package/templates/ai-helper/analytics.html +8 -0
  164. package/templates/ai-helper/dashboard.html +8 -0
  165. package/templates/ai-helper/teacher_conversation_detail.html +8 -0
  166. package/templates/ai-helper/teacher_conversations.html +8 -0
  167. package/tests/integration/README.md +86 -0
  168. package/tests/integration/curl/01-admin-config-set.sh +56 -0
  169. package/tests/integration/curl/02-student-chat.sh +67 -0
  170. package/tests/integration/curl/03-teacher-list.sh +52 -0
  171. package/tests/integration/curl/04-teacher-detail.sh +37 -0
  172. package/tests/integration/curl/05-export.sh +49 -0
  173. package/tests/integration/curl/06-analytics.sh +43 -0
  174. package/tests/performance/README.md +85 -0
  175. package/tests/performance/data/prepare-sample-data.md +57 -0
  176. package/tests/performance/scripts/export-csv-k6.js +41 -0
  177. package/tests/performance/scripts/student-chat-k6.js +44 -0
  178. package/tests/performance/scripts/teacher-conversations-k6.js +33 -0
  179. package/tsconfig.json +42 -0
  180. package/tsconfig.vercel.json +27 -0
  181. package/types/hydrooj/index.d.ts +73 -0
  182. package/vercel.json +3 -0
@@ -0,0 +1,430 @@
1
+ "use strict";
2
+ /**
3
+ * 学生端对话 Handler
4
+ * 处理学生的 AI 对话请求
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.ProblemStatusHandlerPriv = exports.ProblemStatusHandler = exports.ChatHandlerPriv = exports.ChatHandler = void 0;
41
+ const hydrooj_1 = require("hydrooj");
42
+ const openaiClient_1 = require("../services/openaiClient");
43
+ const promptService_1 = require("../services/promptService");
44
+ const rateLimitService_1 = require("../services/rateLimitService");
45
+ const effectivenessService_1 = require("../services/effectivenessService");
46
+ const domainHelper_1 = require("../utils/domainHelper");
47
+ /**
48
+ * ChatHandler - 处理学生的 AI 对话请求
49
+ * POST /ai-helper/chat
50
+ */
51
+ class ChatHandler extends hydrooj_1.Handler {
52
+ async post() {
53
+ try {
54
+ // 获取当前用户 ID(尽早获取,用于频率限制检查)
55
+ const userId = this.user._id;
56
+ // 获取当前域 ID(用于域隔离)
57
+ const domainId = (0, domainHelper_1.getDomainId)(this);
58
+ // 获取 AI 配置(用于频率限制和其他设置)
59
+ const aiConfigModel = this.ctx.get('aiConfigModel');
60
+ const aiConfig = await aiConfigModel.getConfig();
61
+ // 频率限制检查(在任何 AI 请求调用之前执行)
62
+ // 优先使用配置中的限制,如果没有配置则使用默认值 5
63
+ // 注意:使用 ?? 而非 || 以支持 0 值(0 表示禁用限流)
64
+ const rateLimitPerMinute = aiConfig?.rateLimitPerMinute ?? 5;
65
+ // 仅当限制值 > 0 时才执行频率限制检查(0 表示禁用限流)
66
+ if (rateLimitPerMinute > 0) {
67
+ const rateLimitService = new rateLimitService_1.RateLimitService(this.ctx);
68
+ const allowed = await rateLimitService.checkAndIncrement(domainId, userId, rateLimitPerMinute);
69
+ if (!allowed) {
70
+ // 返回 429 + JSON 提示
71
+ const rateLimitMessage = '提问太频繁了,请仔细思考后再提问';
72
+ this.response.status = 429;
73
+ this.response.body = {
74
+ error: rateLimitMessage,
75
+ code: 'RATE_LIMIT_EXCEEDED'
76
+ };
77
+ this.response.type = 'application/json';
78
+ return;
79
+ }
80
+ }
81
+ // 获取数据库模型实例
82
+ const conversationModel = this.ctx.get('conversationModel');
83
+ const messageModel = this.ctx.get('messageModel');
84
+ // 从请求体获取参数
85
+ const { problemId, problemTitle, problemContent, questionType, userThinking, includeCode, code, conversationId } = this.request.body;
86
+ // 验证问题类型
87
+ const validQuestionTypes = ['understand', 'think', 'debug', 'clarify', 'optimize'];
88
+ if (!validQuestionTypes.includes(questionType)) {
89
+ throw new Error('无效的问题类型');
90
+ }
91
+ // 服务端授权校验:optimize 类型需要用户已 AC 该题
92
+ // 防止用户绕过前端直接发送 optimize 请求
93
+ if (questionType === 'optimize') {
94
+ // 先获取题目文档,获取数字类型的 docId(RecordDoc.pid 是 number 类型)
95
+ const pdoc = await hydrooj_1.ProblemModel.get(domainId, problemId, ['docId']);
96
+ if (!pdoc) {
97
+ this.response.status = 404;
98
+ this.response.body = { error: '题目不存在' };
99
+ this.response.type = 'application/json';
100
+ return;
101
+ }
102
+ // 性能优化:使用 findOne 直接检查 AC 记录存在性(无需排序)
103
+ const dbStart = Date.now();
104
+ const acRecord = await hydrooj_1.db.collection('record').findOne({
105
+ domainId,
106
+ uid: userId,
107
+ pid: pdoc.docId,
108
+ status: hydrooj_1.STATUS.STATUS_ACCEPTED
109
+ }, { projection: { _id: 1 } });
110
+ console.log(`[Perf] AC Check: ${Date.now() - dbStart}ms`);
111
+ if (!acRecord) {
112
+ this.response.status = 403;
113
+ this.response.body = {
114
+ error: '代码优化功能仅对已通过该题的用户开放',
115
+ code: 'OPTIMIZE_REQUIRES_AC'
116
+ };
117
+ this.response.type = 'application/json';
118
+ return;
119
+ }
120
+ }
121
+ // 初始化服务
122
+ const promptService = new promptService_1.PromptService();
123
+ // 代码处理逻辑
124
+ let processedCode;
125
+ let codeWarning;
126
+ if (includeCode && code) {
127
+ // 检查代码长度,超过 5000 字符则截断
128
+ if (code.length > 5000) {
129
+ processedCode = code.substring(0, 5000);
130
+ codeWarning = '代码已截断到 5000 字符';
131
+ }
132
+ else {
133
+ processedCode = code;
134
+ }
135
+ }
136
+ else {
137
+ // includeCode=false 时忽略代码字段
138
+ processedCode = undefined;
139
+ }
140
+ const customSystemPromptTemplate = aiConfig?.systemPromptTemplate?.trim() || undefined;
141
+ const extraJailbreakPatterns = parseExtraJailbreakPatterns(aiConfig?.extraJailbreakPatternsText);
142
+ // 从服务端获取可信的题目内容(用于白名单和 System Prompt)
143
+ // 安全考虑:不使用客户端传入的 problemContent 作为白名单,避免被利用绕过越狱检测
144
+ let trustedProblemTitle;
145
+ let trustedProblemContent;
146
+ try {
147
+ const pdoc = await hydrooj_1.ProblemModel.get(domainId, problemId, ['title', 'content']);
148
+ if (pdoc) {
149
+ trustedProblemTitle = pdoc.title;
150
+ // 题目内容可能是字符串或 JSON 对象(多语言支持)
151
+ if (typeof pdoc.content === 'string') {
152
+ trustedProblemContent = pdoc.content;
153
+ }
154
+ else if (pdoc.content && typeof pdoc.content === 'object') {
155
+ // 多语言内容,取第一个可用的值
156
+ const values = Object.values(pdoc.content);
157
+ trustedProblemContent = values[0] || '';
158
+ }
159
+ }
160
+ }
161
+ catch (err) {
162
+ // 题目获取失败不阻塞主流程,但不使用白名单
163
+ console.warn('[ChatHandler] 获取题目内容失败,白名单将为空:', err);
164
+ }
165
+ // 题目内容截断(超过 500 字符) - 用于白名单和 System Prompt
166
+ let processedProblemContent;
167
+ if (trustedProblemContent) {
168
+ if (trustedProblemContent.length > 500) {
169
+ processedProblemContent = trustedProblemContent.substring(0, 500) + '...';
170
+ }
171
+ else {
172
+ processedProblemContent = trustedProblemContent;
173
+ }
174
+ }
175
+ // 验证用户输入
176
+ // validateInput 现在同时做长度校验和越狱关键词检测,防止学生尝试修改系统规则
177
+ // 使用服务端获取的可信题目内容作为白名单,避免客户端注入绕过检测
178
+ const validation = promptService.validateInput(userThinking, processedCode, extraJailbreakPatterns.length ? extraJailbreakPatterns : undefined, processedProblemContent);
179
+ if (!validation.valid) {
180
+ if (validation.matchedPattern) {
181
+ try {
182
+ const effectivenessService = new effectivenessService_1.EffectivenessService(this.ctx);
183
+ await effectivenessService.logJailbreakAttempt({
184
+ userId,
185
+ conversationId,
186
+ problemId,
187
+ questionType,
188
+ matchedPattern: validation.matchedPattern,
189
+ matchedText: validation.matchedText || userThinking.substring(0, 120)
190
+ });
191
+ }
192
+ catch (logErr) {
193
+ console.error('[ChatHandler] 记录越狱日志失败', logErr);
194
+ }
195
+ }
196
+ throw new Error(validation.error || '输入验证失败');
197
+ }
198
+ // 构造 system prompt
199
+ // 优先使用服务端获取的可信题目标题,其次使用前端传入的,最后使用题目ID
200
+ const problemTitleStr = trustedProblemTitle || problemTitle || `题目 ${problemId}`;
201
+ const systemPrompt = promptService.buildSystemPrompt(problemTitleStr, processedProblemContent, customSystemPromptTemplate);
202
+ // 处理对话会话 (新建或复用)
203
+ let currentConversationId;
204
+ if (conversationId) {
205
+ // 验证 conversationId 格式
206
+ const { ObjectId } = await Promise.resolve().then(() => __importStar(require('../utils/mongo')));
207
+ if (!ObjectId.isValid(conversationId)) {
208
+ this.response.status = 400;
209
+ this.response.body = { error: '无效的会话 ID' };
210
+ this.response.type = 'application/json';
211
+ return;
212
+ }
213
+ // 复用已有会话(验证所有权)
214
+ const conversation = await conversationModel.findById(conversationId);
215
+ if (!conversation) {
216
+ this.response.status = 404;
217
+ this.response.body = { error: '会话不存在' };
218
+ this.response.type = 'application/json';
219
+ return;
220
+ }
221
+ // 验证会话归属当前用户和当前域
222
+ if (conversation.userId !== userId || conversation.domainId !== domainId) {
223
+ this.response.status = 403;
224
+ this.response.body = { error: '无权访问此会话' };
225
+ this.response.type = 'application/json';
226
+ return;
227
+ }
228
+ currentConversationId = conversation._id;
229
+ }
230
+ else {
231
+ // 创建新会话
232
+ const now = new Date();
233
+ currentConversationId = await conversationModel.create({
234
+ domainId,
235
+ userId,
236
+ problemId,
237
+ classId: undefined, // TODO: 从用户信息获取班级 ID
238
+ startTime: now,
239
+ endTime: now,
240
+ messageCount: 0,
241
+ isEffective: false, // 初始标记为无效,后续通过有效对话判定服务更新
242
+ tags: [],
243
+ metadata: {
244
+ problemTitle: problemTitleStr,
245
+ problemContent: processedProblemContent
246
+ }
247
+ });
248
+ }
249
+ // 保存学生消息到数据库
250
+ await messageModel.create({
251
+ conversationId: currentConversationId,
252
+ role: 'student',
253
+ content: userThinking,
254
+ timestamp: new Date(),
255
+ questionType: questionType,
256
+ attachedCode: includeCode && !!processedCode,
257
+ attachedError: false, // TODO: 支持附带错误信息
258
+ metadata: processedCode ? {
259
+ codeLength: processedCode.length,
260
+ codeWarning
261
+ } : undefined
262
+ });
263
+ // 增加会话的消息计数
264
+ await conversationModel.incrementMessageCount(currentConversationId);
265
+ // 加载历史消息用于多轮对话(排除刚保存的当前消息)
266
+ // 使用 findRecentByConversationId 仅加载最近 7 条,避免长对话的内存压力
267
+ const historyMessages = (await messageModel.findRecentByConversationId(currentConversationId, 7))
268
+ .slice(0, -1)
269
+ .map((msg) => ({
270
+ role: msg.role,
271
+ content: msg.content
272
+ }));
273
+ // 构造 user prompt(包含历史上下文)
274
+ const userPrompt = promptService.buildUserPrompt(questionType, userThinking, processedCode, undefined, // errorInfo 暂不支持
275
+ historyMessages);
276
+ // 准备消息数组
277
+ const messages = [
278
+ { role: 'user', content: userPrompt }
279
+ ];
280
+ // 从数据库配置创建多模型 AI 客户端(支持 fallback)
281
+ let multiModelClient;
282
+ try {
283
+ multiModelClient = await (0, openaiClient_1.createMultiModelClientFromConfig)(this.ctx, aiConfig ?? undefined);
284
+ }
285
+ catch (error) {
286
+ // 配置不存在或不完整
287
+ console.error('[AI Helper] 创建 AI 客户端失败:', error);
288
+ this.response.status = 500;
289
+ this.response.body = { error: error instanceof Error ? error.message : 'AI 服务未配置' };
290
+ this.response.type = 'application/json';
291
+ return;
292
+ }
293
+ // 调用 AI 服务(支持多模型 fallback)
294
+ let aiResponse;
295
+ try {
296
+ const aiStart = Date.now();
297
+ const result = await multiModelClient.chat(messages, systemPrompt);
298
+ console.log(`[Perf] AI Response: ${Date.now() - aiStart}ms`);
299
+ aiResponse = result.content;
300
+ // 可选:记录使用的模型信息
301
+ console.log(`[AI Helper] 使用模型: ${result.usedModel.endpointName}/${result.usedModel.modelName}`);
302
+ }
303
+ catch (error) {
304
+ // 记录错误日志
305
+ console.error('[AI Helper] AI 调用失败:', error);
306
+ this.response.status = 500;
307
+ this.response.body = { error: error instanceof Error ? error.message : 'AI 服务调用失败' };
308
+ this.response.type = 'application/json';
309
+ return;
310
+ }
311
+ // 保存 AI 消息到数据库
312
+ const aiMessageTimestamp = new Date();
313
+ await messageModel.create({
314
+ conversationId: currentConversationId,
315
+ role: 'ai',
316
+ content: aiResponse,
317
+ timestamp: aiMessageTimestamp,
318
+ questionType: undefined, // AI 消息没有问题类型
319
+ attachedCode: false,
320
+ attachedError: false
321
+ });
322
+ // 增加会话的消息计数并更新结束时间
323
+ await conversationModel.incrementMessageCount(currentConversationId);
324
+ await conversationModel.updateEndTime(currentConversationId, aiMessageTimestamp);
325
+ // 后台异步触发有效对话判定(不阻塞主流程)
326
+ try {
327
+ const effectivenessService = new effectivenessService_1.EffectivenessService(this.ctx);
328
+ // 使用 void 丢弃 Promise,fire-and-forget
329
+ void effectivenessService.analyzeConversation(currentConversationId);
330
+ }
331
+ catch (err) {
332
+ // 捕获同步错误(如构造函数异常),记录日志但不影响主流程
333
+ this.ctx.logger.error('Schedule effectiveness analyze failed', err);
334
+ }
335
+ // 构造响应 (返回真实的 conversationId)
336
+ const response = {
337
+ conversationId: currentConversationId.toHexString(),
338
+ message: {
339
+ role: 'ai',
340
+ content: aiResponse,
341
+ timestamp: aiMessageTimestamp.toISOString()
342
+ }
343
+ };
344
+ // 如果代码被截断,添加警告信息
345
+ if (codeWarning) {
346
+ response.codeWarning = codeWarning;
347
+ }
348
+ this.response.body = response;
349
+ this.response.type = 'application/json';
350
+ }
351
+ catch (err) {
352
+ console.error('[AI Helper] ChatHandler error:', err);
353
+ this.response.status = 500;
354
+ this.response.body = { error: err instanceof Error ? err.message : '服务器内部错误' };
355
+ this.response.type = 'application/json';
356
+ }
357
+ }
358
+ }
359
+ exports.ChatHandler = ChatHandler;
360
+ // 导出路由权限配置 - 需要用户登录
361
+ exports.ChatHandlerPriv = hydrooj_1.PRIV.PRIV_USER_PROFILE;
362
+ function parseExtraJailbreakPatterns(raw) {
363
+ if (!raw) {
364
+ return [];
365
+ }
366
+ const patterns = [];
367
+ const lines = raw.split(/\r?\n/);
368
+ for (const line of lines) {
369
+ const patternText = line.trim();
370
+ if (!patternText)
371
+ continue;
372
+ try {
373
+ patterns.push(new RegExp(patternText, 'gi'));
374
+ }
375
+ catch (err) {
376
+ console.warn('[ChatHandler] 自定义越狱规则解析失败,已跳过:', patternText, err);
377
+ }
378
+ }
379
+ return patterns;
380
+ }
381
+ /**
382
+ * ProblemStatusHandler - 查询用户在指定题目的提交状态
383
+ * GET /ai-helper/problem-status/:problemId
384
+ * 返回用户是否已 AC 该题,以及最近一次 AC 的代码
385
+ */
386
+ class ProblemStatusHandler extends hydrooj_1.Handler {
387
+ async get({ problemId }) {
388
+ // 输入验证:problemId 不能为空且长度合理
389
+ if (!problemId || typeof problemId !== 'string' || problemId.length > 50) {
390
+ this.response.status = 400;
391
+ this.response.body = { error: '无效的题目 ID' };
392
+ this.response.type = 'application/json';
393
+ return;
394
+ }
395
+ const userId = this.user._id;
396
+ const domainId = (0, domainHelper_1.getDomainId)(this);
397
+ // 先获取题目文档,获取数字类型的 docId(RecordDoc.pid 是 number 类型)
398
+ const pdoc = await hydrooj_1.ProblemModel.get(domainId, problemId, ['docId']);
399
+ if (!pdoc) {
400
+ // 题目不存在时返回 hasAccepted: false
401
+ this.response.body = { hasAccepted: false };
402
+ this.response.type = 'application/json';
403
+ return;
404
+ }
405
+ // 性能优化:使用 findOne 直接获取最新 AC 记录
406
+ const dbStart = Date.now();
407
+ const acRecordDoc = await hydrooj_1.db.collection('record').findOne({
408
+ domainId,
409
+ uid: userId,
410
+ pid: pdoc.docId,
411
+ status: hydrooj_1.STATUS.STATUS_ACCEPTED
412
+ }, {
413
+ sort: { _id: -1 }, // 需要排序以获取最新代码
414
+ projection: { status: 1, code: 1, lang: 1 }
415
+ });
416
+ console.log(`[Perf] Status Check: ${Date.now() - dbStart}ms`);
417
+ const hasAccepted = !!acRecordDoc;
418
+ const acCode = acRecordDoc?.code;
419
+ const acLang = acRecordDoc?.lang;
420
+ this.response.body = {
421
+ hasAccepted,
422
+ acCode, // 最近一次 AC 的代码
423
+ acLang // 代码语言
424
+ };
425
+ this.response.type = 'application/json';
426
+ }
427
+ }
428
+ exports.ProblemStatusHandler = ProblemStatusHandler;
429
+ exports.ProblemStatusHandlerPriv = hydrooj_1.PRIV.PRIV_USER_PROFILE;
430
+ //# sourceMappingURL=studentHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studentHandler.js","sourceRoot":"","sources":["../../src/handlers/studentHandler.ts"],"names":[],"mappings":"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"}