ContactDraftMerge.swift
39 lignes · 1792 octets
import Foundation /// Merges sources, by reliability priority: /// 1. OCR regexes (phone / email / url) — always win /// 2. Optional LLM card (`llm`) if present and non-empty — Card2vcf passes `nil` /// 3. Deterministic heuristics (name / company / job / address) enum ContactDraftMerge { static func merge(llm: ContactCard?, ocr: OcrResult) -> ContactCard { let heuristic = ContactHeuristicParser.parse(ocr) let 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(preferred: ocr.phones, extra: base.phones + heuristic.phones), emails: mergeStrings(preferred: ocr.emails, extra: base.emails + heuristic.emails), website: prefer(ocr.urls.first, prefer(base.website, heuristic.website)), address: prefer(base.address, heuristic.address), note: prefer(base.note, heuristic.note), champsDouteux: heuristic.champsDouteux ) } private static func prefer(_ primary: String?, _ fallback: String?) -> String? { primary?.nilIfBlank ?? fallback?.nilIfBlank } private static func mergeStrings(preferred: [String], extra: [String]) -> [String] { var seen = Set<String>() var out: [String] = [] for v in preferred + extra { let n = v.trimmingCharacters(in: .whitespacesAndNewlines) if !n.isEmpty && seen.insert(n).inserted { out.append(n) } } return out } }
GitRust