Quellcode durchsuchen

feat(speaking): pass wordAnalysis and imageUrl through report adapter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jimmylee vor 1 Monat
Ursprung
Commit
58a2f3efe3
1 geänderte Dateien mit 22 neuen und 1 gelöschten Zeilen
  1. 22 1
      src/views/Editor/EnglishSpeaking/services/llmService.ts

+ 22 - 1
src/views/Editor/EnglishSpeaking/services/llmService.ts

@@ -8,6 +8,7 @@ import type {
   TaskHint,
   DialogueReport,
   SentenceEvaluation,
+  WordAnalysisItem,
 } from '@/types/englishSpeaking'
 import { SPEAKING_DIALOGUE_API_BASE_URL } from './speakingApiConfig'
 
@@ -76,13 +77,19 @@ async function* parseSSEStream(reader: ReadableStreamDefaultReader<Uint8Array>):
 
 // ==================== Backend shape types ====================
 
+interface BackendWordAnalysisItemRaw {
+  word: string
+  accuracy_score: number | null
+  error_type: string
+}
+
 interface BackendEvaluation {
   status: 'pending' | 'completed' | 'failed'
   accuracyScore: number | null
   fluencyScore: number | null
   completenessScore: number | null
   prosodyScore: number | null
-  wordAnalysis: unknown
+  wordAnalysis: BackendWordAnalysisItemRaw[] | null
   contentFeedback: {
     comment: string
     betterExpression: string
@@ -95,6 +102,7 @@ interface BackendRound {
   content: string
   audioUrl: string | null
   audioDuration: number | null   // NEW: 秒,由后端 /report 透传
+  imageUrl: string | null         // ← NEW
   evaluation?: BackendEvaluation
 }
 
@@ -128,6 +136,17 @@ function hasCompleteScores(evaluation?: BackendEvaluation): evaluation is Backen
     && typeof evaluation.prosodyScore === 'number'
 }
 
+function normaliseWordAnalysis(
+  raw: BackendWordAnalysisItemRaw[] | null | undefined,
+): WordAnalysisItem[] | undefined {
+  if (!Array.isArray(raw) || raw.length === 0) return undefined
+  return raw.map(w => ({
+    word: w.word,
+    accuracyScore: typeof w.accuracy_score === 'number' ? w.accuracy_score : 0,
+    errorType: (w.error_type ?? 'None') as WordAnalysisItem['errorType'],
+  }))
+}
+
 function adaptReport(raw: BackendReportResponse): DialogueReport {
   const sentenceEvaluations: SentenceEvaluation[] = raw.rounds.map((r, idx) => {
     const pronunciation = r.role === 'student' && hasCompleteScores(r.evaluation)
@@ -146,11 +165,13 @@ function adaptReport(raw: BackendReportResponse): DialogueReport {
       content: r.content,
       audioUrl: r.audioUrl ?? undefined,
       audioDuration: r.audioDuration ?? undefined,
+      imageUrl: r.imageUrl ?? undefined,                      // ← NEW
       score: pronunciation
         ? Math.round((pronunciation.accuracy + pronunciation.fluency + pronunciation.intonation + pronunciation.stress) / 4)
         : undefined,
       pronunciation,
       feedback: r.evaluation?.contentFeedback ?? undefined,
+      wordAnalysis: normaliseWordAnalysis(r.evaluation?.wordAnalysis), // ← NEW
     }
   })