190 lines
6.1 KiB
Python
190 lines
6.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
数据库状态
|
|
"""
|
|
from datetime import datetime
|
|
from typing import Dict, List, cast
|
|
|
|
from pydantic import TypeAdapter
|
|
from pydantic_ai import ModelMessage, ModelMessagesTypeAdapter
|
|
import reflex as rx
|
|
from sqlalchemy import ColumnElement, desc
|
|
from sqlmodel import select
|
|
|
|
from application.models import (
|
|
Conversation,
|
|
Conversations,
|
|
Dialog,
|
|
Dialogs,
|
|
RunResults,
|
|
ThoughtNode,
|
|
)
|
|
|
|
|
|
# 思考节点内存模型类型适配器
|
|
ThoughtNodeTypeAdapter = TypeAdapter(dict[int, ThoughtNode])
|
|
|
|
|
|
class DatabaseState(rx.State):
|
|
"""
|
|
数据库状态
|
|
"""
|
|
|
|
async def get_conversations(self, user_id: str) -> Dict[str, Conversation]:
|
|
"""
|
|
获取会话字典
|
|
:param user_id: 用户唯一标识
|
|
:return: 会话字典
|
|
"""
|
|
conversations: Dict[str, Conversation] = {}
|
|
async with rx.asession() as session:
|
|
result = await session.exec(
|
|
select(Conversations, Dialogs)
|
|
.outerjoin(
|
|
Dialogs,
|
|
cast(
|
|
ColumnElement[bool],
|
|
Conversations.id == Dialogs.conversation_id,
|
|
),
|
|
)
|
|
.where(
|
|
Conversations.user_id == user_id,
|
|
Conversations.is_deleted == False,
|
|
)
|
|
.order_by(Conversations.id, Dialogs.id)
|
|
)
|
|
for conversation, dialog in result.all():
|
|
conversation_memory = conversations.setdefault(
|
|
conversation.id,
|
|
Conversation(
|
|
description=conversation.description,
|
|
created_at=conversation.created_at,
|
|
),
|
|
)
|
|
|
|
if not dialog:
|
|
continue
|
|
conversation_memory.dialogs[dialog.id] = Dialog(
|
|
question=dialog.question,
|
|
thought_nodes=ThoughtNodeTypeAdapter.validate_python(
|
|
dialog.thought_nodes
|
|
), # 反序列化为思考节点内存实例字典
|
|
answer=dialog.answer,
|
|
)
|
|
return conversations
|
|
|
|
async def create_conversation(
|
|
self, user_id: str, description: str = "新会话"
|
|
) -> tuple[str, datetime]:
|
|
"""
|
|
新建会话
|
|
:param user_id: 用户唯一标识
|
|
:param description: 会话描述
|
|
:return: 新建会话唯一标识、创建时间
|
|
"""
|
|
async with rx.asession() as session:
|
|
conversation = Conversations(user_id=user_id, description=description)
|
|
session.add(conversation)
|
|
await session.commit()
|
|
await session.refresh(conversation)
|
|
return conversation.id, conversation.created_at
|
|
|
|
async def delete_conversation(self, conversation_id: str) -> None:
|
|
"""
|
|
删除指定会话(逻辑删除)
|
|
:param conversation_id: 指定会话唯一标识
|
|
:return: None
|
|
"""
|
|
async with rx.asession() as session:
|
|
conversation = await session.get(Conversations, conversation_id)
|
|
if not conversation:
|
|
return
|
|
conversation.is_deleted = True
|
|
await session.commit()
|
|
|
|
async def create_dialog(self, conversation_id: str, question: str) -> str:
|
|
"""
|
|
新建对话
|
|
:param conversation_id: 会话唯一标识
|
|
:param question: 提问
|
|
:return: 新建对话唯一标识
|
|
"""
|
|
async with rx.asession() as session:
|
|
dialog = Dialogs(
|
|
conversation_id=conversation_id,
|
|
question=question,
|
|
)
|
|
session.add(dialog)
|
|
await session.commit()
|
|
await session.refresh(dialog)
|
|
return dialog.id
|
|
|
|
async def complete_dialog(
|
|
self,
|
|
dialog_id: str,
|
|
thought_nodes: dict[int, ThoughtNode],
|
|
answer: str,
|
|
) -> None:
|
|
"""
|
|
完成对话
|
|
:param dialog_id: 对话唯一标识
|
|
:param thought_nodes: 思考节点列表
|
|
:param answer: 回答
|
|
:return: None
|
|
"""
|
|
async with rx.asession() as session:
|
|
dialog = await session.get(Dialogs, dialog_id)
|
|
if not dialog:
|
|
return
|
|
dialog.thought_nodes = ThoughtNodeTypeAdapter.dump_python(
|
|
{k: v for k, v in thought_nodes.items()}
|
|
)
|
|
dialog.answer = answer
|
|
await session.commit()
|
|
|
|
async def get_message_history(self, conversation_id: str) -> List[ModelMessage]:
|
|
"""
|
|
获取消息历史
|
|
:param conversation_id: 会话唯一标识
|
|
:return: 消息历史
|
|
"""
|
|
message_history: List[ModelMessage] = []
|
|
async with rx.asession() as session:
|
|
result = await session.exec(
|
|
select(RunResults)
|
|
.where(RunResults.conversation_id == conversation_id)
|
|
.order_by(desc(RunResults.dialog_id))
|
|
)
|
|
for record in result.all():
|
|
message_history.extend(
|
|
ModelMessagesTypeAdapter.validate_json(record.new_messages)
|
|
)
|
|
return message_history
|
|
|
|
async def save_new_messages(
|
|
self,
|
|
conversation_id: str,
|
|
dialog_id: str,
|
|
new_messages: List[ModelMessage],
|
|
) -> None:
|
|
"""
|
|
保存新增消息
|
|
:param conversation_id: 会话唯一标识
|
|
:param dialog_id: 对话唯一标识
|
|
:param new_messages: 新增消息
|
|
:return: None
|
|
"""
|
|
async with rx.asession() as session:
|
|
session.add(
|
|
RunResults(
|
|
conversation_id=conversation_id,
|
|
dialog_id=dialog_id,
|
|
new_messages=ModelMessagesTypeAdapter.dump_json(
|
|
new_messages
|
|
).decode(
|
|
"utf-8"
|
|
), # 序列化为 JSON 字符串
|
|
)
|
|
)
|
|
await session.commit()
|