File size: 4,146 Bytes
3c665d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa3ae1f
 
3c665d2
aa3ae1f
 
3c665d2
 
 
aa3ae1f
3c665d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b00a200
 
3c665d2
 
 
 
b00a200
3c665d2
 
 
 
 
 
 
 
f0b682f
8ae8e0b
 
 
 
 
 
 
 
17e7bd7
 
 
 
 
 
 
 
 
 
 
f0b682f
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import type { InitResponse, RLState, SchemaGraph, SSEEvent } from './types'

const BASE_URL: string = import.meta.env.VITE_API_URL ?? ''

async function* parseSSE(response: Response): AsyncGenerator<SSEEvent> {
  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<SSEEvent> {
  const body: Record<string, unknown> = { 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<SSEEvent> {
  const body: Record<string, unknown> = { 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<InitResponse> {
  const res = await fetch(`${BASE_URL}/api/init`)
  if (!res.ok) throw new Error(`HTTP ${res.status}`)
  return res.json() as Promise<InitResponse>
}

export async function fetchRLState(): Promise<RLState> {
  const res = await fetch(`${BASE_URL}/api/rl-state`)
  if (!res.ok) throw new Error(`HTTP ${res.status}`)
  return res.json() as Promise<RLState>
}

export async function fetchSchemaGraph(): Promise<SchemaGraph> {
  const res = await fetch(`${BASE_URL}/api/schema-graph`)
  if (!res.ok) throw new Error(`HTTP ${res.status}`)
  return res.json() as Promise<SchemaGraph>
}

export async function submitFeedback(
  question: string,
  sql: string,
  correct: boolean,
  remark?: string,
): Promise<void> {
  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<string, string[]>()

export async function fetchSuggestQuestions(cacheKey: string): Promise<string[]> {
  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()
}