- 接入数据库驱动的七维风险评分第一阶段逻辑\n- 增加主模型失败后的 DeepSeek 语义、流式和预防建议兜底\n- 将 AI 预防建议改为基于评分、历史异常和标准规则动态生成\n- 增加无历史案例时的标准库兜底校验和通用规则匹配\n- 修复未知供应商识别及测试占位名称过滤\n- 增加后端滚动日志文件配置和 LLM 请求日志\n- 历史会话直接读取已保存结果,避免重新调用模型和重算风险\n- 补充评分、供应商识别和 LLM 协议测试
74 lines
2.5 KiB
Python
74 lines
2.5 KiB
Python
"""Persistence queries for user-owned assistant conversations."""
|
|
|
|
from sqlalchemy import func, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import selectinload
|
|
|
|
from app.models.entities import Conversation, ConversationMessage
|
|
|
|
|
|
class ConversationRepository:
|
|
def __init__(self, session: AsyncSession) -> None:
|
|
self.session = session
|
|
|
|
async def list_for_user(
|
|
self,
|
|
user_id: int,
|
|
*,
|
|
limit: int = 50,
|
|
search: str | None = None,
|
|
) -> list[Conversation]:
|
|
filters = [Conversation.user_id == user_id]
|
|
if search:
|
|
filters.append(Conversation.title.ilike(f"%{search}%"))
|
|
statement = (
|
|
select(Conversation)
|
|
.where(*filters)
|
|
.options(selectinload(Conversation.messages))
|
|
.order_by(Conversation.updated_at.desc(), Conversation.id.desc())
|
|
.limit(limit)
|
|
)
|
|
return list(await self.session.scalars(statement))
|
|
|
|
async def get_page_for_user(
|
|
self,
|
|
conversation_id: int,
|
|
user_id: int,
|
|
*,
|
|
limit: int = 20,
|
|
offset: int = 0,
|
|
) -> tuple[Conversation, list[ConversationMessage], int] | None:
|
|
conversation = await self.session.scalar(
|
|
select(Conversation)
|
|
.where(
|
|
Conversation.id == conversation_id,
|
|
Conversation.user_id == user_id,
|
|
)
|
|
)
|
|
if conversation is None:
|
|
return None
|
|
total = await self.session.scalar(
|
|
select(func.count()).select_from(ConversationMessage).where(
|
|
ConversationMessage.conversation_id == conversation_id,
|
|
)
|
|
)
|
|
messages = list(
|
|
await self.session.scalars(
|
|
select(ConversationMessage)
|
|
.where(ConversationMessage.conversation_id == conversation_id)
|
|
.order_by(ConversationMessage.created_at.desc(), ConversationMessage.id.desc())
|
|
.offset(offset)
|
|
.limit(limit)
|
|
)
|
|
)
|
|
messages.reverse()
|
|
return conversation, messages, int(total or 0)
|
|
|
|
async def get_for_user(self, conversation_id: int, user_id: int) -> Conversation | None:
|
|
statement = (
|
|
select(Conversation)
|
|
.where(Conversation.id == conversation_id, Conversation.user_id == user_id)
|
|
.options(selectinload(Conversation.messages))
|
|
)
|
|
return await self.session.scalar(statement)
|