tetes
Möglichkeiten
Geschichte
Home App
Schichten
Digitaler Zwilling
Blog
Fallstudien
Zusammenarbeit
Kontakt
tetes

Docker Homelab. 40+ Dienste. 0 Cloud-Abonnements.

mariuszbinczyk.com

Navigation

  • Möglichkeiten
  • Geschichte
  • Home App
  • Schichten
  • Zusammenarbeit
  • Kontakt

Kontakt

  • GitHub
  • Email
  • PL / EN / DE

© 2026 tetes.pl — Alle Rechte vorbehalten

0d98bb6
ÜberDatenschutz
>|
Sprache:ENPLDE
Home App·29. Mai 2026·7 Min. Lesezeit·Aktualisiert: 13. Juni 2026

Notizbuch mit Kamera, Stimme und OCR — lokal selbst gebaut

Ich habe meiner Heim-App Bild-Uploads, polnische Spracheingabe und Texterkennung aus Fotos (OCR) hinzugefügt. Alles läuft lokal, ohne externe APIs.

#homelab#homeapp#notizen#ocr#self-hosted
Notizbuch mit Kamera, Stimme und OCR — lokal selbst gebaut
ℹ
Note

Der Artikel beschreibt Funktionen aus Home App v2.12 — einer Heim-App auf einem privaten Server. Der Code ist nicht öffentlich, aber die beschriebenen Muster (TipTap Image, Web Speech API, Tesseract.js) sind allgemein anwendbar.

Hintergrund

Ein Rezept auf einem Zettel, ein Beleg zum Abrechnen, eine Idee beim Kochen — früher landeten sie in der Kamerarolle des Handys oder gingen schlicht verloren.

Seit einigen Monaten nutze ich das Notizbuch in Home App intensiv — eine eigene Web-App, die auf meinem Heimserver läuft. Eine Sache fehlte mir: ein Bild einfügen, eine Notiz mit der Handykamera aufnehmen, einen Gedanken schnell per Sprache diktieren oder eine Datei (z. B. PDF) an eine Notiz anhängen zu können.

Ich nutze kommerzielle Apps (Notion, Obsidian, Evernote), und jede kann etwas davon — aber meine Daten bleiben beim Anbieter. Ich wollte dasselbe, nur lokal.

Vier Wege, ein Bild einzufügen

Vor der Umsetzung beherrschte das Notizbuch nur Text ( mit ein paar Erweiterungen: Aufgabenlisten, Überschriften, Links). Ich habe vier Upload-Kanäle ergänzt:

1. Drag & Drop — zieh eine Bilddatei auf den Editor. Es erscheint ein violetter gestrichelter Rahmen als Drop-Zone. Loslassen → das Bild landet auf dem Server und wird im Editor eingefügt.

2. Dateiauswahl — eine Schaltfläche in der Toolbar öffnet den System-Dateidialog. Unter Android zeigt er die Galerie. Auf dem iPhone akzeptiert er auch HEIC (das native Format der Apple-Kamera).

3. Kamera — eine zweite Schaltfläche in der Toolbar (capture=environment) öffnet direkt die rückseitige Handykamera. Keine Zwischenschritte.

4. Aus der Zwischenablage einfügen — Strg+V (oder langes Drücken → Einfügen am Telefon) nach einem Screenshot oder einem kopierten Bild fügt es direkt ein. Im Browser über das Clipboard-Paste-Event von TipTap unterstützt.

Wie es serverseitig funktioniert

Bilder gehen über multer (Express, in-memory, 25 MB Limit) an einen Dienst, der sharp nutzt:

  • Original mit vollständigen EXIF-Daten gespeichert
  • Display-Variante: max. 1920 px, JPEG q85, EXIF-Rotation angewendet
  • Thumbnail: max. 400 px, JPEG q80

Deduplizierung über SHA-256 — dieselbe Datei zweimal hochgeladen = eine Datei auf der Platte, zwei Referenzen. Der Speicher liegt in einem bind-gemounteten Host-Verzeichnis und ist vom Standard-Backup des Homelabs erfasst.

