152 lines
4.2 KiB
Python
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")
|