feat:新增大屏存取发布接口
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user