// src/services/api.ts import type { JobConfig } from '../types'; export type PipelinePlots = { original_sentiment: string; counterfactual_sentiment: string; }; export type PipelineResultsDTO = { data_loaded: number; model_loaded: string; generation_file: string; generation_samples: number; counterfactual_file: string; counterfactual_added: number; counterfactual_total: number; sampling_method: string; sentiment_subset_file: string; sentiment_subset_size: number; cf_sentiment_subset_file: string; cf_sentiment_subset_size: number; // 後端還會給 stereotype 的欄位,但前端不需要可不宣告 config_used: import('../types').JobConfig; metrics: import('../types').JobMetrics & { finalMeanDiff: number; cfFinalMeanDiff: number; }; plots: PipelinePlots; }; export type PipelineResponseDTO = { status: 'success' | 'error'; message: string; timestamp: string; results: PipelineResultsDTO; }; const BASE = import.meta.env.VITE_API_BASE ?? '/api'; async function runPipeline(config: any) { const r = await fetch(`${BASE}/pipeline`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ config }), }); if (!r.ok) { const text = await r.text(); throw new Error(`Pipeline failed (${r.status}): ${text}`); } return r.json(); } async function checkHealth() { const r = await fetch(`${BASE}/health`); return r.json(); } function resolvePath(p?: string) { if (!p) return ''; if (p.startsWith('http')) return p; const path = p.startsWith('/') ? p : `/${p}`; return `${BASE}${path}`; } export const MLBiasAPI = { runPipeline, checkHealth, resolvePath };