import os import uuid import hashlib from fastapi import APIRouter, UploadFile, File, BackgroundTasks from typing import List import db import config import preview_utils from services import order_processing router = APIRouter(prefix="/files", tags=["files"]) @router.post("/upload") async def upload_files(background_tasks: BackgroundTasks, files: List[UploadFile] = File(...)): if not files: return {"uploaded": []} uploaded_data = [] for file in files: if not file.filename: continue file_ext = os.path.splitext(file.filename)[1] unique_filename = f"{uuid.uuid4()}{file_ext}" file_path = os.path.join(config.UPLOAD_DIR, unique_filename) db_file_path = f"uploads/{unique_filename}" sha256_hash = hashlib.sha256() with open(file_path, "wb") as buffer: while chunk := file.file.read(8192): sha256_hash.update(chunk) buffer.write(chunk) file_hash = sha256_hash.hexdigest() # --- CACHE CHECK (Hash based) --- filament_g = None print_time = None dimensions = None cached_record = db.execute_query( "SELECT filament_g, print_time, dimensions FROM order_files WHERE file_hash = %s AND print_time IS NOT NULL AND dimensions IS NOT NULL LIMIT 1", (file_hash,) ) if cached_record: filament_g = cached_record[0]['filament_g'] print_time = cached_record[0]['print_time'] dimensions = cached_record[0]['dimensions'] # Only slice if not cached if not print_time and config.SYNC_SLICING_ON_UPLOAD and file_ext.lower() == ".stl": import slicer_utils result = slicer_utils.slice_model(file_path) if result and result.get('success'): filament_g = result.get('filament_g') print_time = result.get('print_time_str') dimensions = result.get('dimensions') preview_path = None db_preview_path = None if file_ext.lower() == ".stl": preview_filename = f"{uuid.uuid4()}.png" preview_path = os.path.join(config.PREVIEW_DIR, preview_filename) db_preview_path = f"uploads/previews/{preview_filename}" preview_utils.generate_stl_preview(file_path, preview_path) query = "INSERT INTO order_files (order_id, filename, file_path, file_size, quantity, file_hash, print_time, filament_g, preview_path, dimensions) VALUES (NULL, %s, %s, %s, 1, %s, %s, %s, %s, %s)" f_id = db.execute_commit(query, (file.filename, db_file_path, file.size, file_hash, print_time, filament_g, db_preview_path, dimensions)) # If preview/slicing didn't happen (not cached and not sync), run in background if not print_time or not db_preview_path: background_tasks.add_task(order_processing.process_single_file_async, f_id) uploaded_data.append({ "id": f_id, "filename": file.filename, "size": file.size, "print_time": print_time, "filament_g": filament_g, "preview_path": db_preview_path, "dimensions": dimensions }) return {"uploaded": uploaded_data}