This commit is contained in:
parent
3f52e7bd61
commit
998a0fc572
|
|
@ -1,8 +1,8 @@
|
||||||
"""empty message
|
"""empty message
|
||||||
|
|
||||||
Revision ID: a7968da75b72
|
Revision ID: 4269426de639
|
||||||
Revises:
|
Revises:
|
||||||
Create Date: 2026-07-26 23:23:19.558164
|
Create Date: 2026-07-27 10:10:56.902466
|
||||||
|
|
||||||
"""
|
"""
|
||||||
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 = 'a7968da75b72'
|
revision: str = '4269426de639'
|
||||||
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
|
||||||
|
|
@ -28,7 +28,9 @@ app = rx.App(
|
||||||
"outline": "none",
|
"outline": "none",
|
||||||
"box-shadow": "none",
|
"box-shadow": "none",
|
||||||
},
|
},
|
||||||
"*::placeholder": {
|
".rt-TextAreaInput::placeholder, .rt-TextFieldInput::placeholder": {
|
||||||
|
"font-family": "var(--font-family)",
|
||||||
|
"font-size": "var(--prismui-font-size-2)",
|
||||||
"color": "var(--prismui-color-3)",
|
"color": "var(--prismui-color-3)",
|
||||||
"opacity": 1,
|
"opacity": 1,
|
||||||
}, # 覆盖占位符样式
|
}, # 覆盖占位符样式
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
领域模型
|
领域模型
|
||||||
"""
|
"""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, List
|
from typing import Dict
|
||||||
from pydantic_ai._uuid import uuid7
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from dataclasses import dataclass
|
from pydantic_ai._uuid import uuid7
|
||||||
|
|
||||||
|
|
||||||
class Thought(BaseModel):
|
class Thought(BaseModel):
|
||||||
|
|
@ -25,7 +25,7 @@ class Dialog(BaseModel):
|
||||||
|
|
||||||
id: str = Field(default_factory=lambda: str(uuid7()), description="对话唯一标识")
|
id: str = Field(default_factory=lambda: str(uuid7()), description="对话唯一标识")
|
||||||
user_prompt: str = Field(..., description="用户提示词")
|
user_prompt: str = Field(..., description="用户提示词")
|
||||||
thoughts: List[Thought] = Field(default_factory=list, description="思考列表")
|
thoughts: Dict[int, Thought] = Field(default_factory=dict, description="思考列表")
|
||||||
result_output: str = Field(default="", description="结果输出")
|
result_output: str = Field(default="", description="结果输出")
|
||||||
is_thinking: bool = Field(
|
is_thinking: bool = Field(
|
||||||
default=False, description="正在思考,True 表示正在思考,False 表示未正在思考"
|
default=False, description="正在思考,True 表示正在思考,False 表示未正在思考"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
会话页面
|
会话页面
|
||||||
"""
|
"""
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from application.domain_models import (
|
from application.domain_models import (
|
||||||
Conversation,
|
Conversation,
|
||||||
|
|
@ -14,143 +15,160 @@ from application.states import ConversationState, AuthState
|
||||||
|
|
||||||
|
|
||||||
def conversation_history_item(
|
def conversation_history_item(
|
||||||
item: ConversationHistoryItem,
|
conversation: ConversationHistoryItem,
|
||||||
) -> rx.Component:
|
) -> rx.Component:
|
||||||
"""
|
"""
|
||||||
会话历史项
|
会话历史项
|
||||||
:param item: 会话历史项
|
:param conversation: 会话历史项
|
||||||
:return: Component
|
:return: Component
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 会话激活状态
|
# 高亮:若为当前会话或显示更多则高亮
|
||||||
is_actived: bool = item.id == ConversationState.conversation_id
|
highlight: bool = (
|
||||||
|
conversation.id == ConversationState.shown_more_conversation_id
|
||||||
|
) | (conversation.id == ConversationState.conversation_id)
|
||||||
|
|
||||||
return rx.list.item(
|
return rx.list.item(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
# 对话描述
|
# 对话描述
|
||||||
rx.text(
|
rx.text(
|
||||||
item.description,
|
conversation.description,
|
||||||
flex=1,
|
flex=1,
|
||||||
height="22px",
|
height="22px",
|
||||||
line_height="22px",
|
line_height="22px",
|
||||||
padding_right="4px",
|
padding_right="18px",
|
||||||
color="var(--prismui-color-2)",
|
color="var(--prismui-color-2)",
|
||||||
overflow="hidden",
|
|
||||||
text_overflow="ellipsis",
|
text_overflow="ellipsis",
|
||||||
white_space="nowrap",
|
white_space="nowrap",
|
||||||
),
|
overflow="hidden",
|
||||||
# 更多按钮
|
|
||||||
rx.box(
|
|
||||||
rx.popover.root(
|
|
||||||
# 触发事件:点击更多按钮
|
|
||||||
rx.popover.trigger(
|
|
||||||
rx.box(
|
|
||||||
rx.icon(
|
|
||||||
"ellipsis",
|
|
||||||
width="14px",
|
|
||||||
height="14px",
|
|
||||||
color="var(--prismui-color-2)",
|
|
||||||
),
|
|
||||||
cursor="pointer",
|
|
||||||
)
|
|
||||||
),
|
|
||||||
# 气泡卡片
|
|
||||||
rx.popover.content(
|
|
||||||
rx.vstack(
|
|
||||||
rx.box(
|
|
||||||
position="absolute",
|
|
||||||
top="-12px",
|
|
||||||
left="50%",
|
|
||||||
transform="translateX(-50%) rotate(45deg)",
|
|
||||||
width="8px",
|
|
||||||
height="8px",
|
|
||||||
background_color="var(--prismui-background-color-1)",
|
|
||||||
),
|
|
||||||
rx.popover.close(
|
|
||||||
rx.box(
|
|
||||||
"删除",
|
|
||||||
width="100%",
|
|
||||||
height="24px",
|
|
||||||
padding="4px",
|
|
||||||
border_radius="var(--prismui-border-radius-1)",
|
|
||||||
line_height="16px",
|
|
||||||
font_size="var(--prismui-font-size-1)",
|
|
||||||
color="var(--prismui-color-1)",
|
|
||||||
style={
|
|
||||||
"_hover": {
|
|
||||||
"background_color": "var(--prismui-background-color-6)",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
# 点击事件:删除对话
|
|
||||||
on_click=lambda: ConversationState.delete_conversation(
|
|
||||||
item.id
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
position="relative",
|
|
||||||
width="100%",
|
|
||||||
),
|
|
||||||
side="bottom",
|
|
||||||
side_offset=8,
|
|
||||||
position="relative",
|
|
||||||
align="center",
|
|
||||||
padding="8px",
|
|
||||||
border_radius="var(--prismui-border-radius-1)",
|
|
||||||
box_shadow="0 2px 12px rgba(0,0,0,0.1)",
|
|
||||||
font_family="var(--prismui-font-family)",
|
|
||||||
overflow="visible",
|
|
||||||
),
|
|
||||||
open_delay=0,
|
|
||||||
),
|
|
||||||
min_width="14px",
|
|
||||||
cursor="pointer",
|
|
||||||
style={
|
|
||||||
"opacity": rx.cond(
|
|
||||||
is_actived, "1", "0"
|
|
||||||
), # 若当前会话已激活则不透明,否则透明
|
|
||||||
"transition": "opacity 0.18s ease",
|
|
||||||
"pointer_events": rx.cond(is_actived, "auto", "none"),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
display="flex",
|
display="flex",
|
||||||
align_items="center",
|
align_items="center",
|
||||||
width="100%",
|
width="100%",
|
||||||
margin_bottom="8px",
|
margin_bottom="8px",
|
||||||
cursor="pointer",
|
|
||||||
),
|
),
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.spacer(),
|
rx.spacer(),
|
||||||
# 创建时间
|
# 创建时间
|
||||||
rx.text(
|
rx.text(
|
||||||
"1",
|
conversation.created_at,
|
||||||
margin_bottom="8px",
|
line_height="20px",
|
||||||
|
font_size="var(--prismui-font-size-1)",
|
||||||
|
color="var(--prismui-color-8)",
|
||||||
),
|
),
|
||||||
|
justify_content="space-between",
|
||||||
|
align_items="center",
|
||||||
|
width="100%",
|
||||||
|
height="20px",
|
||||||
|
margin_bottom="8px",
|
||||||
),
|
),
|
||||||
|
# 点击事件:切换会话
|
||||||
|
on_click=lambda: ConversationState.switch_conversation(conversation.id),
|
||||||
|
width="100%",
|
||||||
),
|
),
|
||||||
|
# 更多按钮:点击更多按钮显示气泡卡片,可删除会话
|
||||||
|
rx.box(
|
||||||
|
rx.popover.root(
|
||||||
|
rx.popover.trigger(
|
||||||
|
rx.box(
|
||||||
|
rx.icon(
|
||||||
|
"ellipsis",
|
||||||
|
width="14px",
|
||||||
|
height="14px",
|
||||||
|
color="var(--prismui-color-2)",
|
||||||
|
),
|
||||||
|
cursor="pointer",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
rx.popover.content(
|
||||||
|
rx.vstack(
|
||||||
|
rx.box(
|
||||||
|
position="absolute",
|
||||||
|
top="-6px",
|
||||||
|
left="50%",
|
||||||
|
transform="translateX(-50%) rotate(45deg)",
|
||||||
|
width="8px",
|
||||||
|
height="8px",
|
||||||
|
background_color="var(--prismui-background-color-1)",
|
||||||
|
),
|
||||||
|
rx.popover.close(
|
||||||
|
rx.box(
|
||||||
|
"删除",
|
||||||
|
# 点击事件:删除对话
|
||||||
|
on_click=lambda: ConversationState.delete_conversation(
|
||||||
|
conversation.id
|
||||||
|
),
|
||||||
|
display="flex",
|
||||||
|
align_items="center",
|
||||||
|
justify_content="center",
|
||||||
|
width="100%",
|
||||||
|
height="24px",
|
||||||
|
border_radius="var(--prismui-border-radius-1)",
|
||||||
|
line_height="16px",
|
||||||
|
font_family="var(--prismui-font-family)",
|
||||||
|
font_size="var(--prismui-font-size-1)",
|
||||||
|
color="var(--prismui-color-1)",
|
||||||
|
style={
|
||||||
|
"_hover": {
|
||||||
|
"background_color": "var(--prismui-background-color-6)",
|
||||||
|
}, # 鼠标悬停显示背景颜色
|
||||||
|
},
|
||||||
|
cursor="pointer",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
position="relative",
|
||||||
|
width="100%",
|
||||||
|
),
|
||||||
|
side="bottom",
|
||||||
|
side_offset=8,
|
||||||
|
position="relative",
|
||||||
|
align="center",
|
||||||
|
padding="4px 8px",
|
||||||
|
border_radius="var(--prismui-border-radius-1)",
|
||||||
|
box_shadow="var(--prismui-box-shadow-6)",
|
||||||
|
overflow="visible",
|
||||||
|
),
|
||||||
|
on_open_change=lambda is_shown: ConversationState.set_shown_more_conversation_id(
|
||||||
|
conversation.id, is_shown
|
||||||
|
),
|
||||||
|
open_delay=0,
|
||||||
|
),
|
||||||
|
position="absolute",
|
||||||
|
top="27px",
|
||||||
|
right="16px",
|
||||||
|
transform="translateY(-50%)",
|
||||||
|
z_index=99,
|
||||||
|
min_width="14px",
|
||||||
|
cursor="pointer",
|
||||||
|
opacity=rx.cond(highlight, "1", "0"),
|
||||||
|
transition="opacity 0.18s ease",
|
||||||
|
pointer_events=rx.cond(highlight, "auto", "none"),
|
||||||
|
),
|
||||||
|
display="flex",
|
||||||
|
position="relative",
|
||||||
|
align_items="flex-start",
|
||||||
width="100%",
|
width="100%",
|
||||||
padding="16px",
|
padding="16px",
|
||||||
margin_bottom="8px",
|
margin_bottom="8px",
|
||||||
background=rx.cond(
|
background=rx.cond(
|
||||||
is_actived,
|
highlight,
|
||||||
"linear-gradient(to right, #f3efff, #f3efff33, #e2f1fd33, #e2f1fd)",
|
"var(--prismui-background-3)",
|
||||||
"var(--prismui-background-color-1)",
|
"var(--prismui-background-color-1)",
|
||||||
),
|
),
|
||||||
border_radius="var(--prismui-border-radius-3)",
|
border_radius="var(--prismui-border-radius-3)",
|
||||||
box_shadow=rx.cond(is_actived, "2px 2px 8px #e9e9e9", "none"),
|
box_shadow=rx.cond(highlight, "var(--prismui-box-shadow-7)", "none"),
|
||||||
|
cursor="pointer",
|
||||||
style={
|
style={
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
"background": "linear-gradient(to right, #f3efff, #f3efff33, #e2f1fd33, #e2f1fd)",
|
"background": "var(--prismui-background-3)",
|
||||||
"box_shadow": "2px 2px 8px #e9e9e9",
|
"box_shadow": "var(--prismui-box-shadow-7)",
|
||||||
}, # 鼠标悬停背景颜色和阴影
|
}, # 鼠标悬停背景颜色和阴影
|
||||||
"&:hover > div > div:last-child": {
|
"&:hover > div:last-child": {
|
||||||
"opacity": "1 !important",
|
"opacity": "1",
|
||||||
"pointer_events": "auto !important",
|
"pointer_events": "auto",
|
||||||
}, # 鼠标悬停强制显示右侧三点按钮
|
}, # 鼠标悬停显示更多按钮
|
||||||
},
|
},
|
||||||
cursor="pointer",
|
|
||||||
# 点击事件:切换会话
|
|
||||||
on_click=ConversationState.switch_conversation(item.id),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -223,12 +241,11 @@ def greeting() -> rx.Component:
|
||||||
src="/logo.png",
|
src="/logo.png",
|
||||||
width="64px",
|
width="64px",
|
||||||
height="64px",
|
height="64px",
|
||||||
object_fit="contain",
|
|
||||||
),
|
),
|
||||||
rx.box(
|
rx.box(
|
||||||
"棱镜球",
|
"棱镜球",
|
||||||
font_size="32px",
|
font_size="calc(var(--prismui-font-size-3) * 2)",
|
||||||
font_weight="700",
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
letter_spacing="1px",
|
letter_spacing="1px",
|
||||||
),
|
),
|
||||||
display="flex",
|
display="flex",
|
||||||
|
|
@ -248,14 +265,12 @@ def greeting() -> rx.Component:
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
line_height="1.5",
|
line_height="1.5",
|
||||||
font_size="var(--devui-font-size)",
|
|
||||||
),
|
),
|
||||||
display="flex",
|
display="flex",
|
||||||
flex_direction="column",
|
flex_direction="column",
|
||||||
width="100%",
|
width="100%",
|
||||||
align_items="center",
|
align_items="center",
|
||||||
gap="12px",
|
gap="12px",
|
||||||
color="var(--prismui-color-text)",
|
|
||||||
),
|
),
|
||||||
# 演示案例
|
# 演示案例
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
|
|
@ -263,23 +278,22 @@ def greeting() -> rx.Component:
|
||||||
rx.text(
|
rx.text(
|
||||||
"演示案例",
|
"演示案例",
|
||||||
line_height="24px",
|
line_height="24px",
|
||||||
font_size="16px",
|
font_size="var(--prismui-font-size-3)",
|
||||||
font_weight="700",
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
),
|
),
|
||||||
display="flex",
|
display="flex",
|
||||||
width="100%",
|
|
||||||
justify_content="space-between",
|
justify_content="space-between",
|
||||||
align_items="center",
|
align_items="center",
|
||||||
|
width="100%",
|
||||||
margin_bottom="16px",
|
margin_bottom="16px",
|
||||||
),
|
),
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.box(
|
rx.box(
|
||||||
"智能客服",
|
"智能客服",
|
||||||
padding="10px 16px",
|
padding="10px 16px",
|
||||||
background_color="var(--devui-dividing-line)",
|
background_color="var(--prismui-background-color-6)",
|
||||||
border_radius="var(--devui-border-radius-full)",
|
border_radius="var(--prismui-border-radius-9)",
|
||||||
font_size="var(--devui-font-size)",
|
color="var(--prismui-color-10)",
|
||||||
color="var(--devui-aide-text)",
|
|
||||||
cursor="pointer",
|
cursor="pointer",
|
||||||
),
|
),
|
||||||
display="flex",
|
display="flex",
|
||||||
|
|
@ -289,26 +303,26 @@ def greeting() -> rx.Component:
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
padding="24px",
|
padding="24px",
|
||||||
background_color="var(--devui-base-bg)",
|
background_color="var(--prismui-background-color-1)",
|
||||||
border_radius="24px",
|
border_radius="var(--prismui-border-radius-7)",
|
||||||
),
|
),
|
||||||
display="flex",
|
display="flex",
|
||||||
flex_direction="column",
|
flex_direction="column",
|
||||||
|
align_items="center",
|
||||||
|
gap="24px",
|
||||||
width="100%",
|
width="100%",
|
||||||
min_height="0",
|
min_height="0",
|
||||||
margin="auto 0",
|
margin="auto 0",
|
||||||
align_items="center",
|
|
||||||
gap="24px",
|
|
||||||
color="var(--prismui-color-text)",
|
color="var(--prismui-color-text)",
|
||||||
),
|
),
|
||||||
display="flex",
|
display="flex",
|
||||||
flex="1",
|
flex="1",
|
||||||
flex_direction="column",
|
flex_direction="column",
|
||||||
|
justify_content="flex-start",
|
||||||
|
gap="24px",
|
||||||
width="100%",
|
width="100%",
|
||||||
max_width="1200px",
|
max_width="1200px",
|
||||||
padding="0 12px",
|
padding="0 12px",
|
||||||
justify_content="flex-start",
|
|
||||||
gap="24px",
|
|
||||||
overflow="auto",
|
overflow="auto",
|
||||||
style={
|
style={
|
||||||
"&::-webkit-scrollbar": {
|
"&::-webkit-scrollbar": {
|
||||||
|
|
@ -318,20 +332,20 @@ def greeting() -> rx.Component:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def thought(thought: Thought):
|
def thought(thought):
|
||||||
"""
|
"""
|
||||||
思考节点
|
思考卡片
|
||||||
|
|
||||||
:param thought: 思考节点实例
|
:param thought: 思考实例
|
||||||
:return: Component
|
:return: Component
|
||||||
"""
|
"""
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
rx.match(
|
rx.match(
|
||||||
thought.type,
|
thought[1].type,
|
||||||
(
|
(
|
||||||
"thinking",
|
"thinking",
|
||||||
rx.text(
|
rx.text(
|
||||||
thought.content,
|
thought[1].content,
|
||||||
line_height="22px",
|
line_height="22px",
|
||||||
font_size="var(--prismui-font-size-2)",
|
font_size="var(--prismui-font-size-2)",
|
||||||
color="var(--prismui-color-3)",
|
color="var(--prismui-color-3)",
|
||||||
|
|
@ -354,28 +368,26 @@ def dialog(dialog: Dialog) -> rx.Component:
|
||||||
is_thinking = dialog.is_thinking
|
is_thinking = dialog.is_thinking
|
||||||
# 思考折叠面板展开状态
|
# 思考折叠面板展开状态
|
||||||
is_expanded = dialog.is_expanded
|
is_expanded = dialog.is_expanded
|
||||||
# 思考节点
|
|
||||||
thoughts = dialog.thoughts
|
|
||||||
|
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
# 问题和操作栏
|
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.spacer(),
|
rx.spacer(),
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
# 问题
|
# 用户提示词
|
||||||
rx.text(
|
rx.text(
|
||||||
dialog.user_prompt,
|
dialog.user_prompt,
|
||||||
max_width="600px",
|
max_width="600px",
|
||||||
padding="12px 16px",
|
padding="12px 16px",
|
||||||
background_color="var(--prismui-background-color-3)",
|
background_color="var(--prismui-background-color-3)",
|
||||||
border_radius="var(--prismui-border-radius-3)",
|
border_radius="var(--prismui-border-radius-3)",
|
||||||
|
line_height="1.5",
|
||||||
|
color="var(--prismui-color-text)",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
white_space="pre-line",
|
||||||
color="var(--prismui-color-text)",
|
|
||||||
),
|
),
|
||||||
# 操作栏
|
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
|
# 再次发送
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.icon(
|
rx.icon(
|
||||||
"rotate-ccw",
|
"rotate-ccw",
|
||||||
|
|
@ -396,11 +408,10 @@ def dialog(dialog: Dialog) -> rx.Component:
|
||||||
margin_top="8px",
|
margin_top="8px",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
width="100%",
|
|
||||||
margin_top="8px",
|
|
||||||
align_items="flex-start",
|
align_items="flex-start",
|
||||||
gap="4px",
|
gap="4px",
|
||||||
font_size="var(--devui-font-size)",
|
width="100%",
|
||||||
|
margin_top="8px",
|
||||||
),
|
),
|
||||||
# 思考折叠面板
|
# 思考折叠面板
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
|
|
@ -437,7 +448,7 @@ def dialog(dialog: Dialog) -> rx.Component:
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.auto_scroll(
|
rx.auto_scroll(
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
thoughts,
|
dialog.thoughts,
|
||||||
thought,
|
thought,
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
|
|
@ -464,35 +475,43 @@ def dialog(dialog: Dialog) -> rx.Component:
|
||||||
"p": lambda text: rx.text(
|
"p": lambda text: rx.text(
|
||||||
text,
|
text,
|
||||||
margin_bottom="8px",
|
margin_bottom="8px",
|
||||||
|
line_height="1.5",
|
||||||
|
word_wrap="break-word",
|
||||||
|
word_break="break-all",
|
||||||
|
white_space="pre-line",
|
||||||
|
),
|
||||||
|
"h2": lambda text: rx.text(
|
||||||
|
text,
|
||||||
|
margin_bottom="8px",
|
||||||
|
line_height="1.5",
|
||||||
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
white_space="pre-line",
|
||||||
line_height="24px",
|
|
||||||
font_size="var(--prismui-font-size-1)",
|
|
||||||
color="var(--prismui-color-1)",
|
|
||||||
),
|
),
|
||||||
"strong": lambda text: rx.text(
|
"strong": lambda text: rx.text(
|
||||||
text,
|
text,
|
||||||
display="inline",
|
display="inline",
|
||||||
font_weight="var(--prismui-font-weight-1)",
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
),
|
),
|
||||||
"ul": lambda children: rx.vstack(
|
"ul": lambda children: rx.vstack(
|
||||||
children, margin_bottom="8px", gap="4px"
|
children, margin_bottom="8px", gap="4px"
|
||||||
),
|
),
|
||||||
"li": lambda text: rx.text(
|
"li": lambda text: rx.text(
|
||||||
text,
|
text,
|
||||||
|
display="list-item",
|
||||||
|
list_style_type="disc",
|
||||||
|
list_style_position="outside",
|
||||||
|
margin="0 0 4px 16px",
|
||||||
|
line_height="1.5",
|
||||||
|
font_size="var(--prismui-font-size-1)",
|
||||||
|
color="var(--prismui-color-1)",
|
||||||
word_wrap="break-word",
|
word_wrap="break-word",
|
||||||
word_break="break-all",
|
word_break="break-all",
|
||||||
white_space="pre-line",
|
white_space="pre-line",
|
||||||
line_height="24px",
|
style={},
|
||||||
font_size="var(--prismui-font-size-1)",
|
|
||||||
color="var(--prismui-color-1)",
|
|
||||||
style={
|
|
||||||
"display": "list-item",
|
|
||||||
"list_style_type": "disc",
|
|
||||||
"list_style_position": "inside",
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
"hr": lambda _: rx.divider(margin="8px 0"),
|
||||||
},
|
},
|
||||||
width="100%",
|
width="100%",
|
||||||
margin_top="8px",
|
margin_top="8px",
|
||||||
|
|
@ -503,21 +522,19 @@ def dialog(dialog: Dialog) -> rx.Component:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def dialogs() -> rx.Component:
|
def dialogs_showing() -> rx.Component:
|
||||||
"""
|
"""
|
||||||
对话列表
|
对话列表展示
|
||||||
:return: Component
|
:return: Component
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 获取当前会话的对话历史
|
# 当前会话的对话列表
|
||||||
dialogs = ConversationState.dialogs
|
dialogs = ConversationState.dialogs
|
||||||
|
# 若对话列表为空则显示欢迎,否则显示对话列表
|
||||||
# 若运行字典为空则品牌图标、名称和介绍、预设用户提示词等,否则遍历运行项
|
|
||||||
return rx.cond(
|
return rx.cond(
|
||||||
dialogs.length() == 0,
|
dialogs.length() == 0,
|
||||||
# 欢迎
|
# 欢迎
|
||||||
greeting(),
|
greeting(),
|
||||||
# 遍历对话项
|
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rx.auto_scroll(
|
rx.auto_scroll(
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
|
|
@ -539,54 +556,53 @@ def dialogs() -> rx.Component:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_conversation_button() -> rx.Component:
|
def create_conversation() -> rx.Component:
|
||||||
"""
|
"""
|
||||||
新建会话按钮
|
创建会话
|
||||||
:return: Component
|
:return: Component
|
||||||
"""
|
"""
|
||||||
return rx.hstack(
|
return rx.hstack(
|
||||||
rx.el.style(
|
rx.el.style(
|
||||||
"""
|
"""
|
||||||
.rt-TooltipArrow polygon {
|
.rt-TooltipArrow polygon {
|
||||||
fill: #ffffff !important;
|
fill: var(--prismui-background-color-1) !important;
|
||||||
}
|
}
|
||||||
.rt-TooltipText {
|
.rt-TooltipText {
|
||||||
color: var(--prismui-color-text) !important;
|
font-family: var(--prismui-font-family) !important;
|
||||||
|
color: var(--prismui-color-1) !important;
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
rx.spacer(),
|
rx.spacer(),
|
||||||
rx.dialog.root(
|
rx.dialog.root(
|
||||||
# 触发事件:点击图标
|
|
||||||
rx.dialog.trigger(
|
rx.dialog.trigger(
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.tooltip(
|
rx.tooltip(
|
||||||
rx.icon(
|
rx.icon(
|
||||||
"plus",
|
"plus",
|
||||||
size=14,
|
width="14px",
|
||||||
color="var(--prismui-color-text)",
|
height="14px",
|
||||||
style={
|
style={
|
||||||
"_hover": {
|
"_hover": {
|
||||||
"color": "var(--devui-brand)",
|
"color": "var(--prismui-color-5)",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
content="新建会话",
|
content="新建会话",
|
||||||
background_color="#ffffff",
|
|
||||||
box_shadow="0 2px 12px 0 rgba(37, 43, 58, .24)",
|
|
||||||
color="#252b3a",
|
|
||||||
side="top",
|
side="top",
|
||||||
side_offset=9,
|
side_offset=9,
|
||||||
|
background_color="var(--prismui-background-color-1)",
|
||||||
|
box_shadow="var(--prismui-box-shadow-3)",
|
||||||
),
|
),
|
||||||
display="flex",
|
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",
|
justify_content="center",
|
||||||
align_items="center",
|
align_items="center",
|
||||||
|
width="24px",
|
||||||
|
height="24px",
|
||||||
|
background_color="var(--prismui-background-color-1)",
|
||||||
|
box_shadow="var(--prismui-box-shadow-8)",
|
||||||
|
border_radius="var(--prismui-border-radius-9)",
|
||||||
cursor="pointer",
|
cursor="pointer",
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
@ -623,103 +639,104 @@ def create_conversation_button() -> rx.Component:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def operation() -> rx.Component:
|
def user_prompt_sending() -> rx.Component:
|
||||||
"""
|
"""
|
||||||
操作区
|
用户提示词发送
|
||||||
:return: Component
|
:return: Component
|
||||||
"""
|
"""
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
# 自定义输入组件
|
rx.vstack(
|
||||||
rx.form(
|
rx.text_area(
|
||||||
rx.box(
|
# 值绑定用户提示词
|
||||||
rx.vstack(
|
value=ConversationState.user_prompt,
|
||||||
rx.hstack(
|
# 输入事件:设置用户提示词
|
||||||
rx.text_area(
|
on_change=ConversationState.set_user_prompt,
|
||||||
name="question",
|
placeholder="请输入您的问题,按Enter换行",
|
||||||
placeholder="请输入您的问题,按Enter换行",
|
vertical_align="middle",
|
||||||
vertical_align="middle",
|
width="100%",
|
||||||
width="100%",
|
height="64px",
|
||||||
height="64px",
|
padding="4px 0",
|
||||||
padding="4px 0",
|
background_color="var(--prismui-background-color-1)",
|
||||||
background_color="var(--devui-base-bg)",
|
border="none !important",
|
||||||
font_size="var(--devui-font-size)",
|
outline="none !important",
|
||||||
color="var(--prismui-color-text)",
|
box_shadow="none !important",
|
||||||
style={
|
|
||||||
"border": "none !important",
|
|
||||||
"outline": "none !important",
|
|
||||||
"boxShadow": "none !important",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
width="100%",
|
|
||||||
padding="0 16px",
|
|
||||||
),
|
|
||||||
rx.hstack(
|
|
||||||
rx.spacer(),
|
|
||||||
rx.button(
|
|
||||||
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="20pxvar(--devui-border-radius-4)",
|
|
||||||
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.running_status,
|
|
||||||
disabled=ConversationState.running_status,
|
|
||||||
),
|
|
||||||
width="100%",
|
|
||||||
justify_content="flex-end",
|
|
||||||
align_items="center",
|
|
||||||
height="32px",
|
|
||||||
padding="0 16px",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
style={
|
style={
|
||||||
"* textarea::placeholder": {
|
".rt-TextAreaInput": {
|
||||||
"fontFamily": "var(--font-family)",
|
"border": "none !important",
|
||||||
"fontSize": "var(--devui-font-size)",
|
"outline": "none !important",
|
||||||
"color": "var(--placeholder)",
|
"box-shadow": "none !important",
|
||||||
"opacity": 1,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
display="flex",
|
rx.hstack(
|
||||||
flex_direction="column",
|
rx.spacer(),
|
||||||
|
rx.button(
|
||||||
|
rx.icon(
|
||||||
|
"send",
|
||||||
|
margin_right="4px",
|
||||||
|
width="15px",
|
||||||
|
height="15px",
|
||||||
|
color="var(--prismui-color-9)",
|
||||||
|
),
|
||||||
|
rx.text(
|
||||||
|
"发送",
|
||||||
|
line_height="21px",
|
||||||
|
color="var(--prismui-color-9)",
|
||||||
|
),
|
||||||
|
loading=ConversationState.running_status,
|
||||||
|
# 是否禁用绑定用户提示词发送禁用状态
|
||||||
|
disabled=ConversationState.is_user_prompt_sending_disabled,
|
||||||
|
# 点击事件:发送用户提示词
|
||||||
|
on_click=ConversationState.handle_user_prompt,
|
||||||
|
display="inline-flex",
|
||||||
|
position="relative",
|
||||||
|
justify_content="center",
|
||||||
|
align_items="center",
|
||||||
|
padding="0 12px",
|
||||||
|
background_color=rx.cond(
|
||||||
|
ConversationState.is_user_prompt_sending_disabled,
|
||||||
|
"var(--prismui-color-11)",
|
||||||
|
"var(--prismui-color-5)",
|
||||||
|
),
|
||||||
|
border="none",
|
||||||
|
border_radius="var(--prismui-border-radius-5)",
|
||||||
|
inline_height="1.5",
|
||||||
|
font_size="var(--prismui-font-size-2)",
|
||||||
|
white_space="nowrap",
|
||||||
|
overflow="hidden",
|
||||||
|
cursor=rx.cond(
|
||||||
|
ConversationState.is_user_prompt_sending_disabled,
|
||||||
|
"not-allowed",
|
||||||
|
"pointer",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
width="100%",
|
||||||
|
justify_content="flex-end",
|
||||||
|
align_items="center",
|
||||||
|
height="32px",
|
||||||
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
padding="12px 0",
|
padding="12px 16px",
|
||||||
background_color="var(--devui-base-bg)",
|
background_color="var(--prismui-background-color-1)",
|
||||||
border="none",
|
border_radius="var(--prismui-border-radius-6)",
|
||||||
border_radius="16px",
|
box_shadow="var(--prismui-box-shadow-9)",
|
||||||
box_shadow="0 1px 8px 0 var(--mc-box-shadow)",
|
|
||||||
on_submit=ConversationState.run,
|
|
||||||
reset_on_submit=True,
|
|
||||||
),
|
),
|
||||||
# 底部文案
|
# 免责声明
|
||||||
rx.text(
|
rx.text(
|
||||||
"内容由大模型生成,无法确保准确性和完整性,仅供参考",
|
"内容由大模型生成,无法确保准确性和完整性,仅供参考",
|
||||||
margin_top="8px",
|
width="100%",
|
||||||
text_align="center",
|
text_align="center",
|
||||||
font_size="12px",
|
margin_top="8px",
|
||||||
color="var(--devui-aide-text)",
|
line_height="18px",
|
||||||
|
font_size="var(--prismui-font-size-1)",
|
||||||
|
color="var(--prismui-color-10)",
|
||||||
),
|
),
|
||||||
|
display="flex",
|
||||||
|
flex_direction="column",
|
||||||
width="100%",
|
width="100%",
|
||||||
max_width="1200px",
|
max_width="1200px",
|
||||||
padding="0 12px 12px",
|
padding="0 12px 12px",
|
||||||
align_items="center",
|
border="none",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -774,12 +791,12 @@ def conversation() -> rx.Component:
|
||||||
conversation_history(is_conversation_history_shown),
|
conversation_history(is_conversation_history_shown),
|
||||||
rx.box(
|
rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
# 对话历史
|
# 对话列表展示
|
||||||
dialogs(),
|
dialogs_showing(),
|
||||||
# 新建对话按钮
|
# 创建对话
|
||||||
create_conversation_button(),
|
create_conversation(),
|
||||||
# 操作区
|
# 用户提示词发送
|
||||||
operation(),
|
user_prompt_sending(),
|
||||||
display="flex",
|
display="flex",
|
||||||
flex_flow="column",
|
flex_flow="column",
|
||||||
width="100%",
|
width="100%",
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ def login_popup() -> rx.Component:
|
||||||
"登录解锁更多功能",
|
"登录解锁更多功能",
|
||||||
margin_bottom="24px",
|
margin_bottom="24px",
|
||||||
line_height="32px",
|
line_height="32px",
|
||||||
font_size="var(--prismui-font-size-3)",
|
font_size="var(--prismui-font-size-4)",
|
||||||
font_weight="var(--prismui-font-weight-3)",
|
font_weight="var(--prismui-font-weight-3)",
|
||||||
),
|
),
|
||||||
# 邮箱输入框
|
# 邮箱输入框
|
||||||
|
|
@ -281,7 +281,11 @@ def login_popup() -> rx.Component:
|
||||||
"var(--prismui-color-4)",
|
"var(--prismui-color-4)",
|
||||||
"var(--prismui-color-5)",
|
"var(--prismui-color-5)",
|
||||||
),
|
),
|
||||||
cursor="pointer",
|
cursor=rx.cond(
|
||||||
|
AuthState.is_captcha_sending_disabled,
|
||||||
|
"not-allowed",
|
||||||
|
"pointer",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
height="45px",
|
height="45px",
|
||||||
|
|
@ -390,7 +394,7 @@ def login_popup() -> rx.Component:
|
||||||
padding="20px",
|
padding="20px",
|
||||||
background_color="var(--prismui-background-color-1)",
|
background_color="var(--prismui-background-color-1)",
|
||||||
border="var(--prismui-border-2)",
|
border="var(--prismui-border-2)",
|
||||||
border_radius="var(--prismui-border-radius-5)",
|
border_radius="var(--prismui-border-radius-6)",
|
||||||
),
|
),
|
||||||
rx.text(
|
rx.text(
|
||||||
"加微信好友",
|
"加微信好友",
|
||||||
|
|
@ -407,7 +411,7 @@ def login_popup() -> rx.Component:
|
||||||
),
|
),
|
||||||
background="var(--prismui-background-2)",
|
background="var(--prismui-background-2)",
|
||||||
border="1px solid #2222220f",
|
border="1px solid #2222220f",
|
||||||
border_radius="var(--prismui-border-radius-5)",
|
border_radius="var(--prismui-border-radius-6)",
|
||||||
box_shadow="0 4px 64px 0 #0000001a",
|
box_shadow="0 4px 64px 0 #0000001a",
|
||||||
overflow="hidden",
|
overflow="hidden",
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,15 @@ class ConversationState(rx.State):
|
||||||
|
|
||||||
# 会话历史展示状态,True表示展示,False表示隐藏
|
# 会话历史展示状态,True表示展示,False表示隐藏
|
||||||
is_conversation_history_shown: bool = False
|
is_conversation_history_shown: bool = False
|
||||||
|
# 显示更多的会话唯一标识
|
||||||
|
shown_more_conversation_id: str = ""
|
||||||
|
|
||||||
# 会话创建状态,True表示正在创建,False表示未正在创建
|
# 会话创建状态,True表示正在创建,False表示未正在创建
|
||||||
is_conversation_creating: bool = False
|
is_conversation_creating: bool = False
|
||||||
|
|
||||||
|
# 用户提示词
|
||||||
|
user_prompt: str = ""
|
||||||
|
|
||||||
async def resume(self, user_id: str) -> None:
|
async def resume(self, user_id: str) -> None:
|
||||||
"""
|
"""
|
||||||
恢复当前用户会话状态
|
恢复当前用户会话状态
|
||||||
|
|
@ -112,22 +117,6 @@ class ConversationState(rx.State):
|
||||||
"""
|
"""
|
||||||
self.is_conversation_history_shown = not self.is_conversation_history_shown
|
self.is_conversation_history_shown = not self.is_conversation_history_shown
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def format_conversation_created_at(created_at: datetime) -> str:
|
|
||||||
"""
|
|
||||||
格式化会话创建时间
|
|
||||||
:param created_at: 会话创建时间
|
|
||||||
:return: 格式化后的会话创建时间
|
|
||||||
"""
|
|
||||||
match (datetime.now().date() - created_at.date()).days:
|
|
||||||
case 0:
|
|
||||||
formated_created_at = f"今天 {created_at.strftime('%H:%M')}"
|
|
||||||
case 1:
|
|
||||||
formated_created_at = f"昨天 {created_at.strftime('%H:%M')}"
|
|
||||||
case _:
|
|
||||||
formated_created_at = created_at.strftime("%Y-%m-%d %H:%M")
|
|
||||||
return formated_created_at
|
|
||||||
|
|
||||||
@rx.var
|
@rx.var
|
||||||
def conversation_history_items(self) -> List[ConversationHistoryItem]:
|
def conversation_history_items(self) -> List[ConversationHistoryItem]:
|
||||||
"""
|
"""
|
||||||
|
|
@ -138,17 +127,34 @@ class ConversationState(rx.State):
|
||||||
for conversation in reversed(
|
for conversation in reversed(
|
||||||
self.conversations.values()
|
self.conversations.values()
|
||||||
): # 按照会话唯一标识倒序排序
|
): # 按照会话唯一标识倒序排序
|
||||||
|
# 格式化会话创建时间
|
||||||
|
match (datetime.now().date() - conversation.created_at.date()).days:
|
||||||
|
case 0:
|
||||||
|
created_at = f"{conversation.created_at.strftime('%H:%M')}"
|
||||||
|
case 1:
|
||||||
|
created_at = f"昨天 {conversation.created_at.strftime('%H:%M')}"
|
||||||
|
case _:
|
||||||
|
created_at = conversation.created_at.strftime("%Y-%m-%d %H:%M")
|
||||||
|
|
||||||
items.append(
|
items.append(
|
||||||
ConversationHistoryItem(
|
ConversationHistoryItem(
|
||||||
id=conversation.id,
|
id=conversation.id,
|
||||||
description=conversation.description,
|
description=conversation.description,
|
||||||
created_at=self.format_conversation_created_at(
|
created_at=created_at,
|
||||||
created_at=conversation.created_at
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
@rx.event
|
||||||
|
def set_shown_more_conversation_id(
|
||||||
|
self, conversation_id: str, is_shown: bool
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
设置显示更多的会话唯一标识
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.shown_more_conversation_id = conversation_id if is_shown else ""
|
||||||
|
|
||||||
@rx.event
|
@rx.event
|
||||||
async def delete_conversation(self, conversation_id: str) -> None:
|
async def delete_conversation(self, conversation_id: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -212,6 +218,27 @@ class ConversationState(rx.State):
|
||||||
"""
|
"""
|
||||||
self.is_conversation_creating = not self.is_conversation_creating
|
self.is_conversation_creating = not self.is_conversation_creating
|
||||||
|
|
||||||
|
@rx.event
|
||||||
|
def set_user_prompt(self, user_prompt: str) -> None:
|
||||||
|
"""
|
||||||
|
设置用户提示词
|
||||||
|
:param user_prompt: 用户提示词
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.user_prompt = user_prompt.strip()
|
||||||
|
|
||||||
|
@rx.var
|
||||||
|
def is_user_prompt_sending_disabled(self) -> bool:
|
||||||
|
"""
|
||||||
|
用户提示词发送禁用状态
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
# 当前会话
|
||||||
|
conversation = self.conversations.get(self.conversation_id)
|
||||||
|
if not conversation:
|
||||||
|
return True
|
||||||
|
return conversation.is_running or not self.user_prompt
|
||||||
|
|
||||||
@rx.var
|
@rx.var
|
||||||
def running_status(self) -> bool:
|
def running_status(self) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|
@ -227,7 +254,7 @@ class ConversationState(rx.State):
|
||||||
@rx.var
|
@rx.var
|
||||||
def dialogs(self) -> List[Dialog]:
|
def dialogs(self) -> List[Dialog]:
|
||||||
"""
|
"""
|
||||||
获取当前会话的对话列表
|
当前会话的对话列表
|
||||||
:return: 当前会话的对话列表
|
:return: 当前会话的对话列表
|
||||||
"""
|
"""
|
||||||
# 当前会话
|
# 当前会话
|
||||||
|
|
@ -237,17 +264,18 @@ class ConversationState(rx.State):
|
||||||
return list(conversation.dialogs.values())
|
return list(conversation.dialogs.values())
|
||||||
|
|
||||||
@rx.event
|
@rx.event
|
||||||
async def run(self, form_data: dict[str, Any]) -> AsyncGenerator[None]:
|
async def handle_user_prompt(self) -> AsyncGenerator[None]:
|
||||||
"""
|
"""
|
||||||
运行
|
处理用户提示词
|
||||||
:param form_data: 表单数据
|
:return: AsyncGenerator[None]
|
||||||
:return: AsyncGenerator
|
|
||||||
"""
|
"""
|
||||||
# 解析用户提示词
|
if not self.user_prompt:
|
||||||
user_prompt = form_data["user_prompt"].strip()
|
|
||||||
if not user_prompt:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 清空前端用户提示词
|
||||||
|
user_prompt = self.user_prompt
|
||||||
|
self.user_prompt = ""
|
||||||
|
|
||||||
# 当前会话
|
# 当前会话
|
||||||
conversation = self.conversations[self.conversation_id]
|
conversation = self.conversations[self.conversation_id]
|
||||||
# 将当前会话的运行状态设置为正在运行
|
# 将当前会话的运行状态设置为正在运行
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"""
|
"""
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from random import choices
|
from random import choices
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List
|
||||||
|
|
||||||
from pydantic import TypeAdapter
|
from pydantic import TypeAdapter
|
||||||
from pydantic_ai import ModelMessage, ModelMessagesTypeAdapter
|
from pydantic_ai import ModelMessage, ModelMessagesTypeAdapter
|
||||||
|
|
@ -106,8 +106,8 @@ class DialogRecord(SQLModel, table=True):
|
||||||
)
|
)
|
||||||
conversation_id: str = Field(..., index=True, description="会话唯一标识")
|
conversation_id: str = Field(..., index=True, description="会话唯一标识")
|
||||||
user_prompt: str = Field(..., description="用户提示词")
|
user_prompt: str = Field(..., description="用户提示词")
|
||||||
thoughts: List[ThoughtRecord] = Field(
|
thoughts: Dict[int, ThoughtRecord] = Field(
|
||||||
default_factory=List, sa_type=JSON, description="思考列表"
|
default_factory=dict, sa_type=JSON, description="思考列表"
|
||||||
)
|
)
|
||||||
result_output: str = Field(default="", description="结果输出")
|
result_output: str = Field(default="", description="结果输出")
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ class ResultRecord(SQLModel, table=True):
|
||||||
|
|
||||||
|
|
||||||
# 思考领域模型类型适配器
|
# 思考领域模型类型适配器
|
||||||
ThoughtTypeAdapter = TypeAdapter(List[Thought])
|
ThoughtTypeAdapter = TypeAdapter(Dict[int, Thought])
|
||||||
|
|
||||||
|
|
||||||
class DatabaseState(rx.State):
|
class DatabaseState(rx.State):
|
||||||
|
|
@ -282,7 +282,7 @@ class DatabaseState(rx.State):
|
||||||
|
|
||||||
async def create_dialog_record(
|
async def create_dialog_record(
|
||||||
self, conversation_id: str, user_prompt: str
|
self, conversation_id: str, user_prompt: str
|
||||||
) -> Dialog:
|
) -> Dict[str, Dialog]:
|
||||||
"""
|
"""
|
||||||
创建对话记录
|
创建对话记录
|
||||||
:param conversation_id: 会话唯一标识
|
:param conversation_id: 会话唯一标识
|
||||||
|
|
@ -297,12 +297,12 @@ class DatabaseState(rx.State):
|
||||||
session.add(record)
|
session.add(record)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
await session.refresh(record)
|
await session.refresh(record)
|
||||||
return Dialog(id=record.id, user_prompt=user_prompt)
|
return {record.id: Dialog(id=record.id, user_prompt=user_prompt)}
|
||||||
|
|
||||||
async def complete_dialog_record(
|
async def complete_dialog_record(
|
||||||
self,
|
self,
|
||||||
id: str,
|
id: str,
|
||||||
thoughts: List[Thought],
|
thoughts: Dict[int, Thought],
|
||||||
result_output: str,
|
result_output: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@
|
||||||
--prismui-background-color-6: #f2f2f3;
|
--prismui-background-color-6: #f2f2f3;
|
||||||
--prismui-background-1: linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%);
|
--prismui-background-1: linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%);
|
||||||
--prismui-background-2: linear-gradient(180deg, #fffffff2, #f8fafff2 99%);
|
--prismui-background-2: linear-gradient(180deg, #fffffff2, #f8fafff2 99%);
|
||||||
|
--prismui-background-3: linear-gradient(to right, #f3efff, #f3efff33, #e2f1fd33, #e2f1fd);
|
||||||
--prismui-font-family: HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei;
|
--prismui-font-family: HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei;
|
||||||
--prismui-font-size-1: 12px;
|
--prismui-font-size-1: 12px;
|
||||||
--prismui-font-size-2: 14px;
|
--prismui-font-size-2: 14px;
|
||||||
--prismui-font-size-3: 20px;
|
--prismui-font-size-3: 16px;
|
||||||
|
--prismui-font-size-4: 20px;
|
||||||
--prismui-font-weight-1: normal;
|
--prismui-font-weight-1: normal;
|
||||||
--prismui-font-weight-2: 500;
|
--prismui-font-weight-2: 500;
|
||||||
--prismui-font-weight-3: 700;
|
--prismui-font-weight-3: 700;
|
||||||
|
|
@ -21,17 +23,27 @@
|
||||||
--prismui-color-5: #5e7ce0;
|
--prismui-color-5: #5e7ce0;
|
||||||
--prismui-color-6: #f66f6a;
|
--prismui-color-6: #f66f6a;
|
||||||
--prismui-color-7: #f2f2f3;
|
--prismui-color-7: #f2f2f3;
|
||||||
|
--prismui-color-8: #aeaeae;
|
||||||
--prismui-color-9: #ffffff;
|
--prismui-color-9: #ffffff;
|
||||||
|
--prismui-color-10: #71757f;
|
||||||
|
--prismui-color-11: #beccfa;
|
||||||
--prismui-border-1: 1px solid #060a260f;
|
--prismui-border-1: 1px solid #060a260f;
|
||||||
--prismui-border-radius-1: 4px;
|
--prismui-border-radius-1: 4px;
|
||||||
--prismui-border-radius-2: 6px;
|
--prismui-border-radius-2: 6px;
|
||||||
--prismui-border-radius-3: 8px;
|
--prismui-border-radius-3: 8px;
|
||||||
--prismui-border-radius-4: 12px;
|
--prismui-border-radius-4: 12px;
|
||||||
--prismui-border-radius-5: 20px;
|
--prismui-border-radius-5: 16px;
|
||||||
|
--prismui-border-radius-6: 20px;
|
||||||
|
--prismui-border-radius-7: 24px;
|
||||||
|
--prismui-border-radius-9: 100px;
|
||||||
--prismui-box-shadow-1: 0 4px 64px 0 #0000001a;
|
--prismui-box-shadow-1: 0 4px 64px 0 #0000001a;
|
||||||
--prismui-box-shadow-2: 0 4px 12px #0000001a;
|
--prismui-box-shadow-2: 0 4px 12px #0000001a;
|
||||||
--prismui-box-shadow-3: 0 2px 12px 0 #252b3a3d;
|
--prismui-box-shadow-3: 0 2px 12px 0 #252b3a3d;
|
||||||
--prismui-box-shadow-4: 2px 0 4px 0 #d5d5d540;
|
--prismui-box-shadow-4: 2px 0 4px 0 #d5d5d540;
|
||||||
--prismui-box-shadow-5: -2px -2px 4px #0000000d;
|
--prismui-box-shadow-5: -2px -2px 4px #0000000d;
|
||||||
|
--prismui-box-shadow-6: 0 2px 12px #00000019;
|
||||||
|
--prismui-box-shadow-7: 2px 2px 8px #e9e9e9;
|
||||||
|
--prismui-box-shadow-8:0 1px 8px #1919190f;
|
||||||
|
--prismui-box-shadow-9: 0 1px 8px 0 #1919190f;
|
||||||
background-color: var(--prismui-background-color-1);
|
background-color: var(--prismui-background-color-1);
|
||||||
}
|
}
|
||||||
Binary file not shown.
Loading…
Reference in New Issue