// server/utils/answer.ts - OCS 答题提示词构建、答案清洗和响应格式化 import type { ISearchErrorResponse, ISearchSuccessResponse } from "~~/shared/types/answer"; /** `/api/search` 从 OCS 请求中最终抽取出的标准参数 */ export interface SearchParams { /** 题目正文,对应 OCS 的 `${title}` */ title: string; /** 题型:single、multiple、judgement、completion;未知值也允许透传给提示词 */ type: string; /** 选项文本,通常是 A/B/C/D 多行内容;没有选项时为空字符串 */ options: string; } /** OCS 兼容响应类型别名,与 shared/types/answer.ts 保持一致 */ export type OcsSuccessResponse = ISearchSuccessResponse; export type OcsErrorResponse = ISearchErrorResponse; /** * 不同题型对应的补充说明 * * 这里保留旧 Python 服务的语义:题型只影响提示词,不做硬编码答题 */ const QUESTION_TYPE_PROMPTS: Record = { single: "这是一道单选题。", multiple: "这是一道多选题,答案请用#符号分隔。", judgement: "这是一道判断题,需要回答:正确/对/true/√ 或者 错误/错/false/×。", completion: "这是一道填空题。" }; /** * 全局系统提示词 * * 重点约束“只给答案、不解释”,因为 OCS 需要的是可直接填入的答案文本, * 多余解释会降低自动匹配和展示效果 */ export const ANSWER_SYSTEM_PROMPT = "你是一个专业的考试答题助手。请直接回答答案,不要解释。选择题只回答选项的内容(如:地球);多选题用#号分隔答案,只回答选项的内容(如中国#世界#地球);判断题只回答: 正确/对/true/√ 或 错误/错/false/×;填空题直接给出答案。"; /** * 将 OCS 请求参数整理成发给模型的用户提示词 * * 旧 Python 服务就是在这里把题目、题型和选项拼成结构化文本; * Nuxt 版保持同样逻辑,方便答案行为尽量一致 */ export const parseQuestionAndOptions = ( question: string, options: string, questionType: string ) => { let prompt = `问题: ${question}\n`; const typePrompt = QUESTION_TYPE_PROMPTS[questionType]; if (typePrompt) { prompt += `${typePrompt}\n`; } if (options) { prompt += `选项:\n${options}\n`; } prompt += "请直接给出答案,不要解释。"; return prompt; }; /** * 从模型返回文本里提取最终答案 * * 旧服务对多选题做了一个兼容处理:如果模型返回类似 “答案是 A、B、C”, * 就尝试抽取 A-F 并改成 OCS 需要的 `A#B#C`。如果模型已经返回 `#` * 分隔内容,或者不是多选题,则直接返回原文本 */ export const extractAnswer = (aiResponse: string, questionType: string) => { const trimmedResponse = aiResponse.trim(); if (questionType === "multiple") { const lines = trimmedResponse.split("\n"); for (const line of lines) { if (/[A-D]/iu.test(line) && !line.includes("#")) { const options = ["A", "B", "C", "D", "E", "F"].filter((option) => line.toUpperCase().includes(option) ); if (options.length > 0) { return options.join("#"); } } } } return trimmedResponse; }; /** 生成 OCS 兼容成功响应,集中在一个函数里避免各 handler 自己拼结构 */ export const formatAnswerForOcs = ( question: string, answer: string ): OcsSuccessResponse => { return { code: 1, question, answer }; }; /** 生成 OCS 兼容失败响应;错误文案由调用处决定 */ export const createOcsErrorResponse = (msg: string): OcsErrorResponse => { return { code: 0, msg }; };