05e173b293
Replace the WebView shell with SwiftUI screens, add account-scoped Wiki and TTS APIs with adaptive review and photo scan support, and keep web/iOS pages usable while data loads asynchronously. Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from config import get_settings
|
|
from models import User, WikiLlmUsage
|
|
|
|
|
|
class WikiLlmQuotaExceeded(Exception):
|
|
def __init__(self, *, daily_limit: int, used_today: int):
|
|
self.daily_limit = daily_limit
|
|
self.used_today = used_today
|
|
super().__init__(
|
|
f"今日 AI 整理额度已用完({used_today}/{daily_limit} 次),请充值后继续使用"
|
|
)
|
|
|
|
|
|
class WikiLlmQuotaService:
|
|
def daily_limit(self) -> int:
|
|
return max(1, int(get_settings().ai_wiki_daily_llm_limit))
|
|
|
|
def usage_date(self, now: datetime | None = None) -> str:
|
|
current = now or datetime.now(timezone.utc)
|
|
return current.strftime("%Y-%m-%d")
|
|
|
|
def get_usage_row(self, db: Session, user: User, usage_date: str | None = None) -> WikiLlmUsage:
|
|
day = usage_date or self.usage_date()
|
|
row = (
|
|
db.query(WikiLlmUsage)
|
|
.filter(WikiLlmUsage.user_id == user.id, WikiLlmUsage.usage_date == day)
|
|
.first()
|
|
)
|
|
if not row:
|
|
row = WikiLlmUsage(
|
|
user_id=user.id,
|
|
usage_date=day,
|
|
call_count=0,
|
|
)
|
|
db.add(row)
|
|
db.flush()
|
|
return row
|
|
|
|
def used_today(self, db: Session, user: User) -> int:
|
|
return int(self.get_usage_row(db, user).call_count)
|
|
|
|
def remaining_today(self, db: Session, user: User) -> int:
|
|
return max(0, self.daily_limit() - self.used_today(db, user))
|
|
|
|
def quota_dict(self, db: Session, user: User) -> dict:
|
|
limit = self.daily_limit()
|
|
used = self.used_today(db, user)
|
|
remaining = max(0, limit - used)
|
|
return {
|
|
"daily_limit": limit,
|
|
"used_today": used,
|
|
"remaining_today": remaining,
|
|
"quota_exceeded": remaining <= 0,
|
|
"recharge_message": (
|
|
"今日 AI 整理额度已用完,请充值后继续使用"
|
|
if remaining <= 0
|
|
else None
|
|
),
|
|
}
|
|
|
|
def consume(self, db: Session, user: User, *, count: int = 1) -> dict:
|
|
if count <= 0:
|
|
return self.quota_dict(db, user)
|
|
row = self.get_usage_row(db, user)
|
|
limit = self.daily_limit()
|
|
if row.call_count + count > limit:
|
|
raise WikiLlmQuotaExceeded(daily_limit=limit, used_today=row.call_count)
|
|
row.call_count += count
|
|
db.flush()
|
|
return self.quota_dict(db, user)
|
|
|
|
def require_available(self, db: Session, user: User) -> dict:
|
|
quota = self.quota_dict(db, user)
|
|
if quota["quota_exceeded"]:
|
|
raise WikiLlmQuotaExceeded(
|
|
daily_limit=quota["daily_limit"],
|
|
used_today=quota["used_today"],
|
|
)
|
|
return quota
|
|
|
|
|
|
wiki_llm_quota_service = WikiLlmQuotaService()
|