260 lines
8.5 KiB
Python
260 lines
8.5 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, update
|
||
|
||
from application.models import (
|
||
Captchas,
|
||
Conversation,
|
||
Conversations,
|
||
Dialog,
|
||
Dialogs,
|
||
RunResults,
|
||
ThoughtNode,
|
||
Users,
|
||
)
|
||
|
||
|
||
# 思考节点领域模型类型适配器
|
||
ThoughtNodeTypeAdapter = TypeAdapter(dict[int, ThoughtNode])
|
||
|
||
|
||
class DatabaseState(rx.State):
|
||
"""
|
||
数据库状态
|
||
"""
|
||
|
||
async def create_captchas_record(self, email: str) -> str:
|
||
"""
|
||
创建验证码记录
|
||
:param email: 邮箱
|
||
:return: 验证码
|
||
"""
|
||
async with rx.asession() as session:
|
||
# 前置处理:将该邮箱有效且未使用的验证码记录的是否有效设置为无效
|
||
await session.exec(
|
||
update(Captchas)
|
||
.where(
|
||
Captchas.email == email, # type: ignore
|
||
Captchas.is_valid == True, # type: ignore
|
||
Captchas.is_unused == True, # type: ignore
|
||
)
|
||
.values(is_valid=False)
|
||
)
|
||
await session.flush()
|
||
# 创建验证码记录
|
||
record = Captchas(
|
||
email=email,
|
||
)
|
||
session.add(record)
|
||
await session.commit()
|
||
await session.refresh(record)
|
||
return record.captcha
|
||
|
||
async def update_captcha(self, email: str, captcha: str) -> bool:
|
||
"""
|
||
更新验证码记录
|
||
:param email: 邮箱
|
||
:param captcha: 验证码
|
||
:return: 是否更新成功,True 表示更新成功,False 表示更新失败
|
||
"""
|
||
async with rx.asession() as session:
|
||
result = await session.exec(
|
||
select(Captchas).where(
|
||
Captchas.email == email,
|
||
Captchas.captcha == captcha,
|
||
Captchas.is_valid == True,
|
||
Captchas.is_unused == True,
|
||
Captchas.expired_at > datetime.now(),
|
||
)
|
||
)
|
||
record = result.first()
|
||
if not record:
|
||
return False
|
||
record.is_unused = False
|
||
await session.commit()
|
||
await session.refresh(record)
|
||
return True
|
||
|
||
async def create_users_record(self, email: str) -> str:
|
||
"""
|
||
创建用户记录
|
||
:param email: 邮箱
|
||
:return: 创建用户记录的唯一标识
|
||
"""
|
||
async with rx.asession() as session:
|
||
result = await session.exec(select(Users).where(Users.email == email))
|
||
record = result.first()
|
||
# 若用户记录存在则返回用户唯一标识,否则创建新用户记录并返回所创建的用户唯一标识
|
||
if record:
|
||
return record.id
|
||
new_user = Users(email=email)
|
||
session.add(new_user)
|
||
await session.commit()
|
||
await session.refresh(new_user)
|
||
return new_user.id
|
||
|
||
async def retrieve_conversations(self, user_id: str) -> Dict[str, Conversation]:
|
||
"""
|
||
获取会话字典
|
||
:param user_id: 用户唯一标识
|
||
:return: 会话字典
|
||
"""
|
||
records: Dict[str, Conversation] = {}
|
||
async with rx.asession() as session:
|
||
result = await session.exec(
|
||
select(Conversations, Dialogs)
|
||
.outerjoin(
|
||
Dialogs,
|
||
Conversations.id == Dialogs.conversation_id, # type: ignore
|
||
)
|
||
.where(
|
||
Conversations.user_id == user_id,
|
||
Conversations.is_deleted == False,
|
||
)
|
||
.order_by(Conversations.id, Dialogs.id)
|
||
)
|
||
for conversation, dialog in result.all():
|
||
record = records.setdefault(
|
||
conversation.id,
|
||
Conversation(
|
||
description=conversation.description,
|
||
created_at=conversation.created_at,
|
||
),
|
||
)
|
||
if not dialog:
|
||
continue
|
||
record.dialogs[dialog.id] = Dialog(
|
||
question=dialog.question,
|
||
thought_nodes=ThoughtNodeTypeAdapter.validate_python(
|
||
dialog.thought_nodes
|
||
),
|
||
answer=dialog.answer,
|
||
)
|
||
return records
|
||
|
||
async def create_conversations_record(
|
||
self, user_id: str, description: str = "新会话"
|
||
) -> tuple[str, datetime]:
|
||
"""
|
||
创建会话记录
|
||
:param user_id: 用户唯一标识
|
||
:param description: 会话描述
|
||
:return: 创建会话记录的唯一标识和创建时间
|
||
"""
|
||
async with rx.asession() as session:
|
||
record = Conversations(user_id=user_id, description=description)
|
||
session.add(record)
|
||
await session.commit()
|
||
await session.refresh(record)
|
||
return record.id, record.created_at
|
||
|
||
async def delete_conversations_record(self, conversation_id: str) -> None:
|
||
"""
|
||
逻辑删除会话记录
|
||
:param conversation_id: 指定会话记录唯一标识
|
||
:return: None
|
||
"""
|
||
async with rx.asession() as session:
|
||
record = await session.get(Conversations, conversation_id)
|
||
if not record:
|
||
return
|
||
record.is_deleted = True
|
||
await session.commit()
|
||
|
||
async def create_dialogs_record(self, conversation_id: str, question: str) -> str:
|
||
"""
|
||
创建对话记录
|
||
:param conversation_id: 会话唯一标识
|
||
:param question: 问题
|
||
:return: 创建对话记录的唯一标识
|
||
"""
|
||
async with rx.asession() as session:
|
||
record = Dialogs(
|
||
conversation_id=conversation_id,
|
||
question=question,
|
||
)
|
||
session.add(record)
|
||
await session.commit()
|
||
await session.refresh(record)
|
||
return record.id
|
||
|
||
async def update_dialog_record(
|
||
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:
|
||
record = await session.get(Dialogs, dialog_id)
|
||
if not record:
|
||
return
|
||
record.thought_nodes = ThoughtNodeTypeAdapter.dump_python(
|
||
{k: v for k, v in thought_nodes.items()}
|
||
)
|
||
record.answer = answer
|
||
await session.commit()
|
||
|
||
async def create_run_result_record(
|
||
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()
|
||
|
||
async def retrieve_message_history(
|
||
self, conversation_id: str
|
||
) -> List[ModelMessage]:
|
||
"""
|
||
获取消息历史
|
||
:param conversation_id: 会话唯一标识
|
||
:return: 消息历史
|
||
"""
|
||
records: 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():
|
||
records.extend(
|
||
ModelMessagesTypeAdapter.validate_json(record.new_messages)
|
||
)
|
||
return records
|