7678d28717
Self-hosted, verifiable pipeline for extracting structured data (station, date/time, price per litre, litres, discount, total) from German fuel receipt photos: grayscale + mild bilateral filter + contrast stretch, Tesseract OCR, then LLM structuring via a small local model (Qwen 2.5, served by Ollama). Each step is independently runnable and inspectable through numbered scripts against a shared tooling container. Ollama runs as its own long-lived container (0_run_ollama.sh), separate from the stateless per-receipt pipeline steps, so the model stays loaded in memory between runs. Includes a containerized ground-truth batch test (test_batch.sh) that reproduces the full pipeline over the test receipts and reports per-field accuracy. Targets eventual deployment on a Raspberry Pi 4 k3s cluster.
35 lines
928 B
Python
35 lines
928 B
Python
#!/usr/bin/env python3
|
|
"""Step 2: run Tesseract OCR (German) over a preprocessed receipt image,
|
|
writing the raw recognized text to the output directory for inspection
|
|
before it is handed to the structuring step."""
|
|
import argparse
|
|
import os
|
|
|
|
import pytesseract
|
|
from PIL import Image
|
|
|
|
|
|
def ocr(path: str, out_dir: str) -> str:
|
|
os.makedirs(out_dir, exist_ok=True)
|
|
img = Image.open(path)
|
|
text = pytesseract.image_to_string(img, lang="deu", config="--psm 3")
|
|
|
|
out_path = os.path.join(out_dir, "ocr.txt")
|
|
with open(out_path, "w", encoding="utf-8") as f:
|
|
f.write(text)
|
|
return out_path
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-in", dest="in_path", required=True)
|
|
parser.add_argument("-out", dest="out_dir", required=True)
|
|
args = parser.parse_args()
|
|
|
|
out_path = ocr(args.in_path, args.out_dir)
|
|
print(out_path)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|