Files
TradeMate Dev f17a6ccbac chore: post-deployment cleanup and docs update
- Make AI routing rules DB-driven (read from system_configs, removed from config.py)
- Add translation quota tracking to LLM translation (OpenAIProvider)
- Add Alibaba MT ECS RAM role support (STS token, no AccessKey needed)
- Fix admin sidebar link for AI模型配置 page
- Fix Quota.vue API path (quotas → translation-quotas)
- Fix login auto-redirect to dashboard
- Add provider dropdown selects to AI routing config UI
- Clean up stale ai_provider_* system_configs records
- Remove OpencodeGo, Spark providers (code + DB)
- Update deploy config: nginx port 8000, systemd cwd
2026-06-02 15:40:02 +08:00

117 lines
4.4 KiB
Python

from typing import Dict, Any, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models.translation_quota import TranslationQuota
from datetime import datetime
import logging
logger = logging.getLogger(__name__)
class TranslationQuotaService:
def __init__(self, db: AsyncSession):
self.db = db
def _default_desc(self, version: str) -> str:
labels = {"ecommerce": "阿里云翻译电商版", "general": "阿里云翻译通用版", "llm": "AI模型翻译"}
return labels.get(version, f"阿里云翻译{version}")
async def _get_or_create(self, version: str) -> TranslationQuota:
result = await self.db.execute(
select(TranslationQuota).where(TranslationQuota.version == version)
)
quota = result.scalar_one_or_none()
if not quota:
now = datetime.utcnow()
quota = TranslationQuota(
version=version,
monthly_limit=1000000,
used_chars=0,
current_month=now.strftime("%Y-%m"),
enabled=True,
description=self._default_desc(version),
)
self.db.add(quota)
await self.db.flush()
return quota
async def check_quota(self, version: str) -> bool:
quota = await self._get_or_create(version)
now = datetime.utcnow()
current = now.strftime("%Y-%m")
if quota.current_month != current:
quota.current_month = current
quota.used_chars = 0
await self.db.flush()
return quota.enabled and quota.used_chars < quota.monthly_limit
async def consume(self, version: str, chars: int):
quota = await self._get_or_create(version)
if not quota.enabled:
raise ValueError(f"Translation API [{version}] is disabled")
now = datetime.utcnow()
current = now.strftime("%Y-%m")
if quota.current_month != current:
quota.current_month = current
quota.used_chars = 0
quota.used_chars += chars
await self.db.flush()
remaining = max(0, quota.monthly_limit - quota.used_chars)
logger.info(f"Quota [{version}] consumed {chars} chars, remaining {remaining} this month")
return remaining
async def get_all_quotas(self) -> list:
for v in ("ecommerce", "general", "llm"):
await self._get_or_create(v)
result = await self.db.execute(select(TranslationQuota).order_by(TranslationQuota.version))
quotas = result.scalars().all()
rows = []
for q in quotas:
now = datetime.utcnow()
current = now.strftime("%Y-%m")
if q.current_month != current:
q.current_month = current
q.used_chars = 0
await self.db.flush()
rows.append({
"version": q.version,
"monthly_limit": q.monthly_limit,
"used_chars": q.used_chars,
"current_month": q.current_month,
"enabled": q.enabled,
"description": q.description,
})
return rows
async def update_quota(self, version: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
quota = await self._get_or_create(version)
if "monthly_limit" in data:
quota.monthly_limit = int(data["monthly_limit"])
if "enabled" in data:
quota.enabled = bool(data["enabled"])
if "description" in data:
quota.description = str(data["description"])
await self.db.flush()
return {
"version": quota.version,
"monthly_limit": quota.monthly_limit,
"used_chars": quota.used_chars,
"current_month": quota.current_month,
"enabled": quota.enabled,
"description": quota.description,
}
async def reset_usage(self, version: str) -> Optional[Dict[str, Any]]:
quota = await self._get_or_create(version)
quota.used_chars = 0
quota.current_month = datetime.utcnow().strftime("%Y-%m")
await self.db.flush()
return {
"version": quota.version,
"monthly_limit": quota.monthly_limit,
"used_chars": quota.used_chars,
"current_month": quota.current_month,
"enabled": quota.enabled,
}