feat(день2): экран верификации с предложениями + обучение, детектор переплаты
- очередь верификации: предложенный кандидат (топ эмбеддинг), подтвердить/другое/пропустить - POST /match пополняет синонимы (learned_synonym) — обучающаяся нормализация - сравнение: медиана + разброс цен + отклонение клиники (переплата/выгода) - эмбеддер: дедуп названий + ретрай при 429 (квота Gemini) - развёрнуто на med.secondbrain.tools Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+10
-6
@@ -37,18 +37,21 @@ CREATE TABLE IF NOT EXISTS price_item (
|
||||
item_id INTEGER PRIMARY KEY AUTOINCREMENT, doc_id TEXT, partner_id TEXT,
|
||||
service_name_raw TEXT, service_code_source TEXT, service_id TEXT,
|
||||
prices TEXT, price_resident REAL, price_nonresident REAL, unit TEXT,
|
||||
effective_date TEXT, map_method TEXT, map_confidence REAL, status TEXT, is_active INTEGER
|
||||
effective_date TEXT, map_method TEXT, map_confidence REAL, status TEXT, is_active INTEGER,
|
||||
suggested_service_id TEXT, suggested_score REAL
|
||||
);
|
||||
-- Синонимы, выученные при ручной верификации (для дообучения нормализации).
|
||||
CREATE TABLE IF NOT EXISTS learned_synonym (name_norm TEXT PRIMARY KEY, service_id TEXT);
|
||||
CREATE INDEX IF NOT EXISTS price_item_service ON price_item(service_id);
|
||||
CREATE INDEX IF NOT EXISTS price_item_partner ON price_item(partner_id);
|
||||
"""
|
||||
|
||||
|
||||
def _open(db_path: str) -> sqlite3.Connection:
|
||||
# Полная пересборка: удаляем файл, чтобы схема всегда создавалась свежей.
|
||||
Path(db_path).unlink(missing_ok=True)
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.executescript(SCHEMA)
|
||||
for table in ("price_item", "price_document", "partner", "service"):
|
||||
conn.execute(f"DELETE FROM {table}") # пересборка с нуля при каждом прогоне
|
||||
return conn
|
||||
|
||||
|
||||
@@ -102,11 +105,12 @@ def run(data_dir: str, db_path: str, dict_path: str, embedder=None, use_vision:
|
||||
"""INSERT INTO price_item
|
||||
(doc_id, partner_id, service_name_raw, service_code_source, service_id, prices,
|
||||
price_resident, price_nonresident, unit, effective_date, map_method, map_confidence,
|
||||
status, is_active)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,1)""",
|
||||
status, is_active, suggested_service_id, suggested_score)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,1,?,?)""",
|
||||
(doc_id, partner_id, raw, code, match.service_id, json.dumps(prices, ensure_ascii=False),
|
||||
prices.get("resident"), prices.get("nonresident"), unit, eff_iso, match.method,
|
||||
round(match.confidence, 3), status),
|
||||
round(match.confidence, 3), status, match.suggested_service_id,
|
||||
round(match.suggested_score, 3) if match.suggested_score else None),
|
||||
)
|
||||
report["items"] += 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user