Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import logging | |
| import traceback | |
| import time | |
| import psutil | |
| import polars as pl | |
| from datetime import datetime | |
| from dotenv import load_dotenv | |
| from fastapi import FastAPI, UploadFile, File, Form, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| load_dotenv() | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Vercel filesystem is read-only except for /tmp | |
| IS_VERCEL = "VERCEL" in os.environ | |
| UPLOAD_ROOT = "/tmp/uploads" if IS_VERCEL else "uploads" | |
| EXPORT_ROOT = "/tmp/exports" if IS_VERCEL else "exports" | |
| def get_dated_path(root): | |
| path = os.path.join(root, datetime.now().strftime("%Y-%m-%d")) | |
| os.makedirs(path, exist_ok=True) | |
| return path | |
| async def upload_file(file: UploadFile = File(...)): | |
| try: | |
| dir_path = get_dated_path(UPLOAD_ROOT) | |
| ext = os.path.splitext(file.filename)[1] | |
| now = datetime.now() | |
| new_filename = f"{now.strftime('%Y%m%d_%H%M%S')}_{int(now.timestamp())}{ext}" | |
| file_path = os.path.join(dir_path, new_filename) | |
| content = await file.read() | |
| with open(file_path, "wb") as f: | |
| f.write(content) | |
| df = pl.read_excel(file_path) if new_filename.endswith(('.xlsx', '.xls')) else pl.read_csv(file_path) | |
| return {"filename": new_filename, "path": file_path, "columns": df.columns, "total_rows": len(df)} | |
| except Exception as e: | |
| logging.error(traceback.format_exc()) | |
| raise HTTPException(status_code=400, detail=str(e)) | |
| async def filter_data(file_path: str = Form(...), filters: str = Form(...), sorts: str = Form(...)): | |
| start_time = time.time() | |
| try: | |
| process = psutil.Process(os.getpid()) | |
| df = pl.read_excel(file_path) if file_path.endswith(('.xlsx', '.xls')) else pl.read_csv(file_path) | |
| # Filtering | |
| for f in json.loads(filters): | |
| col, op, val = f['col'], f['op'], f['val'] | |
| if not val: continue | |
| selector = pl.col(col) | |
| if op == "=": df = df.filter(selector.cast(pl.Utf8) == str(val)) | |
| elif op == "!=": df = df.filter(selector.cast(pl.Utf8) != str(val)) | |
| elif op == "like": df = df.filter(selector.cast(pl.Utf8).str.contains(str(val))) | |
| # Sorting | |
| sort_list = json.loads(sorts) | |
| if sort_list: | |
| df = df.sort([s['col'] for s in sort_list], descending=[s['desc'] for s in sort_list]) | |
| if len(df) > 0: | |
| if "S.No" in df.columns: df = df.drop("S.No") | |
| df = df.insert_column(0, pl.Series("S.No", list(range(1, len(df) + 1)))) | |
| return { | |
| "data": df.to_dicts(), | |
| "performance": { | |
| "execution_time": f"{round(time.time() - start_time, 4)}s", | |
| "memory_usage": f"{round(process.memory_info().rss / (1024 * 1024), 2)} MB", | |
| "cpu_utilization": f"{psutil.cpu_percent()}%", | |
| "physical_cores": psutil.cpu_count(logical=False), | |
| "logical_cores": psutil.cpu_count(logical=True), | |
| "total_records": len(df) | |
| } | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def export_data(data: str = Form(...)): | |
| try: | |
| df = pl.from_dicts(json.loads(data)) | |
| dir_path = get_dated_path(EXPORT_ROOT) | |
| path = os.path.join(dir_path, f"export_{datetime.now().strftime('%H%M%S')}.xlsx") | |
| df.write_excel(path) | |
| return {"path": path} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host=os.getenv("BACKEND_HOST", "172.18.177.164"), port=int(os.getenv("BACKEND_PORT", 8000))) |