diff --git a/agent/application/application.py b/agent/application/application.py index 7191d2c..66c1f00 100644 --- a/agent/application/application.py +++ b/agent/application/application.py @@ -22,13 +22,20 @@ 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-icon-fill-weak": "#babbc0", "--devui-border-radius-feedback": "4px", "--devui-border-radius-card": "8px", - "--devui-font-size-sm": "11px", - "--devui-font-size": "12px", + "--font-family": "HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei", + "--devui-font-size-sm": "12px", + "--devui-font-size": "14px", "--devui-font-size-lg": "14px", "--devui-text": "#252b3a", "--devui-text-weak": "#575d6c", + "--devui-light-text": "#ffffff", + "--placeholder": "#babbc0", + "--devui-aide-text": "#71757f", + "--devui-primary": "#5e7ce0", } # 自定义主题颜色 ) # 此处变量名需使用 app ,具体原因目前尚不清楚 # 注册首页路由 diff --git a/agent/application/assets/conversation.svg b/agent/application/assets/conversation.svg deleted file mode 100644 index 1277a20..0000000 --- a/agent/application/assets/conversation.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/agent/application/assets/knowledge_base.svg b/agent/application/assets/knowledge_base.svg deleted file mode 100644 index 1277a20..0000000 --- a/agent/application/assets/knowledge_base.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/agent/application/assets/logo.png b/agent/application/assets/logo.png deleted file mode 100644 index c9b75a7..0000000 Binary files a/agent/application/assets/logo.png and /dev/null differ diff --git a/agent/application/components/conversation.py b/agent/application/components/conversation.py index 5f7396b..8808d76 100644 --- a/agent/application/components/conversation.py +++ b/agent/application/components/conversation.py @@ -38,49 +38,53 @@ def render_conversation_history_item( ), # 渲染气泡卡片 rx.popover.content( - rx.box( - width="14px", - height="14px", - position="absolute", - top="-7px", - left="50%", - transform="translateX(-50%) rotate(45deg)", - background_color="var(--devui-base-bg, #ffffff)", - box_shadow="-2px -2px 4px rgba(0,0,0,0.05)", - ), - rx.popover.close( + rx.vstack( rx.box( - "删除", - width="100%", # 宽度 - height="24px", # 高度 - padding="4px", # 内边距 - line_height="16px", # 行高 - font_size="12px", # 字体大小 - color="#252b3a", - display="flex", # 弹性布局 - flex_wrap="wrap", # 换行 - align_items="center", # 子元素垂直居中 - background_color="var(--devui-base-bg)", # 背景颜色 - white_space="nowrap", # 不换行 - border_radius="var(--devui-border-radius-feedback)", # 圆角 - # 点击事件:删除对话 - on_click=lambda: ConversationState.delete_conversation( - conversation_id - ), + position="absolute", # 绝对定位 + width="8px", # 宽度 + height="8px", # 高度 + top="-12px", # 向上移动 + left="50%", # 向左移动 + transform="translateX(-50%) rotate(45deg)", # 旋转45度 + background_color="#ffffff", # 背景颜色 + box_shadow="-2px -2px 4px rgba(0,0,0,0.05)", # 阴影 ), + rx.popover.close( + rx.box( + "删除", + width="100%", # 宽度 + height="24px", # 高度 + padding="4px", # 内边距 + border_radius="4px", # 圆角 + line_height="16px", # 行高 + font_family="HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei", # 字体 + font_size="12px", # 字体大小 + color="#252b3a", # 字体颜色 + style={ + "_hover": { + "background_color": "#f2f2f3", # 鼠标悬停显示背景颜色 + } + }, + # 点击事件:删除对话 + on_click=lambda: ConversationState.delete_conversation( + conversation_id + ), + ) + ), + position="relative", # 相对定位 + width="100%", # 宽度 ), + position="relative", # 相对定位 + align="center", # 水平居中对齐 padding="8px", # 内边距 - arrow_size=10, # 三角大小 - side="bottom", # 气泡在按钮下方,三角朝上 - side_offset=8, # 气泡和按钮之间间距 - align="center", # 水平居中对齐触发按钮中线 - style={ - "position": "relative", # 关键:给三角提供定位基准 - "background_color": "var(--devui-base-bg, #ffffff) !important", - "border_radius": "var(--devui-border-radius-feedback, 8px) !important", - "box_shadow": "0 2px 12px rgba(0,0,0,0.1)", - }, + border_radius="4px", # 圆角 + background_color="#ffffff", # 背景颜色 + box_shadow="0 2px 12px rgba(0,0,0,0.1)", # 阴影 + overflow="visible", # 溢出可见 + side="bottom", # 气泡卡片位于底部 + side_offset=-2, # 偏移量 ), + open_delay=0, ) # 指定对话的激活状态 @@ -356,64 +360,100 @@ def render_create_conversation_component() -> rx.Component: ) -def render_input_component() -> rx.Component: +def render_input_bar() -> rx.Component: """ - 渲染输入组件 + 渲染输入栏 """ return rx.vstack( # 渲染自定义输入组件 rx.form( rx.box( rx.vstack( - # 输入区域 - rx.input( - name="user_prompt", - placeholder="发消息...", - flex="auto", - border="none", # 外框边线 - outline="none", # 高亮轮廓线 - padding_bottom="8px", + rx.hstack( + rx.text_area( + name="user_prompt", + placeholder="请输入您的问题,并按Enter发送,按Shift+Enter换行", + vertical_align="middle", + width="100%", + height="64px", + padding="4px 0", + background_color="var(--devui-base-bg)", + font_size="var(--devui-font-size)", + color="var(--devui-text)", + style={ + "border": "none !important", + "outline": "none !important", + "boxShadow": "none !important", + }, + ), + width="100%", + padding="0 16px", ), - # 操作区域,暂仅包含发送按钮 rx.hstack( rx.spacer(), # 占位符 - # 发送按钮 rx.button( - rx.icon("arrow-up", size=18), - color_scheme="blue", - radius="full", - width="36px", - height="36px", - padding="0", + rx.icon( + "send", + margin_right="4px", + width="12px", + height="12px", + ), + rx.text("发送"), + position="relative", + display="inline-flex", + padding="0 12px", + background_color="var(--devui-primary)", + border="none", + border_radius="20px", + align_items="center", + justify_content="center", + white_space="nowrap", + inline_height="1.5", + font_size="var(--devui-font-size)", + color="var(--devui-light-text)", + overflow="hidden", + cursor="pointer", type="submit", loading=ConversationState.get_running_status, disabled=ConversationState.get_running_status, ), width="100%", + justify_content="flex-end", + align_items="center", + height="32px", + padding="0 16px", ), - spacing="8", - padding_x="12px", - padding_y="12px", ), - border=f"1px solid {rx.color('mauve', 4)}", - radius="large", - background_color="white", + style={ + "* textarea::placeholder": { + "fontFamily": "var(--font-family)", + "fontSize": "var(--devui-font-size)", + "color": "var(--placeholder)", + "opacity": 1, + }, + }, ), - max_width="50em", # 最大宽度 - margin="0 auto", # 水平居中 - align_items="center", # 子元素垂直居中 - spacing="0", # 子元素间距 + display="flex", + flex_direction="column", + width="100%", + padding="12px 0", + background_color="var(--devui-base-bg)", + border="none", + border_radius="16px", + box_shadow="0 1px 8px 0 var(--mc-box-shadow)", on_submit=ConversationState.run, reset_on_submit=True, ), # 渲染底部文案 rx.text( "内容由大模型生成,无法确保准确性和完整性,仅供参考", + margin_top="8px", text_align="center", - font_size=".75em", - color=rx.color("mauve", 10), + font_size="12px", + color="var(--devui-aide-text)", ), width="100%", - padding_x="16px", - align="stretch", + max_width="1200px", + padding="0 12px 12px", + align_items="center", ) diff --git a/agent/application/components/frame.py b/agent/application/components/frame.py index 8f0b4ae..e07da2f 100644 --- a/agent/application/components/frame.py +++ b/agent/application/components/frame.py @@ -90,11 +90,11 @@ def render_sidebar() -> rx.Component: render_brand_logo(), # 渲染品牌名称 rx.text( - "MateAI", + "Gluballu", line_height="20px", # 行高 font_size="11px", font_weight="700", - color="var(--devui-base-text-dark)", + color="var(--devui-text)", ), display="flex", # 弹性布局 flex_direction="column", # 垂直方向布局 diff --git a/agent/application/pages/conversation.py b/agent/application/pages/conversation.py index d5416d1..00a5838 100644 --- a/agent/application/pages/conversation.py +++ b/agent/application/pages/conversation.py @@ -7,7 +7,7 @@ import reflex as rx from application.components.conversation import ( render_conversation_component, render_conversation_history_item, - render_input_component, + render_input_bar, render_create_conversation_component, ) from application.state.conversation import ConversationState @@ -23,29 +23,25 @@ def render_conversation_page() -> rx.Component: # 对话历史折叠面板打开状态 is_open = ConversationHistoryCollapseState.is_open - return rx.hstack( - # 渲染左侧 + return rx.box( rx.hstack( - # 若对话历史折叠面板打开则渲染,否则不渲染 - rx.cond( - is_open, - # 渲染标题、搜索栏和对话历史列表 + # 渲染对话历史 + rx.box( rx.vstack( # 标题 rx.hstack( rx.text( "对话历史", - font_size="var(--devui-font-size-lg)", # 字体大小 - font_weight="700", # 字体粗细 - margin_bottom="8px", # 底部外边距 - white_space="nowrap", # 不换行 + margin_bottom="8px", + font_size="var(--devui-font-size-lg)", + font_weight="700", + white_space="nowrap", ), - display="flex", # 弹性布局 - align_items="center", # 子元素垂直居中 - justify_content="space-between", # 子元素两端对齐 + display="flex", + align_items="center", + justify_content="space-between", ), - # 渲染搜索栏(暂未实现) - # 渲染对话历史列表 + # 渲染列表 rx.vstack( rx.foreach( ConversationState.get_conversation_history, @@ -53,74 +49,93 @@ def render_conversation_page() -> rx.Component: item[0], item[1] ), ), - flex="1", # 占满父元素高度 - margin_top="8px", # 顶部外边距 - width="100%", # 宽度 - overflow="auto", # 允许溢出时显示垂直滚动条 - align_items="stretch", # 子元素水平拉伸 + flex="1", + margin_top="8px", + width="100%", + align_items="stretch", + overflow="hidden", # 禁用滚动条 ), + display="flex", + flex_direction="column", + padding="12px", + height="100%", + background_color="#f9f9f9cc", backdrop_filter="blur(50px)", # 背景模糊 - background_color="#f9f9f9cc", # 背景颜色 - display="flex", # 弹性布局 - flex_direction="column", # 垂直方向布局 - gap="12px", # 子元素间距 - min_width="240px", # 最小宽度 - max_width="380px", # 最大宽度 - width="25%", # 宽度 - height="100%", # 高度 - padding="12px", # 内边距 + gap="12px", color="var(--devui-text)", - transition="all 0.3s ease-in-out", # 过渡动画 ), - rx.fragment(), + width=rx.cond(is_open, "25%", "0px"), + min_width=rx.cond(is_open, "240px", "0px"), + max_width=rx.cond(is_open, "380px", "0px"), + height="100%", + overflow="hidden", + transition="all 0.3s ease-in-out", ), - rx.button( - rx.cond( - is_open, - rx.icon("chevron-left", size=16), - rx.icon("chevron-right", size=16), + # 渲染对话区域 + rx.box( + rx.vstack( + # 渲染运行历史 + render_conversation_component(), + # 渲染创建对话按钮 + render_create_conversation_component(), + # 渲染输入栏 + render_input_bar(), + display="flex", + flex_flow="column", + width="100%", + height="100%", + gap="8px", + align_items="center", ), - width="24px", - height="80px", - border_radius=rx.cond(is_open, "0 8px 8px 0", "9999px"), - background=rx.color("mauve", 2), - variant="ghost", - box_shadow="0 2px 8px rgba(0,0,0,0.08)", - on_click=ConversationHistoryCollapseState.toggle, + position="relative", + display="flex", + flex="1", + width="0", + height="100%", + background="linear-gradient(180deg, #fffffff2, #f8fafff2 99%)", ), - align_items="center", - height="100vh", - spacing="0", + position="relative", + display="flex", + flex="1", + height="100%", + min_height="0", + overflow="hidden", + transition="all 0.3s ease-in-out", ), - # 渲染右侧布局占位层 - rx.box( - # 渲染内容排版层 - rx.vstack( - # 渲染对话 - render_conversation_component(), - # 渲染创建对话 - render_create_conversation_component(), - # 渲染输入 - render_input_component(), - width="100%", # 宽度 - height="100%", # 高度 - display="flex", # 弹性布局 - flex_flow="column", # 垂直方向布局 - align_items="center", # 子元素水平居中 - gap="8px", # 子元素间距 + # 渲染打开/关闭对话历史折叠面板按钮 + rx.button( + rx.cond( + is_open, + rx.icon( + "chevron-left", + width="16px", + height="16px", + color="var(--devui-icon-fill-weak)", + ), + rx.icon( + "chevron-right", + width="16px", + height="16px", + color="var(--devui-icon-fill-weak)", + ), ), - background_color="linear-gradient(180deg, #fffffff2, #f8fafff2 99%)", # 背景颜色 - position="relative", # 相对定位 - display="flex", # 弹性布局 - flex="1", # 分配父容器宽度 - width="0", # 宽度 - height="100%", # 高度 + position="absolute", + top="50%", + left=rx.cond(is_open, "calc(clamp(240px, 25%, 380px) - 8px)", "0"), + z_index=99, + width="16px", + height="40px", + background="var(--devui-base-bg)", + box_shadow="var(--mc-float-block-shadow)", + border_radius=rx.cond(is_open, "6px", "0 6px 6px 0"), + transition="all 0.3s ease-in-out", + cursor="pointer", + # 点击事件:打开/关闭对话历史折叠面板 + on_click=ConversationHistoryCollapseState.toggle, ), - position="relative", # 相对定位 - flex="1", # 分配父容器宽度 - display="flex", # 弹性布局 - overflow="hidden", # 隐藏溢出内容 - height="100%", # 高度 - min_height="0", # 最小高度 - border_radius="12px", # 圆角 + position="relative", + width="100%", + height="100%", + border_radius="12px", + overflow="hidden", # 溢出隐藏 ) diff --git a/agent/assets/send.svg b/agent/assets/send.svg new file mode 100644 index 0000000..ed9661e --- /dev/null +++ b/agent/assets/send.svg @@ -0,0 +1,3 @@ + + +