| |
| |
| |
| |
| |
|
|
| const getBaseUrl = () => { |
| const override = localStorage.getItem('hyperflow_backend_url'); |
| if (override) return override; |
| const envUrl = import.meta.env.VITE_BACKEND_URL; |
| if (envUrl) return envUrl; |
| if (typeof window !== 'undefined') { |
| const hn = window.location.hostname; |
| if (hn === 'localhost' || hn === '127.0.0.1') { |
| return 'http://127.0.0.1:8000'; |
| } |
| } |
| return 'https://gaurav711-hyperflow.hf.space'; |
| }; |
|
|
| export function setBackendUrl(url) { |
| if (url) { |
| localStorage.setItem('hyperflow_backend_url', url.replace(/\/$/, '')); |
| } else { |
| localStorage.removeItem('hyperflow_backend_url'); |
| } |
| } |
|
|
| export function getBackendUrl() { |
| return getBaseUrl(); |
| } |
|
|
| async function apiFetch(path, options = {}) { |
| try { |
| const base = getBaseUrl(); |
| const url = base ? `${base}${path}` : path; |
| const headers = { 'Content-Type': 'application/json', ...options.headers }; |
| |
| |
| const personalToken = localStorage.getItem('swiggy_access_token'); |
| if (personalToken) { |
| headers['Authorization'] = `Bearer ${personalToken}`; |
| } |
|
|
| const res = await fetch(url, { |
| headers, |
| ...options, |
| }); |
| if (!res.ok) { |
| const err = await res.json().catch(() => ({ detail: res.statusText })); |
| throw new Error(err.detail || 'API error'); |
| } |
| return res.json(); |
| } catch (err) { |
| console.warn(`[API] ${path} failed (offline fallback):`, err.message); |
| return null; |
| } |
| } |
|
|
| |
|
|
| export async function fetchLoginUrl() { |
| return apiFetch('/api/v1/auth/login-url'); |
| } |
|
|
| export async function exchangeCode(code, state) { |
| return apiFetch('/api/v1/auth/exchange', { |
| method: 'POST', |
| body: JSON.stringify({ code, state }), |
| }); |
| } |
|
|
| |
|
|
| export async function fetchRestockAlerts(storeId = 'store_01') { |
| return apiFetch(`/api/v1/forecast/${storeId}/restock-alerts`); |
| } |
|
|
| export async function fetchForecast(storeId, skuId) { |
| return apiFetch(`/api/v1/forecast/${storeId}/${skuId}`); |
| } |
|
|
| export async function fetchAvailabilityMetrics(storeId = 'store_01') { |
| return apiFetch(`/api/v1/metrics/availability/${storeId}`); |
| } |
|
|
| export async function fetchProfitability(storeId) { |
| return apiFetch(`/api/v1/profitability/${storeId}`); |
| } |
|
|
| export async function fetchBumpRate() { |
| return apiFetch('/api/v1/metrics/bump-rate'); |
| } |
|
|
| export async function fetchRobustness() { |
| return apiFetch('/api/v1/metrics/robustness'); |
| } |
|
|
| export async function triggerRetrain() { |
| return apiFetch('/api/v1/ml/retrain', { method: 'POST' }); |
| } |
|
|
| |
|
|
| export async function reserveInventory({ order_id, store_id, sku_id, qty_requested }) { |
| return apiFetch('/api/v1/orders/reserve', { |
| method: 'POST', |
| body: JSON.stringify({ order_id, store_id, sku_id, qty_requested }), |
| }); |
| } |
|
|
| |
|
|
| export async function fetchRestaurants() { |
| return apiFetch('/api/v1/restaurants'); |
| } |
|
|
| export async function fetchRestaurantMenu(restaurantId) { |
| return apiFetch(`/api/v1/restaurants/${restaurantId}/menu`); |
| } |
|
|
| export async function createRestaurant(data) { |
| return apiFetch('/api/v1/restaurants', { |
| method: 'POST', |
| body: JSON.stringify(data), |
| }); |
| } |
|
|
| export async function fetchCoupons() { |
| return apiFetch('/api/v1/coupons'); |
| } |
|
|
| export async function createCoupon(data) { |
| return apiFetch('/api/v1/coupons', { |
| method: 'POST', |
| body: JSON.stringify(data), |
| }); |
| } |
|
|
| |
|
|
| export async function fetchDineoutReservations() { |
| return apiFetch('/api/v1/dineout/reservations'); |
| } |
|
|
| export async function reserveDineout({ hotel, time, party }) { |
| return apiFetch('/api/v1/dineout/reserve', { |
| method: 'POST', |
| body: JSON.stringify({ hotel, time, party }), |
| }); |
| } |
|
|
| |
|
|
| export async function fetchExpenseLogs() { |
| return apiFetch('/api/v1/user/expenses'); |
| } |
|
|
| |
|
|
| export async function fetchFestivalSettings() { |
| return apiFetch('/api/v1/settings/festival'); |
| } |
|
|
| export async function updateFestivalSettings(theme_name) { |
| return apiFetch(`/api/v1/settings/festival?theme_name=${theme_name}`, { |
| method: 'POST', |
| }); |
| } |
|
|
| |
|
|
| |
| |
| |
| |
| |
| export function connectLiveMetrics(onMessage) { |
| const base = getBaseUrl(); |
| const wsBase = base |
| ? base.replace(/^http/, 'ws') |
| : `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}`; |
| const ws = new WebSocket(`${wsBase}/ws/live-metrics`); |
| ws.onmessage = (e) => { |
| try { |
| onMessage(JSON.parse(e.data)); |
| } catch {} |
| }; |
| ws.onerror = (e) => console.warn('[WS] live-metrics error', e); |
| return ws; |
| } |
|
|
| |
|
|
| export async function fetchFoodAddresses() { |
| return apiFetch('/api/v1/food/addresses'); |
| } |
|
|
| export async function updateFoodCart({ addressId, items, couponCode }) { |
| return apiFetch('/api/v1/food/cart', { |
| method: 'POST', |
| body: JSON.stringify({ addressId, items, couponCode }), |
| }); |
| } |
|
|
| export async function placeFoodOrder({ addressId, paymentMethod }) { |
| return apiFetch('/api/v1/food/orders', { |
| method: 'POST', |
| body: JSON.stringify({ addressId, paymentMethod }), |
| }); |
| } |
|
|
| export async function trackFoodOrder(orderId) { |
| return apiFetch(`/api/v1/food/orders/${orderId}/track`); |
| } |
|
|
| |
|
|
| export async function fetchDemandOracle(addressId = 'default_address', lat = 20.3533, lng = 85.8333) { |
| return apiFetch(`/api/v2/oracle/demand?addressId=${addressId}&lat=${lat}&lng=${lng}`); |
| } |
|
|
| export async function predictRefund({ order_id, complaint_type, complaint_text, item_name, item_price }) { |
| return apiFetch('/api/v2/refund/predict', { |
| method: 'POST', |
| body: JSON.stringify({ order_id, complaint_type, complaint_text, item_name, item_price }), |
| }); |
| } |
|
|
| export async function fetchDineoutSniper(latitude = 20.3533, longitude = 85.8333, cuisine = 'Buffet', date = '2026-07-25') { |
| return apiFetch(`/api/v2/dineout/sniper?latitude=${latitude}&longitude=${longitude}&cuisine=${cuisine}&date=${date}`); |
| } |
|
|
| export async function analyzeDispatch(store_location = [20.3533, 85.8333], orders_count = 5) { |
| return apiFetch('/api/v2/dispatch/analyze', { |
| method: 'POST', |
| body: JSON.stringify({ store_location, orders_count }), |
| }); |
| } |
|
|
| export function connectETALive(orderId, onMessage) { |
| const base = getBaseUrl(); |
| const wsBase = base |
| ? base.replace(/^http/, 'ws') |
| : `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}`; |
| const token = localStorage.getItem('swiggy_access_token') || ''; |
| const ws = new WebSocket(`${wsBase}/api/v2/ws/eta-live/${orderId}?token=${token}`); |
| ws.onmessage = (e) => { |
| try { |
| onMessage(JSON.parse(e.data)); |
| } catch {} |
| }; |
| ws.onerror = (e) => console.warn('[WS] eta-live error', e); |
| return ws; |
| } |
|
|
|
|