amazon-transcreation/backend/app/services/output_service.py
DJP 98fa16bfc3 feat: complete Phase 1-2 scaffold — backend, frontend, pipeline skeleton
Full-stack Amazon AI Transcreation Platform with:
- FastAPI backend (async, PostgreSQL, Redis, Celery) with 11 DB tables
- JWT auth (SSO-ready abstract provider pattern)
- 6-agent pipeline orchestrator with deterministic modules
- Next.js 14 frontend with Amazon branding (Ember fonts, orange/dark theme)
- Job wizard, monitoring HUD, output review, admin screens
- 154 TM/reference files imported, 12 locales configured
- Docker Compose for all services

Agents 2-5 (TM retrieval, ranker, transcreator, compliance) are stubs
pending Phase 3 LLM integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 12:31:43 -04:00

104 lines
3 KiB
Python

from uuid import UUID
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from app.models.job import LocaleInstance
from app.models.output import OutputRow
from app.models.source import SourceLine
from app.schemas.output import (
OutputPreviewResponse,
OutputRowResponse,
SourceLinePreview,
)
class OutputService:
"""Service for assembling output preview data and triggering exports."""
async def get_preview(
self,
db: AsyncSession,
job_id: UUID,
locale_code: str,
) -> OutputPreviewResponse | None:
"""Assemble output preview data for a specific locale instance."""
# Get the locale instance
result = await db.execute(
select(LocaleInstance)
.where(
LocaleInstance.job_id == job_id,
LocaleInstance.locale_code == locale_code,
)
)
instance = result.scalar_one_or_none()
if instance is None:
return None
# Get source lines
source_result = await db.execute(
select(SourceLine)
.where(SourceLine.job_id == job_id)
.order_by(SourceLine.row_order)
)
source_lines = [
SourceLinePreview.model_validate(sl)
for sl in source_result.scalars().all()
]
# Get output rows
output_result = await db.execute(
select(OutputRow)
.where(OutputRow.instance_id == instance.id)
.order_by(OutputRow.row_order)
)
output_rows = [
OutputRowResponse.model_validate(row)
for row in output_result.scalars().all()
]
return OutputPreviewResponse(
locale_code=locale_code,
instance_id=instance.id,
source_lines=source_lines,
output_rows=output_rows,
total_rows=len(output_rows),
)
async def get_output_rows(
self,
db: AsyncSession,
instance_id: UUID,
) -> list[OutputRow]:
"""Get all output rows for a locale instance."""
result = await db.execute(
select(OutputRow)
.where(OutputRow.instance_id == instance_id)
.order_by(OutputRow.row_order)
)
return list(result.scalars().all())
async def trigger_export(
self,
db: AsyncSession,
job_id: UUID,
locale_code: str,
) -> str | None:
"""Trigger export generation for a locale and return the file path."""
result = await db.execute(
select(LocaleInstance)
.where(
LocaleInstance.job_id == job_id,
LocaleInstance.locale_code == locale_code,
)
)
instance = result.scalar_one_or_none()
if instance is None:
return None
if instance.output_file_path:
return instance.output_file_path
# Export would be triggered here; for now return None indicating no export yet
return None