This commit is contained in:
liubiren 2026-10-14 20:54:23 +08:00
parent c76b69f18a
commit 4d4093a199
4 changed files with 72 additions and 156 deletions

View File

@ -13,82 +13,6 @@ from application.states.models import (
) )
def task_history_item(
item: TaskHistoryItem,
) -> rx.Component:
"""
任务历史项
:param item: 任务历史项
:return: rx.Component
"""
# 高亮
is_highlight = (item.id == TaskState.popover_shown_task_history_item_id) | (
item.id == TaskState.task_id
)
return rx.hstack(
# 渲染任务历史项的任务描述
rx.text(
item.description,
line_height="20px",
padding_right="18px",
color="var(--prismui-color-2)",
text_overflow="ellipsis",
white_space="nowrap",
cursor="inherit",
),
align_items="center",
width="100%",
cursor="pointer",
on_click=lambda: TaskState.set_task_id(item.id),
)
def task_history() -> rx.Component:
"""
任务历史
:return: rx.Component
"""
return rx.vstack(
# 任务历史的标题
rx.hstack(
rx.text(
"任务历史",
margin_bottom="8px",
font_weight="var(--prismui-font-weight-3)",
white_space="nowrap",
),
align_items="center",
justify_content="space-between",
),
rx.auto_scroll(
rx.foreach(
TaskState.task_history,
# 渲染任务历史项
task_history_item,
),
flex="1",
align_items="stretch",
width="100%",
margin_top="8px",
style={
"&::-webkit-scrollbar": {
"display": "none",
},
},
overflow="auto",
),
display="flex",
flex_direction="column",
height="100%",
padding="12px",
background_color="#f9f9f9cc",
backdrop_filter="blur(50px)",
gap="12px",
)
def workflow_button(workflow_type: WorkflowType): def workflow_button(workflow_type: WorkflowType):
""" """
工作流按钮 工作流按钮

View File

@ -73,39 +73,55 @@ def task_history_item(
:return: Component :return: Component
""" """
# 高亮 # 悬停状态
is_highlight = (item.id == TaskState.popover_shown_task_history_item_id) | ( is_hovered = item.id == TaskState.hovered_task_id
item.id == TaskState.task_id
)
# 若悬停状态为是则渲染任务描述和更多图标,否则:若运行状态为是则渲染正在运行图标,否则不渲染;同时渲染任务描述和上一次运行日期时间
return rx.list.item( return rx.list.item(
rx.hstack( rx.cond(
# 渲染任务正在运行图标 is_hovered,
rx.cond( rx.hstack(
item.is_running, rx.text(
rx.icon( item.description,
"play", width="14px", height="14px", color="var(--prismui-color-2)" line_height="20px",
color="var(--prismui-color-2)",
text_overflow="ellipsis",
white_space="nowrap",
), ),
rx.fragment(), rx.icon("ellipsis"),
width="100%",
padding="5px 12px",
), ),
# 渲染任务描述 rx.hstack(
rx.text( rx.cond(item.is_running, rx.image("/is_running.svg"), rx.fragment()),
item.description, # 渲染任务描述
flex=1, rx.text(
line_height="20px", item.description,
color="var(--prismui-color-2)", flex=1,
text_overflow="ellipsis", min_width="0", # 自适应宽度
white_space="nowrap", line_height="20px",
overflow="hidden", color="var(--prismui-color-2)",
white_space="nowrap", # 禁止换行
overflow="hidden",
mask_image="linear-gradient(to right, white calc(100% - 24px), transparent 100%)", # 添加蒙版
),
# 渲染上一次运行日期时间
rx.text(
item.last_run_at,
line_height="20px",
font_size="calc(var(--prismui-font-size-1) - 1px)",
color="var(--prismui-color-2)",
flex_shrink=0, # 禁止缩放
),
gap="8px",
width="100%",
padding="5px 12px",
), ),
display="flex",
align_items="center",
width="100%",
padding="5px 0",
# 点击事件:将指定任务唯一标识设置为当前任务唯一标识
on_click=lambda: TaskState.set_task_id(item.id),
), ),
width="100%", width="100%",
cursor="pointer",
# 点击事件:将指定任务唯一标识设置为当前任务唯一标识
on_click=lambda: TaskState.set_task_id(item.id),
) )

