fix: Rezeptverlauf-Bilder lokal speichern und Windows-Subprocess-Fix

- Bilder beim Extrahieren lokal cachen (data/images/{id}.ext) und über GET /api/history/{id}/image ausliefern; Löschen bei Verlaufseintrag-Entfernung
- history.db in ./data/ Volume verschoben, damit sie Container-Rebuilds überlebt
- yt-dlp Subprocess-Aufrufe auf Windows gefixt: run_in_executor statt asyncio.create_subprocess_exec (SelectorEventLoop-Kompatibilität)
- ./data:/app/data Docker-Volume für persistente Datenhaltung hinzugefügt
This commit is contained in:
Andre
2026-04-14 17:17:03 +02:00
parent 4de67f0192
commit c7582dafbb
13 changed files with 125 additions and 33 deletions
+14 -1
View File
@@ -1,5 +1,6 @@
"""GET /api/extract/stream – SSE endpoint."""
from __future__ import annotations
import asyncio
import json
import logging
from typing import AsyncGenerator
@@ -13,12 +14,22 @@ from app.extractors.video import extract_video
from app.models import Recipe, StatusEvent, ErrorEvent, ExtractResponse
from app.services.nutrition import enrich_nutrition
from app.services.tandoor_service import recipe_to_tandoor
from app.services.history_service import save_recipe as save_to_history
from app.services.history_service import save_recipe as save_to_history, update_image_url
from app.services import image_service
log = logging.getLogger(__name__)
router = APIRouter()
async def _cache_image_background(history_id: int, remote_url: str) -> None:
local_path = await image_service.download_and_cache(history_id, remote_url)
if local_path:
try:
update_image_url(history_id, local_path)
except Exception as e:
log.warning("Failed to update image_url in DB: %s", e)
def _sse(event: str, data: str) -> str:
return f"event: {event}\ndata: {data}\n\n"
@@ -51,6 +62,8 @@ async def _stream(url: str) -> AsyncGenerator[str, None]:
history_id = save_to_history(base.model_dump())
except Exception as db_err:
log.warning("History save failed: %s", db_err)
if history_id and recipe.image_url:
asyncio.create_task(_cache_image_background(history_id, recipe.image_url))
response = ExtractResponse(recipe=recipe, tandoor_json=tandoor_json, history_id=history_id)
yield _sse("result", response.model_dump_json())