# -*- 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")