Spaces:
Sleeping
Sleeping
Download server/api.py from bdurgaprasadreddy/Sortiq: direct link, hf CLI and curl.
- Browser
- Download file 4.56 kB
-
https://huggingface.co/spaces/bdurgaprasadreddy/Sortiq/resolve/main/server/api.py
- Command line
-
hf download hf://spaces/bdurgaprasadreddy/Sortiq/server/api.py
-
curl -L -o api.py https://huggingface.co/spaces/bdurgaprasadreddy/Sortiq/resolve/main/server/api.py
4.56 kB
| import sys | |
| import os | |
| from fastapi import FastAPI, HTTPException, Request | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.responses import FileResponse | |
| from pydantic import BaseModel | |
| import json | |
| import numpy as np | |
| # Add parent directory to path to import from Env | |
| sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from Env.SortingEnv import SortingEnv | |
| app = FastAPI(title="Sortiq Unified App") | |
| # Enable CORS (still useful for local dev) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=False, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Load Q-Table | |
| Q_TABLE_PATH = os.path.join(os.path.dirname(__file__), "q_table.json") | |
| q_table = {} | |
| if os.path.exists(Q_TABLE_PATH): | |
| try: | |
| with open(Q_TABLE_PATH, "r") as f: | |
| q_table = json.load(f) | |
| print(f"Loaded Q-table with {len(q_table)} states") | |
| except Exception as e: | |
| print(f"Error loading Q-table: {e}") | |
| # Global environment instance | |
| DEFAULT_TASK = { | |
| "itemsCount": 10, | |
| "store_capacity": 6, | |
| "crusher_energy": 4 | |
| } | |
| env = SortingEnv(DEFAULT_TASK) | |
| env.reset() | |
| cumulative_score = 0 | |
| is_done = False | |
| # ββ API ENDPOINTS ββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def reset_env(): | |
| global cumulative_score, is_done | |
| try: | |
| state = env.reset() | |
| cumulative_score = 0 | |
| is_done = False | |
| return { | |
| "item": env.current_item, | |
| "storage": env.current_storage, | |
| "energy": env.current_energy, | |
| "episode": 1 | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def agent_step(): | |
| global cumulative_score, is_done | |
| try: | |
| if is_done: | |
| raise HTTPException(status_code=400, detail="Episode finished") | |
| state_str = str(env.state) | |
| if state_str in q_table: | |
| action_idx = int(np.argmax(q_table[state_str])) | |
| else: | |
| action_idx = np.random.randint(0, 2) | |
| action = "STORE" if action_idx == 0 else "CRUSH" | |
| q_vals = q_table.get(state_str, [0.0, 0.0]) | |
| q_dict = {"STORE": float(q_vals[0]), "CRUSH": float(q_vals[1])} | |
| current_item = env.current_item.copy() | |
| next_state, reward, done = env.step(action) | |
| cumulative_score += reward | |
| is_done = done | |
| is_correct = (action == "STORE" and current_item["type"] == "FRUIT") or \ | |
| (action == "CRUSH" and current_item["type"] == "WASTE") | |
| return { | |
| "item": current_item, | |
| "action": action, | |
| "q_values": q_dict, | |
| "reward": float(reward), | |
| "done": done, | |
| "score": float(cumulative_score), | |
| "storage": int(env.current_storage), | |
| "energy": int(env.current_energy), | |
| "is_correct": is_correct | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def health(): | |
| return {"status": "healthy", "q_table_loaded": len(q_table) > 0} | |
| # ββ STATIC FILES (Next.js Frontend) βββββββββββββββββββββββββββββ | |
| static_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "client", "out") | |
| if os.path.exists(static_dir): | |
| # Serve static assets from _next folder | |
| _next_dir = os.path.join(static_dir, "_next") | |
| if os.path.exists(_next_dir): | |
| app.mount("/_next", StaticFiles(directory=_next_dir), name="next-assets") | |
| # Catch-all for other static files and the main index | |
| async def serve_static(full_path: str): | |
| # If the path is empty or just /, serve index.html | |
| if not full_path or full_path == "/": | |
| return FileResponse(os.path.join(static_dir, "index.html")) | |
| # Check if the requested file exists | |
| local_path = os.path.join(static_dir, full_path) | |
| if os.path.exists(local_path) and os.path.isfile(local_path): | |
| return FileResponse(local_path) | |
| # Fallback to index.html for SPA routing (though we're using static export) | |
| return FileResponse(os.path.join(static_dir, "index.html")) | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |