feat(ai): 新增 AI 模块并集成至备课/错题集/试卷/改题四大业务场景
- 新增 src/modules/ai 独立模块,遵循三层架构(actions → services → shared/lib/ai) - 通过 AiClientProvider + useAiClient 实现 React Context 依赖注入,业务组件零直接 import - 6 个 Server Actions 均调用 requirePermission() 权限校验,返回 ActionState<T> - withAiTracking 统一埋点,覆盖 chat/similar_question/grading_assist/lesson_content/question_variant/weakness_analysis - 集成场景:作业批改 AiGradingAssist、错题集 AiErrorBookAnalysis、备课 AiLessonContentGenerator、试卷 AiQuestionVariantGenerator - 全量 i18n(en/zh-CN ai.json),Error Boundary + Skeleton 边界处理 - 同步架构图 004/005,新增审计报告 ai-module-audit-report.md
This commit is contained in:
134
src/modules/ai/schema.ts
Normal file
134
src/modules/ai/schema.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { z } from "zod"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 基础校验
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const AiChatMessageSchema = z.object({
|
||||
role: z.enum(["system", "user", "assistant"]),
|
||||
content: z.string().min(1).max(8000),
|
||||
})
|
||||
|
||||
export const AiChatInputSchema = z.object({
|
||||
messages: z.array(AiChatMessageSchema).min(1).max(50),
|
||||
providerId: z.string().min(1).optional(),
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 业务场景校验
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const SimilarQuestionInputSchema = z.object({
|
||||
questionText: z.string().min(1).max(4000),
|
||||
questionType: z.string().min(1),
|
||||
subject: z.string().optional(),
|
||||
knowledgePointIds: z.array(z.string()).optional(),
|
||||
count: z.number().int().min(1).max(10).optional(),
|
||||
})
|
||||
|
||||
export const GradingInputSchema = z.object({
|
||||
questionText: z.string().min(1).max(4000),
|
||||
questionType: z.string().min(1),
|
||||
studentAnswer: z.string().min(1).max(8000),
|
||||
correctAnswer: z.string().optional(),
|
||||
maxScore: z.number().int().min(1).max(100),
|
||||
subject: z.string().optional(),
|
||||
})
|
||||
|
||||
export const LessonContentInputSchema = z.object({
|
||||
topic: z.string().min(1).max(500),
|
||||
subject: z.string().optional(),
|
||||
grade: z.string().optional(),
|
||||
textbookId: z.string().optional(),
|
||||
chapterId: z.string().optional(),
|
||||
contentType: z.enum(["activity", "assessment", "question", "material"]),
|
||||
additionalContext: z.string().max(2000).optional(),
|
||||
})
|
||||
|
||||
export const QuestionVariantInputSchema = z.object({
|
||||
originalQuestion: z.object({
|
||||
text: z.string().min(1).max(4000),
|
||||
type: z.string().min(1),
|
||||
difficulty: z.number().int().min(1).max(5).optional(),
|
||||
options: z
|
||||
.array(
|
||||
z.object({
|
||||
id: z.string().min(1),
|
||||
text: z.string().min(1),
|
||||
isCorrect: z.boolean().optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
answer: z.string().optional(),
|
||||
}),
|
||||
subject: z.string().optional(),
|
||||
variantType: z.enum(["same_knowledge_point", "different_difficulty", "different_format"]),
|
||||
})
|
||||
|
||||
export const WeaknessAnalysisInputSchema = z.object({
|
||||
studentId: z.string().min(1),
|
||||
subjectId: z.string().optional(),
|
||||
errorItems: z
|
||||
.array(
|
||||
z.object({
|
||||
questionText: z.string().min(1),
|
||||
questionType: z.string().min(1),
|
||||
knowledgePointIds: z.array(z.string()).optional(),
|
||||
errorCount: z.number().int().min(1),
|
||||
masteryLevel: z.number().int().min(0).max(5),
|
||||
})
|
||||
)
|
||||
.min(1)
|
||||
.max(100),
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AI 返回结果校验(用于解析 AI JSON 输出)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const SimilarQuestionResultSchema = z.object({
|
||||
text: z.string().min(1),
|
||||
type: z.string().min(1),
|
||||
difficulty: z.number().int().min(1).max(5).optional(),
|
||||
options: z.array(z.object({ id: z.string(), text: z.string() })).optional(),
|
||||
answer: z.string().optional(),
|
||||
explanation: z.string().optional(),
|
||||
})
|
||||
|
||||
export const SimilarQuestionListSchema = z.array(SimilarQuestionResultSchema)
|
||||
|
||||
export const GradingSuggestionSchema = z.object({
|
||||
suggestedScore: z.number().min(0),
|
||||
confidence: z.number().min(0).max(1),
|
||||
feedback: z.string(),
|
||||
reasoning: z.string(),
|
||||
})
|
||||
|
||||
export const LessonContentResultSchema = z.object({
|
||||
title: z.string().min(1),
|
||||
content: z.string().min(1),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
|
||||
export const QuestionVariantResultSchema = z.object({
|
||||
text: z.string().min(1),
|
||||
type: z.string().min(1),
|
||||
difficulty: z.number().int().min(1).max(5),
|
||||
options: z
|
||||
.array(z.object({ id: z.string(), text: z.string(), isCorrect: z.boolean() }))
|
||||
.optional(),
|
||||
answer: z.string().optional(),
|
||||
explanation: z.string().optional(),
|
||||
})
|
||||
|
||||
export const WeaknessAnalysisResultSchema = z.object({
|
||||
weakAreas: z.array(
|
||||
z.object({
|
||||
area: z.string().min(1),
|
||||
severity: z.enum(["high", "medium", "low"]),
|
||||
suggestion: z.string().min(1),
|
||||
})
|
||||
),
|
||||
studyPlan: z.string().min(1),
|
||||
recommendedResources: z.array(z.string()),
|
||||
})
|
||||
Reference in New Issue
Block a user