| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- import type { ArticleReadingConfig } from '@/types/articleReading'
- import type { TopicDiscussionConfig } from '@/types/englishSpeaking'
- import { SPEAKING_CONFIG_API_BASE_URL, SPEAKING_DIALOGUE_API_BASE_URL } from '@/views/Editor/EnglishSpeaking/services/speakingApiConfig'
- const API_BASE = SPEAKING_CONFIG_API_BASE_URL
- /** 话题讨论与文章朗读共用同一套 config endpoint,靠 config.type 判别。 */
- export type SpeakingActivityConfig = TopicDiscussionConfig | ArticleReadingConfig
- export interface SpeakingConfigRecord<T extends SpeakingActivityConfig = SpeakingActivityConfig> {
- id: string
- config: T
- ownerUid?: string | null
- }
- async function parse<T>(res: Response): Promise<T> {
- if (!res.ok) {
- const detail = await res.text().catch(() => '')
- throw new Error(`[${res.status}] ${detail || res.statusText}`)
- }
- return res.json() as Promise<T>
- }
- /** 新建口语配置(话题讨论或文章朗读) */
- export async function createSpeakingConfig<T extends SpeakingActivityConfig>(
- config: T,
- ownerUid?: string | null,
- ): Promise<SpeakingConfigRecord<T>> {
- const res = await fetch(API_BASE, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ config, ownerUid: ownerUid ?? null }),
- })
- return parse<SpeakingConfigRecord<T>>(res)
- }
- /** 读取口语配置 */
- export async function getSpeakingConfig<T extends SpeakingActivityConfig = SpeakingActivityConfig>(
- id: string,
- ): Promise<SpeakingConfigRecord<T>> {
- const res = await fetch(`${API_BASE}/${encodeURIComponent(id)}`)
- return parse<SpeakingConfigRecord<T>>(res)
- }
- /** 更新口语配置 */
- export async function updateSpeakingConfig<T extends SpeakingActivityConfig>(
- id: string,
- config: T,
- ): Promise<SpeakingConfigRecord<T>> {
- const res = await fetch(`${API_BASE}/${encodeURIComponent(id)}`, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ config }),
- })
- return parse<SpeakingConfigRecord<T>>(res)
- }
- const DIALOGUE_BASE = SPEAKING_DIALOGUE_API_BASE_URL
- export interface ClassSessionSummary {
- userId: string
- sessionId: string
- status: 'active' | 'completed' | 'abandoned'
- overallStatus: 'ready' | 'generating' | 'failed' | null
- currentRound: number
- totalRounds: number
- overallScore: number | null
- dimensions: Record<string, number>
- topHighlights: string[]
- topImprovements: string[]
- createdAt: string | null
- completedAt: string | null
- }
- export interface ListSessionsByConfigResponse {
- summaries: ClassSessionSummary[]
- }
- export async function listSpeakingSessionsByConfig(
- configId: string,
- userIds: string[],
- ): Promise<ListSessionsByConfigResponse> {
- const res = await fetch(`${DIALOGUE_BASE}/sessions/by-config`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- credentials: 'include',
- body: JSON.stringify({ configId, userIds }),
- })
- return parse<ListSessionsByConfigResponse>(res)
- }
- export interface ClassSummaryResponse {
- bullets: [string, string, string]
- generatedAt: string
- fromCache: boolean
- llmStatus: 'ok' | 'fallback'
- }
- export async function generateClassSummary(
- configId: string,
- userIds: string[],
- locale: 'zh' | 'en' | 'hk',
- ): Promise<ClassSummaryResponse> {
- const res = await fetch(`${DIALOGUE_BASE}/sessions/by-config/summary`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- credentials: 'include',
- body: JSON.stringify({ configId, userIds, locale }),
- })
- return parse<ClassSummaryResponse>(res)
- }
|