Files
business-card-scanner/app/config.py
Lucas Orth ab993e98e1 Visitenkarten-Scanner: Stapelscan, Extraktion, Übersicht, vCard-Export
Selbst gehostete PWA, die Visitenkarten von einem Foto freistellt, ausliest
und als Kontakt bereitstellt.

- Stapelscan: OpenCV findet die Kartenrechtecke über mehrere Binärmasken,
  entzerrt sie perspektivisch und schneidet sie einzeln aus. Ohne Fund gilt
  das ganze Foto als eine Karte.
- Extraktion: ein Aufruf je Zuschnitt an das Vision-Modell mit
  JSON-Schema. Kein vorgeschaltetes OCR - das würde Layout und
  Schriftgrößen wegwerfen, aus denen die Feldzuordnung entsteht.
- Metadaten: Aufnahmezeit und GPS aus den EXIF-Daten des Fotos, Ortsname
  über Nominatim, Browserstandort nur als Rückfallebene.
- Übersicht mit Volltextsuche und Filtern, Detailansicht mit Korrekturmaske.
- Notizfeld je Karte, Erinnerungen per Mail inklusive Nachholen verpasster
  Termine nach einem Neustart.
- vCard 3.0 einzeln und als Sammeldatei, Karte gilt danach als exportiert.
- Anmeldung über ein Passwort, Sitzung als signiertes Cookie.
- Deployment per Tag-Push nach den Konventionen in DEPLOY.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 11:45:56 +02:00

56 lines
1.5 KiB
Python

"""Konfiguration. Alle Werte kommen aus der Umgebung (im Betrieb aus .env)."""
import os
from pathlib import Path
def _s(name: str, default: str = "") -> str:
return os.environ.get(name, default).strip()
def _i(name: str, default: int) -> int:
try:
return int(_s(name) or default)
except ValueError:
return default
def _b(name: str, default: bool) -> bool:
v = _s(name).lower()
if not v:
return default
return v in ("1", "true", "yes", "on")
DATA_DIR = Path(_s("DATA_DIR", "./data"))
IMAGE_DIR = DATA_DIR / "images"
DB_PATH = DATA_DIR / "cards.db"
PORT = _i("PORT", 8080)
# Leeres Passwort schaltet die Anmeldung ab - nur fuer die lokale Entwicklung.
APP_PASSWORD = _s("APP_PASSWORD")
SECRET_KEY = _s("SECRET_KEY", "dev-only-insecure-secret")
SESSION_DAYS = _i("SESSION_DAYS", 30)
ANTHROPIC_API_KEY = _s("ANTHROPIC_API_KEY")
ANTHROPIC_MODEL = _s("ANTHROPIC_MODEL", "claude-opus-5")
EXTRACT_CONCURRENCY = _i("EXTRACT_CONCURRENCY", 5)
SMTP_HOST = _s("SMTP_HOST")
SMTP_PORT = _i("SMTP_PORT", 587)
SMTP_USER = _s("SMTP_USER")
SMTP_PASSWORD = _s("SMTP_PASSWORD")
SMTP_FROM = _s("SMTP_FROM") or SMTP_USER
SMTP_STARTTLS = _b("SMTP_STARTTLS", True)
REMINDER_TO = _s("REMINDER_TO")
REVERSE_GEOCODE = _b("REVERSE_GEOCODE", True)
NOMINATIM_URL = _s("NOMINATIM_URL", "https://nominatim.openstreetmap.org/reverse")
USER_AGENT = _s("USER_AGENT", "business-card-scanner/1.0 (self-hosted)")
PUBLIC_BASE_URL = _s("PUBLIC_BASE_URL").rstrip("/")
def ensure_dirs() -> None:
IMAGE_DIR.mkdir(parents=True, exist_ok=True)