Spaces:
Sleeping
fix(upload-extract): LLM output now merges INTO heuristic record (not replace)
Browse filesLive evidence on commit 52b0b5d showed Gemini extraction completing
in ~14s but with data_completeness_pct=17.4% β LOWER than the pure
heuristic baseline (47.8%). Cause: the marketplace catalogue prefers
the rag/extracted/<pid>.json (LLM payload) over the persisted
record.json (heuristic baseline), so a sparse LLM extraction was
overwriting the richer heuristic fields.
Fix: after Gemini writes rag/extracted/<pid>.json, also merge the
LLM scalar values INTO UPLOADED_DOCS_DIR/<pid>/record.json. Heuristic
stays as the floor; LLM fields override where non-empty. This is the
same "extracted + curated overlay" pattern the catalogued 148 use
via 40-data/policy_facts/. Schema-shape preserved: heuristic cells
({value, source_pdf_path, source_quote, _confidence}) get their
value lifted; bare-scalar heuristic fields get replaced wholesale.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- backend/uploaded_docs.py +47 -0
|
@@ -933,6 +933,53 @@ async def extract_one_for_upload(
|
|
| 933 |
out_json = _settings.EXTRACTED_DIR / f"{policy_id}.json"
|
| 934 |
out_json.write_text(policy.model_dump_json(indent=2))
|
| 935 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 936 |
# Persist into DuckDB so admin / re-render paths see the new card.
|
| 937 |
try:
|
| 938 |
upsert_policy(
|
|
|
|
| 933 |
out_json = _settings.EXTRACTED_DIR / f"{policy_id}.json"
|
| 934 |
out_json.write_text(policy.model_dump_json(indent=2))
|
| 935 |
|
| 936 |
+
# ALSO merge the LLM output INTO the persisted record.json so the
|
| 937 |
+
# marketplace catalogue's _load_curated_facts() pass sees the
|
| 938 |
+
# combined heuristic-baseline + LLM-extracted fields (rather than
|
| 939 |
+
# just the LLM payload, which may be sparser than the heuristic
|
| 940 |
+
# for non-standard PDFs). Heuristic stays as the fallback; LLM
|
| 941 |
+
# values override where present + non-empty. This is the same
|
| 942 |
+
# "curated overlay" model the catalogued 148 use via
|
| 943 |
+
# 40-data/policy_facts/.
|
| 944 |
+
try:
|
| 945 |
+
doc_dir = _doc_dir(policy_id)
|
| 946 |
+
rec_path = doc_dir / "record.json"
|
| 947 |
+
if rec_path.exists():
|
| 948 |
+
existing = json.loads(rec_path.read_text())
|
| 949 |
+
llm_dump = policy.model_dump()
|
| 950 |
+
# Carry over LLM scalar values + verbatim source_quotes
|
| 951 |
+
# into the heuristic record. Skip null/empty/empty-list
|
| 952 |
+
# so heuristic stays intact where the LLM was silent.
|
| 953 |
+
for k, v in llm_dump.items():
|
| 954 |
+
if k in ("policy_id", "policy_name", "insurer_slug", "insurer_name"):
|
| 955 |
+
continue
|
| 956 |
+
if v in (None, "", [], {}):
|
| 957 |
+
continue
|
| 958 |
+
# Already in cell-shape ({value, source_quote, ...}) on
|
| 959 |
+
# the heuristic side; lift the LLM scalar into the
|
| 960 |
+
# value field, preserving the heuristic's source_quote
|
| 961 |
+
# / source_pdf_path if the LLM didn't supply one.
|
| 962 |
+
if isinstance(existing.get(k), dict) and "value" in existing[k]:
|
| 963 |
+
existing[k] = {**existing[k], "value": v}
|
| 964 |
+
else:
|
| 965 |
+
existing[k] = v
|
| 966 |
+
# Also carry over the LLM's confidence + insurer_name if
|
| 967 |
+
# detected, both for downstream provenance.
|
| 968 |
+
if getattr(policy, "extraction_confidence_pct", None) is not None:
|
| 969 |
+
existing["_llm_extraction_confidence_pct"] = policy.extraction_confidence_pct
|
| 970 |
+
tmp = rec_path.with_suffix(".json.tmp")
|
| 971 |
+
tmp.write_text(json.dumps(existing, indent=2, ensure_ascii=False, default=str))
|
| 972 |
+
tmp.replace(rec_path)
|
| 973 |
+
_log.info(
|
| 974 |
+
"[upload-extract] merged LLM extraction into record.json for %s",
|
| 975 |
+
policy_id,
|
| 976 |
+
)
|
| 977 |
+
except Exception as _merge_err: # noqa: BLE001
|
| 978 |
+
_log.warning(
|
| 979 |
+
"[upload-extract] record.json merge failed for %s: %s",
|
| 980 |
+
policy_id, _merge_err,
|
| 981 |
+
)
|
| 982 |
+
|
| 983 |
# Persist into DuckDB so admin / re-render paths see the new card.
|
| 984 |
try:
|
| 985 |
upsert_policy(
|