feat:新增大屏存取发布接口

This commit is contained in:
2026-10-11 08:27:30 -07:00
parent dadd797391
commit afc07ba695
23 changed files with 2672 additions and 36 deletions
+51 -11
View File
@@ -21,7 +21,7 @@ def make_title(prompt: str) -> str:
class ConversationStore(Protocol):
"""内存和 MongoDB 实现同一组方法,业务代码不需要关心具体存储"""
async def create(self, user_id: int) -> str: ...
async def create(self, user_id: int, screen_id: str | None = None) -> str: ...
async def exists(self, conversation_id: str, user_id: int) -> bool:
"""会话已签发、未过期且属于该用户;不属于时与不存在同样返回 False"""
@@ -34,9 +34,21 @@ class ConversationStore(Protocol):
async def save_turn(self, turn: Turn) -> None: ...
async def list_by_user(
self, user_id: int, limit: int, offset: int
self, user_id: int, limit: int, offset: int, screen_id: str | None = None
) -> list[ConversationSummary]:
"""该用户已产生对话的会话,按最近更新时间倒序;没有对话的空会话不返回"""
"""该用户已产生对话的会话,按最近更新时间倒序;没有对话的空会话不返回;给了 screen_id 只返回该大屏的"""
...
async def count_by_user(self, user_id: int, screen_id: str | None = None) -> int:
"""与 list_by_user 同一口径的总数"""
...
async def rename(self, conversation_id: str, user_id: int, title: str) -> bool:
"""会话不存在或不属于该用户返回 False"""
...
async def delete(self, conversation_id: str, user_id: int) -> bool:
"""连同对话轮次一起删除;会话不存在或不属于该用户返回 False"""
...
@@ -51,6 +63,8 @@ class InMemoryConversationStore:
# 会话 ID -> 创建时间;轮次按 thread_id 去重并保持首次写入顺序
self._created: dict[str, datetime] = {}
self._owner: dict[str, int] = {}
self._screen: dict[str, str | None] = {}
self._titles: dict[str, str] = {}
self._turns: dict[str, dict[str, Turn]] = {}
def _purge_expired(self) -> None:
@@ -61,15 +75,18 @@ class InMemoryConversationStore:
for key, created in self._created.items()
if created < deadline and not self._turns.get(key)
]:
del self._created[conversation_id]
self._owner.pop(conversation_id, None)
self._turns.pop(conversation_id, None)
self._forget(conversation_id)
async def create(self, user_id: int) -> str:
def _forget(self, conversation_id: str) -> None:
for table in (self._created, self._owner, self._screen, self._titles, self._turns):
table.pop(conversation_id, None)
async def create(self, user_id: int, screen_id: str | None = None) -> str:
self._purge_expired()
conversation_id = str(uuid4())
self._created[conversation_id] = _now()
self._owner[conversation_id] = user_id
self._screen[conversation_id] = screen_id
return conversation_id
async def exists(self, conversation_id: str, user_id: int) -> bool:
@@ -94,8 +111,8 @@ class InMemoryConversationStore:
turn = turn.model_copy(update={"created_at": existing.created_at})
self._turns[turn.conversation_id][turn.thread_id] = turn
async def list_by_user(
self, user_id: int, limit: int, offset: int
def _summaries(
self, user_id: int, screen_id: str | None
) -> list[ConversationSummary]:
summaries = []
for conversation_id, owner in self._owner.items():
@@ -105,14 +122,37 @@ class InMemoryConversationStore:
)
if owner != user_id or not turns:
continue
if screen_id is not None and self._screen.get(conversation_id) != screen_id:
continue
summaries.append(
ConversationSummary(
conversation_id=conversation_id,
title=make_title(turns[0].prompt),
title=self._titles.get(conversation_id) or make_title(turns[0].prompt),
screen_id=self._screen.get(conversation_id),
updated_at=turns[-1].created_at,
)
)
summaries.sort(
key=lambda item: (item.updated_at, item.conversation_id), reverse=True
)
return summaries[offset : offset + limit]
return summaries
async def list_by_user(
self, user_id: int, limit: int, offset: int, screen_id: str | None = None
) -> list[ConversationSummary]:
return self._summaries(user_id, screen_id)[offset : offset + limit]
async def count_by_user(self, user_id: int, screen_id: str | None = None) -> int:
return len(self._summaries(user_id, screen_id))
async def rename(self, conversation_id: str, user_id: int, title: str) -> bool:
if not await self.exists(conversation_id, user_id):
return False
self._titles[conversation_id] = title
return True
async def delete(self, conversation_id: str, user_id: int) -> bool:
if not await self.exists(conversation_id, user_id):
return False
self._forget(conversation_id)
return True