Neben Bildern nimmt derselbe Endpoint auch normale Dateien (z. B. PDF) an — diese überspringen die sharp-Verarbeitung und erscheinen in der Notiz als herunterladbarer Anhang (die Büroklammer-Schaltfläche in der Toolbar). Die Liste erlaubter MIME-Typen wird serverseitig geprüft.

Upload-Pipeline: Browser → Upload → Bilder via sharp / Dateien als Anhang → SHA-256 → PostgreSQL und lokaler Speicher → Backup

Polnische Spracheingabe

Die Web Speech API (SpeechRecognition) ist in Chrome und Edge eingebaut — keine Abhängigkeiten, keine Serverkosten. Ich habe eine Mikrofon-Schaltfläche in die Toolbar des Notizbuchs eingefügt:

  • Klick auf Start → pulsierender roter Punkt + „Słucham…" („Ich höre zu…")
  • Jeder erkannte Satz wird direkt in den Editor eingefügt
  • continuous: true + interimResults: true → Text-Streaming in Echtzeit
  • Sprache: pl-PL fest codiert

Für alltägliche Notizen funktioniert es überraschend gut. Bei Fachvokabular (z. B. englische Fachbegriffe mitten im polnischen Satz) wird es schlechter — aber zum Festhalten von Ideen, To-dos und schnellen Notizen reicht es völlig.

Safari iOS unterstützt die Web Speech API nicht — die Mikrofon-Schaltfläche wird dann automatisch ausgeblendet.

OCR aus einem Foto (Tesseract.js)

Eine dritte neue Schaltfläche startet die Texterkennung:

  1. Du wählst ein Foto (Kamera oder Datei)
  2. Das Foto wird auf den Server hochgeladen (Standard-Pipeline mit sharp)
  3. Tesseract.js läuft als Web Worker im Browser
  4. Das Modell pol+eng (~15 MB, nach dem ersten Download in IndexedDB zwischengespeichert)
  5. OCR liefert Text → es erscheint ein Modal mit:
    • einklappbarer Bildvorschau
    • bearbeitbarem Textfeld mit dem erkannten Text
    • drei Schaltflächen: nur Bild / nur Text / beides (Standard)

Ein wichtiges Detail: erhält die display-Variante vom Server (JPEG nach EXIF-Rotation), nicht das rohe HEIC vom iPhone — das macht heic2any im Browser überflüssig.

Genauigkeit: hervorragend bei gedrucktem Text, akzeptabel bei lesbarer Handschrift, schwach bei unleserlichem Gekritzel. Für die Zukunft habe ich die Anbindung von Vision als Option „Besseres OCR (KI)" vorgesehen — der Endpoint ist bereits vorbereitet und wartet auf ein Modell.

FAB Quick-Capture

Eine schwebende +-Schaltfläche auf der Startseite (unten rechts) plus das Tastenkürzel n — du erstellst eine Notiz, ohne erst den Notizbuch-Bereich zu öffnen. Vier Aktionen im Bottom Sheet:

  • Notiz → leerer Editor
  • Foto → Kamera → Upload → Notiz mit Bild
  • Sprache → leere Notiz + Mikrofon startet automatisch
  • OCR → Kamera → Upload → OCR-Modal

Quick-Capture: vier schnelle Aktionen rund um die „+"-Schaltfläche — Notiz, Foto, Sprache, OCR

Die Notizen landen im Standard-Notizbuch des Nutzers. Hat der Nutzer noch kein Standard-Notizbuch, legt das Backend „Szybkie notatki" („Schnelle Notizen") an und setzt es als Standard.

Notizen verlinken

