files.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import os
  2. import uuid
  3. import hashlib
  4. from fastapi import APIRouter, UploadFile, File, BackgroundTasks
  5. from typing import List
  6. import db
  7. import config
  8. import preview_utils
  9. from services import order_processing
  10. router = APIRouter(prefix="/files", tags=["files"])
  11. @router.post("/upload")
  12. async def upload_files(background_tasks: BackgroundTasks, files: List[UploadFile] = File(...)):
  13. if not files: return {"uploaded": []}
  14. uploaded_data = []
  15. for file in files:
  16. if not file.filename: continue
  17. file_ext = os.path.splitext(file.filename)[1]
  18. unique_filename = f"{uuid.uuid4()}{file_ext}"
  19. file_path = os.path.join(config.UPLOAD_DIR, unique_filename)
  20. db_file_path = f"uploads/{unique_filename}"
  21. sha256_hash = hashlib.sha256()
  22. with open(file_path, "wb") as buffer:
  23. while chunk := file.file.read(8192):
  24. sha256_hash.update(chunk)
  25. buffer.write(chunk)
  26. file_hash = sha256_hash.hexdigest()
  27. # --- CACHE CHECK (Hash based) ---
  28. filament_g = None
  29. print_time = None
  30. dimensions = None
  31. cached_record = db.execute_query(
  32. "SELECT filament_g, print_time, dimensions FROM order_files WHERE file_hash = %s AND print_time IS NOT NULL LIMIT 1",
  33. (file_hash,)
  34. )
  35. if cached_record:
  36. filament_g = cached_record[0]['filament_g']
  37. print_time = cached_record[0]['print_time']
  38. dimensions = cached_record[0]['dimensions']
  39. # Only slice if not cached
  40. if not print_time and config.SYNC_SLICING_ON_UPLOAD and file_ext.lower() == ".stl":
  41. import slicer_utils
  42. result = slicer_utils.slice_model(file_path)
  43. if result and result.get('success'):
  44. filament_g = result.get('filament_g')
  45. print_time = result.get('print_time_str')
  46. dimensions = result.get('dimensions')
  47. preview_path = None
  48. db_preview_path = None
  49. if file_ext.lower() == ".stl":
  50. preview_filename = f"{uuid.uuid4()}.png"
  51. preview_path = os.path.join(config.PREVIEW_DIR, preview_filename)
  52. db_preview_path = f"uploads/previews/{preview_filename}"
  53. preview_utils.generate_stl_preview(file_path, preview_path)
  54. 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)"
  55. f_id = db.execute_commit(query, (file.filename, db_file_path, file.size, file_hash, print_time, filament_g, db_preview_path, dimensions))
  56. # If preview/slicing didn't happen (not cached and not sync), run in background
  57. if not print_time or not db_preview_path:
  58. background_tasks.add_task(order_processing.process_single_file_async, f_id)
  59. uploaded_data.append({
  60. "id": f_id, "filename": file.filename, "size": file.size,
  61. "print_time": print_time, "filament_g": filament_g, "preview_path": db_preview_path,
  62. "dimensions": dimensions
  63. })
  64. return {"uploaded": uploaded_data}