61 lines
2.6 KiB
Python
61 lines
2.6 KiB
Python
"""Offline reprocessing of residual questions against the final canonical identity map."""
|
|
import argparse
|
|
import json
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
from central.app.ai.kb_consolidation import canonical_product_id
|
|
from central.app.ai.workitems import build_work_items
|
|
|
|
|
|
def _erp_code(question):
|
|
import re
|
|
match = re.search(r"PRODUCT\s+(\d+)", question.get("QUESTION", ""))
|
|
return match.group(1) if match else str(question.get("DATABASE_CODE") or "")
|
|
|
|
|
|
def main(questions_path, payload_path, output_path):
|
|
questions_doc = json.loads(Path(questions_path).read_text(encoding="utf-8"))
|
|
payload = json.loads(Path(payload_path).read_text(encoding="utf-8"))
|
|
canonical = {}
|
|
fingerprints = {}
|
|
by_observation = defaultdict(list)
|
|
for product in payload.get("products", []):
|
|
cid = canonical_product_id(product)
|
|
for observation in product.get("observations", []):
|
|
key = f"{observation.get('database')}:{observation.get('erp_code')}"
|
|
canonical[key] = cid
|
|
fingerprints[key] = product.get("fingerprint") or cid
|
|
questions = [dict(question, DATABASE_CODE=_erp_code(question)) for question in questions_doc.get("questions", [])]
|
|
items = build_work_items(questions, fingerprints, canonical)
|
|
by_task = {}
|
|
for item in items:
|
|
bucket = by_task.setdefault(item.task_type, {"items": 0, "cells": 0})
|
|
bucket["items"] += 1
|
|
bucket["cells"] += item.cells_covered
|
|
report = {
|
|
"artifact": "AI_RESIDUAL_PLAN_V3",
|
|
"work_items_before": 750,
|
|
"work_items_after": len(items),
|
|
"llm_items_before": 511,
|
|
# Candidate preparation is evidence-only; without an official validated
|
|
# answer it must not reclassify a selection item as resolved.
|
|
"llm_items_after": 511,
|
|
"llm_reclassification": "UNCHANGED_PENDING_FINAL_PROVIDER_SELECTION",
|
|
"by_task_type": by_task,
|
|
"canonical_observation_keys": len(canonical),
|
|
"ai_write_allowed": False,
|
|
"semantic_decisions": 0,
|
|
}
|
|
Path(output_path).write_text(json.dumps(report, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
|
return report
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--questions", default="docs/LOCAL_FISCAL_CONTEXT_QUESTIONS_V2.json")
|
|
parser.add_argument("--payload", default="docs/runs/ai_kb_seed_payload.json")
|
|
parser.add_argument("--output", default="docs/AI_RESIDUAL_PLAN_V3.json")
|
|
args = parser.parse_args()
|
|
print(json.dumps(main(args.questions, args.payload, args.output), indent=2, ensure_ascii=False))
|