Skip to content

Commit 0f1ed9b

Browse files
committed
feat: smart API routing — use backend when available, fallback to browser-side
1 parent 9f19e6d commit 0f1ed9b

1 file changed

Lines changed: 78 additions & 16 deletions

File tree

frontend/src/api.ts

Lines changed: 78 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,80 @@
11
/**
2-
* API module — standalone browser mode.
3-
* Re-exports all functions from localApi which run entirely in the browser.
2+
* API module — smart routing.
3+
* Uses Python backend when available (local dev), falls back to
4+
* browser-side mujoco-wasm (GitHub Pages / standalone).
45
*/
5-
export {
6-
loadXml,
7-
loadAcmTrials,
8-
loadMatFile,
9-
loadConfig,
10-
exportConfig,
11-
alignToMujoco,
12-
suggestFrames,
13-
bodyTransforms,
14-
loadStacOutput,
15-
runQuickStac,
16-
setApiBase,
17-
getCurrentApiBase,
18-
} from "./localApi";
6+
import * as backend from "./api.backend";
7+
import * as local from "./localApi";
8+
9+
let useBackend: boolean | null = null;
10+
11+
async function checkBackend(): Promise<boolean> {
12+
if (useBackend !== null) return useBackend;
13+
try {
14+
const resp = await fetch("/api/health", { method: "GET", signal: AbortSignal.timeout(1500) });
15+
const data = await resp.json();
16+
useBackend = data.status === "ok";
17+
} catch {
18+
useBackend = false;
19+
}
20+
console.log(`[API] Mode: ${useBackend ? "backend (Python)" : "standalone (browser)"}`);
21+
return useBackend;
22+
}
23+
24+
// Check on module load
25+
const backendReady = checkBackend();
26+
27+
export async function loadXml(path?: string) {
28+
if (await backendReady && path) return backend.loadXml(path);
29+
return local.loadXml(path);
30+
}
31+
32+
export async function loadAcmTrials(maxTrials = 5, decimate = 2) {
33+
if (await backendReady) return backend.loadAcmTrials(maxTrials, decimate);
34+
return local.loadAcmTrials(maxTrials, decimate);
35+
}
36+
37+
export async function loadMatFile(path: string) {
38+
if (await backendReady) return backend.loadMatFile(path);
39+
return local.loadMatFile(path);
40+
}
41+
42+
export async function loadConfig(path?: string) {
43+
if (await backendReady && path) return backend.loadConfig(path);
44+
return local.loadConfig(path);
45+
}
46+
47+
export async function exportConfig(config: Record<string, unknown>, outputPath: string) {
48+
if (await backendReady) return backend.exportConfig(config, outputPath);
49+
return local.exportConfig(config, outputPath);
50+
}
51+
52+
export async function alignToMujoco(data: Record<string, unknown>) {
53+
if (await backendReady) return backend.alignToMujoco(data);
54+
return local.alignToMujoco(data);
55+
}
56+
57+
export async function suggestFrames(data: Record<string, unknown>) {
58+
if (await backendReady) return backend.suggestFrames(data);
59+
return local.suggestFrames(data);
60+
}
61+
62+
export async function bodyTransforms(qpos: number[]) {
63+
if (await backendReady) return backend.bodyTransforms(qpos);
64+
return local.bodyTransforms(qpos);
65+
}
66+
67+
export async function loadStacOutput(path: string) {
68+
if (await backendReady) return backend.loadStacOutput(path);
69+
return local.loadStacOutput(path);
70+
}
71+
72+
export async function runQuickStac(data: Record<string, unknown>) {
73+
if (await backendReady) return backend.runQuickStac(data);
74+
return local.runQuickStac(data);
75+
}
76+
77+
export function setApiBase(url: string) { backend.setApiBase(url); }
78+
export function getCurrentApiBase() {
79+
return useBackend ? backend.getCurrentApiBase() || "localhost:8000" : "(standalone/browser)";
80+
}

0 commit comments

Comments
 (0)