feat(voice): add async selectable summaries

This commit is contained in:
zhangheng
2026-07-22 19:13:55 +08:00
parent 108e280b3f
commit 0a2509d923
17 changed files with 1530 additions and 159 deletions

View File

@@ -2,6 +2,8 @@ import type {
FeedbackDraft,
FeedbackRecord,
FeedbackSession,
FeedbackSummaryRun,
FeedbackSummaryStatus,
GeneratedFeedback,
HealthStatus,
StudentDraft,
@@ -104,10 +106,28 @@ interface RawFeedbackSession {
failed_segment_count: number
needs_generation: boolean
lessons: RawVoiceLesson[]
latest_summary_run?: RawFeedbackSummaryRun | null
created_at: string
updated_at: string
}
interface RawFeedbackSummaryRun {
id: string
feedback_session_id: string
lesson_ids: string[]
status: FeedbackSummaryStatus
content: string | null
method: string | null
model: string | null
prompt_version: string
character_count: number | null
error_message: string | null
attempts: number
created_at: string
completed_at: string | null
applied_at: string | null
}
interface RawVoiceLessonCreated {
id: string
sequence: number
@@ -125,7 +145,7 @@ interface RawVoiceLessonFinished {
interface RawGeneratedFeedback {
content: string
method: 'llm' | 'extractive'
method: 'llm' | 'llm_hierarchical' | 'extractive'
}
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
@@ -345,11 +365,33 @@ function mapFeedbackSession(session: RawFeedbackSession): FeedbackSession {
failedSegmentCount: session.failed_segment_count,
needsGeneration: session.needs_generation,
lessons: session.lessons.map(mapVoiceLesson),
latestSummaryRun: session.latest_summary_run
? mapFeedbackSummaryRun(session.latest_summary_run)
: null,
createdAt: parseTimestamp(session.created_at),
updatedAt: parseTimestamp(session.updated_at)
}
}
function mapFeedbackSummaryRun(run: RawFeedbackSummaryRun): FeedbackSummaryRun {
return {
id: run.id,
feedbackSessionId: run.feedback_session_id,
lessonIds: run.lesson_ids,
status: run.status,
content: run.content,
method: run.method,
model: run.model,
promptVersion: run.prompt_version,
characterCount: run.character_count,
errorMessage: run.error_message,
attempts: run.attempts,
createdAt: parseTimestamp(run.created_at),
completedAt: run.completed_at ? parseTimestamp(run.completed_at) : null,
appliedAt: run.applied_at ? parseTimestamp(run.applied_at) : null
}
}
export async function getHealth(): Promise<HealthStatus> {
const result = await request<RawHealthStatus>('/health', 'GET', undefined, 10000, false)
return {
@@ -607,3 +649,37 @@ export async function generateFeedbackFromVoice(
)
return result
}
export async function createFeedbackSummaryRun(
sessionId: string,
lessonIds: string[],
existingContent: string,
idempotencyKey: string
): Promise<FeedbackSummaryRun> {
const result = await request<RawFeedbackSummaryRun>(
`/api/v1/feedback-sessions/${encodeURIComponent(sessionId)}/summary-runs`,
'POST',
{
lesson_ids: lessonIds,
existing_content: existingContent,
idempotency_key: idempotencyKey
},
30000
)
return mapFeedbackSummaryRun(result)
}
export async function getFeedbackSummaryRun(runId: string): Promise<FeedbackSummaryRun> {
const result = await request<RawFeedbackSummaryRun>(
`/api/v1/feedback-summary-runs/${encodeURIComponent(runId)}`
)
return mapFeedbackSummaryRun(result)
}
export async function applyFeedbackSummaryRun(runId: string): Promise<FeedbackSession> {
const result = await request<RawFeedbackSession>(
`/api/v1/feedback-summary-runs/${encodeURIComponent(runId)}/apply`,
'POST'
)
return mapFeedbackSession(result)
}

View File

@@ -93,10 +93,30 @@ export interface FeedbackSession {
failedSegmentCount: number
needsGeneration: boolean
lessons: VoiceLesson[]
latestSummaryRun: FeedbackSummaryRun | null
createdAt: number
updatedAt: number
}
export type FeedbackSummaryStatus = 'queued' | 'processing' | 'ready' | 'failed' | 'applied'
export interface FeedbackSummaryRun {
id: string
feedbackSessionId: string
lessonIds: string[]
status: FeedbackSummaryStatus
content: string | null
method: string | null
model: string | null
promptVersion: string
characterCount: number | null
errorMessage: string | null
attempts: number
createdAt: number
completedAt: number | null
appliedAt: number | null
}
export interface VoiceLessonCreated {
id: string
sequence: number
@@ -114,5 +134,5 @@ export interface VoiceLessonFinished {
export interface GeneratedFeedback {
content: string
method: 'llm' | 'extractive'
method: 'llm' | 'llm_hierarchical' | 'extractive'
}