generated from john/python-template
V4.7 Phase 2: Evidence Model Simplification (part 2)
This commit is contained in:
@@ -6,9 +6,12 @@ from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from PIL import Image
|
||||
from sqlmodel import col
|
||||
from sqlmodel import select
|
||||
|
||||
from transcription.config import Settings
|
||||
from transcription.db.models import Document
|
||||
from transcription.db.models import ExecutionAttempt
|
||||
from transcription.db.models import JobSourceStatus
|
||||
from transcription.db.models import JobStatus
|
||||
from transcription.providers.base import ProviderUsage
|
||||
@@ -20,6 +23,15 @@ from transcription.services.store import create_job_for_document
|
||||
from transcription.services.workflows import advance_job
|
||||
|
||||
|
||||
async def _attempts_for_job(session, job) -> list[ExecutionAttempt]:
|
||||
"""Load execution attempts for a job; V4.7 moved evidence off JobSource."""
|
||||
job_source_ids = [job_source.id for job_source in job.job_sources]
|
||||
result = await session.exec(
|
||||
select(ExecutionAttempt).where(col(ExecutionAttempt.job_source_id).in_(job_source_ids))
|
||||
)
|
||||
return list(result.all())
|
||||
|
||||
|
||||
def _jpeg_bytes(color: str = "white") -> bytes:
|
||||
output = io.BytesIO()
|
||||
Image.new("RGB", (2, 2), color=color).save(output, format="JPEG")
|
||||
@@ -116,21 +128,24 @@ class TestPipelineSuccessFlow:
|
||||
assert processed is True
|
||||
assert job is not None
|
||||
assert job.status == JobStatus.TRANSCRIBED
|
||||
assert any(job_source.raw_transcription == "Pipeline transcript" for job_source in job.job_sources)
|
||||
attempts = await _attempts_for_job(async_session, job)
|
||||
assert any(attempt.raw_transcription == "Pipeline transcript" for attempt in attempts)
|
||||
assert job.prompt_name == "transcribe_document.md"
|
||||
assert job.user_prompt is not None
|
||||
assert job.temperature == 0.2
|
||||
assert job.top_p == 0.85
|
||||
assert any(
|
||||
job_source.ai_metadata == {"finish_reason": "stop", "usage": {"total_tokens": 42}}
|
||||
for job_source in job.job_sources
|
||||
attempt.normalized_metadata is not None
|
||||
and attempt.normalized_metadata["finish_reason"] == "stop"
|
||||
and attempt.normalized_metadata["usage"] == {"total_tokens": 42}
|
||||
for attempt in attempts
|
||||
)
|
||||
assert any(
|
||||
job_source.raw_api_response
|
||||
attempt.sdk_response_snapshot
|
||||
== {"id": "resp_123", "choices": [{"message": {"content": "Pipeline transcript"}}]}
|
||||
for job_source in job.job_sources
|
||||
for attempt in attempts
|
||||
)
|
||||
assert all(job_source.error_detail is None for job_source in job.job_sources)
|
||||
assert all(attempt.error_detail is None for attempt in attempts)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_worker_transcribes_all_sources_for_multi_page_job(
|
||||
@@ -191,7 +206,8 @@ class TestPipelineSuccessFlow:
|
||||
assert job.status == JobStatus.TRANSCRIBED
|
||||
assert len(job.job_sources) == 3
|
||||
assert all(job_source.status == JobSourceStatus.TRANSCRIBED for job_source in job.job_sources)
|
||||
assert all(job_source.raw_transcription for job_source in job.job_sources)
|
||||
attempts = await _attempts_for_job(async_session, job)
|
||||
assert all(attempt.raw_transcription for attempt in attempts)
|
||||
assert all(
|
||||
job_source.source is not None and job_source.source.raw_transcription for job_source in job.job_sources
|
||||
)
|
||||
@@ -261,7 +277,8 @@ class TestPipelineSuccessFlow:
|
||||
assert len(job.job_sources) == 2
|
||||
statuses = {job_source.status for job_source in job.job_sources}
|
||||
assert statuses == {JobSourceStatus.TRANSCRIBED, JobSourceStatus.FAILED}
|
||||
assert any(job_source.error_detail is not None for job_source in job.job_sources)
|
||||
attempts = await _attempts_for_job(async_session, job)
|
||||
assert any(attempt.error_detail is not None for attempt in attempts)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_worker_skips_already_transcribed_sources_on_resubmit(
|
||||
@@ -293,9 +310,7 @@ class TestPipelineSuccessFlow:
|
||||
page_two = next(js for js in job.job_sources if js.source is not None and js.source.page_number == 2)
|
||||
|
||||
page_one.status = JobSourceStatus.TRANSCRIBED
|
||||
page_one.raw_transcription = "existing transcript"
|
||||
page_two.status = JobSourceStatus.PENDING
|
||||
page_two.raw_transcription = None
|
||||
await services.sources.update_job_source(job_source=page_one, session=async_session)
|
||||
await services.sources.update_job_source(job_source=page_two, session=async_session)
|
||||
await services.jobs.update_job_state(job_id=job.id, status=JobStatus.QUEUED, session=async_session)
|
||||
@@ -387,11 +402,10 @@ class TestPipelineFailureFlow:
|
||||
assert processed is True
|
||||
assert job is not None
|
||||
assert job.status == JobStatus.FAILED
|
||||
assert all(job_source.raw_transcription is None for job_source in job.job_sources)
|
||||
assert any(job_source.error_detail is not None for job_source in job.job_sources)
|
||||
error_detail = next(
|
||||
job_source.error_detail for job_source in job.job_sources if job_source.error_detail is not None
|
||||
)
|
||||
attempts = await _attempts_for_job(async_session, job)
|
||||
assert all(attempt.raw_transcription is None for attempt in attempts)
|
||||
assert any(attempt.error_detail is not None for attempt in attempts)
|
||||
error_detail = next(attempt.error_detail for attempt in attempts if attempt.error_detail is not None)
|
||||
assert "pipeline provider failure" in error_detail
|
||||
assert "[internal_unexpected_error]" in error_detail
|
||||
assert "error_id=" in error_detail
|
||||
|
||||
Reference in New Issue
Block a user