| /** | |
| * JARVIS API Service | |
| * Centralized axios-based API calls to the FastAPI backend. | |
| */ | |
| import axios from 'axios' | |
| // Base URL β uses Vite proxy in dev, env var in production | |
| const BASE_URL = import.meta.env.VITE_API_URL || '/api' | |
| const api = axios.create({ | |
| baseURL: BASE_URL, | |
| timeout: 120_000, // 2 min β model inference can be slow | |
| }) | |
| // ββ Request interceptor ββββββββββββββββββββββββββββ | |
| api.interceptors.request.use( | |
| (config) => { | |
| // Could add auth headers here in future | |
| return config | |
| }, | |
| (error) => Promise.reject(error), | |
| ) | |
| // ββ Response interceptor βββββββββββββββββββββββββββ | |
| api.interceptors.response.use( | |
| (res) => res, | |
| (error) => { | |
| const message = | |
| error.response?.data?.detail || | |
| error.response?.data?.message || | |
| error.message || | |
| 'Unknown error' | |
| return Promise.reject(new Error(message)) | |
| }, | |
| ) | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // CHAT | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const chatAPI = { | |
| /** | |
| * Send a chat message and receive AI response. | |
| * @param {string} message | |
| * @param {string|null} sessionId | |
| * @param {string|null} imageCaption | |
| */ | |
| sendMessage: async (message, sessionId = null, imageCaption = null) => { | |
| const res = await api.post('/chat/message', { | |
| message, | |
| session_id: sessionId, | |
| image_caption: imageCaption, | |
| }) | |
| return res.data | |
| }, | |
| /** | |
| * Get conversation history for a session. | |
| */ | |
| getHistory: async (sessionId, limit = 50) => { | |
| const res = await api.get(`/chat/history/${sessionId}`, { | |
| params: { limit }, | |
| }) | |
| return res.data | |
| }, | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // IMAGE | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const imageAPI = { | |
| /** | |
| * Upload image file for analysis + optional question. | |
| * @param {File} file | |
| * @param {string|null} question | |
| * @param {string|null} sessionId | |
| */ | |
| analyzeImage: async (file, question = null, sessionId = null) => { | |
| const formData = new FormData() | |
| formData.append('file', file) | |
| if (question) formData.append('question', question) | |
| if (sessionId) formData.append('session_id', sessionId) | |
| const res = await api.post('/image/analyze', formData, { | |
| headers: { 'Content-Type': 'multipart/form-data' }, | |
| timeout: 180_000, // vision models can be slow | |
| }) | |
| return res.data | |
| }, | |
| /** | |
| * Quick caption only β no LLM. | |
| */ | |
| quickCaption: async (file) => { | |
| const formData = new FormData() | |
| formData.append('file', file) | |
| const res = await api.post('/image/caption', formData, { | |
| headers: { 'Content-Type': 'multipart/form-data' }, | |
| }) | |
| return res.data | |
| }, | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // VOICE | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const voiceAPI = { | |
| /** | |
| * Transcribe audio Blob β text. | |
| * @param {Blob} audioBlob | |
| * @param {string} language optional ISO language code | |
| */ | |
| transcribe: async (audioBlob, language = null) => { | |
| const formData = new FormData() | |
| formData.append('file', audioBlob, 'recording.webm') | |
| if (language) formData.append('language', language) | |
| const res = await api.post('/voice/transcribe', formData, { | |
| headers: { 'Content-Type': 'multipart/form-data' }, | |
| timeout: 60_000, | |
| }) | |
| return res.data | |
| }, | |
| /** | |
| * Full voice round-trip: audio β text β AI β audio. | |
| * @param {Blob} audioBlob | |
| * @param {string|null} sessionId | |
| * @param {boolean} ttsEnabled | |
| */ | |
| voiceInteract: async (audioBlob, sessionId = null, ttsEnabled = true) => { | |
| const formData = new FormData() | |
| formData.append('file', audioBlob, 'recording.webm') | |
| if (sessionId) formData.append('session_id', sessionId) | |
| formData.append('tts_enabled', ttsEnabled.toString()) | |
| const res = await api.post('/voice/interact', formData, { | |
| headers: { 'Content-Type': 'multipart/form-data' }, | |
| timeout: 180_000, | |
| }) | |
| return res.data | |
| }, | |
| /** | |
| * Text-to-speech: returns audio blob. | |
| * @param {string} text | |
| */ | |
| speak: async (text) => { | |
| const res = await api.post( | |
| '/voice/speak', | |
| { text }, | |
| { responseType: 'blob', timeout: 60_000 }, | |
| ) | |
| return res.data // audio/wav Blob | |
| }, | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // TOOLS | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const toolsAPI = { | |
| /** | |
| * Execute a tool directly. | |
| * @param {string} toolName | |
| * @param {string} argument | |
| */ | |
| executeTool: async (toolName, argument) => { | |
| const res = await api.post('/tools/execute', { | |
| tool_name: toolName, | |
| argument, | |
| }) | |
| return res.data | |
| }, | |
| listTools: async () => { | |
| const res = await api.get('/tools/list') | |
| return res.data | |
| }, | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // SESSIONS | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const sessionsAPI = { | |
| listSessions: async () => { | |
| const res = await api.get('/sessions/') | |
| return res.data | |
| }, | |
| deleteSession: async (sessionId) => { | |
| const res = await api.delete(`/sessions/${sessionId}`) | |
| return res.data | |
| }, | |
| renameSession: async (sessionId, title) => { | |
| const res = await api.patch(`/sessions/${sessionId}`, { title }) | |
| return res.data | |
| }, | |
| } | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // HEALTH | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const healthAPI = { | |
| check: async () => { | |
| const res = await api.get('/health') | |
| return res.data | |
| }, | |
| } | |
| export default api | |