Add per-job run logs and separate vision/text model selection.
Capture pipeline stdout into job.log + API/UI so failed runs can be reviewed, and let users pick OpenRouter vision vs text models independently. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -42,7 +42,9 @@ from backend.pipeline.risk import score_and_prioritize
|
||||
from backend.pipeline.rfi import generate_rfis
|
||||
from backend.pipeline.report import build_report, to_markdown
|
||||
from backend.pipeline._stage import validate_issue
|
||||
from backend.llm import reset_cost, get_cost, set_stage, set_text_backend
|
||||
from backend.llm import (
|
||||
reset_cost, get_cost, set_stage, set_text_backend, set_model_overrides,
|
||||
)
|
||||
|
||||
|
||||
def run_pipeline(
|
||||
@@ -52,6 +54,8 @@ def run_pipeline(
|
||||
project_input: Optional[Dict] = None,
|
||||
source_name: Optional[str] = None,
|
||||
text_local: bool = False,
|
||||
vision_model: Optional[str] = None,
|
||||
text_model: Optional[str] = None,
|
||||
) -> Dict:
|
||||
"""
|
||||
Run the full QAQC pipeline on one PDF and return the report dict.
|
||||
@@ -59,6 +63,9 @@ def run_pipeline(
|
||||
project_input: optional intake fields (project_name, address, occupancy,
|
||||
work_type). Cover-sheet-derived values fill any gaps; intake fields win.
|
||||
|
||||
vision_model / text_model: optional per-run OpenRouter (or local text)
|
||||
model overrides from the UI. Blank/None keeps config defaults.
|
||||
|
||||
If out_dir is given, writes conflicts.json, report.md, and the intermediate
|
||||
artifacts (assertions.json, clusters.json, and one json per QAQC stage).
|
||||
"""
|
||||
@@ -70,7 +77,29 @@ def run_pipeline(
|
||||
|
||||
reset_cost()
|
||||
set_text_backend(text_local)
|
||||
set_model_overrides(vision_model, text_model)
|
||||
if vision_model or text_model:
|
||||
print(f"[Runner] model overrides: vision={vision_model or '(default)'} "
|
||||
f"text={text_model or '(default)'}")
|
||||
|
||||
try:
|
||||
return _run_stages(
|
||||
pdf_path, out_dir, stage, project_input, source_name, text_local,
|
||||
)
|
||||
finally:
|
||||
# Don't leak per-run picks into a later overlapping/CLI call.
|
||||
set_model_overrides(None, None)
|
||||
set_text_backend(False)
|
||||
|
||||
|
||||
def _run_stages(
|
||||
pdf_path: str,
|
||||
out_dir: Optional[str],
|
||||
stage: Callable[[str], None],
|
||||
project_input: Optional[Dict],
|
||||
source_name: Optional[str],
|
||||
text_local: bool,
|
||||
) -> Dict:
|
||||
stage("PDF -> images")
|
||||
pages = convert_pdf_to_images(pdf_path)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user