Spaces:
Sleeping
Sleeping
Turn debug artifacts off by default and keep them inside the session
Browse filesMirrors GitHub commit b436978. Debug output includes unmasked document text; it is now opt-in and written to <session>/debug/. Also replaces retired Llama model names in docstrings, defaults and docs.
- .env.example +2 -2
- config/settings.yaml +5 -2
- docs/hugging-face.md +2 -2
- src/agents.py +6 -6
- src/api.py +6 -7
- src/settings.py +2 -2
- tests/test_settings.py +12 -0
.env.example
CHANGED
|
@@ -2,5 +2,5 @@
|
|
| 2 |
GROQ_API_KEY="replace_with_your_groq_api_key"
|
| 3 |
|
| 4 |
# Optional model overrides
|
| 5 |
-
# GROQ_MODEL="
|
| 6 |
-
# GROQ_CLASSIFIER_MODEL="
|
|
|
|
| 2 |
GROQ_API_KEY="replace_with_your_groq_api_key"
|
| 3 |
|
| 4 |
# Optional model overrides
|
| 5 |
+
# GROQ_MODEL="openai/gpt-oss-120b"
|
| 6 |
+
# GROQ_CLASSIFIER_MODEL="openai/gpt-oss-20b"
|
config/settings.yaml
CHANGED
|
@@ -45,8 +45,11 @@ pipeline:
|
|
| 45 |
session_ttl_days: 30
|
| 46 |
|
| 47 |
debug:
|
| 48 |
-
# Master switch
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
| 50 |
# Root folder for debug runs. Each execution creates a timestamped sub-folder.
|
| 51 |
output_dir: "./output/debug"
|
| 52 |
# Save the raw Markdown produced by docling for each PDF.
|
|
|
|
| 45 |
session_ttl_days: 30
|
| 46 |
|
| 47 |
debug:
|
| 48 |
+
# Master switch. Off by default: debug artifacts include the raw (unmasked)
|
| 49 |
+
# document text. Turn on only for local debugging with synthetic documents.
|
| 50 |
+
# When on, the API writes artifacts inside the session folder, so they are
|
| 51 |
+
# removed with the session (DELETE /api/session/{id} or the TTL cleanup).
|
| 52 |
+
enabled: false
|
| 53 |
# Root folder for debug runs. Each execution creates a timestamped sub-folder.
|
| 54 |
output_dir: "./output/debug"
|
| 55 |
# Save the raw Markdown produced by docling for each PDF.
|
docs/hugging-face.md
CHANGED
|
@@ -30,8 +30,8 @@ GROQ_API_KEY=your_groq_key
|
|
| 30 |
Optional secrets or variables:
|
| 31 |
|
| 32 |
```text
|
| 33 |
-
GROQ_MODEL=
|
| 34 |
-
GROQ_CLASSIFIER_MODEL=
|
| 35 |
```
|
| 36 |
|
| 37 |
## Public Demo Safety
|
|
|
|
| 30 |
Optional secrets or variables:
|
| 31 |
|
| 32 |
```text
|
| 33 |
+
GROQ_MODEL=openai/gpt-oss-120b
|
| 34 |
+
GROQ_CLASSIFIER_MODEL=openai/gpt-oss-20b
|
| 35 |
```
|
| 36 |
|
| 37 |
## Public Demo Safety
|
src/agents.py
CHANGED
|
@@ -6,8 +6,8 @@ Architecture
|
|
| 6 |
PDF path
|
| 7 |
→ docling (PDF → Markdown)
|
| 8 |
→ PIIMasker.mask()
|
| 9 |
-
→ InsuranceExtractionAgents.classify_document() [LLM:
|
| 10 |
-
→ extract_schedule() | extract_certificate() [LLM:
|
| 11 |
→ UKMotorGoldenRecord (with source_document provenance)
|
| 12 |
"""
|
| 13 |
from __future__ import annotations
|
|
@@ -173,9 +173,9 @@ class InsuranceExtractionAgents:
|
|
| 173 |
"""
|
| 174 |
Specialist extraction agents for UK Motor Insurance documents.
|
| 175 |
|
| 176 |
-
Uses two LLM models:
|
| 177 |
-
-
|
| 178 |
-
-
|
| 179 |
|
| 180 |
Parameters
|
| 181 |
----------
|
|
@@ -206,7 +206,7 @@ class InsuranceExtractionAgents:
|
|
| 206 |
|
| 207 |
def classify_document(self, markdown_text: str) -> str:
|
| 208 |
"""
|
| 209 |
-
Use
|
| 210 |
|
| 211 |
The LLM is the primary classifier. If it fails or returns an invalid
|
| 212 |
label, the keyword heuristic is used as a fallback. A discrepancy
|
|
|
|
| 6 |
PDF path
|
| 7 |
→ docling (PDF → Markdown)
|
| 8 |
→ PIIMasker.mask()
|
| 9 |
+
→ InsuranceExtractionAgents.classify_document() [LLM: classifier_model, gpt-oss-20b]
|
| 10 |
+
→ extract_schedule() | extract_certificate() [LLM: model, gpt-oss-120b]
|
| 11 |
→ UKMotorGoldenRecord (with source_document provenance)
|
| 12 |
"""
|
| 13 |
from __future__ import annotations
|
|
|
|
| 173 |
"""
|
| 174 |
Specialist extraction agents for UK Motor Insurance documents.
|
| 175 |
|
| 176 |
+
Uses two LLM models, both set in config/settings.yaml:
|
| 177 |
+
- classifier_model (openai/gpt-oss-20b) — fast document type classification
|
| 178 |
+
- model (openai/gpt-oss-120b) — structured extraction (Schedule / Certificate)
|
| 179 |
|
| 180 |
Parameters
|
| 181 |
----------
|
|
|
|
| 206 |
|
| 207 |
def classify_document(self, markdown_text: str) -> str:
|
| 208 |
"""
|
| 209 |
+
Use the classifier model to classify the document type.
|
| 210 |
|
| 211 |
The LLM is the primary classifier. If it fails or returns an invalid
|
| 212 |
label, the keyword heuristic is used as a fallback. A discrepancy
|
src/api.py
CHANGED
|
@@ -52,15 +52,13 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(na
|
|
| 52 |
|
| 53 |
# ---------------------------------------------------------------------------
|
| 54 |
# Session storage directory (project_root/output/sessions/<timestamp>_<uuid>/)
|
| 55 |
-
# Debug artifacts
|
|
|
|
| 56 |
# ---------------------------------------------------------------------------
|
| 57 |
|
| 58 |
_SESSION_DIR = Path(__file__).parent.parent / "output" / "sessions"
|
| 59 |
_SESSION_DIR.mkdir(parents=True, exist_ok=True)
|
| 60 |
|
| 61 |
-
_DEBUG_DIR = Path(__file__).parent.parent / "output" / "debug"
|
| 62 |
-
_DEBUG_DIR.mkdir(parents=True, exist_ok=True)
|
| 63 |
-
|
| 64 |
_STATIC_DIR = Path(__file__).parent.parent / "ui" / "dist"
|
| 65 |
_SAMPLE_PACK_DIR = Path(__file__).parent.parent / "sample_data" / "policytrace_demo_pack"
|
| 66 |
|
|
@@ -279,10 +277,10 @@ async def process_documents(files: list[UploadFile] = File(...)):
|
|
| 279 |
docs_dir = session_dir / "docs"
|
| 280 |
docs_dir.mkdir(parents=True, exist_ok=True)
|
| 281 |
|
| 282 |
-
# ──
|
| 283 |
debug_dir: Path | None = None
|
| 284 |
if settings.debug.enabled:
|
| 285 |
-
debug_dir =
|
| 286 |
debug_dir.mkdir(parents=True, exist_ok=True)
|
| 287 |
logger.info("Debug artifacts → %s", debug_dir)
|
| 288 |
|
|
@@ -423,7 +421,8 @@ async def delete_session(session_id: str):
|
|
| 423 |
Permanently delete a session directory and all its contents.
|
| 424 |
|
| 425 |
This removes the uploaded PDFs, the Golden Record JSON, the review state,
|
| 426 |
-
and
|
|
|
|
| 427 |
"""
|
| 428 |
import shutil
|
| 429 |
session_dir = _get_session_dir(session_id)
|
|
|
|
| 52 |
|
| 53 |
# ---------------------------------------------------------------------------
|
| 54 |
# Session storage directory (project_root/output/sessions/<timestamp>_<uuid>/)
|
| 55 |
+
# Debug artifacts for API runs live inside each session folder (<session>/debug/),
|
| 56 |
+
# so deleting a session also deletes them.
|
| 57 |
# ---------------------------------------------------------------------------
|
| 58 |
|
| 59 |
_SESSION_DIR = Path(__file__).parent.parent / "output" / "sessions"
|
| 60 |
_SESSION_DIR.mkdir(parents=True, exist_ok=True)
|
| 61 |
|
|
|
|
|
|
|
|
|
|
| 62 |
_STATIC_DIR = Path(__file__).parent.parent / "ui" / "dist"
|
| 63 |
_SAMPLE_PACK_DIR = Path(__file__).parent.parent / "sample_data" / "policytrace_demo_pack"
|
| 64 |
|
|
|
|
| 277 |
docs_dir = session_dir / "docs"
|
| 278 |
docs_dir.mkdir(parents=True, exist_ok=True)
|
| 279 |
|
| 280 |
+
# ── Debug directory (inside the session, so it is deleted with it) ────
|
| 281 |
debug_dir: Path | None = None
|
| 282 |
if settings.debug.enabled:
|
| 283 |
+
debug_dir = session_dir / "debug"
|
| 284 |
debug_dir.mkdir(parents=True, exist_ok=True)
|
| 285 |
logger.info("Debug artifacts → %s", debug_dir)
|
| 286 |
|
|
|
|
| 421 |
Permanently delete a session directory and all its contents.
|
| 422 |
|
| 423 |
This removes the uploaded PDFs, the Golden Record JSON, the review state,
|
| 424 |
+
and any debug artifacts (they are written to <session>/debug/ when
|
| 425 |
+
settings.debug.enabled is true).
|
| 426 |
"""
|
| 427 |
import shutil
|
| 428 |
session_dir = _get_session_dir(session_id)
|
src/settings.py
CHANGED
|
@@ -49,8 +49,8 @@ _DEFAULT_ENTITIES = [
|
|
| 49 |
|
| 50 |
|
| 51 |
class LLMSettings(BaseModel):
|
| 52 |
-
model: str = "
|
| 53 |
-
classifier_model: str = "
|
| 54 |
max_retries: int = 2
|
| 55 |
|
| 56 |
|
|
|
|
| 49 |
|
| 50 |
|
| 51 |
class LLMSettings(BaseModel):
|
| 52 |
+
model: str = "openai/gpt-oss-120b"
|
| 53 |
+
classifier_model: str = "openai/gpt-oss-20b"
|
| 54 |
max_retries: int = 2
|
| 55 |
|
| 56 |
|
tests/test_settings.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Guards on the shipped configuration."""
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
import yaml
|
| 5 |
+
|
| 6 |
+
_SETTINGS = Path(__file__).resolve().parent.parent / "config" / "settings.yaml"
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def test_debug_artifacts_are_off_by_default():
|
| 10 |
+
"""Debug artifacts include unmasked document text, so they must be opt-in."""
|
| 11 |
+
cfg = yaml.safe_load(_SETTINGS.read_text(encoding="utf-8"))
|
| 12 |
+
assert cfg["debug"]["enabled"] is False
|