generated from john/python-template
Pure remediation; no behavior change. Every item traces to a finding in docs/architecture_code_review_2026-08-17.md. Deletions - Delete app_state.py, which had zero importers and whose get_session_factory raised TypeError at runtime [HIGH-01]. - Delete services/transcription.py and point build_prompt_execution imports at services/sources.py; drop the store.py compatibility aliases [MED-05]. - Delete ServiceBase.queue and its unparameterized asyncio.Queue [MED-07]. - Delete db/operations.get_next_queued_job, a divergent duplicate [CRIT-01]. - Drop the discarded load_docs parameter from list_jobs [LOW-03]. Config - Delete worker_retry_backoff_seconds; no backoff behavior existed anywhere, so wiring it would have been a new feature [MED-02]. - Wire sqlite_check_same_thread through get_engine. The engine hardcoded the setting's own default, so this preserves behavior exactly [MED-02]. - Replace DATABASE_URL in docker-compose.yml with the nested DATABASE__DRIVER / DATABASE__PATH names. Settings uses env_nested_delimiter with extra="ignore", so DATABASE_URL was silently discarded [MED-10]. UI - Move the 23KB inline VIBESCRIBE_LOGO_SVG to ui/static/vibescribe_logo.svg and load it through a cached read_svg sibling of read_css [MED-09]. - Route the portrait upload failure through error_presenter.show_error [LOW-07]. - Cancel the job detail auto-refresh timer instead of only deactivating it, and name its interval constant [LOW-06]. Worker - Make WorkerNotifier runtime_checkable and validate the resolved object in resolve_worker_notifier, which previously returned any non-None attribute unchecked [LOW-04]. Docs and lint - Fix two stale paths in services.instructions.md, one of which pointed at the module deleted here [LOW-02]. - ruff check --fix to zero [LOW-01]. Verified: 264 passed, 4 skipped; ruff check clean. Co-authored-by: Copilot App <[email protected]>
71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
"""Opt-in external tests for real document image transcription."""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from transcription.services.sources import transcribe_document_image
|
|
|
|
HAS_OPENROUTER_KEY = bool(os.getenv("OPENROUTER_API_KEY"))
|
|
|
|
REAL_IMAGES_DIR = Path(__file__).resolve().parents[1] / "fixtures" / "images" / "real"
|
|
ARTIFACTS_DIR = Path(__file__).resolve().parents[1] / "artifacts" / "transcriptions"
|
|
SUPPORTED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".tif", ".tiff", ".pdf"}
|
|
|
|
pytestmark = [
|
|
pytest.mark.external,
|
|
pytest.mark.skipif(
|
|
not HAS_OPENROUTER_KEY,
|
|
reason="Set OPENROUTER_API_KEY to run external real-image tests.",
|
|
),
|
|
]
|
|
|
|
|
|
def _real_image_paths() -> list[Path]:
|
|
if not REAL_IMAGES_DIR.exists():
|
|
return []
|
|
return sorted(
|
|
[
|
|
p
|
|
for p in REAL_IMAGES_DIR.iterdir()
|
|
if p.is_file() and p.suffix.lower() in SUPPORTED_EXTENSIONS
|
|
]
|
|
)
|
|
|
|
|
|
def _artifact_filename(image_path: Path) -> str:
|
|
safe_stem = image_path.stem.replace(" ", "_")
|
|
safe_suffix = image_path.suffix.lower().replace(".", "")
|
|
return f"{safe_stem}.{safe_suffix}.txt"
|
|
|
|
|
|
class TestRealImageExternalTranscription:
|
|
"""Validate transcription against real local fixtures via live provider."""
|
|
|
|
def test_real_image_fixture_set_exists(self):
|
|
"""At least one supported real-image fixture exists for external tests."""
|
|
assert REAL_IMAGES_DIR.exists()
|
|
assert _real_image_paths()
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("image_path", _real_image_paths(), ids=lambda p: p.name)
|
|
async def test_transcribes_real_image_fixture(self, image_path: Path):
|
|
"""Real fixture image produces a non-empty transcription result."""
|
|
result = await transcribe_document_image(image_path)
|
|
assert result.provider == "openrouter"
|
|
assert isinstance(result.model, str) and result.model.strip()
|
|
assert isinstance(result.text, str) and result.text.strip()
|
|
|
|
ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True)
|
|
artifact_path = ARTIFACTS_DIR / _artifact_filename(image_path)
|
|
artifact_text = (
|
|
f"source: {image_path.name}\n"
|
|
f"provider: {result.provider}\n"
|
|
f"model: {result.model}\n"
|
|
"---\n"
|
|
f"{result.text}\n"
|
|
)
|
|
artifact_path.write_text(artifact_text, encoding="utf-8")
|
|
assert artifact_path.exists()
|