workonexcel / app_backend.py
rislrohitjain's picture
Initial clean push
a490b79
Raw
History Blame Contribute Delete
3.86 kB
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
@app.post("/upload")
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))
@app.post("/filter")
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))
@app.post("/export")
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)))