deploy
Multilingue FR/EN/ES + pièce jointe billet + recherche conversationnelle
72785ad
Raw
History Blame Contribute Delete
4.11 kB
/* Client API pour le backend FastAPI.
Toutes les fonctions retournent une Promise et lèvent une erreur si non-2xx. */
const API_BASE = (window.VA_CONFIG && window.VA_CONFIG.API_BASE) || 'http://localhost:8000';
function _token() {
try { return localStorage.getItem('va.token'); } catch { return null; }
}
function _lang() {
try { return (window.VA_I18N && window.VA_I18N.getLang()) || 'fr'; } catch { return 'fr'; }
}
async function _fetch(path, opts = {}) {
const headers = { 'Content-Type': 'application/json', ...(opts.headers || {}) };
const tok = _token();
if (tok) headers['Authorization'] = `Bearer ${tok}`;
const res = await fetch(`${API_BASE}${path}`, { ...opts, headers });
const text = await res.text();
let data = null;
try { data = text ? JSON.parse(text) : null; } catch { data = text; }
if (!res.ok) {
const detail = (data && data.detail) || res.statusText;
const err = new Error(typeof detail === 'string' ? detail : JSON.stringify(detail));
err.status = res.status;
err.data = data;
throw err;
}
return data;
}
const api = {
health: () => _fetch('/health'),
searchTrajets: (params = {}) => {
const qs = new URLSearchParams();
Object.entries(params).forEach(([k, v]) => { if (v) qs.set(k, v); });
return _fetch(`/trajets?${qs.toString()}`);
},
getTrajet: (id) => _fetch(`/trajets/${id}`),
cityImage: (q) => _fetch(`/images?q=${encodeURIComponent(q)}`),
createBillet: (payload) => _fetch('/billets', { method: 'POST', body: JSON.stringify({ ...payload, lang: _lang() }) }),
myBillets: () => _fetch('/billets/mine'),
// Upload d'un PDF de billet pour extraction (multipart/form-data).
// On NE fixe PAS Content-Type : le navigateur ajoute le boundary lui-même.
extractBillet: async (file) => {
const fd = new FormData();
fd.append('file', file);
const headers = {};
const tok = _token();
if (tok) headers['Authorization'] = `Bearer ${tok}`;
const res = await fetch(`${API_BASE}/billets/extract`, { method: 'POST', body: fd, headers });
const text = await res.text();
let data = null;
try { data = text ? JSON.parse(text) : null; } catch { data = text; }
if (!res.ok) {
const detail = (data && data.detail) || res.statusText;
const err = new Error(typeof detail === 'string' ? detail : JSON.stringify(detail));
err.status = res.status;
err.data = data;
throw err;
}
return data;
},
accessBillet: (numero_billet, identity) =>
_fetch('/billets/access', {
method: 'POST',
body: JSON.stringify({ numero_billet, identity }),
}),
annulerBillet: (numero_billet, identity) =>
_fetch(`/billets/${numero_billet}/annuler`, {
method: 'POST',
body: JSON.stringify({ numero_billet, identity }),
}),
createReclamation: (payload) => _fetch('/reclamations', { method: 'POST', body: JSON.stringify(payload) }),
suiviReclamation: (numero_suivi) => _fetch(`/reclamations/${numero_suivi}`),
chatStart: (session_token = null) =>
_fetch('/chat/start', { method: 'POST', body: JSON.stringify({ session_token, lang: _lang() }) }),
chatMessage: (session_token, message) =>
_fetch('/chat/message', { method: 'POST', body: JSON.stringify({ session_token, message, lang: _lang() }) }),
chatHistory: (session_token) => _fetch(`/chat/${session_token}/history`),
chatSessions: () => _fetch('/chat/sessions'),
deleteSession: (session_token) => _fetch(`/chat/sessions/${session_token}`, { method: 'DELETE' }),
endSession: (session_token, rating, feedback) =>
_fetch(`/chat/sessions/${session_token}/end`, {
method: 'POST',
body: JSON.stringify({ rating, feedback: feedback || '' }),
}),
signup: (payload) => _fetch('/auth/signup', { method: 'POST', body: JSON.stringify(payload) }),
login: (email, password) => _fetch('/auth/login', { method: 'POST', body: JSON.stringify({ email, password }) }),
googleAuth: (googlePayload) => _fetch('/auth/google', { method: 'POST', body: JSON.stringify(googlePayload) }),
me: () => _fetch('/auth/me'),
};
window.VA_API = api;