amazon-transcreation/backend/app/services/report_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

133 lines
4.6 KiB
Python

from datetime import datetime
from typing import Any
from uuid import UUID
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.audit import TokenUsageLog
from app.models.feedback import Feedback, FlagType
from app.models.job import Job, JobStatus, LocaleInstance, LocaleStatus
from app.models.output import OutputRow, ConfidenceTier
class ReportService:
"""Service for aggregation queries powering reports."""
async def get_usage_stats(
self,
db: AsyncSession,
client_id: UUID | None = None,
date_from: datetime | None = None,
date_to: datetime | None = None,
) -> dict[str, Any]:
"""Get overall usage statistics."""
job_query = select(
func.count(Job.id).label("total_jobs"),
func.sum(Job.total_token_usage).label("total_tokens"),
func.sum(Job.total_estimated_cost).label("total_cost"),
)
if client_id:
job_query = job_query.where(Job.client_id == client_id)
if date_from:
job_query = job_query.where(Job.created_at >= date_from)
if date_to:
job_query = job_query.where(Job.created_at <= date_to)
result = await db.execute(job_query)
row = result.one()
# Status breakdown
status_query = select(
Job.status, func.count(Job.id)
).group_by(Job.status)
if client_id:
status_query = status_query.where(Job.client_id == client_id)
status_result = await db.execute(status_query)
status_breakdown = {
status.value: count for status, count in status_result.all()
}
return {
"total_jobs": row.total_jobs or 0,
"total_tokens": row.total_tokens or 0,
"total_cost": float(row.total_cost or 0.0),
"status_breakdown": status_breakdown,
}
async def get_token_cost_data(
self,
db: AsyncSession,
client_id: UUID | None = None,
date_from: datetime | None = None,
date_to: datetime | None = None,
) -> list[dict[str, Any]]:
"""Get token usage and cost data grouped by date."""
query = (
select(
func.date_trunc("day", TokenUsageLog.timestamp).label("date"),
func.sum(TokenUsageLog.input_tokens).label("input_tokens"),
func.sum(TokenUsageLog.output_tokens).label("output_tokens"),
func.sum(TokenUsageLog.total_tokens).label("total_tokens"),
func.sum(TokenUsageLog.estimated_cost_usd).label("total_cost"),
)
.group_by(func.date_trunc("day", TokenUsageLog.timestamp))
.order_by(func.date_trunc("day", TokenUsageLog.timestamp))
)
if client_id:
query = query.join(LocaleInstance).join(Job).where(
Job.client_id == client_id
)
if date_from:
query = query.where(TokenUsageLog.timestamp >= date_from)
if date_to:
query = query.where(TokenUsageLog.timestamp <= date_to)
result = await db.execute(query)
return [
{
"date": str(row.date),
"input_tokens": row.input_tokens or 0,
"output_tokens": row.output_tokens or 0,
"total_tokens": row.total_tokens or 0,
"total_cost": float(row.total_cost or 0.0),
}
for row in result.all()
]
async def get_quality_metrics(
self,
db: AsyncSession,
client_id: UUID | None = None,
) -> dict[str, Any]:
"""Get quality metrics from output confidence tiers and feedback."""
# Confidence tier distribution
tier_query = select(
OutputRow.confidence_tier, func.count(OutputRow.id)
).group_by(OutputRow.confidence_tier)
if client_id:
tier_query = tier_query.join(LocaleInstance).join(Job).where(
Job.client_id == client_id
)
tier_result = await db.execute(tier_query)
tier_breakdown = {
tier.value: count for tier, count in tier_result.all()
}
# Feedback distribution
feedback_query = select(
Feedback.flag_type, func.count(Feedback.id)
).group_by(Feedback.flag_type)
feedback_result = await db.execute(feedback_query)
feedback_breakdown = {
ft.value: count for ft, count in feedback_result.all()
}
return {
"confidence_tiers": tier_breakdown,
"feedback_distribution": feedback_breakdown,
}