Nach Fotos, OCR und Quick-Capture fehlte mir noch eine Sache: Notizen miteinander zu verknüpfen. Kein gewöhnlicher URL-Link, sondern wie in Obsidian: ich tippe [[, beginne einen Titel, wähle eine Notiz aus den Vorschlägen, und im Text erscheint ein kleiner violetter Chip mit dem Link.

Ein Klick darauf springt direkt zur verlinkten Notiz. Und öffne ich diese Notiz, sehe ich ein Panel „Verlinkungen" — eine Liste aller Stellen, die auf sie verweisen. Das Notizbuch ist damit nicht mehr nur eine chronologische Liste von Einträgen, sondern fühlt sich eher wie ein kleines, privates Wiki an: Ein Thema kann eine eigene Notiz haben, und andere Einträge können darauf zurückverweisen, ohne den Kontext zu kopieren.

Technisch gibt es dafür keine eigene Relationstabelle. Ein Link ist ein TipTap-Knoten in content_json, und Verlinkungen werden durch einen JSON-Scan in PostgreSQL ermittelt (jsonb_path_exists). Bei der Größe eines privaten Notizbuchs ist das einfacher, als eine zusätzliche Kantentabelle bei jedem Autosave synchron zu halten — sollte das Linkvolumen mal deutlich wachsen, wäre das der Punkt, es zu überdenken.

Dabei habe ich auch ein paar Dinge rund um Bilder abgeschlossen:

  • Bildergalerie — eine Notiz mit mehreren Fotos zeigt einen Vorschaustreifen und eine Vollbildansicht.
  • Bildgröße ändern — am Eck-Handle ziehen, live skalieren und in der gewünschten Größe in der Notiz lassen.
  • Markdown-Export — eine fertige Notiz als .md herunterladen, inklusive Text-Darstellung von Links und Anhängen.

Was ich gelernt habe

nginx client_max_body_size — der Standardwert ist 1 MB. Ich hatte vergessen, ihn zu setzen, also wurden Handy-Fotos (typisch 3–5 MB) stillschweigend abgewiesen. Jetzt client_max_body_size 30m.

useLayoutEffect statt useEffect für die Scroll-Position — ich hatte eine Komponente mit horizontalem Snap-Scroll (Dashboard-Seiten). Die Startposition über useEffect + requestAnimationFrame zu setzen, schlug fehl, weil clientWidth zu diesem Zeitpunkt 0 war. useLayoutEffect + scrollLeft = index * window.innerWidth läuft synchron vor dem ersten Rendern.

prev_content_json — nach dem Deployment entdeckte ich, dass das Autosave den Inhalt einer Notiz überschreiben kann, wenn der Nutzer sie während eines App-Neustarts geöffnet hat. Ich habe eine Spalte prev_content_json hinzugefügt — bei jedem Update wird zuerst die vorherige Version des Inhalts atomar dorthin gesichert. Gedacht war das als einmaliger Notfall-Rückgriff, und später, beim Einbau der Notizen-Verlinkung, hat es tatsächlich meine Daten gerettet.

Was als Nächstes kommt

  • Ollama Vision für schwierige OCR-Fälle (sobald ein Modell verfügbar ist)
  • Versionsverlauf (mehr als ein Schritt zurück)
  • PWA Share Target — „An Notizbuch teilen" aus dem Android-Teilen-Menü

Das Notizbuch ist nur ein Modul von Home App. Wie aus einem Einkaufsproblem im Haushalt eine ganze Familien-App wurde, beschreibe ich in der Fallstudie zum Familien-Dashboard.


Home App läuft auf einem privaten x86-Server. Stack: React 19 + TipTap 3 + Express + PostgreSQL.

Häufige Fragen

Landen meine Fotos und Notizen in der Cloud?

Nein. Bild-Upload, Diktat und OCR laufen lokal auf dem Heimserver — die Daten verlassen das Zuhause nicht.

Brauche ich teure Hardware für OCR und Diktat?

Nein. OCR läuft im Browser (Tesseract.js) und das Diktat nutzt die eingebaute Web Speech API. Ein gewöhnlicher Heimserver genügt.

Kann ich PDFs anhängen und mit dem Handy fotografieren?

Ja. Das Notizbuch unterstützt Datei-Upload, Screenshots, Handy-Fotos und das Ziehen von Bildern direkt in den Editor.

Tags

#homelab#homeapp#notizen#ocr#self-hosted
← Zurück zum Blog

← Vorheriger

Ein lokales LLM ohne GPU: was mich ein Jahr Ollama auf einem alten i5 gelehrt hat