refactor(llm): centralize usage persistence
This commit is contained in:
@@ -86,9 +86,10 @@ def build_container(settings: Settings) -> ApplicationContainer:
|
|||||||
MarketInsightService(database, market_repository, review_repository, gateway),
|
MarketInsightService(database, market_repository, review_repository, gateway),
|
||||||
)
|
)
|
||||||
accounts = AccountService(database, account_repository, PasswordHasher(), cipher)
|
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)
|
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(
|
screener = ScreenerService(
|
||||||
database, screener_repository, market_repository, gateway, llm
|
database, screener_repository, market_repository, gateway, llm
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -226,27 +226,6 @@ class AccountRepository:
|
|||||||
def delete_profile(connection: sqlite3.Connection, user_id: int) -> None:
|
def delete_profile(connection: sqlite3.Connection, user_id: int) -> None:
|
||||||
connection.execute("DELETE FROM birth_profiles WHERE user_id = ?", (user_id,))
|
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
|
@staticmethod
|
||||||
def list_memberships(connection: sqlite3.Connection) -> tuple[MembershipAccount, ...]:
|
def list_memberships(connection: sqlite3.Connection) -> tuple[MembershipAccount, ...]:
|
||||||
rows = connection.execute(
|
rows = connection.execute(
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from backend.features.accounts.models import (
|
|||||||
UserRecord,
|
UserRecord,
|
||||||
)
|
)
|
||||||
from backend.features.accounts.repository import AccountRepository
|
from backend.features.accounts.repository import AccountRepository
|
||||||
|
from backend.llm.repository import LLMRepository
|
||||||
from backend.security import PasswordHasher, PasswordPolicyError, SecretCipher
|
from backend.security import PasswordHasher, PasswordPolicyError, SecretCipher
|
||||||
|
|
||||||
USERNAME_PATTERN = re.compile(r"[A-Za-z0-9_\-\u4e00-\u9fff]{3,30}")
|
USERNAME_PATTERN = re.compile(r"[A-Za-z0-9_\-\u4e00-\u9fff]{3,30}")
|
||||||
@@ -281,14 +282,17 @@ class MembershipService:
|
|||||||
"3_years": 36,
|
"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._database = database
|
||||||
self._repository = repository
|
self._repository = repository
|
||||||
|
self._usage = usage
|
||||||
|
|
||||||
def view_for(self, principal: Principal) -> MembershipView:
|
def view_for(self, principal: Principal) -> MembershipView:
|
||||||
today = datetime.now(SHANGHAI).date().isoformat()
|
today = datetime.now(SHANGHAI).date().isoformat()
|
||||||
with self._database.read() as connection:
|
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())
|
return membership_view(principal.user, principal.membership, used_today, now_utc())
|
||||||
|
|
||||||
def can_use_smart_features(self, principal: Principal) -> bool:
|
def can_use_smart_features(self, principal: Principal) -> bool:
|
||||||
@@ -299,7 +303,7 @@ class MembershipService:
|
|||||||
now = now_utc()
|
now = now_utc()
|
||||||
with self._database.read() as connection:
|
with self._database.read() as connection:
|
||||||
accounts = self._repository.list_memberships(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(
|
return tuple(
|
||||||
MembershipAccountView(
|
MembershipAccountView(
|
||||||
account.user,
|
account.user,
|
||||||
@@ -317,7 +321,7 @@ class MembershipService:
|
|||||||
today = datetime.now(SHANGHAI).date().isoformat()
|
today = datetime.now(SHANGHAI).date().isoformat()
|
||||||
with self._database.read() as connection:
|
with self._database.read() as connection:
|
||||||
account = self._repository.get_membership_account(connection, user_id)
|
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:
|
if account is None:
|
||||||
raise BusinessError("account_not_found", "账号不存在。")
|
raise BusinessError("account_not_found", "账号不存在。")
|
||||||
return MembershipAccountView(
|
return MembershipAccountView(
|
||||||
|
|||||||
@@ -12,6 +12,16 @@ class LLMRepository:
|
|||||||
).fetchone()
|
).fetchone()
|
||||||
return int(row["successful_calls"]) if row else 0
|
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
|
@staticmethod
|
||||||
def active_today(connection: sqlite3.Connection, user_id: int, day_prefix: str) -> int:
|
def active_today(connection: sqlite3.Connection, user_id: int, day_prefix: str) -> int:
|
||||||
row = connection.execute(
|
row = connection.execute(
|
||||||
|
|||||||
Reference in New Issue
Block a user