ContactDraftMerge.kt
41 lignes · 1793 octets
package fr.ebii.card2vcf.contact import fr.ebii.card2vcf.ocr.OcrResult /** * Fusionne les sources, par priorité de fiabilité : * 1. Regex OCR (tél / email / url) — toujours prioritaire * 2. Carte LLM optionnelle (`llm`) si présente et non vide — Card2vcf passe `null` * 3. Heuristiques déterministes (nom / société / poste / adresse) */ object ContactDraftMerge { fun merge(llm: ContactCard?, ocr: OcrResult): ContactCard { val heuristic = ContactHeuristicParser.parse(ocr) val base = llm ?: ContactCard() return ContactCard( fullName = prefer(base.fullName, heuristic.fullName), firstName = prefer(base.firstName, heuristic.firstName), lastName = prefer(base.lastName, heuristic.lastName), company = prefer(base.company, heuristic.company), jobTitle = prefer(base.jobTitle, heuristic.jobTitle), phones = mergeStrings(ocr.phones, base.phones + heuristic.phones), emails = mergeStrings(ocr.emails, base.emails + heuristic.emails), website = prefer(ocr.urls.firstOrNull(), prefer(base.website, heuristic.website)), address = prefer(base.address, heuristic.address), note = prefer(base.note, heuristic.note), champsDouteux = heuristic.champsDouteux, ) } private fun prefer(primary: String?, fallback: String?): String? = primary?.takeIf { it.isNotBlank() } ?: fallback?.takeIf { it.isNotBlank() } private fun mergeStrings(preferred: List<String>, extra: List<String>): List<String> { val seen = linkedSetOf<String>() (preferred + extra).forEach { v -> val n = v.trim() if (n.isNotEmpty()) seen.add(n) } return seen.toList() } }
GitRust