Spaces:
Runtime error
Runtime error
Download Frontend/server.js from rabieifical/math-engine: direct link, hf CLI and curl.
- Browser
- Download file 7.37 kB
-
https://huggingface.co/spaces/rabieifical/math-engine/resolve/main/Frontend/server.js
- Command line
-
hf download hf://spaces/rabieifical/math-engine/Frontend/server.js
-
curl -L -o server.js https://huggingface.co/spaces/rabieifical/math-engine/resolve/main/Frontend/server.js
7.37 kB
| import express from "express"; | |
| import { createServer as createViteServer } from "vite"; | |
| import path from "path"; | |
| import { fileURLToPath } from "url"; | |
| import dotenv from "dotenv"; | |
| import fs from "fs/promises"; | |
| dotenv.config(); | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = path.dirname(__filename); | |
| const HISTORY_FILE = path.join(__dirname, "history.json"); | |
| async function startServer() { | |
| const app = express(); | |
| const PORT = process.env.PORT || 3000; | |
| app.use(express.json()); | |
| // History API Routes | |
| app.get("/api/history", async (req, res) => { | |
| try { | |
| const data = await fs.readFile(HISTORY_FILE, "utf-8"); | |
| res.json(JSON.parse(data)); | |
| } catch (error) { | |
| // Return empty array if file doesn't exist | |
| res.json([]); | |
| } | |
| }); | |
| app.post("/api/history", async (req, res) => { | |
| try { | |
| const { query, result, type, timestamp } = req.body; | |
| let history = []; | |
| try { | |
| const data = await fs.readFile(HISTORY_FILE, "utf-8"); | |
| history = JSON.parse(data); | |
| } catch (e) { | |
| // File doesn't exist, start with empty | |
| } | |
| const newEntry = { | |
| id: Math.random().toString(36).substr(2, 9), | |
| query, | |
| result, | |
| type, | |
| timestamp: timestamp || new Date().toISOString() | |
| }; | |
| history = [newEntry, ...history].slice(0, 100); // Keep last 100 | |
| await fs.writeFile(HISTORY_FILE, JSON.stringify(history, null, 2)); | |
| res.json(newEntry); | |
| } catch (error) { | |
| console.error("Save history error:", error); | |
| res.status(500).json({ error: "Failed to save history" }); | |
| } | |
| }); | |
| // In-memory cache for Wolfram responses | |
| const wolframCache = new Map(); | |
| const CACHE_TTL = 1000 * 60 * 60; // 1 hour cache | |
| // Wolfram Alpha Proxy Route | |
| app.get("/api/wolfram", async (req, res) => { | |
| try { | |
| const { q, type, pod } = req.query; | |
| const appId = process.env.WOLFRAM_APP_ID; | |
| if (!q) { | |
| return res.status(400).json({ error: "Missing query parameter 'q'" }); | |
| } | |
| if (!appId || appId === "YOUR_WOLFRAM_APP_ID") { | |
| return res.status(400).json({ error: "Wolfram AppID not configured" }); | |
| } | |
| // Cache lookup | |
| const cacheKey = `${type}:${q}:${pod || ""}`; | |
| const cached = wolframCache.get(cacheKey); | |
| if (cached && Date.now() - cached.timestamp < CACHE_TTL) { | |
| return res.json(cached.data); | |
| } | |
| let result; | |
| let usedUrl = ""; | |
| if (type === "simple" || type === "pod") { | |
| const imageUri = `https://api.wolframalpha.com/v1/simple?appid=${appId}&i=${encodeURIComponent(q)}&background=F8FAFC&fontsize=16`; | |
| result = { imageUrl: imageUri }; | |
| // We don't really need to fetch for simple images as we return the URL, but let's cache the URL structure | |
| } else if (type === "advanced") { | |
| usedUrl = `https://api.wolframalpha.com/v1/query?appid=${appId}&input=${encodeURIComponent(q)}&output=json`; | |
| const response = await fetch(usedUrl); | |
| if (!response.ok) { | |
| const errorMsg = await response.text(); | |
| throw new Error(`Wolfram Error ${response.status}: ${errorMsg}`); | |
| } | |
| result = await response.json(); | |
| } else { | |
| // Default to short answer API | |
| usedUrl = `https://api.wolframalpha.com/v1/result?appid=${appId}&i=${encodeURIComponent(q)}`; | |
| const response = await fetch(usedUrl); | |
| if (response.status === 501) { | |
| // Fallback to Full Results API if Short Answer fails | |
| const fallbackUrl = `https://api.wolframalpha.com/v1/query?appid=${appId}&input=${encodeURIComponent(q)}&output=json`; | |
| const fallbackRes = await fetch(fallbackUrl); | |
| if (fallbackRes.ok) { | |
| const data = await fallbackRes.json(); | |
| const pods = data.queryresult?.pods || []; | |
| const targetPod = pods.find(p => p.primary || ['Result', 'Solution', 'Roots', 'Derivative', 'Integral', 'Limit', 'Exact result'].includes(p.title)); | |
| if (targetPod && targetPod.subpods && targetPod.subpods.length > 0) { | |
| const text = targetPod.subpods.map(sp => sp.plaintext).filter(Boolean).join(' | '); | |
| if (text) { | |
| result = { result: text }; | |
| wolframCache.set(cacheKey, { data: result, timestamp: Date.now() }); | |
| return res.json(result); | |
| } | |
| } | |
| } | |
| // If fallback fails to find text, return null result instead of 501 to avoid console errors | |
| result = { result: null }; | |
| wolframCache.set(cacheKey, { data: result, timestamp: Date.now() }); | |
| return res.json(result); | |
| } | |
| if (!response.ok) { | |
| const errorMsg = await response.text(); | |
| throw new Error(`Wolfram Error ${response.status}: ${errorMsg}`); | |
| } | |
| const text = await response.text(); | |
| result = { result: text }; | |
| } | |
| // Save to cache | |
| wolframCache.set(cacheKey, { data: result, timestamp: Date.now() }); | |
| // Cleanup old cache entries occasionally | |
| if (wolframCache.size > 1000) { | |
| const oldestKey = wolframCache.keys().next().value; | |
| if (oldestKey) wolframCache.delete(oldestKey); | |
| } | |
| res.json(result); | |
| } catch (error) { | |
| console.error("Wolfram Proxy Error:", error); | |
| const statusCode = error.message?.includes("400") ? 400 : 500; | |
| res.status(statusCode).json({ | |
| error: "Failed to fetch from Wolfram Alpha", | |
| details: error.message | |
| }); | |
| } | |
| }); | |
| // Proxy remaining /api/ requests to Python backend (default: http://localhost:8000) | |
| const backendProxyEndpoints = ["/api/search", "/api/explain", "/api/evaluate", "/api/health", "/api/stats"]; | |
| backendProxyEndpoints.forEach(endpoint => { | |
| app.get(endpoint, async (req, res) => { | |
| try { | |
| const BACKEND_URL = process.env.BACKEND_URL || "http://localhost:8000"; | |
| const targetPath = endpoint.replace(/^\/api/, ""); | |
| const queryParams = new URLSearchParams(req.query).toString(); | |
| const targetUrl = `${BACKEND_URL}${targetPath}${queryParams ? "?" + queryParams : ""}`; | |
| const response = await fetch(targetUrl); | |
| let data; | |
| const contentType = response.headers.get("content-type"); | |
| if (contentType && contentType.includes("application/json")) { | |
| data = await response.json(); | |
| } else { | |
| data = { detail: await response.text() }; | |
| } | |
| res.status(response.status).json(data); | |
| } catch (error) { | |
| console.error(`Error proxying ${endpoint}:`, error); | |
| res.status(500).json({ error: "Failed to connect to backend", details: error.message }); | |
| } | |
| }); | |
| }); | |
| // Vite middleware for development | |
| if (process.env.NODE_ENV !== "production") { | |
| const vite = await createViteServer({ | |
| server: { middlewareMode: true }, | |
| appType: "spa", | |
| }); | |
| app.use(vite.middlewares); | |
| } else { | |
| // Production serving | |
| const distPath = path.join(process.cwd(), "dist"); | |
| app.use(express.static(distPath)); | |
| app.get("*", (req, res) => { | |
| res.sendFile(path.join(distPath, "index.html")); | |
| }); | |
| } | |
| app.listen(PORT, "0.0.0.0", () => { | |
| console.log(`🚀 Server running on http://localhost:${PORT}`); | |
| }); | |
| } | |
| startServer(); | |