- Add TranslationLog model to track translation API usage per task - Integrate Dify API actual price (total_price) into translation stats - Display translation statistics in admin dashboard with per-task costs - Remove unused Export and Settings pages to simplify frontend - Add GET /api/v2/admin/translation-stats endpoint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
88 lines
3.7 KiB
Python
88 lines
3.7 KiB
Python
"""
|
|
Tool_OCR - Translation Log Model
|
|
Tracks translation usage statistics for billing and monitoring
|
|
"""
|
|
|
|
from sqlalchemy import Column, Integer, String, DateTime, Float, ForeignKey
|
|
from sqlalchemy.orm import relationship
|
|
from datetime import datetime
|
|
|
|
from app.core.database import Base
|
|
|
|
|
|
class TranslationLog(Base):
|
|
"""
|
|
Translation log model for tracking API usage and costs.
|
|
|
|
Each record represents a single translation job completion,
|
|
storing token usage and estimated costs for billing purposes.
|
|
"""
|
|
|
|
__tablename__ = "tool_ocr_translation_logs"
|
|
|
|
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
|
user_id = Column(Integer, ForeignKey("tool_ocr_users.id", ondelete="CASCADE"),
|
|
nullable=False, index=True,
|
|
comment="Foreign key to users table")
|
|
task_id = Column(String(255), nullable=False, index=True,
|
|
comment="Task UUID that was translated")
|
|
target_lang = Column(String(10), nullable=False, index=True,
|
|
comment="Target language code (e.g., 'en', 'ja', 'zh-TW')")
|
|
source_lang = Column(String(10), nullable=True,
|
|
comment="Source language code (or 'auto')")
|
|
|
|
# Token usage statistics
|
|
input_tokens = Column(Integer, default=0, nullable=False,
|
|
comment="Number of input tokens used")
|
|
output_tokens = Column(Integer, default=0, nullable=False,
|
|
comment="Number of output tokens generated")
|
|
total_tokens = Column(Integer, default=0, nullable=False,
|
|
comment="Total tokens (input + output)")
|
|
|
|
# Translation statistics
|
|
total_elements = Column(Integer, default=0, nullable=False,
|
|
comment="Total elements in document")
|
|
translated_elements = Column(Integer, default=0, nullable=False,
|
|
comment="Number of elements translated")
|
|
total_characters = Column(Integer, default=0, nullable=False,
|
|
comment="Total characters translated")
|
|
|
|
# Cost tracking (estimated based on token pricing)
|
|
estimated_cost = Column(Float, default=0.0, nullable=False,
|
|
comment="Estimated cost in USD")
|
|
|
|
# Processing info
|
|
processing_time_seconds = Column(Float, default=0.0, nullable=False,
|
|
comment="Translation processing time")
|
|
provider = Column(String(50), default="dify", nullable=False,
|
|
comment="Translation provider (e.g., 'dify')")
|
|
|
|
# Timestamps
|
|
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
|
|
|
# Relationships
|
|
user = relationship("User", back_populates="translation_logs")
|
|
|
|
def __repr__(self):
|
|
return f"<TranslationLog(id={self.id}, task_id='{self.task_id}', target_lang='{self.target_lang}', tokens={self.total_tokens})>"
|
|
|
|
def to_dict(self):
|
|
"""Convert translation log to dictionary"""
|
|
return {
|
|
"id": self.id,
|
|
"user_id": self.user_id,
|
|
"task_id": self.task_id,
|
|
"target_lang": self.target_lang,
|
|
"source_lang": self.source_lang,
|
|
"input_tokens": self.input_tokens,
|
|
"output_tokens": self.output_tokens,
|
|
"total_tokens": self.total_tokens,
|
|
"total_elements": self.total_elements,
|
|
"translated_elements": self.translated_elements,
|
|
"total_characters": self.total_characters,
|
|
"estimated_cost": self.estimated_cost,
|
|
"processing_time_seconds": self.processing_time_seconds,
|
|
"provider": self.provider,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None
|
|
}
|