Update speiseplan_core/missing.py
Browse files- speiseplan_core/missing.py +54 -1
speiseplan_core/missing.py
CHANGED
|
@@ -1,9 +1,20 @@
|
|
| 1 |
from __future__ import annotations
|
|
|
|
| 2 |
from dataclasses import dataclass, asdict
|
| 3 |
-
from
|
|
|
|
|
|
|
| 4 |
import pandas as pd
|
| 5 |
import numpy as np
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
@dataclass
|
| 9 |
class MissingItem:
|
|
@@ -89,4 +100,46 @@ def build_missing_report(
|
|
| 89 |
"uncertain_match_count": int(uncertain_mask.sum()),
|
| 90 |
"not_confirmed_count": int(not_confirmed_mask.sum()),
|
| 91 |
"items": [asdict(x) for x in items],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
}
|
|
|
|
| 1 |
from __future__ import annotations
|
| 2 |
+
|
| 3 |
from dataclasses import dataclass, asdict
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from typing import Any, Optional
|
| 6 |
+
|
| 7 |
import pandas as pd
|
| 8 |
import numpy as np
|
| 9 |
|
| 10 |
+
# ✅ Pipeline imports (no UI Space call) — this file lives in speiseplan_core
|
| 11 |
+
from .pipeline import (
|
| 12 |
+
fetch_speiseplan_pdf_cached,
|
| 13 |
+
fetch_speiseplan_pdf_by_week_cached,
|
| 14 |
+
get_text_any,
|
| 15 |
+
process_text,
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
|
| 19 |
@dataclass
|
| 20 |
class MissingItem:
|
|
|
|
| 100 |
"uncertain_match_count": int(uncertain_mask.sum()),
|
| 101 |
"not_confirmed_count": int(not_confirmed_mask.sum()),
|
| 102 |
"items": [asdict(x) for x in items],
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def missing_pipeline_api(
|
| 107 |
+
tenant_id: Optional[str] = None,
|
| 108 |
+
mode: str = "latest", # latest | this_week
|
| 109 |
+
week_start_date: Optional[str] = None,
|
| 110 |
+
match_threshold: Optional[int] = None,
|
| 111 |
+
limit: int = 50,
|
| 112 |
+
) -> dict[str, Any]:
|
| 113 |
+
"""
|
| 114 |
+
✅ Missing-API Wrapper:
|
| 115 |
+
- lädt Speiseplan (latest/this_week oder explizit week_start_date)
|
| 116 |
+
- extrahiert Text
|
| 117 |
+
- parsed zu DF via process_text
|
| 118 |
+
- erzeugt Missing-Report via build_missing_report
|
| 119 |
+
"""
|
| 120 |
+
if week_start_date:
|
| 121 |
+
pdf_bytes, meta = fetch_speiseplan_pdf_by_week_cached(week_start_date, tenant_id)
|
| 122 |
+
else:
|
| 123 |
+
pdf_bytes, meta = fetch_speiseplan_pdf_cached(mode=mode, tenant_id=tenant_id)
|
| 124 |
+
|
| 125 |
+
tmp = Path("/tmp/speiseplan_missing_input.pdf")
|
| 126 |
+
tmp.write_bytes(pdf_bytes)
|
| 127 |
+
|
| 128 |
+
text = get_text_any(tmp)
|
| 129 |
+
default_date = str(meta.get("week_start_date") or "")
|
| 130 |
+
df = process_text(text, default_date=default_date)
|
| 131 |
+
|
| 132 |
+
report = build_missing_report(
|
| 133 |
+
df_results=df,
|
| 134 |
+
match_threshold=int(match_threshold or 92),
|
| 135 |
+
limit=int(limit or 50),
|
| 136 |
+
)
|
| 137 |
+
|
| 138 |
+
return {
|
| 139 |
+
"ok": True,
|
| 140 |
+
"tenant_id": tenant_id or "",
|
| 141 |
+
"mode": (mode or "latest"),
|
| 142 |
+
"week_start_date": meta.get("week_start_date"),
|
| 143 |
+
"meta": meta,
|
| 144 |
+
**report,
|
| 145 |
}
|