HyperFlow / frontend /src /api.js
Gaurav711's picture
deploy: revert to 733e96b
d491dc1
Raw
History Blame Contribute Delete
8.93 kB
/**
* HyperFlow 3.0 β€” API Service Layer
* Connects the React frontend to the FastAPI backend
* All endpoints proxied via Vite dev server β†’ /api β†’ http://localhost:8000
*/
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 };
// Inject personal Swiggy token from localStorage if available
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; // caller uses null to fall back to local state
}
}
// ─── OAuth 2.1 + PKCE ─────────────────────────────────────────────────────────
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 }),
});
}
// ─── Dark Store / Inventory ───────────────────────────────────────────────────
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' });
}
// ─── Inventory Reservation ────────────────────────────────────────────────────
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 }),
});
}
// ─── Restaurants & Coupons ───────────────────────────────────────────────────
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),
});
}
// ─── Dineout ─────────────────────────────────────────────────────────────────
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 }),
});
}
// ─── Expense Logs ─────────────────────────────────────────────────────────────
export async function fetchExpenseLogs() {
return apiFetch('/api/v1/user/expenses');
}
// ─── Festival Settings ────────────────────────────────────────────────────────
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',
});
}
// ─── WebSocket Live Metrics ───────────────────────────────────────────────────
/**
* Opens a WebSocket connection to the live metrics stream.
* @param {function} onMessage - callback(data: object)
* @returns {WebSocket} - call .close() to disconnect
*/
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;
}
// ─── Swiggy Food MCP Direct Tool Calls ────────────────────────────────────────
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`);
}
// ─── HyperFlow 4.0 v2 Core Endpoints ──────────────────────────────────────────
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;
}