Spracherkennung für OCR-Texte und Qualitätsbewertung (Konfidenzwert), um schlechte OCR-Ergebnisse kenntlich zu machen. Letztes Ticket vor QA-03. - ocr/language.go: RecognizeWithLanguageAndConfidence erkennt ein Bild einzeln je Kandidatensprache (deu/eng) im Tesseract-TSV-Modus — die Sprache mit höherem Konfidenzwert gewinnt, derselbe Lauf liefert den Konfidenzwert direkt mit. - search: neue Felder ocr_language/ocr_confidence (Migrationen 0006/0007, gleiches ALTER-Muster wie SRC-05), in Document/Result gespiegelt. Client.AttachmentsBelowConfidence filtert gezielt auf niedrige Konfidenz, schließt Dokumente ohne OCR-Anhang aus. - Regressionsbug gefunden und behoben: reindex.go (SRC-09) kannte die neuen OCR-Spalten nicht, Reindex wäre mit "unknown column" fehlgeschlagen. Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-10-PRUEFPROTOKOLL.md): 1. TestRecognizeWithLanguageAndConfidence_MultilingualCorpus: deutsches und englisches Testbild real korrekt als deu/eng erkannt. 2. TestRecognizeWithLanguageAndConfidence_DegradedImageLowersConfidence: künstliche Verschlechterung senkt Konfidenz real von 91,76 auf 28,21. 3. TestAttachmentsBelowConfidence_QueryReturnsExpectedResults: Abfrage unterhalb Schwelle liefert real genau die erwarteten 2 von 4 Treffern. Kein Umbau: Search/Facets/SearchWithFilters/Index/Delete-Verhalten sonst unverändert, dedup/indexworker/storage/crypto/encstorage/savedsearch unverändert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
58 lines
2.5 KiB
Go
58 lines
2.5 KiB
Go
// Package search implementiert SRC-01: den Manticore-RT-Suchindex für
|
|
// Mail-Inhalte. Bekannter Fehler vermeiden (siehe known-issues-archivmail.md
|
|
// #11/#12): archivmail baute WHERE-Klauseln und teils Spalten-/Tabellennamen
|
|
// dynamisch über fmt.Sprintf/strings.Join zusammen. Für dieses Paket gilt
|
|
// verbindlich: Spalten- und Tabellennamen kommen AUSSCHLIESSLICH aus den
|
|
// Konstanten dieser Datei, nirgendwo sonst im Paket wird ein Feld- oder
|
|
// Tabellenname zur Laufzeit zusammengesetzt. Suchanfragen laufen über die
|
|
// strukturierte Manticore-HTTP-JSON-API (Query/Insert-Sub, kein
|
|
// String-Zusammenbau von SQL), nicht über die SQL-Schnittstelle.
|
|
package search
|
|
|
|
import "hash/fnv"
|
|
|
|
// IndexName ist der einzige Ort, an dem der Manticore-Indexname als
|
|
// Literal steht.
|
|
const IndexName = "mail_documents"
|
|
|
|
// Statische Feld-Whitelist des mail_documents-Index (muss deckungsgleich
|
|
// mit migrations/0001_mail_documents.sql bleiben).
|
|
const (
|
|
FieldTenantSlug = "tenant_slug"
|
|
FieldMessageID = "message_id"
|
|
FieldSubject = "subject"
|
|
FieldBody = "body"
|
|
FieldAttachmentText = "attachment_text"
|
|
FieldSentAt = "sent_at"
|
|
// Facettenfelder (SRC-05), nachgezogen über migrations/0002..0005.
|
|
FieldSender = "sender"
|
|
FieldMailbox = "mailbox"
|
|
FieldAttachmentType = "attachment_type"
|
|
FieldTag = "tag"
|
|
// OCR-Sprach-/Qualitätsfelder (SRC-10), nachgezogen über
|
|
// migrations/0006..0007.
|
|
FieldOCRLanguage = "ocr_language"
|
|
FieldOCRConfidence = "ocr_confidence"
|
|
)
|
|
|
|
// FacetFields sind die je Kachel unterstützten Filterdimensionen
|
|
// (Akzeptanzkriterium 1: Absender, Postfach, Anhangstyp, Tag — Zeitraum
|
|
// läuft separat über FieldSentAt als Bereichsfacette, siehe facets.go).
|
|
// Statische Liste — Aufrufer können ausschließlich diese Feldnamen als
|
|
// Facetten-/Filterdimension angeben, kein beliebiger Client-Feldname.
|
|
var FacetFields = []string{FieldSender, FieldMailbox, FieldAttachmentType, FieldTag}
|
|
|
|
// DocumentID berechnet deterministisch die Manticore-Dokument-ID aus
|
|
// Mandant und Message-ID (FNV-1a, 64 Bit). Deterministisch statt einer
|
|
// separat vergebenen ID, damit Re-Indexierung (Index) und Löschung
|
|
// (Delete) für dieselbe Mail immer dieselbe Dokument-ID referenzieren,
|
|
// ohne dass der Aufrufer sie zwischenspeichern muss (SRC-02: Löschungen
|
|
// müssen ohne zusätzlichen Zustand nachgezogen werden können).
|
|
func DocumentID(tenantSlug, messageID string) uint64 {
|
|
h := fnv.New64a()
|
|
_, _ = h.Write([]byte(tenantSlug))
|
|
_, _ = h.Write([]byte{0})
|
|
_, _ = h.Write([]byte(messageID))
|
|
return h.Sum64()
|
|
}
|