import { Injectable, Logger } from '@nestjs/common'; import { AiGatewayService } from '../ai/gateway/ai-gateway.service'; import { QuizGenerationResultSchema } from '../ai/prompts/schemas/quiz-generation.schema'; import type { QuizGenerationSnapshot } from './quiz-generation-snapshot-builder'; /** * M-AI-07-03: Quiz Generation Executor * * 将 Quiz 生成输入快照适配到统一 Job Engine 的 EXECUTE 阶段。 * * 职责:从 Snapshot 构造模型输入、通过 AiGateway 调用、返回结构化输出。 * 不负责:写数据库、写 Job 状态、重试、Artifact、Credential。 */ @Injectable() export class QuizGenerationExecutor { private readonly logger = new Logger(QuizGenerationExecutor.name); constructor(private readonly aiGateway: AiGatewayService) {} async execute(snapshot: QuizGenerationSnapshot, timeoutMs: number) { const s = snapshot.snapshot; // 构造知识点列表文本 const itemsText = s.knowledgeItems .map((item, i) => `【知识点${i + 1}】${item.title}\n${item.content}`, ) .join('\n\n'); const typeDesc = s.questionTypes.join('、'); const userMessage = [ `【知识库】${s.knowledgeBaseTitle}`, s.knowledgeBaseDescription ? `描述:${s.knowledgeBaseDescription}` : '', '', itemsText, '', `请为以上知识点生成 ${s.questionCount} 道测验题目。`, `题型:${typeDesc}`, `难度:${s.difficultyLevel}`, ].filter(Boolean).join('\n'); this.logger.log( `Quiz Generation Executor calling AI: userId=${s.userId} ` + `kb=${s.targetId} items=${s.knowledgeItems.length} ` + `questionCount=${s.questionCount} types=${s.questionTypes.join(',')} ` + `difficulty=${s.difficultyLevel} modelTier=${s.modelTier} timeoutMs=${timeoutMs}`, ); const response = await this.aiGateway.generate( { feature: 'quiz-generation', userId: s.userId, tier: s.modelTier as any, promptKey: s.promptKey, promptVersion: s.promptVersion, messages: [{ role: 'user' as const, content: userMessage }], outputSchema: QuizGenerationResultSchema, maxTokens: 4096, }, timeoutMs, ); this.logger.log( `Quiz Generation Executor completed: userId=${s.userId} ` + `kb=${s.targetId} questions=${(response.parsed as any)?.questions?.length} ` + `tokens=${response.usage.inputTokens}/${response.usage.outputTokens}`, ); return response; } }