Commit Graph

5 Commits

Author SHA1 Message Date
Lucas Orth
1e8918e0cd Bildeditor, klickbare Felder, Einstellungen; Kopfzeile und Namensfeld raus
All checks were successful
Build & Deploy / deploy (push) Successful in 1m29s
Bildbearbeitung im Nachgang: Drehen in 90-Grad-Schritten, Ausrichten per
Schieberegler, Zuschneiden per Rahmen mit anfassbaren Ecken. Der Server
rechnet jede Korrektur vom unbearbeiteten Original, das beim ersten
Eingriff daneben abgelegt wird - sonst summieren sich die Verluste über
mehrere Korrekturen, und Zurücksetzen wäre nicht möglich. Zwei
Zuschnitte hintereinander werden ineinander verrechnet.

Der Ort ließ sich nicht übernehmen, weil beide Quellen versagen können:
iOS entfernt beim Weitergeben an eine Webseite oft die GPS-Daten aus dem
Foto, und der Browserstandort scheiterte bisher stumm. Jetzt meldet er
seinen Grund ("Standortfreigabe fehlt"), die Detailansicht zeigt die
Herkunft des Ortes, und der Scan-Ort ist von Hand nachtragbar.

E-Mail, Web, Telefon und Mobil sind in der Tabelle jetzt Links; Straße,
PLZ, Ort und Land stehen als eine Adresszeile, die die eingestellte
Navigations-App öffnet.

Einstellungen als vierter Reiter: Navigations-App (Apple Karten, Google
Maps, OpenStreetMap), Statusübersicht und Abmelden - der Knopf saß
vorher in der Kopfzeile.

Die Kopfzeile ist weg. Sie kostete auf dem Telefon eine Bildschirmzeile
und wiederholte nur, was die Tableiste schon sagt.

Kein full_name mehr, nur Vor- und Nachname; akademische Titel gehören in
den Vornamen. Bestehende Datensätze werden bei der Migration am letzten
Leerzeichen aufgeteilt. Die Spalte bleibt ungenutzt stehen: SQLite baut
zum Löschen die ganze Tabelle neu, der Gewinn wären ein paar Byte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 15:19:10 +02:00
Lucas Orth
a7fbc15792 Hintergrundverarbeitung, Bildaufbereitung, Sammelexport entfernt
All checks were successful
Build & Deploy / deploy (push) Successful in 1m24s
Auslesen im Hintergrund: /api/scan antwortet, sobald die Karten
freigestellt und gespeichert sind, und stößt die Extraktion als Task an.
Ein Zwanzigerstapel blockierte vorher den Upload für die ganze Dauer
aller Modellaufrufe. Die Oberfläche zeigt "wird gelesen" und lädt nach,
solange etwas offen ist.

Zwei Folgen davon sind mitbehandelt: Beim Schreiben der Ergebnisse steht
COALESCE, damit ein Handeintrag während des Lesens nicht überschrieben
wird, und offene Karten werden beim Start nachgeholt, statt dauerhaft in
der Warteschlange zu hängen.

Bildaufbereitung des Zuschnitts:
- Der Einzug zieht die erkannten Ecken um 1,5 % zur Mitte, damit kein
  Untergrund im Zuschnitt bleibt.
- Die Beleuchtung wird ausgeglichen (Division durch eine weichgezeichnete
  Fassung), damit das Papier weiß wird statt grau. Dunkle Karten bleiben
  unangetastet - bei ihnen ist das Dunkle das Papier, kein Schatten.
- Das Modell meldet die nötige Drehung im Schema; das gespeicherte Bild
  wird entsprechend gedreht. Geometrisch ist die Lage nicht bestimmbar.

Sammelexport entfernt: Der Button "Alle als vCard" ist weg, mit ihm der
Endpunkt /vcf sowie vcard.build_many und db.execute_many, die dadurch
keinen Aufrufer mehr hatten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 12:56:58 +02:00
Lucas Orth
bc1981f1bd Scan-Pfad entschlacken, Container-Limits setzen
Drei Änderungen, die den Spitzenverbrauch eines Stapelscans senken:

- Zuschnitte werden nicht mehr auf 1400 px hochgerechnet. Auf einem
  Stapelfoto ist eine Karte nur ein paar hundert Pixel breit; sie
  aufzublasen erzeugt vier Mal so viele Pixel ohne mehr Information und
  kostet zusätzlich Bildtokens beim Modellaufruf. OUT_WIDTH ist jetzt
  eine Obergrenze.
- Die um 180 Grad gedrehte Fassung entsteht erst, wenn ein Ergebnis leer
  bleibt, statt für jede Karte auf Vorrat. Das halbiert die
  JPEG-Kodierungen im Normalfall.
- Zuschnitte werden einzeln kodiert und sofort freigegeben, statt
  gesammelt im Speicher zu liegen.

Dazu mem_limit und cpus für den App-Container: ein Ausreißer soll den
Container treffen, nicht den Host, auf dem auch Jitsi und MySQL laufen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 12:22:37 +02:00
Lucas Orth
811dba4e98 Toten Code entfernen
Some checks failed
Build & Deploy / deploy (push) Failing after 11m38s
Ungenutzte Hilfsfunktion, ungenutzter Konfigurationswert und drei
CSS-Regeln ohne Verwendung im Markup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 11:46:52 +02:00
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