Python/产品需求文档AI生成/application/components/chat.py

152 lines
4.2 KiB
Python

# -*- coding: utf-8 -*-
"""
会话相关组件
"""
import reflex as rx
from reflex.constants.colors import ColorType
from application.models import Type_, Message, Dialog
from application.state import ChatState
def input_message_component(message: str, color: ColorType) -> rx.Component:
"""
输入消息组件
:param message: 消息
:param color: 颜色
:return: Component
"""
return rx.markdown(
message,
color=rx.color(color=color, shade=12),
background_color=rx.color(color=color, shade=4),
display="inline-block",
padding_inline="1em",
border_radius="8px",
)
def output_message_component(message: Message) -> rx.Component:
"""
输出消息组件
:param message: 消息
:return: 气泡组件
"""
color = rx.cond(
message.type_ == Type_.TEXT,
"accent",
rx.cond(
message.type_ == Type_.THINKING,
"iris",
rx.cond(
message.type_ == Type_.CALL,
"orange",
rx.cond(
message.type_ == Type_.TOOL_RETURN,
"teal",
rx.cond(
message.type_ == Type_.ERROR,
"red",
"mauve", # 兜底
),
),
),
),
)
return rx.markdown(
message.content,
color=rx.color(color=color, shade=12),
background_color=rx.color(color=color, shade=4),
display="inline-block",
padding_inline="1em",
padding_block="0.5em",
border_radius="8px",
margin_bottom="4px",
key=message.id,
)
def dialog_item_component(dialog: Dialog) -> rx.Component:
"""
对话项组件
:param dialog: 对话
:return: Component
"""
return rx.box(
rx.box(
input_message_component(message=dialog.input_, color="mauve"),
text_align="right",
margin_bottom="8px",
),
rx.box(
rx.foreach(dialog.output, output_message_component),
text_align="left",
margin_bottom="8px",
),
max_width="50em",
margin_inline="auto",
key=dialog.id,
)
def dialog_list_component() -> rx.Component:
"""
对话列表组件
:return: Component
"""
return rx.auto_scroll(
rx.foreach(ChatState.get_current_chat_dialogs, dialog_item_component),
flex="1",
padding="8px",
overflow_y="auto",
)
def input_component() -> rx.Component:
"""
输入组件
"""
return rx.center(
rx.vstack(
rx.form(
rx.hstack(
rx.input(
name="input",
placeholder="请输入...",
flex="auto",
),
rx.button(
"发送",
type="submit",
loading=ChatState.get_current_chat_status, # 正在流式输出时按钮显示为 loading
disabled=ChatState.get_current_chat_status, # 正在流式输出时按钮禁用
),
max_width="50em",
margin="0 auto",
align_items="center",
),
on_submit=ChatState.process, # 处理输入,返回流式输出
reset_on_submit=True, # 提交后清空输入框
),
rx.text(
"抹茶兔兔工作室",
text_align="center",
font_size=".75em",
color=rx.color("mauve", 10),
),
width="100%",
padding_x="16px",
align="stretch",
),
position="sticky",
bottom="0",
left="0",
padding_y="16px",
backdrop_filter="auto",
backdrop_blur="lg",
border_top=f"1px solid {rx.color('mauve', 3)}",
background_color=rx.color("mauve", 2),
align="stretch",
width="100%",
) # rx.center 等价 rx.box(display="flex", align_items="center", justify_content="center")