| const API_BASE = process.env.REACT_APP_API_URL !== undefined ? process.env.REACT_APP_API_URL : 'http://localhost:8001'; |
|
|
| export async function fetchModels() { |
| const resp = await fetch(`${API_BASE}/api/models`, { cache: 'no-store' }); |
| if (!resp.ok) throw new Error(`Failed to fetch models: ${resp.status}`); |
| return resp.json(); |
| } |
|
|
| export async function runComparisonStream(query, neonSelections, comparisonModelIds, sessionId, onGroupStart, onResponse, onDone, personaTarget = 'neon-only') { |
| const resp = await fetch(`${API_BASE}/api/compare/stream`, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ |
| query, |
| neon_selections: neonSelections, |
| comparison_model_ids: comparisonModelIds, |
| session_id: sessionId, |
| persona_target: personaTarget, |
| }), |
| }); |
| if (!resp.ok) { |
| const err = await resp.json().catch(() => ({ detail: resp.statusText })); |
| throw new Error(err.detail || 'Comparison failed'); |
| } |
|
|
| const reader = resp.body.getReader(); |
| const decoder = new TextDecoder(); |
| let buffer = ''; |
|
|
| while (true) { |
| const { value, done } = await reader.read(); |
| if (done) break; |
| buffer += decoder.decode(value, { stream: true }); |
|
|
| const parts = buffer.split('\n\n'); |
| buffer = parts.pop(); |
|
|
| for (const part of parts) { |
| const lines = part.trim().split('\n'); |
| let eventType = 'message'; |
| let data = ''; |
| for (const line of lines) { |
| if (line.startsWith('event: ')) eventType = line.slice(7).trim(); |
| else if (line.startsWith('data: ')) data = line.slice(6); |
| } |
| if (!data) continue; |
| try { |
| const parsed = JSON.parse(data); |
| if (eventType === 'group_start') onGroupStart(parsed); |
| else if (eventType === 'response') onResponse(parsed); |
| else if (eventType === 'done') onDone(); |
| } catch (e) { |
| console.warn('SSE parse error', e, data); |
| } |
| } |
| } |
| } |
|
|
| export async function uploadCsvComparison(file, neonSelections, comparisonModelIds, personaTarget = 'neon-only') { |
| const form = new FormData(); |
| form.append('file', file); |
| form.append('neon_selections', JSON.stringify(neonSelections)); |
| form.append('comparison_model_ids', JSON.stringify(comparisonModelIds)); |
| form.append('persona_target', personaTarget); |
|
|
| const resp = await fetch(`${API_BASE}/api/compare/csv`, { |
| method: 'POST', |
| body: form, |
| }); |
| if (!resp.ok) { |
| const err = await resp.json().catch(() => ({ detail: resp.statusText })); |
| throw new Error(err.detail || 'CSV comparison failed'); |
| } |
| return resp.blob(); |
| } |
|
|
| export async function downloadHistory(sessionId) { |
| const resp = await fetch(`${API_BASE}/api/history/${sessionId}/csv`); |
| if (!resp.ok) throw new Error('No history available'); |
| return resp.blob(); |
| } |
|
|