- backend/text_layer.py: PyMuPDF text-layer extraction, fuzzy evidence
bbox matching, 300-DPI crop rendering, coverage-gap signal
- extractor (classic + agent): TEXT LAYER block appended at call sites;
grounding guard gains text-layer rescue tier (grounding=text_layer stamp)
- verifier: {text_layer} oracle excerpt + evidence-located hi-DPI crops
replacing full-page images (fallback preserved, I2 guard intact)
- coverage gaps: text-bearing pages with zero extraction -> failed-scope
gap findings (agent) / log-only (classic)
- config knobs: TEXT_LAYER_ENABLED/MIN_CHARS/MAX_CHARS, VERIFY_TEXT_MAX_CHARS,
VERIFY_HI_DPI_CROPS, VERIFY_CROP_DPI, VERIFY_CROP_MARGIN_PTS
- tests: 22 new (text_layer unit, grounding/render, runner-level flow)
Spec: docs/superpowers/specs/2026-08-12-text-layer-grounding-design.md
96 lines
3.3 KiB
Bash
96 lines
3.3 KiB
Bash
# Copy to backend/.env and fill in your OpenRouter key.
|
|
|
|
AI_BASE_URL=https://openrouter.ai/api/v1
|
|
AI_API_KEY=sk-or-...
|
|
MODEL=google/gemini-2.5-pro
|
|
|
|
# Optional Agent-mode OpenRouter model overrides (inherit MODEL/TEXT_MODEL when blank)
|
|
AGENT_EXTRACT_MODEL=
|
|
AGENT_INDEX_MODEL=
|
|
AGENT_JURISDICTION_MODEL=
|
|
AGENT_LINKER_MODEL=
|
|
AGENT_CONFLICT_MODEL=
|
|
AGENT_CODE_MODEL=
|
|
AGENT_CONSTRUCT_MODEL=
|
|
AGENT_COMPLETENESS_MODEL=
|
|
AGENT_BRAIN_MODEL=
|
|
AGENT_RFI_MODEL=
|
|
|
|
# Agent-mode hard scope limits / concurrency
|
|
AGENT_LINK_MAX_ASSERTIONS=60
|
|
AGENT_CLUSTER_MAX_ASSERTIONS=24
|
|
AGENT_CONFLICT_MAX_IMAGES=6
|
|
AGENT_CODE_BATCH_SIZE=60
|
|
AGENT_BRAIN_MAX_TOKENS=16384
|
|
AGENT_LINK_CONCURRENCY=4
|
|
AGENT_CONFLICT_CONCURRENCY=4
|
|
AGENT_SPECIALIST_CONCURRENCY=4
|
|
AGENT_RFI_CONCURRENCY=4
|
|
|
|
# Agent-mode human-review gate (pipeline stops after Brain until a human reviews)
|
|
AGENT_REQUIRE_REVIEW=true
|
|
# Max clean clusters added to the review queue as non-blocking spot-checks
|
|
AGENT_REVIEW_AUDIT_SAMPLE=5
|
|
# Allow future cross-job review-feedback aggregation to include source_text/images/comments
|
|
REVIEW_AGGREGATE_INCLUDE_TEXT=false
|
|
|
|
# Pipeline tuning
|
|
PDF_DPI=100
|
|
MAX_PAGES=60
|
|
MAX_DIMENSION=2400
|
|
LLM_TIMEOUT=180
|
|
EXTRACT_MAX_TOKENS=65536
|
|
# Reasoning effort for per-sheet extraction (low keeps Gemini thinking tokens
|
|
# from eating the output budget). Blank = don't send the parameter.
|
|
EXTRACT_REASONING_EFFORT=low
|
|
# Hard thinking-token budget for extraction (OpenRouter reasoning max_tokens /
|
|
# Gemini thinking_budget). Stronger than effort; 0 = fall back to effort only.
|
|
EXTRACT_REASONING_MAX_TOKENS=2048
|
|
REASON_MAX_TOKENS=4096
|
|
EXTRACT_CONCURRENCY=4
|
|
REASON_CONCURRENCY=4
|
|
|
|
# Public URL users reach this server on (used for the link in result emails)
|
|
APP_BASE_URL=https://conchecker.scoutitsystems.com
|
|
# APP_BUILD is set by CI at image build time (sha-<short_sha>) - do not set manually.
|
|
|
|
# LLM observability (job-log verbosity + raw request/response dumps)
|
|
# LLM_VERBOSE: one line per LLM call in job.log (model, sizes, item counts, cost)
|
|
# LLM_RAW_DUMP: full prompt+response per call in outputs/<job_id>/llm_raw/
|
|
# (base64 images excluded). Both default on; set false to quiet down.
|
|
LLM_VERBOSE=true
|
|
LLM_RAW_DUMP=true
|
|
|
|
# Email notifications (optional). Leave SMTP_HOST blank to disable.
|
|
# Examples:
|
|
# Gmail: SMTP_HOST=smtp.gmail.com SMTP_PORT=587 (use an App Password)
|
|
# M365: SMTP_HOST=smtp.office365.com SMTP_PORT=587
|
|
SMTP_HOST=
|
|
SMTP_PORT=587
|
|
SMTP_USER=
|
|
SMTP_PASSWORD=
|
|
SMTP_FROM=
|
|
SMTP_USE_TLS=true
|
|
SMTP_USE_SSL=false
|
|
|
|
# Wave 5b evidence verification (vision fact-check of cited sheet text)
|
|
AGENT_VERIFY_MAX_CHECKS=20
|
|
AGENT_VERIFY_SEVERITIES=critical,high
|
|
AGENT_VERIFY_REASONING_EFFORT=low
|
|
VERIFY_MAX_TOKENS=8192
|
|
|
|
# Text-layer grounding (deterministic PDF text layer via PyMuPDF)
|
|
# TEXT_LAYER_ENABLED: master switch for text-layer extraction/grounding
|
|
# TEXT_LAYER_MIN_CHARS: below this per page the sheet stays vision-only
|
|
# TEXT_LAYER_MAX_CHARS: cap of text layer injected into the extractor prompt
|
|
# VERIFY_TEXT_MAX_CHARS: cap of the text-layer excerpt in verify scopes
|
|
# VERIFY_HI_DPI_CROPS: evidence-located high-DPI crops in the verifier
|
|
# VERIFY_CROP_DPI / VERIFY_CROP_MARGIN_PTS: crop render DPI / padding (PDF points)
|
|
TEXT_LAYER_ENABLED=true
|
|
TEXT_LAYER_MIN_CHARS=20
|
|
TEXT_LAYER_MAX_CHARS=12000
|
|
VERIFY_TEXT_MAX_CHARS=8000
|
|
VERIFY_HI_DPI_CROPS=true
|
|
VERIFY_CROP_DPI=300
|
|
VERIFY_CROP_MARGIN_PTS=36
|