// const API_BASE_URL = 'http://localhost:8000' const API_BASE_URL = 'https://2nzi-pnlcalib.hf.space' class FootballVisionAPI { constructor() { this.baseURL = API_BASE_URL } async healthCheck() { try { const response = await fetch(`${this.baseURL}/health`) return await response.json() } catch (error) { throw new Error(`Health check failed: ${error.message}`) } } async calibrateCamera(imageFile, linesData) { const formData = new FormData() formData.append('image', imageFile) formData.append('lines_data', JSON.stringify(linesData)) try { const response = await fetch(`${this.baseURL}/calibrate`, { method: 'POST', body: formData }) // Toujours retourner un objet de résultat, même en cas d'erreur if (!response.ok) { let errorMessage = `HTTP error! status: ${response.status}` // Essayer de récupérer le message d'erreur du serveur try { const errorData = await response.json() if (errorData.detail) { // Gestion spéciale pour les erreurs Pydantic if (typeof errorData.detail === 'string') { errorMessage = errorData.detail } else if (Array.isArray(errorData.detail)) { // Erreurs de validation Pydantic errorMessage = errorData.detail.map(err => { if (err.msg && err.loc) { return `${err.loc.join('.')}: ${err.msg}` } return err.msg || 'Erreur de validation' }).join(', ') } } else if (errorData.message) { errorMessage = errorData.message } } catch (parseError) { // Si on ne peut pas parser la réponse, garder le message d'erreur HTTP } return { status: 'failed', message: errorMessage, error: errorMessage } } const result = await response.json() // S'assurer que le résultat a un status, sinon l'ajouter if (!result.status) { result.status = 'success' } return result } catch (error) { // En cas d'erreur de réseau ou autre, retourner un objet d'erreur return { status: 'failed', message: `Calibration failed: ${error.message}`, error: error.message } } } async inferenceImage(imageFile, options = {}) { if (!imageFile) { throw new Error('No image file provided') } const formData = new FormData() formData.append('image', imageFile) const { kpThreshold = 0.15, lineThreshold = 0.15 } = options // S'assurer que les valeurs sont des nombres const kpThresholdNum = Number(kpThreshold) const lineThresholdNum = Number(lineThreshold) formData.append('kp_threshold', kpThresholdNum.toString()) formData.append('line_threshold', lineThresholdNum.toString()) console.log('🔥 Sending inference request with:', { fileName: imageFile.name, fileType: imageFile.type, fileSize: imageFile.size, kpThreshold, lineThreshold }) try { const response = await fetch(`${this.baseURL}/inference/image`, { method: 'POST', body: formData }) if (!response.ok) { let errorMessage = `HTTP error! status: ${response.status}` // Essayer de récupérer le message d'erreur détaillé du serveur try { const errorData = await response.json() console.error('🔥 Detailed API error:', errorData) if (errorData.detail) { // Gestion spéciale pour les erreurs Pydantic if (typeof errorData.detail === 'string') { errorMessage = errorData.detail } else if (Array.isArray(errorData.detail)) { // Erreurs de validation Pydantic errorMessage = errorData.detail.map(err => { if (err.msg && err.loc) { return `${err.loc.join('.')}: ${err.msg}` } return err.msg || 'Erreur de validation' }).join(', ') } } else if (errorData.message) { errorMessage = errorData.message } } catch (parseError) { console.error('🔥 Could not parse error response:', parseError) } throw new Error(errorMessage) } return await response.json() } catch (error) { throw new Error(`Image inference failed: ${error.message}`) } } async inferenceVideo(videoFile, options = {}) { const formData = new FormData() formData.append('video', videoFile) const { kpThreshold = 0.15, lineThreshold = 0.15, frameStep = 10 } = options formData.append('kp_threshold', kpThreshold) formData.append('line_threshold', lineThreshold) formData.append('frame_step', frameStep) try { const response = await fetch(`${this.baseURL}/inference/video`, { method: 'POST', body: formData }) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) } return await response.json() } catch (error) { throw new Error(`Video inference failed: ${error.message}`) } } async manualCalibration(file, calibrationData) { const formData = new FormData() formData.append('file', file) formData.append('calibration_data', JSON.stringify(calibrationData)) try { const response = await fetch(`${this.baseURL}/calibrate/manual`, { method: 'POST', body: formData }) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) } return await response.json() } catch (error) { throw new Error(`Manual calibration failed: ${error.message}`) } } } export default new FootballVisionAPI()