FEAT: Integrated Document Engine with WebP optimization, Thumbnail generation and Hybrid (NAS/SSD) storage logic
This commit is contained in:
Binary file not shown.
82
backend/app/services/document_service.py
Normal file
82
backend/app/services/document_service.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
from PIL import Image
|
||||
from uuid import uuid4
|
||||
from fastapi import UploadFile, BackgroundTasks
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.models.document import Document
|
||||
|
||||
class DocumentService:
|
||||
@staticmethod
|
||||
def _clean_temp(path: str):
|
||||
"""30 perc után törli az ideiglenes fájlt (opcionális, ha maradunk a puffer mellett)"""
|
||||
time.sleep(1800)
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
@staticmethod
|
||||
async def process_upload(
|
||||
file: UploadFile,
|
||||
parent_type: str,
|
||||
parent_id: str,
|
||||
db: AsyncSession,
|
||||
background_tasks: BackgroundTasks
|
||||
):
|
||||
file_uuid = str(uuid4())
|
||||
|
||||
# 1. Könyvtárstruktúra meghatározása
|
||||
temp_dir = "/app/temp/uploads"
|
||||
nas_vault_dir = f"/mnt/nas/app_data/organizations/{parent_id}/vault"
|
||||
ssd_thumb_dir = f"/app/static/previews/organizations/{parent_id}"
|
||||
|
||||
for d in [temp_dir, nas_vault_dir, ssd_thumb_dir]:
|
||||
os.makedirs(d, exist_ok=True)
|
||||
|
||||
# 2. Mentés a TEMP-be
|
||||
temp_path = os.path.join(temp_dir, f"{file_uuid}_{file.filename}")
|
||||
content = await file.read()
|
||||
with open(temp_path, "wb") as f:
|
||||
f.write(content)
|
||||
|
||||
# 3. Képfeldolgozás (Pillow)
|
||||
img = Image.open(temp_path)
|
||||
|
||||
# A) Thumbnail generálás (300px WebP az SSD-re)
|
||||
thumb_filename = f"{file_uuid}_thumb.webp"
|
||||
thumb_path = os.path.join(ssd_thumb_dir, thumb_filename)
|
||||
thumb_img = img.copy()
|
||||
thumb_img.thumbnail((300, 300))
|
||||
thumb_img.save(thumb_path, "WEBP", quality=80)
|
||||
|
||||
# B) Nagy kép optimalizálás (Max 1600px WebP a NAS-ra)
|
||||
vault_filename = f"{file_uuid}.webp"
|
||||
vault_path = os.path.join(nas_vault_dir, vault_filename)
|
||||
|
||||
if img.width > 1600:
|
||||
ratio = 1600 / float(img.width)
|
||||
new_height = int(float(img.height) * float(ratio))
|
||||
img = img.resize((1600, new_height), Image.Resampling.LANCZOS)
|
||||
|
||||
img.save(vault_path, "WEBP", quality=85)
|
||||
|
||||
# 4. Adatbázis rögzítés
|
||||
new_doc = Document(
|
||||
id=uuid4(),
|
||||
parent_type=parent_type,
|
||||
parent_id=parent_id,
|
||||
original_name=file.filename,
|
||||
file_hash=file_uuid,
|
||||
file_size=os.path.getsize(vault_path),
|
||||
has_thumbnail=True,
|
||||
thumbnail_path=f"/static/previews/organizations/{parent_id}/{thumb_filename}"
|
||||
)
|
||||
db.add(new_doc)
|
||||
await db.commit()
|
||||
|
||||
# 5. Puffer törlés ütemezése (30 perc)
|
||||
# background_tasks.add_task(DocumentService._clean_temp, temp_path)
|
||||
# MVP-ben töröljük azonnal, ha már a NAS-on van a biztonságos másolat
|
||||
os.remove(temp_path)
|
||||
|
||||
return new_doc
|
||||
Reference in New Issue
Block a user