import axios from 'axios'; import { logger } from '../utils/logger'; // API base URL (e.g. https://habith-smart-traffic.hf.space) // The backend explicitly defines /api/detect for detection and /health for health check const rawBase = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000'; const API_BASE_URL = rawBase.replace(/\/api\/?$/, ''); // Keep base at root level const TIMEOUT = parseInt(import.meta.env.VITE_API_TIMEOUT || '90000'); logger.info(`API Configuration: ${API_BASE_URL} (Timeout: ${TIMEOUT}ms)`); // Create Axios instance const apiClient = axios.create({ baseURL: API_BASE_URL, timeout: TIMEOUT, headers: { 'Content-Type': 'application/json' }, }); // Request Interceptor apiClient.interceptors.request.use( (config) => { logger.debug(`[API] ${config.method.toUpperCase()} ${config.url}`); config.metadata = { startTime: Date.now() }; return config; }, (error) => { logger.error('Request Error:', error); return Promise.reject(error); } ); // Response Interceptor apiClient.interceptors.response.use( (response) => { const duration = Date.now() - response.config.metadata?.startTime; logger.debug(`[API Response] ${response.status} (${duration}ms)`, response.data); return response; }, (error) => { logger.error(`API Response Error: ${error.response?.status || 'Unknown'}`, error); return Promise.reject(error); } ); /** * Detect vehicles in uploaded images * @param {FormData} formData - Form data with image files (roads parameter) */ export const detectVehicles = async (formData) => { try { logger.group('Vehicle Detection'); logger.time('Detection Request'); // The Hugging Face backend uses @app.post("/api/detect") const response = await apiClient.post('/api/detect', formData, { headers: { 'Content-Type': 'multipart/form-data' }, }); logger.timeEnd('Detection Request'); logger.info(`Detection Success: ${response.data.total_vehicles} vehicles detected`); logger.groupEnd(); return response.data; } catch (error) { logger.error('Vehicle Detection Failed:', error); // Safely extract error message let errorMessage = 'Detection failed. Please check the backend is running.'; if (error.response?.data?.detail) { const detail = error.response.data.detail; if (typeof detail === 'string') { errorMessage = detail; } else if (Array.isArray(detail)) { // Handle Pydantic validation errors: {type, loc, msg, input, url} errorMessage = detail.map(d => `${d.loc?.join('.') || 'Error'}: ${d.msg || 'Invalid input'}`).join('; '); } else if (typeof detail === 'object') { errorMessage = JSON.stringify(detail); } } else if (error.message) { errorMessage = error.message; } throw { message: errorMessage, status: error.response?.status, originalError: error }; } }; /** * Health check */ export const checkHealth = async () => { try { logger.debug('Checking backend health...'); // The backend uses @app.get("/health") const response = await apiClient.get('/health'); logger.info('Backend is healthy', response.data); return response.data; } catch (error) { logger.warn('Backend health check failed:', error.message); throw { message: 'Backend server is not responding', status: error.response?.status, originalError: error, }; } }; export default apiClient;