diff --git a/next/backend/bootstrap/container.py b/next/backend/bootstrap/container.py index a86995b..ad137a7 100644 --- a/next/backend/bootstrap/container.py +++ b/next/backend/bootstrap/container.py @@ -86,9 +86,10 @@ def build_container(settings: Settings) -> ApplicationContainer: MarketInsightService(database, market_repository, review_repository, gateway), ) accounts = AccountService(database, account_repository, PasswordHasher(), cipher) - memberships = MembershipService(database, account_repository) + llm_repository = LLMRepository() + memberships = MembershipService(database, account_repository, llm_repository) model_pool = ModelPoolService(database, model_pool_repository, cipher) - llm = LLMGateway(database, LLMRepository(), memberships, model_pool) + llm = LLMGateway(database, llm_repository, memberships, model_pool) screener = ScreenerService( database, screener_repository, market_repository, gateway, llm ) diff --git a/next/backend/features/accounts/repository.py b/next/backend/features/accounts/repository.py index 83197f9..82e20fc 100644 --- a/next/backend/features/accounts/repository.py +++ b/next/backend/features/accounts/repository.py @@ -226,27 +226,6 @@ class AccountRepository: def delete_profile(connection: sqlite3.Connection, user_id: int) -> None: connection.execute("DELETE FROM birth_profiles WHERE user_id = ?", (user_id,)) - @staticmethod - def usage_today(connection: sqlite3.Connection, user_id: int, usage_date: str) -> int: - row = connection.execute( - """ - SELECT successful_calls FROM llm_usage_daily - WHERE user_id = ? AND usage_date = ? - """, - (user_id, usage_date), - ).fetchone() - return int(row["successful_calls"]) if row else 0 - - @staticmethod - def usage_for_users(connection: sqlite3.Connection, usage_date: str) -> dict[int, int]: - return { - int(row["user_id"]): int(row["successful_calls"]) - for row in connection.execute( - "SELECT user_id, successful_calls FROM llm_usage_daily WHERE usage_date = ?", - (usage_date,), - ) - } - @staticmethod def list_memberships(connection: sqlite3.Connection) -> tuple[MembershipAccount, ...]: rows = connection.execute( diff --git a/next/backend/features/accounts/service.py b/next/backend/features/accounts/service.py index 677dd43..0d2b46b 100644 --- a/next/backend/features/accounts/service.py +++ b/next/backend/features/accounts/service.py @@ -24,6 +24,7 @@ from backend.features.accounts.models import ( UserRecord, ) from backend.features.accounts.repository import AccountRepository +from backend.llm.repository import LLMRepository from backend.security import PasswordHasher, PasswordPolicyError, SecretCipher USERNAME_PATTERN = re.compile(r"[A-Za-z0-9_\-\u4e00-\u9fff]{3,30}") @@ -281,14 +282,17 @@ class MembershipService: "3_years": 36, } - def __init__(self, database: Database, repository: AccountRepository) -> None: + def __init__( + self, database: Database, repository: AccountRepository, usage: LLMRepository + ) -> None: self._database = database self._repository = repository + self._usage = usage def view_for(self, principal: Principal) -> MembershipView: today = datetime.now(SHANGHAI).date().isoformat() with self._database.read() as connection: - used_today = self._repository.usage_today(connection, principal.user.id, today) + used_today = self._usage.usage_today(connection, principal.user.id, today) return membership_view(principal.user, principal.membership, used_today, now_utc()) def can_use_smart_features(self, principal: Principal) -> bool: @@ -299,7 +303,7 @@ class MembershipService: now = now_utc() with self._database.read() as connection: accounts = self._repository.list_memberships(connection) - usage = self._repository.usage_for_users(connection, today) + usage = self._usage.usage_for_users(connection, today) return tuple( MembershipAccountView( account.user, @@ -317,7 +321,7 @@ class MembershipService: today = datetime.now(SHANGHAI).date().isoformat() with self._database.read() as connection: account = self._repository.get_membership_account(connection, user_id) - used_today = self._repository.usage_today(connection, user_id, today) + used_today = self._usage.usage_today(connection, user_id, today) if account is None: raise BusinessError("account_not_found", "账号不存在。") return MembershipAccountView( diff --git a/next/backend/llm/repository.py b/next/backend/llm/repository.py index 1243964..be76b16 100644 --- a/next/backend/llm/repository.py +++ b/next/backend/llm/repository.py @@ -12,6 +12,16 @@ class LLMRepository: ).fetchone() return int(row["successful_calls"]) if row else 0 + @staticmethod + def usage_for_users(connection: sqlite3.Connection, usage_date: str) -> dict[int, int]: + return { + int(row["user_id"]): int(row["successful_calls"]) + for row in connection.execute( + "SELECT user_id, successful_calls FROM llm_usage_daily WHERE usage_date = ?", + (usage_date,), + ) + } + @staticmethod def active_today(connection: sqlite3.Connection, user_id: int, day_prefix: str) -> int: row = connection.execute(