feat: add translation billing stats and remove Export/Settings pages
- 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>
This commit is contained in:
@@ -39,7 +39,8 @@ def run_translation_task(
|
||||
task_id: str,
|
||||
task_db_id: int,
|
||||
target_lang: str,
|
||||
source_lang: str = "auto"
|
||||
source_lang: str = "auto",
|
||||
user_id: int = None
|
||||
):
|
||||
"""
|
||||
Background task to run document translation.
|
||||
@@ -49,10 +50,12 @@ def run_translation_task(
|
||||
task_db_id: Task database ID (for verification)
|
||||
target_lang: Target language code
|
||||
source_lang: Source language code ('auto' for detection)
|
||||
user_id: User ID for logging translation statistics
|
||||
"""
|
||||
from app.core.database import SessionLocal
|
||||
from app.services.translation_service import get_translation_service
|
||||
from app.schemas.translation import TranslationJobState, TranslationProgress
|
||||
from app.models.translation_log import TranslationLog
|
||||
|
||||
db = SessionLocal()
|
||||
translation_service = get_translation_service()
|
||||
@@ -132,6 +135,44 @@ def run_translation_task(
|
||||
result_file_path=str(output_path) if output_path else None
|
||||
))
|
||||
logger.info(f"Translation completed for task {task_id}")
|
||||
|
||||
# Log translation statistics to database
|
||||
if user_id and output_path:
|
||||
try:
|
||||
with open(output_path, 'r', encoding='utf-8') as f:
|
||||
translation_result = json.load(f)
|
||||
|
||||
stats = translation_result.get('statistics', {})
|
||||
total_tokens = stats.get('total_tokens', 0)
|
||||
|
||||
# Use actual price from Dify API if available, otherwise calculate estimated cost
|
||||
actual_price = stats.get('total_price', 0.0)
|
||||
if actual_price > 0:
|
||||
estimated_cost = actual_price
|
||||
else:
|
||||
# Fallback: Calculate estimated cost based on token pricing
|
||||
estimated_cost = (total_tokens / 1_000_000) * settings.translation_cost_per_million_tokens
|
||||
|
||||
translation_log = TranslationLog(
|
||||
user_id=user_id,
|
||||
task_id=task_id,
|
||||
target_lang=target_lang,
|
||||
source_lang=source_lang,
|
||||
total_tokens=total_tokens,
|
||||
input_tokens=0, # Dify doesn't provide separate input/output tokens
|
||||
output_tokens=0,
|
||||
total_elements=stats.get('total_elements', 0),
|
||||
translated_elements=stats.get('translated_elements', 0),
|
||||
total_characters=stats.get('total_characters', 0),
|
||||
processing_time_seconds=stats.get('processing_time_seconds', 0.0),
|
||||
provider=translation_result.get('provider', 'dify'),
|
||||
estimated_cost=estimated_cost
|
||||
)
|
||||
db.add(translation_log)
|
||||
db.commit()
|
||||
logger.info(f"Logged translation stats for task {task_id}: {total_tokens} tokens, ${estimated_cost:.6f}")
|
||||
except Exception as log_error:
|
||||
logger.error(f"Failed to log translation stats: {log_error}")
|
||||
else:
|
||||
translation_service.set_job_state(task_id, TranslationJobState(
|
||||
task_id=task_id,
|
||||
@@ -255,7 +296,8 @@ async def start_translation(
|
||||
task_id=task_id,
|
||||
task_db_id=task.id,
|
||||
target_lang=target_lang,
|
||||
source_lang=request.source_lang
|
||||
source_lang=request.source_lang,
|
||||
user_id=current_user.id
|
||||
)
|
||||
|
||||
logger.info(f"Started translation job for task {task_id}, target_lang={target_lang}")
|
||||
|
||||
Reference in New Issue
Block a user