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>
133 lines
4.6 KiB
Python
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,
|
|
}
|