Files
ai-bayarea/python/debug_one_pdf.py
2026-07-12 12:30:20 -05:00

96 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""
debug_one_pdf.py - Verarbeitet EIN PDF und zeigt die ROHE Modell-Antwort,
egal ob sie als JSON parst oder nicht. Zum Debuggen einzelner Problemfaelle.
Aufruf:
python3 debug_one_pdf.py \
--api http://localhost:8000/v1 --model "gemma-4-12b" \
--pdf ~/data/S/"Scott, Dexter Notes 031226.pdf"
"""
import argparse, io, base64, json, re
from openai import OpenAI
from pypdf import PdfReader
from pdf2image import convert_from_path
# --- dieselbe Konfiguration wie im Hauptscript ---
JSON_SCHEMA = {
"type": "object",
"properties": {
"is_buyer_sheet": {"type": "boolean"},
"name_company": {"type": ["string", "null"]},
"prospective_buyer": {"type": ["string", "null"]},
"company": {"type": ["string", "null"]},
"phone": {"type": ["string", "null"]},
"cell": {"type": ["string", "null"]},
"email": {"type": ["string", "null"]},
"address": {"type": ["string", "null"]},
"state": {"type": ["string", "null"]},
"how_did_you_hear": {"type": ["string", "null"]},
"interested_in_updates": {"type": ["boolean", "null"]},
"types_of_business_raw": {"type": ["string", "null"]},
"types_of_business": {"type": "array", "items": {"type": "string"}},
"background_experience": {"type": ["string", "null"]},
"date_of_introduction": {"type": ["string", "null"]},
},
"required": ["is_buyer_sheet", "name_company", "prospective_buyer", "company",
"phone", "cell", "email", "address", "state", "how_did_you_hear",
"interested_in_updates", "types_of_business_raw", "types_of_business",
"background_experience", "date_of_introduction"],
}
SYSTEM_PROMPT = """Du bist ein praezises Datenextraktions-System fuer Formulare der Firma "BizMatch Business Brokerage". Extrahiere die verlangten Felder als JSON. Fehlende Felder -> null. ERFINDE NICHTS."""
ap = argparse.ArgumentParser()
ap.add_argument("--api", default="http://localhost:8000/v1")
ap.add_argument("--model", default="gemma-4-12b")
ap.add_argument("--pdf", required=True)
ap.add_argument("--max-tokens", type=int, default=512)
args = ap.parse_args()
client = OpenAI(base_url=args.api, api_key="x", timeout=120, max_retries=0)
n_pages = len(PdfReader(args.pdf).pages)
print(f"PDF: {args.pdf}")
print(f"Seiten: {n_pages}")
# Vision-Pfad (2 Seiten, wie im Hauptscript)
imgs = convert_from_path(args.pdf, first_page=1, last_page=2, dpi=150)
payload = [{"type":"text","text":"Extrahiere die Felder aus diesem Buyer Information Sheet:"}]
for img in imgs:
w,h = img.size
scale = min(1.0, 1600/max(w,h))
if scale < 1.0:
img = img.resize((int(w*scale), int(h*scale)))
buf = io.BytesIO(); img.convert("RGB").save(buf, format="JPEG", quality=80)
b64 = base64.b64encode(buf.getvalue()).decode()
payload.append({"type":"image_url","image_url":{"url":f"data:image/jpeg;base64,{b64}"}})
print(f"\nSende {len(imgs)} Bild(er) an das Modell, max_tokens={args.max_tokens}...\n")
resp = client.chat.completions.create(
model=args.model,
messages=[{"role":"system","content":SYSTEM_PROMPT},
{"role":"user","content":payload}],
temperature=0.0,
max_tokens=args.max_tokens,
response_format={"type":"json_schema","json_schema":{"name":"buyer","schema":JSON_SCHEMA}},
extra_body={"chat_template_kwargs":{"enable_thinking":False}},
)
choice = resp.choices[0]
raw = choice.message.content
print("=== finish_reason ===")
print(choice.finish_reason)
print(f"\n=== ROHE ANTWORT ({len(raw or '')} Zeichen) ===")
print(repr(raw))
print("\n=== ANTWORT LESBAR ===")
print(raw)
print("\n=== PARSE-VERSUCH ===")
try:
parsed = json.loads(raw)
print("OK, parst sauber:")
print(json.dumps(parsed, indent=2, ensure_ascii=False))
except Exception as e:
print(f"FEHLER: {e}")