migration: preserve mentor and llm streaming slice
This commit is contained in:
+4
-136
@@ -11,10 +11,12 @@ from backend.features.accounts.repository import AccountRepositoryMixin
|
||||
from backend.features.auction.repository import AuctionRepositoryMixin
|
||||
from backend.features.dragon_tiger.repository import DragonTigerRepositoryMixin
|
||||
from backend.features.market.repository import MarketRepositoryMixin
|
||||
from backend.features.mentor.repository import MentorRepositoryMixin
|
||||
from backend.features.pools.repository import PoolRepositoryMixin
|
||||
from backend.features.popularity.repository import PopularityRepositoryMixin
|
||||
from backend.features.screener.repository import ScreenerRepositoryMixin
|
||||
from backend.features.system.repository import SystemSettingsRepositoryMixin
|
||||
from backend.llm.repository import LLMAuditRepositoryMixin
|
||||
|
||||
|
||||
class ReviewDatabase(
|
||||
@@ -22,10 +24,12 @@ class ReviewDatabase(
|
||||
AuctionRepositoryMixin,
|
||||
DragonTigerRepositoryMixin,
|
||||
MarketRepositoryMixin,
|
||||
MentorRepositoryMixin,
|
||||
PoolRepositoryMixin,
|
||||
PopularityRepositoryMixin,
|
||||
ScreenerRepositoryMixin,
|
||||
SystemSettingsRepositoryMixin,
|
||||
LLMAuditRepositoryMixin,
|
||||
):
|
||||
def __init__(self, path: Path) -> None:
|
||||
self.path = path
|
||||
@@ -655,47 +659,6 @@ class ReviewDatabase(
|
||||
)
|
||||
MigrationRunner().apply(connection, MIGRATIONS)
|
||||
|
||||
def record_llm_usage(
|
||||
self,
|
||||
user_id: int,
|
||||
feature: str,
|
||||
source: str,
|
||||
model: str,
|
||||
status: str,
|
||||
latency_ms: int = 0,
|
||||
*,
|
||||
role: str = "",
|
||||
prompt_version: str = "",
|
||||
error_code: str = "",
|
||||
input_tokens: int = 0,
|
||||
output_tokens: int = 0,
|
||||
) -> None:
|
||||
now = datetime.now(timezone.utc).isoformat(timespec="seconds")
|
||||
with self.connect() as connection:
|
||||
connection.execute(
|
||||
"""
|
||||
INSERT INTO llm_usage
|
||||
(user_id, feature, source, model, status, latency_ms, created_at,
|
||||
role, prompt_version, error_code, input_tokens, output_tokens)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
user_id, feature, source, model, status, int(latency_ms), now,
|
||||
role, prompt_version, error_code, int(input_tokens), int(output_tokens),
|
||||
),
|
||||
)
|
||||
|
||||
def count_llm_usage_since(self, user_id: int, source: str, since: str) -> int:
|
||||
with self.connect() as connection:
|
||||
row = connection.execute(
|
||||
"""
|
||||
SELECT COUNT(*) AS total FROM llm_usage
|
||||
WHERE user_id = ? AND source = ? AND created_at >= ?
|
||||
""",
|
||||
(user_id, source, since),
|
||||
).fetchone()
|
||||
return int(row["total"] if row else 0)
|
||||
|
||||
|
||||
def list_watchlist(self, user_id: int) -> list[dict[str, Any]]:
|
||||
with self.connect() as connection:
|
||||
@@ -870,101 +833,6 @@ class ReviewDatabase(
|
||||
|
||||
|
||||
|
||||
def save_mentor_exchange(
|
||||
self,
|
||||
user_id: int,
|
||||
mentor_id: str,
|
||||
trade_date: str,
|
||||
question: str,
|
||||
answer: str,
|
||||
meta: str = "",
|
||||
) -> None:
|
||||
now = datetime.now().astimezone().isoformat(timespec="seconds")
|
||||
with self.connect() as connection:
|
||||
connection.executemany(
|
||||
"""
|
||||
INSERT INTO mentor_messages
|
||||
(user_id, mentor_id, trade_date, role, content, meta, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
[
|
||||
(int(user_id), mentor_id, trade_date, "user", question, "", now),
|
||||
(int(user_id), mentor_id, trade_date, "assistant", answer, meta, now),
|
||||
],
|
||||
)
|
||||
connection.execute(
|
||||
"""
|
||||
DELETE FROM mentor_messages
|
||||
WHERE user_id = ? AND id NOT IN (
|
||||
SELECT id FROM mentor_messages WHERE user_id = ? ORDER BY id DESC LIMIT 500
|
||||
)
|
||||
""",
|
||||
(int(user_id), int(user_id)),
|
||||
)
|
||||
|
||||
def list_mentor_messages(
|
||||
self, user_id: int, mentor_id: str, trade_date: str, limit: int = 100
|
||||
) -> list[dict[str, Any]]:
|
||||
with self.connect() as connection:
|
||||
rows = connection.execute(
|
||||
"""
|
||||
SELECT role, content, meta, created_at FROM mentor_messages
|
||||
WHERE user_id = ? AND mentor_id = ? AND trade_date = ?
|
||||
ORDER BY id DESC LIMIT ?
|
||||
""",
|
||||
(int(user_id), mentor_id, trade_date, max(1, min(500, int(limit)))),
|
||||
).fetchall()
|
||||
return [dict(row) for row in reversed(rows)]
|
||||
|
||||
def delete_mentor_messages(self, user_id: int, mentor_id: str, trade_date: str) -> int:
|
||||
with self.connect() as connection:
|
||||
cursor = connection.execute(
|
||||
"DELETE FROM mentor_messages WHERE user_id = ? AND mentor_id = ? AND trade_date = ?",
|
||||
(int(user_id), mentor_id, trade_date),
|
||||
)
|
||||
return int(cursor.rowcount)
|
||||
|
||||
def list_mentor_preferences(self, user_id: int) -> list[dict[str, Any]]:
|
||||
with self.connect() as connection:
|
||||
rows = connection.execute(
|
||||
"""
|
||||
SELECT mentor_id, pinned, sort_order
|
||||
FROM mentor_preferences
|
||||
WHERE user_id = ?
|
||||
ORDER BY sort_order, mentor_id
|
||||
""",
|
||||
(int(user_id),),
|
||||
).fetchall()
|
||||
return [
|
||||
{
|
||||
"mentor_id": str(row["mentor_id"]),
|
||||
"pinned": bool(row["pinned"]),
|
||||
"sort_order": int(row["sort_order"]),
|
||||
}
|
||||
for row in rows
|
||||
]
|
||||
|
||||
def save_mentor_preferences(
|
||||
self, user_id: int, ordered_ids: list[str], pinned_ids: set[str]
|
||||
) -> None:
|
||||
now = datetime.now().astimezone().isoformat(timespec="seconds")
|
||||
values = [
|
||||
(int(user_id), mentor_id, int(mentor_id in pinned_ids), index, now)
|
||||
for index, mentor_id in enumerate(ordered_ids)
|
||||
]
|
||||
with self.connect() as connection:
|
||||
connection.execute(
|
||||
"DELETE FROM mentor_preferences WHERE user_id = ?",
|
||||
(int(user_id),),
|
||||
)
|
||||
connection.executemany(
|
||||
"""
|
||||
INSERT INTO mentor_preferences
|
||||
(user_id, mentor_id, pinned, sort_order, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
values,
|
||||
)
|
||||
|
||||
def list_wencai_saved_queries(
|
||||
self, user_id: int, limit: int = 30
|
||||
|
||||
Reference in New Issue
Block a user