import { FASTAPI_BASE_URL, authHeaders, readError, type ApiEnvelope, type ScoreType } from './session' export type DimensionScore = { dimension: string score: number max_score: number comment?: string evidence?: string[] deductions?: string[] improvement?: string } export type ScoreDetail = { dimension: string score: number deducted_reason?: string ai_confidence?: number comment?: string } export type EvaluationResult = { evaluation_id: number score_type: ScoreType total_score: number dimension_scores: DimensionScore[] score_details: ScoreDetail[] errors: string[] improvement_plan: string[] evidence_summary: string[] guideline_refs: string[] overall_comment: string } export type EvaluationDetail = { evaluation_id: number session_id: number case_id: number case_title: string score_type: ScoreType total_score: number dimension_scores: DimensionScore[] score_details: ScoreDetail[] overall_comment: string pdf_file_path?: string created_at?: string } export type EvaluationPdfExport = { export_id: number file_path: string } export type EvaluationPdfDownload = { blob?: Blob filePath?: string fileName: string } export async function generateEvaluation(sessionId: number, scoreType: ScoreType = 'percentage') { const response = await fetch(`${FASTAPI_BASE_URL}/sessions/${sessionId}/evaluation`, { method: 'POST', headers: authHeaders(), body: JSON.stringify({ score_type: scoreType }) }) if (!response.ok) { throw new Error(await readError(response)) } const result = (await response.json()) as ApiEnvelope if (result.code !== 'OK' || !result.data) { throw new Error(result.message || '评价生成失败') } return result.data } export async function fetchEvaluationDetail(evaluationId: number) { const response = await fetch(`${FASTAPI_BASE_URL}/evaluations/${evaluationId}`, { method: 'GET', headers: authHeaders() }) if (!response.ok) { throw new Error(await readError(response)) } const result = (await response.json()) as ApiEnvelope if (result.code !== 'OK' || !result.data) { throw new Error(result.message || '评价详情加载失败') } return result.data } export async function downloadEvaluationPdf(evaluationId: number): Promise { const response = await fetch(`${FASTAPI_BASE_URL}/evaluations/${evaluationId}/download-pdf`, { method: 'GET', headers: authHeaders('application/pdf') }) if (!response.ok) { throw new Error(await readError(response)) } const contentType = response.headers.get('Content-Type') || '' const disposition = response.headers.get('Content-Disposition') || '' const fileName = readDownloadFileName(disposition, evaluationId) if (contentType.includes('application/json')) { const result = (await response.json()) as ApiEnvelope if (result.code !== 'OK' || !result.data?.file_path) { throw new Error(result.message || 'PDF 下载失败') } return { filePath: result.data.file_path, fileName: readFileNameFromPath(result.data.file_path, fileName) } } return { blob: await response.blob(), fileName } } function readDownloadFileName(disposition: string, evaluationId: number) { const utf8Name = disposition.match(/filename\*=UTF-8''([^;]+)/i)?.[1] if (utf8Name) return decodeURIComponent(utf8Name) const quotedName = disposition.match(/filename="?([^"]+)"?/i)?.[1] if (quotedName) return quotedName return `training_record_${evaluationId}.pdf` } function readFileNameFromPath(filePath: string, fallback: string) { const cleanPath = filePath.split('?')[0].split('#')[0] const name = cleanPath.split('/').filter(Boolean).pop() return name || fallback }