feat: Generation Page AI workflows + AI/Vector modules + exam session fixes
Generation Page (complete rebuild): - Full production-parity exam generation wizard with 4 IELTS modules - Reading: AI passage gen, 5 exercise types (MCQ, Fill, Write, T/F, Match) - Listening: 4 section types, AI context gen, TTS audio gen (ElevenLabs) - Writing: Task 1/2, AI instruction gen, word limits, marks - Speaking: 3 parts, AI script gen, avatar video gen (7 avatars) - Per-module config: timer, CEFR difficulty, access, approval, rubrics - Exam submission workflow (draft/published) Exam Structures: - New encoach.exam.structure model + CRUD controller - ExamStructuresPage wired to real API AI Module (encoach_ai): - OpenAI service, ElevenLabs TTS, AWS Polly, ELAI avatars - AI settings model with Odoo config parameters - 7 generation endpoints (passage, exercises, instructions, scripts, context) Vector Module (encoach_vector): - pgvector integration for RAG-based content search - Embedding service with sentence-transformers Exam Session Fixes: - Fixed ExamSession.tsx field mapping (question_type→type, exam_title→title) - Fixed submit payload to include attempt_id and answers - Fixed normalizeType to handle null/undefined Tested: 12/12 API tests passed, browser-verified with real OpenAI calls Made-with: Cursor
This commit is contained in:
@@ -22,8 +22,9 @@ export default function AiWritingHelper({ text, task_type = "ielts_writing" }: P
|
||||
const mutation = useMutation({
|
||||
mutationFn: (mode: NonNullable<Mode>) =>
|
||||
coachingService.writingHelp({
|
||||
text: text.trim(),
|
||||
task_type: `${task_type}:${mode}`,
|
||||
task: task_type,
|
||||
draft: text.trim(),
|
||||
help_type: mode,
|
||||
}),
|
||||
onSuccess: () => setShowResult(true),
|
||||
onError: (err: Error) => {
|
||||
@@ -84,20 +85,20 @@ export default function AiWritingHelper({ text, task_type = "ielts_writing" }: P
|
||||
|
||||
{showResult && !loading && mutation.data && activeMode === "improve" && (
|
||||
<div className="space-y-3">
|
||||
{mutation.data.feedback && (
|
||||
{mutation.data.tips?.length > 0 && (
|
||||
<div className="rounded-lg border bg-muted/30 p-3">
|
||||
<p className="text-xs font-semibold text-primary mb-1 flex items-center gap-1">
|
||||
<Sparkles className="h-3 w-3" /> Feedback
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">{mutation.data.feedback}</p>
|
||||
<p className="text-sm text-muted-foreground">{mutation.data.tips.join(" ")}</p>
|
||||
</div>
|
||||
)}
|
||||
{mutation.data.improved && (
|
||||
{mutation.data.improved_text && (
|
||||
<div className="rounded-lg border bg-muted/30 p-3">
|
||||
<p className="text-xs font-semibold text-primary mb-1 flex items-center gap-1">
|
||||
<Sparkles className="h-3 w-3" /> Improved Version
|
||||
</p>
|
||||
<p className="text-sm">{mutation.data.improved}</p>
|
||||
<p className="text-sm">{mutation.data.improved_text}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -108,17 +109,17 @@ export default function AiWritingHelper({ text, task_type = "ielts_writing" }: P
|
||||
<p className="text-xs font-semibold text-primary mb-1 flex items-center gap-1">
|
||||
<Sparkles className="h-3 w-3" /> Grammar notes
|
||||
</p>
|
||||
{(mutation.data.grammar_notes?.length ?? 0) > 0 ? (
|
||||
mutation.data.grammar_notes!.map((note, i) => (
|
||||
{(mutation.data.changes?.length ?? 0) > 0 ? (
|
||||
mutation.data.changes.map((c, i) => (
|
||||
<div key={i} className="text-sm border-l-2 border-warning pl-2">
|
||||
<p className="text-muted-foreground">{note}</p>
|
||||
<p className="text-muted-foreground"><strong>{c.original}</strong> → {c.revised} — {c.reason}</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">No grammar issues flagged.</p>
|
||||
)}
|
||||
{mutation.data.feedback ? (
|
||||
<p className="text-xs text-muted-foreground pt-2 border-t">{mutation.data.feedback}</p>
|
||||
{mutation.data.tips?.length > 0 ? (
|
||||
<p className="text-xs text-muted-foreground pt-2 border-t">{mutation.data.tips.join("; ")}</p>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
@@ -128,9 +129,9 @@ export default function AiWritingHelper({ text, task_type = "ielts_writing" }: P
|
||||
<p className="text-xs font-semibold text-primary mb-1 flex items-center gap-1">
|
||||
<Sparkles className="h-3 w-3" /> Estimated band / assessment
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">{mutation.data.feedback}</p>
|
||||
{mutation.data.improved ? (
|
||||
<p className="text-sm mt-2 pt-2 border-t">{mutation.data.improved}</p>
|
||||
<p className="text-sm text-muted-foreground">{mutation.data.tips?.join(" ") ?? ""}</p>
|
||||
{mutation.data.improved_text ? (
|
||||
<p className="text-sm mt-2 pt-2 border-t">{mutation.data.improved_text}</p>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user