View File

@ -35,22 +35,6 @@ from application.states.models import (
from application.workshop.events import AgentRuntimeEvent from application.workshop.events import AgentRuntimeEvent
def format_datetime(datetime: datetime) -> str:
"""
格式化日期时间
:param datetime: 日期时间
:return: 格式化后日期时间字符串
"""
match (datetime.now().date() - datetime.date()).days:
case 0:
formatted_datetime = f"{datetime.strftime('%H:%M')}"
case 1:
formatted_datetime = f"昨天 {datetime.strftime('%H:%M')}"
case _:
formatted_datetime = datetime.strftime("%Y-%m-%d %H:%M")
return formatted_datetime
class TaskState(rx.State): class TaskState(rx.State):
""" """
任务状态 任务状态
@ -64,8 +48,8 @@ class TaskState(rx.State):
# 当前任务唯一标识 # 当前任务唯一标识
task_id: str = "" task_id: str = ""
# 悬停气泡显示的任务历史项唯一标识(一个任务只允许存在一个悬停气泡任务历史项) # 鼠标悬停的任务唯一标识
popover_shown_task_history_item_id: str = "" hovered_task_id: str = ""
# 当前数据库状态(私有变量) # 当前数据库状态(私有变量)
# 私有变量:reflex 约定以 _ 开头的变量为私有变量,后端不序列化,前端不可使用 # 私有变量:reflex 约定以 _ 开头的变量为私有变量,后端不序列化,前端不可使用
@ -97,9 +81,7 @@ class TaskState(rx.State):
self.tasks = await db_state.read_tasks(self.user_id) self.tasks = await db_state.read_tasks(self.user_id)
# 若当前用户的任务字典为空则先创建任务记录再添加任务 # 若当前用户的任务字典为空则先创建任务记录再添加任务
if not self.tasks: if not self.tasks:
self.tasks.update( self.tasks.update(await db_state.create_task_record(self.user_id))
await db_state.create_task_record(self.user_id)
)
# 将最后一个任务的唯一标识作为当前任务唯一标识 # 将最后一个任务的唯一标识作为当前任务唯一标识
self.task_id = next(reversed(self.tasks.keys())) self.task_id = next(reversed(self.tasks.keys()))
@ -116,34 +98,42 @@ class TaskState(rx.State):
task.is_running = True task.is_running = True
message.is_running = True message.is_running = True
@rx.event
def toggle_task_history_shown(self) -> None:
"""
显示 / 隐藏任务历史
:return: None
"""
self.is_task_history_shown = not self.is_task_history_shown
@rx.var @rx.var
def task_history(self) -> list[TaskHistoryItem]: def task_history(self) -> list[TaskHistoryItem]:
""" """
获取任务历史项列表(按照任务创建日期时间降序排序) 获取任务历史项列表(按照任务创建日期时间降序排序)
:return: 任务历史项列表 :return: 任务历史项列表
""" """
def formatter(datetime: datetime) -> str:
"""
格式器
:param datetime: 日期时间
:return: 格式化后日期时间字符串
"""
# 时间间隔
delta = (datetime.now().date() - datetime.date()).total_seconds()
if delta < 60:
return f"刚刚"
elif delta < 60 * 60:
return f"{round(delta / 60)}分钟前"
elif delta < 60 * 60 * 24:
return f"{round(delta / 60 / 60)}小时前"
else:
return f"{round(delta / 60 / 60 / 24)}天前"
return [ return [
TaskHistoryItem( TaskHistoryItem(
id=task.id, id=task.id,
description=task.description, description=task.description,
last_run_at=format_datetime(task.last_run_at), last_run_at=formatter(task.last_run_at),
is_running=task.is_running, is_running=task.is_running,
) )
for task in reversed(self.tasks.values()) for task in reversed(self.tasks.values())
] ]
@rx.event @rx.event
def set_task_history_item_popover_shown( def set_task_history_item_popover_shown(self, item_id: str, is_shown: bool) -> None:
self, item_id: str, is_shown: bool
) -> None:
""" """
设置会话历史项悬停气泡显示 / 隐藏 设置会话历史项悬停气泡显示 / 隐藏
:return: None :return: None
@ -165,9 +155,7 @@ class TaskState(rx.State):
# 删除后,若当前用户的任务字典为空则创建任务 # 删除后,若当前用户的任务字典为空则创建任务
if not self.tasks: if not self.tasks:
self.tasks.update( self.tasks.update(await db_state.create_task_record(self.user_id))
await db_state.create_task_record(self.user_id)
)
# 删除后,若当前任务唯一标识不存在则将最后一个任务的唯一标识作为当前任务唯一标识 # 删除后,若当前任务唯一标识不存在则将最后一个任务的唯一标识作为当前任务唯一标识
if self.task_id not in self.tasks: if self.task_id not in self.tasks:
@ -213,9 +201,7 @@ class TaskState(rx.State):
# 获取当前数据库状态 # 获取当前数据库状态
db_state = await self.get_db_state() db_state = await self.get_db_state()
# 创建任务记录再添加任务 # 创建任务记录再添加任务
self.tasks.update( self.tasks.update(await db_state.create_task_record(self.user_id))
await db_state.create_task_record(self.user_id)
)
# 将最后一个任务的唯一标识作为当前任务唯一标识 # 将最后一个任务的唯一标识作为当前任务唯一标识
self.task_id = next(reversed(self.tasks.keys())) self.task_id = next(reversed(self.tasks.keys()))
@ -337,9 +323,7 @@ class TaskState(rx.State):
index_map_to_message_id: dict[int, str] = {} index_map_to_message_id: dict[int, str] = {}
# 查询消息历史列表 # 查询消息历史列表
message_history = await db_state.read_message_history( message_history = await db_state.read_message_history(task_id=self.task_id)
task_id=self.task_id
)
# 使用量 # 使用量
usage = task.usage usage = task.usage
@ -490,9 +474,7 @@ class TaskState(rx.State):
content_delta=content_delta, content_delta=content_delta,
provider_details=provider_details, provider_details=provider_details,
): ):
message = task.messages[ message = task.messages[index_map_to_message_id[index]]
index_map_to_message_id[index]
]
# 若内容增量非空则将内容追加至消息内容,否则若供应商详情可调用更新消息内容 # 若内容增量非空则将内容追加至消息内容,否则若供应商详情可调用更新消息内容
if content_delta: if content_delta:
message.content += content_delta message.content += content_delta
@ -519,9 +501,7 @@ class TaskState(rx.State):
case TextPartDelta( case TextPartDelta(
content_delta=content_delta, content_delta=content_delta,
): ):
message = task.messages[ message = task.messages[index_map_to_message_id[index]]
index_map_to_message_id[index]
]
# 增量更新 # 增量更新
message.content += content_delta message.content += content_delta
yield # 通知前端更新渲染 yield # 通知前端更新渲染
@ -535,9 +515,7 @@ class TaskState(rx.State):
# 思考分片 # 思考分片
case ThinkingPart(): case ThinkingPart():
# 获取消息 # 获取消息
message = task.messages[ message = task.messages[index_map_to_message_id[index]]
index_map_to_message_id[index]
]
message.is_running = False message.is_running = False
message.title = "思考已完成" message.title = "思考已完成"
yield # 通知前端更新渲染 yield # 通知前端更新渲染
@ -546,9 +524,7 @@ class TaskState(rx.State):
# 文本分片 # 文本分片
case TextPart(): case TextPart():
# 获取消息 # 获取消息
message = task.messages[ message = task.messages[index_map_to_message_id[index]]
index_map_to_message_id[index]
]
messages.append(message) messages.append(message)
# ========== 工具调用结果事件 ========== # ========== 工具调用结果事件 ==========

Binary file not shown.