diff --git a/agent/application/application.py b/agent/application/application.py index 66c1f00..7667e6e 100644 --- a/agent/application/application.py +++ b/agent/application/application.py @@ -23,9 +23,11 @@ app = rx.App( "--devui-base-bg": "#ffffff", "--mc-global-bg": "linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%)", "--mc-box-shadow": "rgba(25, 25, 25, .06)", + "--devui-shadow-length-connected-overlay": "0px 0px 12px 0px rgba(0, 0, 0, 0.1)", "--devui-icon-fill-weak": "#babbc0", "--devui-border-radius-feedback": "4px", "--devui-border-radius-card": "8px", + "--devui-border-radius-full": "100px", "--font-family": "HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei", "--devui-font-size-sm": "12px", "--devui-font-size": "14px", @@ -36,6 +38,8 @@ app = rx.App( "--placeholder": "#babbc0", "--devui-aide-text": "#71757f", "--devui-primary": "#5e7ce0", + "--devui-brand": "#5e7ce0", + "--devui-brand-hover": "#7693f5", } # 自定义主题颜色 ) # 此处变量名需使用 app ,具体原因目前尚不清楚 # 注册首页路由 diff --git a/agent/application/components/conversation.py b/agent/application/components/conversation.py index 8808d76..07dc685 100644 --- a/agent/application/components/conversation.py +++ b/agent/application/components/conversation.py @@ -4,7 +4,6 @@ """ import reflex as rx -from typing import Tuple from application.models import Run, Reasoning, Conversation from application.state.conversation import ConversationState from application.state.create_conversation_modal import CreateConversationModalState @@ -31,7 +30,7 @@ def render_conversation_history_item( return rx.popover.root( # 触发事件:点击更多按钮 rx.popover.trigger( - rx.button( + rx.box( rx.icon("ellipsis", size=14, color="var(--devui-text-weak)"), cursor="pointer", # 鼠标光标显示为手指 ) @@ -82,7 +81,7 @@ def render_conversation_history_item( box_shadow="0 2px 12px rgba(0,0,0,0.1)", # 阴影 overflow="visible", # 溢出可见 side="bottom", # 气泡卡片位于底部 - side_offset=-2, # 偏移量 + side_offset=9, # 偏移量 ), open_delay=0, ) @@ -274,9 +273,9 @@ def render_run_component(run_id: str, run: Run) -> rx.Component: ) -def render_conversation_component() -> rx.Component: +def render_conversation_box() -> rx.Component: """ - 渲染对话组件,包括若干次运行 + 渲染对话框 :return: Component """ # 运行字典 @@ -323,18 +322,45 @@ def render_conversation_component() -> rx.Component: ) -def render_create_conversation_component() -> rx.Component: +def render_create_conversation_button() -> rx.Component: """ - 渲染创建对话组件 + 渲染新建对话按钮 + :return: Component """ return rx.hstack( rx.spacer(), # 占位符 rx.dialog.root( - # 触发事件:点击创建对话图标,支持鼠标悬停提示 + # 触发事件:点击图标 rx.dialog.trigger( - rx.box(rx.tooltip(rx.icon("circle-plus"), content="创建对话")) + rx.box( + rx.tooltip( + rx.icon( + "plus", + size=14, + color="var(--devui-text)", + style={ + "_hover": { + "color": "var(--devui-brand)", + } + }, + ), + content="新建对话", + background_color="var(--devui-base-bg)", + box_shadow="0 2px 12px 0 rgba(37, 43, 58, .24)", + side="top", + side_offset=9, + ), + display="flex", + width="24px", + height="24px", + background_color="var(--devui-base-bg)", + box_shadow="0 1px 8px #1919190f", + border_radius="var(--devui-border-radius-full)", + justify_content="center", + align_items="center", + cursor="pointer", + ) ), - # 内容层 rx.dialog.content( rx.form( rx.hstack( @@ -349,6 +375,7 @@ def render_create_conversation_component() -> rx.Component: wrap="wrap", width="100%", ), + # 提交事件:新建对话 on_submit=ConversationState.create_conversation, ), background_color=rx.color("mauve", 1), @@ -356,13 +383,20 @@ def render_create_conversation_component() -> rx.Component: open=CreateConversationModalState.is_open, on_open_change=CreateConversationModalState.toggle, ), + display="flex", width="100%", + max_width="1200px", + height="39px", + padding="0 12px", + justify_content="flex-end", + align_items="center", + gap="4px", ) -def render_input_bar() -> rx.Component: +def render_input_box() -> rx.Component: """ - 渲染输入栏 + 渲染输入框 """ return rx.vstack( # 渲染自定义输入组件 diff --git a/agent/application/components/frame.py b/agent/application/components/frame.py index e07da2f..5b4760b 100644 --- a/agent/application/components/frame.py +++ b/agent/application/components/frame.py @@ -7,87 +7,78 @@ import reflex as rx from application.state.frame import FrameState -# 初始化侧边栏图标导航按钮字典 -sidebar_icon_nav_buttons = { - "conversation": {"src": "/conversation.svg", "text": "对话"}, - "knowledge_base": {"src": "/knowledge_base.svg", "text": "知识库"}, -} - - -def render_brand_logo(width: str = "34px", height: str = "34px") -> rx.Component: - """ - 渲染品牌 Logo - :param width: 宽度,默认为 34px - :param height: 高度,默认为 34px - """ - return rx.image( - src="/logo.png", - width=width, - height=height, - object_fit="contain", # 等比缩放 - ) - - -def render_sidebar_icon_nav_button( - sidebar_icon_nav_button: str, -) -> rx.Component: - """ - 渲染侧边栏图标导航按钮 - :param sidebar_icon_nav_button: 侧边栏图标导航按钮 - """ - # 指定侧边栏图标导航按钮的激活状态 - is_actived = sidebar_icon_nav_button == FrameState.sidebar_icon_nav_button - - return rx.box( - # 渲染图标盒子 - rx.box( - rx.image( - src=sidebar_icon_nav_buttons[sidebar_icon_nav_button]["src"], - width="24px", - height="24px", - object_fit="contain", # 等比缩放 - ), - display="flex", # 弹性布局 - justify_content="center", # 水平居中对齐 - align_items="center", # 垂直居中对齐 - width="36px", # 宽度 - height="36px", # 高度 - border_radius="var(--devui-border-radius-card)", # 圆角 - # 若已激活则渲染图标盒子背景颜色和阴影,否则不渲染 - style={ - "background-color": rx.cond( - is_actived, "var(--devui-base-bg)", "transparent" - ), - "box-shadow": rx.cond(is_actived, "0 4px 12px #0000001a", "none"), - }, - ), - # 渲染标签 - rx.text( - sidebar_icon_nav_buttons[sidebar_icon_nav_button]["text"], - color="var(--devui-text)", - font_size="var(--devui-font-size-sm)", - line_height="20px", - ), - display="flex", # 弹性布局 - flex_direction="column", # 垂直方向布局 - align_items="center", # 垂直居中对齐 - gap="4px", - font_size="var(--devui-font-size-sm)", # 字体大小 - cursor="pointer", # 鼠标指针 - ) - def render_sidebar() -> rx.Component: """ 渲染侧边栏 """ + + # 初始化按钮字典 + BUTTONS = { + "conversation": {"src": "/conversation.svg", "text": "对话"}, + "knowledge_base": {"src": "/knowledge_base.svg", "text": "知识库"}, + } + + def render_button( + button: str, + ) -> rx.Component: + """ + 渲染按钮 + :param button: 按钮名称 + """ + # 指定按钮的激活状态 + is_actived = button == FrameState.sidebar_icon_nav_button + + return rx.box( + # 渲染图标 + rx.box( + rx.image( + src=BUTTONS[button]["src"], + width="24px", + height="24px", + object_fit="contain", # 等比缩放 + ), + display="flex", # 弹性布局 + justify_content="center", # 水平居中对齐 + align_items="center", # 垂直居中对齐 + width="36px", # 宽度 + height="36px", # 高度 + border_radius="var(--devui-border-radius-card)", # 圆角 + # 若已激活则渲染图标盒子背景颜色和阴影,否则不渲染 + style={ + "background-color": rx.cond( + is_actived, "var(--devui-base-bg)", "transparent" + ), + "box-shadow": rx.cond(is_actived, "0 4px 12px #0000001a", "none"), + }, + ), + # 渲染标签 + rx.text( + BUTTONS[button]["text"], + color="var(--devui-text)", + font_size="var(--devui-font-size-sm)", + line_height="20px", + ), + display="flex", # 弹性布局 + flex_direction="column", # 垂直方向布局 + align_items="center", # 垂直居中对齐 + gap="4px", + font_size="var(--devui-font-size-sm)", # 字体大小 + cursor="pointer", # 鼠标指针 + ) + return rx.vstack( # 渲染顶部 rx.vstack( # 渲染品牌 LOGO 和名称 rx.vstack( # 渲染品牌 Logo - render_brand_logo(), + rx.image( + src="/logo.png", + width="34px", + height="34px", + object_fit="contain", # 等比缩放 + ), # 渲染品牌名称 rx.text( "Gluballu", @@ -106,10 +97,10 @@ def render_sidebar() -> rx.Component: rx.divider( width="32px", height="1px", margin="16px 0", background_color="#babbc0" ), - # 渲染侧边栏图标导航按钮:对话 - render_sidebar_icon_nav_button(sidebar_icon_nav_button="conversation"), - # 渲染侧边栏图标导航按钮:知识库 - render_sidebar_icon_nav_button(sidebar_icon_nav_button="knowledge_base"), + # 渲染按钮:对话 + render_button(button="conversation"), + # 渲染按钮:知识库 + render_button(button="knowledge_base"), margin_top="12px", # 上外边距 display="flex", # 弹性布局 flex_direction="column", # 垂直方向布局 diff --git a/agent/application/pages/conversation.py b/agent/application/pages/conversation.py index 00a5838..4741658 100644 --- a/agent/application/pages/conversation.py +++ b/agent/application/pages/conversation.py @@ -5,10 +5,10 @@ import reflex as rx from application.components.conversation import ( - render_conversation_component, + render_conversation_box, render_conversation_history_item, - render_input_bar, - render_create_conversation_component, + render_input_box, + render_create_conversation_button, ) from application.state.conversation import ConversationState from application.state.conversation_history_collapse import ( @@ -18,17 +18,17 @@ from application.state.conversation_history_collapse import ( def render_conversation_page() -> rx.Component: """ - 渲染对话页面:左侧为对话历史折叠面板,右侧为对话历史、运行历史、创建和输入等组件 + 渲染对话页面:左侧为对话历史折叠面板,右侧为对话历史、运行历史、新建和输入等组件 """ # 对话历史折叠面板打开状态 is_open = ConversationHistoryCollapseState.is_open return rx.box( rx.hstack( - # 渲染对话历史 + # 渲染对话历史折叠面板 rx.box( rx.vstack( - # 标题 + # 渲染标题 rx.hstack( rx.text( "对话历史", @@ -42,7 +42,7 @@ def render_conversation_page() -> rx.Component: justify_content="space-between", ), # 渲染列表 - rx.vstack( + rx.auto_scroll( rx.foreach( ConversationState.get_conversation_history, lambda item, _: render_conversation_history_item( @@ -74,12 +74,12 @@ def render_conversation_page() -> rx.Component: # 渲染对话区域 rx.box( rx.vstack( - # 渲染运行历史 - render_conversation_component(), - # 渲染创建对话按钮 - render_create_conversation_component(), - # 渲染输入栏 - render_input_bar(), + # 渲染对话框 + render_conversation_box(), + # 渲染新建对话按钮 + render_create_conversation_button(), + # 渲染输入框 + render_input_box(), display="flex", flex_flow="column", width="100%", diff --git a/agent/application/pages/knowledge_base.py b/agent/application/pages/knowledge_base.py index a5ba748..d1104f3 100644 --- a/agent/application/pages/knowledge_base.py +++ b/agent/application/pages/knowledge_base.py @@ -4,8 +4,9 @@ """ import reflex as rx + def render_knowledge_base_page() -> rx.Component: """ 渲染知识库页面:暂时为空 """ - return rx.fragment() \ No newline at end of file + return rx.fragment() diff --git a/agent/application/state/conversation.py b/agent/application/state/conversation.py index 88e0277..4759663 100644 --- a/agent/application/state/conversation.py +++ b/agent/application/state/conversation.py @@ -60,6 +60,7 @@ agent: Agent = Agent( retries=1, ) + class ConversationState(rx.State): """ 对话状态 @@ -81,7 +82,7 @@ class ConversationState(rx.State): @rx.event async def create_conversation(self, form_data: Dict[str, Any]) -> None: """ - 创建对话 + 新建对话 :param form_data: 表单数据 :return: None """ @@ -90,16 +91,16 @@ class ConversationState(rx.State): if not description: description = "新对话" - # 创建对话 + # 新建对话 self.conversations[str(uuid7())] = Conversation(description=description) # 将末位对话唯一标识设置为当前对话唯一标识 self.conversation_id = next(reversed(self.conversations.keys())) - # 获取创建对话模态窗状态 + # 获取新建对话模态窗状态 create_conversation_modal_state = await self.get_state( CreateConversationModalState ) - # 关闭创建对话模态窗 + # 关闭新建对话模态窗 create_conversation_modal_state.is_open = False @rx.event @@ -376,4 +377,3 @@ class ConversationState(rx.State): # 指定运行 run = self.conversations[self.conversation_id].runs[run_id] run.is_reasoning_panel_open = not run.is_reasoning_panel_open - diff --git a/agent/application/utils/__init__.py b/agent/application/utils/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/agent/application/utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ -