This commit is contained in:
parent
33fb9d3d34
commit
a4dc4ce40e
|
|
@ -23,9 +23,11 @@ app = rx.App(
|
||||||
"--devui-base-bg": "#ffffff",
|
"--devui-base-bg": "#ffffff",
|
||||||
"--mc-global-bg": "linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%)",
|
"--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)",
|
"--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-icon-fill-weak": "#babbc0",
|
||||||
"--devui-border-radius-feedback": "4px",
|
"--devui-border-radius-feedback": "4px",
|
||||||
"--devui-border-radius-card": "8px",
|
"--devui-border-radius-card": "8px",
|
||||||
|
"--devui-border-radius-full": "100px",
|
||||||
"--font-family": "HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei",
|
"--font-family": "HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei",
|
||||||
"--devui-font-size-sm": "12px",
|
"--devui-font-size-sm": "12px",
|
||||||
"--devui-font-size": "14px",
|
"--devui-font-size": "14px",
|
||||||
|
|
@ -36,6 +38,8 @@ app = rx.App(
|
||||||
"--placeholder": "#babbc0",
|
"--placeholder": "#babbc0",
|
||||||
"--devui-aide-text": "#71757f",
|
"--devui-aide-text": "#71757f",
|
||||||
"--devui-primary": "#5e7ce0",
|
"--devui-primary": "#5e7ce0",
|
||||||
|
"--devui-brand": "#5e7ce0",
|
||||||
|
"--devui-brand-hover": "#7693f5",
|
||||||
} # 自定义主题颜色
|
} # 自定义主题颜色
|
||||||
) # 此处变量名需使用 app ,具体原因目前尚不清楚
|
) # 此处变量名需使用 app ,具体原因目前尚不清楚
|
||||||
# 注册首页路由
|
# 注册首页路由
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
"""
|
"""
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
from typing import Tuple
|
|
||||||
from application.models import Run, Reasoning, Conversation
|
from application.models import Run, Reasoning, Conversation
|
||||||
from application.state.conversation import ConversationState
|
from application.state.conversation import ConversationState
|
||||||
from application.state.create_conversation_modal import CreateConversationModalState
|
from application.state.create_conversation_modal import CreateConversationModalState
|
||||||
|
|
@ -31,7 +30,7 @@ def render_conversation_history_item(
|
||||||
return rx.popover.root(
|
return rx.popover.root(
|
||||||
# 触发事件:点击更多按钮
|
# 触发事件:点击更多按钮
|
||||||
rx.popover.trigger(
|
rx.popover.trigger(
|
||||||
rx.button(
|
rx.box(
|
||||||
rx.icon("ellipsis", size=14, color="var(--devui-text-weak)"),
|
rx.icon("ellipsis", size=14, color="var(--devui-text-weak)"),
|
||||||
cursor="pointer", # 鼠标光标显示为手指
|
cursor="pointer", # 鼠标光标显示为手指
|
||||||
)
|
)
|
||||||
|
|
@ -82,7 +81,7 @@ def render_conversation_history_item(
|
||||||
box_shadow="0 2px 12px rgba(0,0,0,0.1)", # 阴影
|
box_shadow="0 2px 12px rgba(0,0,0,0.1)", # 阴影
|
||||||
overflow="visible", # 溢出可见
|
overflow="visible", # 溢出可见
|
||||||
side="bottom", # 气泡卡片位于底部
|
side="bottom", # 气泡卡片位于底部
|
||||||
side_offset=-2, # 偏移量
|
side_offset=9, # 偏移量
|
||||||
),
|
),
|
||||||
open_delay=0,
|
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
|
: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(
|
return rx.hstack(
|
||||||
rx.spacer(), # 占位符
|
rx.spacer(), # 占位符
|
||||||
rx.dialog.root(
|
rx.dialog.root(
|
||||||
# 触发事件:点击创建对话图标,支持鼠标悬停提示
|
# 触发事件:点击图标
|
||||||
rx.dialog.trigger(
|
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.dialog.content(
|
||||||
rx.form(
|
rx.form(
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
|
|
@ -349,6 +375,7 @@ def render_create_conversation_component() -> rx.Component:
|
||||||
wrap="wrap",
|
wrap="wrap",
|
||||||
width="100%",
|
width="100%",
|
||||||
),
|
),
|
||||||
|
# 提交事件:新建对话
|
||||||
on_submit=ConversationState.create_conversation,
|
on_submit=ConversationState.create_conversation,
|
||||||
),
|
),
|
||||||
background_color=rx.color("mauve", 1),
|
background_color=rx.color("mauve", 1),
|
||||||
|
|
@ -356,13 +383,20 @@ def render_create_conversation_component() -> rx.Component:
|
||||||
open=CreateConversationModalState.is_open,
|
open=CreateConversationModalState.is_open,
|
||||||
on_open_change=CreateConversationModalState.toggle,
|
on_open_change=CreateConversationModalState.toggle,
|
||||||
),
|
),
|
||||||
|
display="flex",
|
||||||
width="100%",
|
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(
|
return rx.vstack(
|
||||||
# 渲染自定义输入组件
|
# 渲染自定义输入组件
|
||||||
|
|
|
||||||
|
|
@ -7,87 +7,78 @@ import reflex as rx
|
||||||
|
|
||||||
from application.state.frame import FrameState
|
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:
|
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(
|
return rx.vstack(
|
||||||
# 渲染顶部
|
# 渲染顶部
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
# 渲染品牌 LOGO 和名称
|
# 渲染品牌 LOGO 和名称
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
# 渲染品牌 Logo
|
# 渲染品牌 Logo
|
||||||
render_brand_logo(),
|
rx.image(
|
||||||
|
src="/logo.png",
|
||||||
|
width="34px",
|
||||||
|
height="34px",
|
||||||
|
object_fit="contain", # 等比缩放
|
||||||
|
),
|
||||||
# 渲染品牌名称
|
# 渲染品牌名称
|
||||||
rx.text(
|
rx.text(
|
||||||
"Gluballu",
|
"Gluballu",
|
||||||
|
|
@ -106,10 +97,10 @@ def render_sidebar() -> rx.Component:
|
||||||
rx.divider(
|
rx.divider(
|
||||||
width="32px", height="1px", margin="16px 0", background_color="#babbc0"
|
width="32px", height="1px", margin="16px 0", background_color="#babbc0"
|
||||||
),
|
),
|
||||||
# 渲染侧边栏图标导航按钮:对话
|
# 渲染按钮:对话
|
||||||
render_sidebar_icon_nav_button(sidebar_icon_nav_button="conversation"),
|
render_button(button="conversation"),
|
||||||
# 渲染侧边栏图标导航按钮:知识库
|
# 渲染按钮:知识库
|
||||||
render_sidebar_icon_nav_button(sidebar_icon_nav_button="knowledge_base"),
|
render_button(button="knowledge_base"),
|
||||||
margin_top="12px", # 上外边距
|
margin_top="12px", # 上外边距
|
||||||
display="flex", # 弹性布局
|
display="flex", # 弹性布局
|
||||||
flex_direction="column", # 垂直方向布局
|
flex_direction="column", # 垂直方向布局
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
from application.components.conversation import (
|
from application.components.conversation import (
|
||||||
render_conversation_component,
|
render_conversation_box,
|
||||||
render_conversation_history_item,
|
render_conversation_history_item,
|
||||||
render_input_bar,
|
render_input_box,
|
||||||
render_create_conversation_component,
|
render_create_conversation_button,
|
||||||
)
|
)
|
||||||
from application.state.conversation import ConversationState
|
from application.state.conversation import ConversationState
|
||||||
from application.state.conversation_history_collapse import (
|
from application.state.conversation_history_collapse import (
|
||||||
|
|
@ -18,17 +18,17 @@ from application.state.conversation_history_collapse import (
|
||||||
|
|
||||||
def render_conversation_page() -> rx.Component:
|
def render_conversation_page() -> rx.Component:
|
||||||
"""
|
"""
|
||||||
渲染对话页面:左侧为对话历史折叠面板,右侧为对话历史、运行历史、创建和输入等组件
|
渲染对话页面:左侧为对话历史折叠面板,右侧为对话历史、运行历史、新建和输入等组件
|
||||||
"""
|
"""
|
||||||
# 对话历史折叠面板打开状态
|
# 对话历史折叠面板打开状态
|
||||||
is_open = ConversationHistoryCollapseState.is_open
|
is_open = ConversationHistoryCollapseState.is_open
|
||||||
|
|
||||||
return rx.box(
|
return rx.box(
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
# 渲染对话历史
|
# 渲染对话历史折叠面板
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
# 标题
|
# 渲染标题
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.text(
|
rx.text(
|
||||||
"对话历史",
|
"对话历史",
|
||||||
|
|
@ -42,7 +42,7 @@ def render_conversation_page() -> rx.Component:
|
||||||
justify_content="space-between",
|
justify_content="space-between",
|
||||||
),
|
),
|
||||||
# 渲染列表
|
# 渲染列表
|
||||||
rx.vstack(
|
rx.auto_scroll(
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
ConversationState.get_conversation_history,
|
ConversationState.get_conversation_history,
|
||||||
lambda item, _: render_conversation_history_item(
|
lambda item, _: render_conversation_history_item(
|
||||||
|
|
@ -74,12 +74,12 @@ def render_conversation_page() -> rx.Component:
|
||||||
# 渲染对话区域
|
# 渲染对话区域
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
# 渲染运行历史
|
# 渲染对话框
|
||||||
render_conversation_component(),
|
render_conversation_box(),
|
||||||
# 渲染创建对话按钮
|
# 渲染新建对话按钮
|
||||||
render_create_conversation_component(),
|
render_create_conversation_button(),
|
||||||
# 渲染输入栏
|
# 渲染输入框
|
||||||
render_input_bar(),
|
render_input_box(),
|
||||||
display="flex",
|
display="flex",
|
||||||
flex_flow="column",
|
flex_flow="column",
|
||||||
width="100%",
|
width="100%",
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@
|
||||||
"""
|
"""
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
|
|
||||||
def render_knowledge_base_page() -> rx.Component:
|
def render_knowledge_base_page() -> rx.Component:
|
||||||
"""
|
"""
|
||||||
渲染知识库页面:暂时为空
|
渲染知识库页面:暂时为空
|
||||||
"""
|
"""
|
||||||
return rx.fragment()
|
return rx.fragment()
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ agent: Agent = Agent(
|
||||||
retries=1,
|
retries=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConversationState(rx.State):
|
class ConversationState(rx.State):
|
||||||
"""
|
"""
|
||||||
对话状态
|
对话状态
|
||||||
|
|
@ -81,7 +82,7 @@ class ConversationState(rx.State):
|
||||||
@rx.event
|
@rx.event
|
||||||
async def create_conversation(self, form_data: Dict[str, Any]) -> None:
|
async def create_conversation(self, form_data: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
创建对话
|
新建对话
|
||||||
:param form_data: 表单数据
|
:param form_data: 表单数据
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
|
@ -90,16 +91,16 @@ class ConversationState(rx.State):
|
||||||
if not description:
|
if not description:
|
||||||
description = "新对话"
|
description = "新对话"
|
||||||
|
|
||||||
# 创建对话
|
# 新建对话
|
||||||
self.conversations[str(uuid7())] = Conversation(description=description)
|
self.conversations[str(uuid7())] = Conversation(description=description)
|
||||||
# 将末位对话唯一标识设置为当前对话唯一标识
|
# 将末位对话唯一标识设置为当前对话唯一标识
|
||||||
self.conversation_id = next(reversed(self.conversations.keys()))
|
self.conversation_id = next(reversed(self.conversations.keys()))
|
||||||
|
|
||||||
# 获取创建对话模态窗状态
|
# 获取新建对话模态窗状态
|
||||||
create_conversation_modal_state = await self.get_state(
|
create_conversation_modal_state = await self.get_state(
|
||||||
CreateConversationModalState
|
CreateConversationModalState
|
||||||
)
|
)
|
||||||
# 关闭创建对话模态窗
|
# 关闭新建对话模态窗
|
||||||
create_conversation_modal_state.is_open = False
|
create_conversation_modal_state.is_open = False
|
||||||
|
|
||||||
@rx.event
|
@rx.event
|
||||||
|
|
@ -376,4 +377,3 @@ class ConversationState(rx.State):
|
||||||
# 指定运行
|
# 指定运行
|
||||||
run = self.conversations[self.conversation_id].runs[run_id]
|
run = self.conversations[self.conversation_id].runs[run_id]
|
||||||
run.is_reasoning_panel_open = not run.is_reasoning_panel_open
|
run.is_reasoning_panel_open = not run.is_reasoning_panel_open
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
|
|
||||||
Loading…
Reference in New Issue