| import type { RecommendationResponse, TaskStatus, ConversationSummary, Conversation, ConversationMessage } from './types' |
|
|
| |
| const BASE_URL = import.meta.env.VITE_API_BASE_URL || |
| (import.meta.env.PROD ? '' : 'http://localhost:8000') |
|
|
| |
| |
| |
| |
| |
| export async function recommend( |
| query: string, |
| userId: string = "default", |
| conversationHistory?: Array<{ role: string; content: string }>, |
| conversationId?: string, |
| useOnlineAgent: boolean = false |
| ): Promise<RecommendationResponse> { |
| const url = `${BASE_URL}/api/process` |
| |
| try { |
| const res = await fetch(url, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ |
| query, |
| user_id: userId, |
| conversation_history: conversationHistory, |
| conversation_id: conversationId, |
| use_online_agent: useOnlineAgent |
| }), |
| }) |
| |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| console.error('[API] recommend error:', { |
| status: res.status, |
| statusText: res.statusText, |
| error: errorMessage, |
| query, |
| useOnlineAgent |
| }) |
| throw new Error(errorMessage) |
| } |
| |
| const response = (await res.json()) as RecommendationResponse |
| console.log('[API] recommend response:', { |
| hasLlmReply: !!response.llm_reply, |
| hasConfirmationRequest: !!response.confirmation_request, |
| hasThinkingSteps: !!response.thinking_steps, |
| thinkingStepsCount: response.thinking_steps?.length || 0, |
| hasRestaurants: !!response.restaurants, |
| restaurantsCount: response.restaurants?.length || 0, |
| intent: response.intent, |
| preferences: response.preferences, |
| fullResponse: response |
| }) |
| return response |
| } catch (error: any) { |
| |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}. Please ensure the backend server is running.`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function recommendStream( |
| query: string, |
| userId: string = "default", |
| conversationHistory?: Array<{ role: string; content: string }>, |
| onChunk?: (chunk: string) => void, |
| onComplete?: (fullText: string) => void, |
| useOnlineAgent: boolean = false |
| ): Promise<string> { |
| const url = `${BASE_URL}/api/process/stream` |
| |
| return new Promise((resolve, reject) => { |
| try { |
| fetch(url, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ |
| query, |
| user_id: userId, |
| conversation_history: conversationHistory, |
| use_online_agent: useOnlineAgent |
| }), |
| }) |
| .then(async (res) => { |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| throw new Error(`HTTP ${res.status} ${res.statusText}: ${text}`) |
| } |
|
|
| const reader = res.body?.getReader() |
| const decoder = new TextDecoder() |
| let fullText = '' |
|
|
| if (!reader) { |
| throw new Error('Response body is not readable') |
| } |
|
|
| while (true) { |
| const { done, value } = await reader.read() |
| |
| if (done) { |
| if (onComplete) { |
| onComplete(fullText) |
| } |
| resolve(fullText) |
| break |
| } |
|
|
| const chunk = decoder.decode(value, { stream: true }) |
| const lines = chunk.split('\n') |
|
|
| for (const line of lines) { |
| if (line.startsWith('data: ')) { |
| try { |
| const data = JSON.parse(line.slice(6)) |
| |
| if (data.error) { |
| reject(new Error(data.content)) |
| return |
| } |
|
|
| if (data.content) { |
| fullText += data.content |
| if (onChunk) { |
| onChunk(data.content) |
| } |
| } |
|
|
| if (data.done) { |
| if (onComplete) { |
| onComplete(fullText) |
| } |
| resolve(fullText) |
| return |
| } |
| } catch (e) { |
| |
| } |
| } |
| } |
| } |
| }) |
| .catch(reject) |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| reject(new Error(`Network error: Cannot connect to backend at ${BASE_URL}`)) |
| } else { |
| reject(error) |
| } |
| } |
| }) |
| } |
|
|
| |
| export async function getTaskStatus( |
| taskId: string, |
| userId?: string, |
| conversationId?: string |
| ): Promise<TaskStatus> { |
| |
| const params = new URLSearchParams() |
| if (userId) params.append('user_id', userId) |
| if (conversationId) params.append('conversation_id', conversationId) |
| const queryString = params.toString() |
| const url = queryString |
| ? `${BASE_URL}/api/status/${taskId}?${queryString}` |
| : `${BASE_URL}/api/status/${taskId}` |
| |
| try { |
| const res = await fetch(url) |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| console.error('[API] getTaskStatus error:', { |
| taskId, |
| status: res.status, |
| error: errorMessage |
| }) |
| throw new Error(errorMessage) |
| } |
| const status = (await res.json()) as TaskStatus |
| console.log('[API] getTaskStatus response:', { |
| taskId, |
| status: status.status, |
| progress: status.progress, |
| message: status.message, |
| hasResult: !!status.result, |
| hasError: !!status.error, |
| resultRestaurantsCount: status.result?.restaurants?.length || 0, |
| resultThinkingStepsCount: status.result?.thinking_steps?.length || 0, |
| fullStatus: status |
| }) |
| return status |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function healthCheck(): Promise<{ status: string; timestamp: string }> { |
| const url = `${BASE_URL}/health` |
| try { |
| const res = await fetch(url) |
| if (!res.ok) { |
| throw new Error(`Health check failed: ${res.status} ${res.statusText}`) |
| } |
| return (await res.json()) as { status: string; timestamp: string } |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Cannot connect to backend at ${BASE_URL}. Please ensure the backend server is running on port 8000.`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function updatePreferences(preferences: Record<string, any>): Promise<{ preferences: Record<string, any> }> { |
| const url = `${BASE_URL}/api/update-preferences` |
| const res = await fetch(url, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(preferences), |
| }) |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| throw new Error(`HTTP ${res.status} ${res.statusText} ${text}`) |
| } |
| return (await res.json()) as { preferences: Record<string, any> } |
| } |
|
|
| |
| export async function getUserPreferences(userId: string = "default"): Promise<{ preferences: Record<string, any> }> { |
| const url = `${BASE_URL}/api/user-preferences/${userId}` |
| const res = await fetch(url) |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| throw new Error(`HTTP ${res.status} ${res.statusText} ${text}`) |
| } |
| return (await res.json()) as { preferences: Record<string, any> } |
| } |
|
|
| |
| export async function getConversationPreferences( |
| userId: string, |
| conversationId: string |
| ): Promise<{ preferences: Record<string, any> }> { |
| const url = `${BASE_URL}/api/conversations/${userId}/${conversationId}/preferences` |
| const res = await fetch(url) |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| throw new Error(`HTTP ${res.status} ${res.statusText} ${text}`) |
| } |
| return (await res.json()) as { preferences: Record<string, any> } |
| } |
|
|
| |
| export async function updateConversationPreferences( |
| userId: string, |
| conversationId: string, |
| preferences: Record<string, any> |
| ): Promise<{ preferences: Record<string, any> }> { |
| const url = `${BASE_URL}/api/conversations/${userId}/${conversationId}/preferences` |
| const res = await fetch(url, { |
| method: 'PUT', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(preferences), |
| }) |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| throw new Error(`HTTP ${res.status} ${res.statusText} ${text}`) |
| } |
| return (await res.json()) as { preferences: Record<string, any> } |
| } |
|
|
| |
|
|
| |
| export async function getConversations(userId: string): Promise<ConversationSummary[]> { |
| const url = `${BASE_URL}/api/conversations/${userId}` |
| |
| try { |
| const res = await fetch(url) |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| throw new Error(errorMessage) |
| } |
| return (await res.json()) as ConversationSummary[] |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function getConversation(userId: string, conversationId: string): Promise<Conversation> { |
| const url = `${BASE_URL}/api/conversations/${userId}/${conversationId}` |
| |
| try { |
| const res = await fetch(url) |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| throw new Error(errorMessage) |
| } |
| return (await res.json()) as Conversation |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function createConversation( |
| userId: string, |
| options?: { title?: string; model?: string } |
| ): Promise<Conversation> { |
| const url = `${BASE_URL}/api/conversations/${userId}` |
| |
| try { |
| const res = await fetch(url, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ |
| title: options?.title, |
| model: options?.model || 'RestRec', |
| }), |
| }) |
| |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| throw new Error(errorMessage) |
| } |
| |
| return (await res.json()) as Conversation |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function updateConversation( |
| userId: string, |
| conversationId: string, |
| updates: { title?: string; model?: string } |
| ): Promise<Conversation> { |
| const url = `${BASE_URL}/api/conversations/${userId}/${conversationId}` |
| |
| try { |
| const res = await fetch(url, { |
| method: 'PUT', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(updates), |
| }) |
| |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| throw new Error(errorMessage) |
| } |
| |
| return (await res.json()) as Conversation |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function addMessage( |
| userId: string, |
| conversationId: string, |
| role: 'user' | 'assistant', |
| content: string, |
| metadata?: Record<string, any> |
| ): Promise<{ success: boolean; message: string }> { |
| const url = `${BASE_URL}/api/conversations/${userId}/${conversationId}/messages` |
| |
| try { |
| const res = await fetch(url, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ |
| role, |
| content, |
| metadata, |
| }), |
| }) |
| |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| throw new Error(errorMessage) |
| } |
| |
| return (await res.json()) as { success: boolean; message: string } |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}`) |
| } |
| throw error |
| } |
| } |
|
|
| |
| export async function deleteConversation( |
| userId: string, |
| conversationId: string |
| ): Promise<{ success: boolean; message: string }> { |
| const url = `${BASE_URL}/api/conversations/${userId}/${conversationId}` |
| |
| try { |
| const res = await fetch(url, { |
| method: 'DELETE', |
| }) |
| |
| if (!res.ok) { |
| const text = await res.text().catch(() => '') |
| let errorMessage = `HTTP ${res.status} ${res.statusText}` |
| try { |
| const errorData = JSON.parse(text) |
| errorMessage += `: ${errorData.detail || text}` |
| } catch { |
| errorMessage += `: ${text || 'Unknown error'}` |
| } |
| throw new Error(errorMessage) |
| } |
| |
| return (await res.json()) as { success: boolean; message: string } |
| } catch (error: any) { |
| if (error instanceof TypeError && error.message.includes('fetch')) { |
| throw new Error(`Network error: Cannot connect to backend at ${BASE_URL}`) |
| } |
| throw error |
| } |
| } |
|
|
|
|
|
|
|
|