import type { InitResponse, RLState, SchemaGraph, SSEEvent } from './types' const BASE_URL: string = import.meta.env.VITE_API_URL ?? '' async function* parseSSE(response: Response): AsyncGenerator { const reader = response.body!.getReader() const decoder = new TextDecoder() let buffer = '' while (true) { const { done, value } = await reader.read() if (done) break buffer += decoder.decode(value, { stream: true }) const lines = buffer.split('\n') buffer = lines.pop() ?? '' for (const line of lines) { if (!line.startsWith('data: ')) continue const raw = line.slice(6).trim() if (raw === '[DONE]') return try { yield JSON.parse(raw) as SSEEvent } catch { // ignore malformed lines } } } } export async function* streamExecuteQuery( question: string, taskId: string, previousSql?: string, ): AsyncGenerator { const body: Record = { question, task_id: taskId } if (previousSql) body.previousSql = previousSql const res = await fetch(`${BASE_URL}/api/execute-query`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) if (!res.ok) { throw new Error(`HTTP ${res.status}: ${res.statusText}`) } yield* parseSSE(res) } export async function* streamBenchmark( taskId: string, queryIds?: string[] ): AsyncGenerator { const body: Record = { task_id: taskId } if (queryIds) body.queryIds = queryIds const res = await fetch(`${BASE_URL}/api/benchmark`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) if (!res.ok) { throw new Error(`HTTP ${res.status}: ${res.statusText}`) } yield* parseSSE(res) } export async function fetchInit(): Promise { const res = await fetch(`${BASE_URL}/api/init`) if (!res.ok) throw new Error(`HTTP ${res.status}`) return res.json() as Promise } export async function fetchRLState(): Promise { const res = await fetch(`${BASE_URL}/api/rl-state`) if (!res.ok) throw new Error(`HTTP ${res.status}`) return res.json() as Promise } export async function fetchSchemaGraph(): Promise { const res = await fetch(`${BASE_URL}/api/schema-graph`) if (!res.ok) throw new Error(`HTTP ${res.status}`) return res.json() as Promise } export async function submitFeedback( question: string, sql: string, correct: boolean, remark?: string, ): Promise { await fetch(`${BASE_URL}/api/feedback`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ question, sql, correct, remark }), }) } export async function fetchPromptHistory() { const res = await fetch(`${BASE_URL}/api/prompt-history`) if (!res.ok) throw new Error(`HTTP ${res.status}`) return res.json() } export async function fetchBenchmarkQuestions( taskId: string ): Promise<{ questions: { id: string; question: string; difficulty: string }[] }> { const res = await fetch(`${BASE_URL}/api/benchmark-questions?task_id=${encodeURIComponent(taskId)}`) if (!res.ok) throw new Error(`HTTP ${res.status}`) return res.json() } const _suggestionsCache = new Map() export async function fetchSuggestQuestions(cacheKey: string): Promise { if (_suggestionsCache.has(cacheKey)) return _suggestionsCache.get(cacheKey)! const res = await fetch(`${BASE_URL}/api/suggest-questions`) if (!res.ok) return [] const data = await res.json() as { questions: string[] } _suggestionsCache.set(cacheKey, data.questions ?? []) return data.questions ?? [] } export async function connectExternalDb(path: string): Promise<{ success: boolean; message: string; tables: { name: string; rows: number }[]; dbLabel: string }> { const res = await fetch(`${BASE_URL}/api/connect-db`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path }), }) if (!res.ok) throw new Error(`HTTP ${res.status}`) return res.json() }