This commit is contained in:
liubiren 2026-07-15 19:59:42 +08:00
parent 7d6d1d64a8
commit d1aac8762a
6 changed files with 124 additions and 66 deletions

View File

@ -1,8 +1,8 @@
"""empty message """empty message
Revision ID: 6cd382f48060 Revision ID: 51f049b860bb
Revises: Revises:
Create Date: 2026-07-13 17:24:40.090382 Create Date: 2026-07-13 22:23:49.155469
""" """
from typing import Sequence, Union from typing import Sequence, Union
@ -12,7 +12,7 @@ import sqlalchemy as sa
import sqlmodel import sqlmodel
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = '6cd382f48060' revision: str = '51f049b860bb'
down_revision: Union[str, Sequence[str], None] = None down_revision: Union[str, Sequence[str], None] = None
branch_labels: Union[str, Sequence[str], None] = None branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None

View File

@ -20,7 +20,9 @@ app = rx.App(
"*::before, *::after": { "*::before, *::after": {
"box_sizing": "border-box", "box_sizing": "border-box",
}, },
"--prismui-background-color": "#ffffff", "--prismui-background-color-1": "#ffffff",
"--prismui-background-color-2": "rgb(235, 235, 235)",
"--prismui-background-color-3": "#f6f6f8",
"--mc-float-block-shadow": "rgba(213, 213, 213, 0.25)", "--mc-float-block-shadow": "rgba(213, 213, 213, 0.25)",
"--devui-global-bg": "#f6f6f8", "--devui-global-bg": "#f6f6f8",
"--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%)",
@ -32,10 +34,18 @@ app = rx.App(
"--prismui-border-radius": "8px", "--prismui-border-radius": "8px",
"--devui-border-radius-full": "100px", "--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",
"--prismui-font-size": "14px",
"--prismui-font-size-1": "14px",
"--prismui-font-size-2": "12px",
"--prismui-font-size-sm": "12px", "--prismui-font-size-sm": "12px",
"--prismui-font-weight-1": "700",
"--devui-font-size": "14px", "--devui-font-size": "14px",
"--devui-font-size-lg": "14px", "--devui-font-size-lg": "14px",
"--prismui-color-text": "#252b3a", "--prismui-color-text": "#252b3a",
"--prismui-color-text-light": "#babbc0",
"--prismui-color-1": "#252b3a",
"--prismui-color-2": "#575d6c",
"--prismui-color-3": "#babbc0",
"--devui-text-weak": "#575d6c", "--devui-text-weak": "#575d6c",
"--devui-light-text": "#ffffff", "--devui-light-text": "#ffffff",
"--placeholder": "#babbc0", "--placeholder": "#babbc0",

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
"""
排版相关组件
"""
import reflex as rx

View File

@ -23,7 +23,7 @@ def render_conversation_history_item(
""" """
# 会话激活状态 # 会话激活状态
is_conversation_actived = conversation_id == ConversationState.conversation_id is_actived = conversation_id == ConversationState.conversation_id
return rx.box( return rx.box(
rx.hstack( rx.hstack(
@ -105,10 +105,10 @@ def render_conversation_history_item(
cursor="pointer", cursor="pointer",
style={ style={
"opacity": rx.cond( "opacity": rx.cond(
is_conversation_actived, "1", "0" is_actived, "1", "0"
), # 若当前会话已激活则不透明,否则透明 ), # 若当前会话已激活则不透明,否则透明
"pointer_events": rx.cond( "pointer_events": rx.cond(
is_conversation_actived, "auto", "none" is_actived, "auto", "none"
), # 若当前会话已激活则可点击,否则不可点击 ), # 若当前会话已激活则可点击,否则不可点击
"transition": "opacity 0.18s ease", "transition": "opacity 0.18s ease",
}, },
@ -127,13 +127,11 @@ def render_conversation_history_item(
cursor="pointer", cursor="pointer",
style={ style={
"background": rx.cond( "background": rx.cond(
is_conversation_actived, is_actived,
"linear-gradient(to right, #f3efff, #f3efff33, #e2f1fd33, #e2f1fd)", "linear-gradient(to right, #f3efff, #f3efff33, #e2f1fd33, #e2f1fd)",
"var(--devui-base-bg)", "var(--devui-base-bg)",
), ),
"box_shadow": rx.cond( "box_shadow": rx.cond(is_actived, "2px 2px 8px #e9e9e9", "none"),
is_conversation_actived, "2px 2px 8px #e9e9e9", "none"
),
"&:hover": { "&:hover": {
"background": "linear-gradient(to right, #f3efff, #f3efff33, #e2f1fd33, #e2f1fd)", "background": "linear-gradient(to right, #f3efff, #f3efff33, #e2f1fd33, #e2f1fd)",
"box_shadow": "2px 2px 8px #e9e9e9", "box_shadow": "2px 2px 8px #e9e9e9",
@ -313,28 +311,33 @@ def render_greeting() -> rx.Component:
) )
def render_reasoning_thought_node(thought_node_id: int, thought_node: ThoughtNode): def render_thought_node(thought_node_id: int, thought_node: ThoughtNode):
""" """
渲染思考节点 渲染思考节点
:param thought_node_id: 思考节点唯一标识 :param thought_node_id: 思考节点唯一标识
:param thought_node: 思考节点实例 :param thought_node: 思考节点实例
:return: Component :return: Component
""" """
return rx.hstack( return rx.vstack(
rx.vstack( rx.match(
rx.box( thought_node.kind,
width="8px", (
height="8px", "thinking",
background_color=rx.color("blue", 7), rx.markdown(
thought_node.content,
component_map={
"p": lambda text: rx.text(
text,
color="var(--prismui-color-text-light)",
margin="0 0 8px",
font_size="var(--prismui-font-size-sm)",
)
},
),
), ),
rx.box(width="2px", flex=1, background_color=rx.color("blue", 3)), rx.fragment(),
align_items="center",
spacing="0",
height="100%",
), ),
rx.markdown(thought_node.content, color=rx.color("gray", 11), padding_y="4px"),
align_items="flex-start", align_items="flex-start",
spacing="2",
width="100%", width="100%",
key=thought_node_id, key=thought_node_id,
) )
@ -343,51 +346,51 @@ def render_reasoning_thought_node(thought_node_id: int, thought_node: ThoughtNod
def render_dialog_history_item(dialog_id: str, dialog: Dialog) -> rx.Component: def render_dialog_history_item(dialog_id: str, dialog: Dialog) -> rx.Component:
""" """
渲染对话历史条目 渲染对话历史条目
:param run: 对话实例 :param dialog_id: 对话唯一标识
:param dialog: 对话实例
:return: Component :return: Component
""" """
# 推理状态 # 推理状态
is_thinking = dialog.is_thinking is_thinking = dialog.is_thinking
# 思考折叠面板展开状态
is_collapse_expanded = dialog.is_collapse_expanded
# 思考节点 # 思考节点
thought_nodes = dialog.thought_nodes thought_nodes = dialog.thought_nodes
# 推理折叠面板展开状态
is_reasoning_panel_open = dialog.is_collapse_expanded
return rx.vstack( return rx.vstack(
# 渲染问题和再次发送按钮 # 渲染问题和操作栏
rx.hstack( rx.hstack(
rx.spacer(), rx.spacer(),
rx.vstack( rx.vstack(
# 渲染问题 # 渲染问题
rx.markdown( rx.text(
dialog.question, dialog.question,
max_width="600px", max_width="600px",
padding="12px 16px", padding="12px 16px",
background_color="var(--devui-global-bg)", background_color="var(--prismui-background-color-3)",
border_radius="12px", border_radius="12px",
word_wrap="break-word", word_wrap="break-word",
word_break="break-all", word_break="break-all",
white_space="pre-line",
color="var(--prismui-color-text)", color="var(--prismui-color-text)",
style={
"& p.rt-Text": {
"padding": "0",
"margin": "0 !important",
},
},
), ),
# 再次发送按钮 # 操作栏
rx.hstack( rx.hstack(
rx.box( rx.box(
rx.icon( rx.icon(
"rotate-ccw", "rotate-ccw",
width="14px", width="14px",
height="14px", height="14px",
color="var(--devui-text-weak)", color="var(--prismui-color-2)",
), ),
padding="4px", padding="4px",
border_radius="4px", border_radius="4px",
cursor="pointer", cursor="pointer",
style={
"_hover": {
"background_color": "var(--prismui-background-color-2)",
}
},
), ),
width="100%", width="100%",
margin_top="8px", margin_top="8px",
@ -399,32 +402,72 @@ def render_dialog_history_item(dialog_id: str, dialog: Dialog) -> rx.Component:
gap="4px", gap="4px",
font_size="var(--devui-font-size)", font_size="var(--devui-font-size)",
), ),
# 渲染智能体思考链面板和回答 # 渲染思考折叠面板
rx.vstack( rx.vstack(
# 标题栏
rx.auto_scroll( rx.box(
rx.foreach( rx.hstack(
thought_nodes, rx.text(
lambda i, _: render_reasoning_thought_node(i[0], i[1]), rx.cond(is_thinking, "思考中", "思考完成"),
color="var(--prismui-color-3)",
font_size="var(--prismui-font-size-2)",
),
rx.icon(
"chevron-right",
width="14px",
height="14px",
color="var(--prismui-color-3)",
style={
"transition": "transform 0.2s ease-in-out",
"transform": rx.cond(
is_collapse_expanded, "rotate(90deg)", "rotate(0deg)"
),
},
),
align_items="center",
gap="4px",
margin_bottom="8px",
line_height="22px",
), ),
width="100%", cursor="pointer",
padding="0 12px", # 点击事件,展开/折叠思考折叠面板
on_click=lambda: ConversationState.toggle_collapse(dialog_id),
), ),
# 渲染回答 rx.cond(
rx.markdown( is_collapse_expanded,
dialog.answer, rx.auto_scroll(
display="inline-block", rx.foreach(
max_width="85%", thought_nodes,
padding_x="1.25em", lambda i, _: render_thought_node(i[0], i[1]),
padding_y="0.5em", ),
margin_left="auto", width="100%",
margin_bottom="8px", ),
background_color=rx.color("gray", 2), rx.fragment(),
border_radius="12px",
color="var(--prismui-color-text)",
), ),
text_align="left", text_align="left",
width="100%", width="100%",
margin_top="8px",
),
# 渲染回答
rx.markdown(
dialog.answer,
component_map={
"p": lambda text: rx.text(
text,
word_wrap="break-word",
word_break="break-all",
white_space="pre-line",
line_height="24px",
font_size="var(--prismui-font-size-1)",
color="var(--prismui-color-1)",
),
"strong": lambda text: rx.text(
text,
display="inline",
font_weight="var(--prismui-font-weight-1)",
),
},
width="100%",
margin_bottom="8px", margin_bottom="8px",
), ),
width="100%", width="100%",
@ -470,7 +513,7 @@ def render_dialog_history() -> rx.Component:
def render_create_conversation_button() -> rx.Component: def render_create_conversation_button() -> rx.Component:
""" """
渲染新建话按钮 渲染新建话按钮
:return: Component :return: Component
""" """
return rx.hstack( return rx.hstack(
@ -501,7 +544,7 @@ def render_create_conversation_button() -> rx.Component:
} }
}, },
), ),
content="新建", content="新建",
background_color="#ffffff", background_color="#ffffff",
box_shadow="0 2px 12px 0 rgba(37, 43, 58, .24)", box_shadow="0 2px 12px 0 rgba(37, 43, 58, .24)",
color="#252b3a", color="#252b3a",
@ -524,11 +567,11 @@ def render_create_conversation_button() -> rx.Component:
rx.hstack( rx.hstack(
rx.input( rx.input(
name="description", name="description",
placeholder="请输入话描述", placeholder="请输入话描述",
flex="auto", flex="auto",
min_width="20ch", min_width="20ch",
), ),
rx.button(""), rx.button(""),
spacing="2", spacing="2",
wrap="wrap", wrap="wrap",
width="100%", width="100%",
@ -711,7 +754,7 @@ def render_conversation_history_collapse_button(
z_index=99, z_index=99,
width="16px", width="16px",
height="40px", height="40px",
background="var(--prismui-background-color)", background="var(--prismui-background-color-1)",
box_shadow="2px 0 4px 0 var(--mc-float-block-shadow)", box_shadow="2px 0 4px 0 var(--mc-float-block-shadow)",
border_radius=rx.cond(is_collapse_expanded, "6px", "0 6px 6px 0"), border_radius=rx.cond(is_collapse_expanded, "6px", "0 6px 6px 0"),
transition="all 0.3s ease-in-out", transition="all 0.3s ease-in-out",

View File

@ -395,9 +395,9 @@ class ConversationState(rx.State):
yield yield
@rx.event @rx.event
def toggle_reasoning_panel(self, dialog_id: str) -> None: def toggle_collapse(self, dialog_id: str) -> None:
""" """
展开/折叠指定运行唯一标识的推理面板 展开/折叠思考折叠面板
""" """
# 指定运行 # 指定运行
dialog = self.conversations[self.conversation_id].dialogs[dialog_id] dialog = self.conversations[self.conversation_id].dialogs[dialog_id]

BIN
agent/database.db Normal file

Binary file not shown.