This commit is contained in:
parent
bcd2616d11
commit
09f3ff2cc2
|
|
@ -0,0 +1,58 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: e41b99574371
|
||||
Revises: 3e4ccabe44c3
|
||||
Create Date: 2026-10-12 16:52:21.920854
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'e41b99574371'
|
||||
down_revision: Union[str, Sequence[str], None] = '3e4ccabe44c3'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('messagerecord', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_messagerecord_conversation_id'))
|
||||
batch_op.create_index(batch_op.f('ix_messagerecord_task_id'), ['task_id'], unique=False)
|
||||
|
||||
with op.batch_alter_table('runrecord', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_runrecord_conversation_id'))
|
||||
batch_op.create_index(batch_op.f('ix_runrecord_task_id'), ['task_id'], unique=False)
|
||||
|
||||
with op.batch_alter_table('taskrecord', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_conversationrecord_is_deleted'))
|
||||
batch_op.drop_index(batch_op.f('ix_conversationrecord_user_id'))
|
||||
batch_op.create_index(batch_op.f('ix_taskrecord_is_deleted'), ['is_deleted'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_taskrecord_user_id'), ['user_id'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('taskrecord', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_taskrecord_user_id'))
|
||||
batch_op.drop_index(batch_op.f('ix_taskrecord_is_deleted'))
|
||||
batch_op.create_index(batch_op.f('ix_conversationrecord_user_id'), ['user_id'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_conversationrecord_is_deleted'), ['is_deleted'], unique=False)
|
||||
|
||||
with op.batch_alter_table('runrecord', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_runrecord_task_id'))
|
||||
batch_op.create_index(batch_op.f('ix_runrecord_conversation_id'), ['task_id'], unique=False)
|
||||
|
||||
with op.batch_alter_table('messagerecord', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_messagerecord_task_id'))
|
||||
batch_op.create_index(batch_op.f('ix_messagerecord_conversation_id'), ['task_id'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -23,48 +23,30 @@ def task_history_item(
|
|||
"""
|
||||
|
||||
# 高亮
|
||||
is_highlight = (
|
||||
item.id == TaskState.popover_shown_task_history_item_id
|
||||
) | (item.id == TaskState.task_id)
|
||||
is_highlight = (item.id == TaskState.popover_shown_task_history_item_id) | (
|
||||
item.id == TaskState.task_id
|
||||
)
|
||||
|
||||
return rx.list.item(
|
||||
rx.vstack(
|
||||
rx.hstack(
|
||||
# 会话历史项的会话描述
|
||||
rx.text(
|
||||
item.description,
|
||||
flex=1,
|
||||
height="22px",
|
||||
line_height="22px",
|
||||
padding_right="18px",
|
||||
color="var(--prismui-color-2)",
|
||||
text_overflow="ellipsis",
|
||||
white_space="nowrap",
|
||||
overflow="hidden",
|
||||
),
|
||||
display="flex",
|
||||
align_items="center",
|
||||
width="100%",
|
||||
margin_bottom="8px",
|
||||
),
|
||||
rx.hstack(
|
||||
rx.spacer(),
|
||||
# 会话历史项的会话创建日期时间
|
||||
rx.text(
|
||||
item.created_at,
|
||||
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",
|
||||
rx.hstack(
|
||||
# 会话历史项的会话描述
|
||||
rx.text(
|
||||
item.description,
|
||||
flex=1,
|
||||
height="22px",
|
||||
line_height="22px",
|
||||
padding_right="18px",
|
||||
color="var(--prismui-color-2)",
|
||||
text_overflow="ellipsis",
|
||||
white_space="nowrap",
|
||||
overflow="hidden",
|
||||
),
|
||||
display="flex",
|
||||
align_items="center",
|
||||
width="100%",
|
||||
margin_bottom="8px",
|
||||
# 点击事件:设置激活任务
|
||||
on_click=lambda: TaskState.set_task(item.id),
|
||||
width="100%",
|
||||
),
|
||||
# 会话历史项的更多按钮
|
||||
rx.box(
|
||||
|
|
@ -95,9 +77,7 @@ def task_history_item(
|
|||
rx.box(
|
||||
"删除",
|
||||
# 点击事件:删除任务
|
||||
on_click=lambda: TaskState.delete_task(
|
||||
item.id
|
||||
),
|
||||
on_click=lambda: TaskState.delete_task(item.id),
|
||||
display="flex",
|
||||
align_items="center",
|
||||
justify_content="center",
|
||||
|
|
@ -225,6 +205,7 @@ def task_history(
|
|||
overflow="hidden",
|
||||
)
|
||||
|
||||
|
||||
def conversation_history(
|
||||
is_conversation_history_shown: bool,
|
||||
) -> rx.Component:
|
||||
|
|
@ -452,9 +433,7 @@ def thinking(item: MessageHistoryItem) -> rx.Component:
|
|||
line_height="22px",
|
||||
),
|
||||
# 点击事件,展示 / 隐藏消息历史项
|
||||
on_click=lambda: TaskState.toggle_message_history_item_shown(
|
||||
item.id
|
||||
),
|
||||
on_click=lambda: TaskState.toggle_message_history_item_shown(item.id),
|
||||
cursor="pointer",
|
||||
),
|
||||
# 思考的内容
|
||||
|
|
@ -515,9 +494,7 @@ def tool_call(item: MessageHistoryItem) -> rx.Component:
|
|||
line_height="22px",
|
||||
),
|
||||
# 点击事件,展示 / 隐藏消息历史项
|
||||
on_click=lambda: TaskState.toggle_message_history_item_shown(
|
||||
item.id
|
||||
),
|
||||
on_click=lambda: TaskState.toggle_message_history_item_shown(item.id),
|
||||
cursor="pointer",
|
||||
),
|
||||
rx.box(
|
||||
|
|
@ -769,9 +746,7 @@ def message_history() -> rx.Component:
|
|||
rx.vstack(
|
||||
rx.auto_scroll(
|
||||
rx.vstack(
|
||||
rx.foreach(
|
||||
TaskState.message_history, message_history_item
|
||||
),
|
||||
rx.foreach(TaskState.message_history, message_history_item),
|
||||
# 若等待流式输出则显示加载动效
|
||||
rx.cond(
|
||||
TaskState.awaiting_stream,
|
||||
|
|
@ -1072,7 +1047,6 @@ def create_task_page() -> rx.Component:
|
|||
)
|
||||
|
||||
|
||||
|
||||
def conversation_page() -> rx.Component:
|
||||
"""
|
||||
会话页面:布局参考 MetaChat,从左到右分别为会话历史和工作区。其中,工作区从上到下分别为消息历史和用户提示词输入框。
|
||||
|
|
@ -1114,4 +1088,4 @@ def conversation_page() -> rx.Component:
|
|||
height="100%",
|
||||
border_radius="var(--prismui-border-radius-4)",
|
||||
overflow="hidden",
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -76,45 +76,35 @@ def task_history_item(
|
|||
)
|
||||
|
||||
return rx.list.item(
|
||||
rx.vstack(
|
||||
rx.hstack(
|
||||
# 会话历史项的会话描述
|
||||
rx.text(
|
||||
item.description,
|
||||
flex=1,
|
||||
height="22px",
|
||||
line_height="22px",
|
||||
padding_right="18px",
|
||||
color="var(--prismui-color-2)",
|
||||
text_overflow="ellipsis",
|
||||
white_space="nowrap",
|
||||
overflow="hidden",
|
||||
rx.hstack(
|
||||
# 渲染任务正在运行图标
|
||||
rx.cond(
|
||||
item.is_running,
|
||||
rx.icon(
|
||||
"play", width="14px", height="14px", color="var(--prismui-color-2)"
|
||||
),
|
||||
display="flex",
|
||||
align_items="center",
|
||||
width="100%",
|
||||
margin_bottom="8px",
|
||||
rx.fragment(),
|
||||
),
|
||||
rx.hstack(
|
||||
rx.spacer(),
|
||||
# 会话历史项的会话创建日期时间
|
||||
rx.text(
|
||||
item.created_at,
|
||||
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",
|
||||
# 渲染任务描述
|
||||
rx.text(
|
||||
item.description,
|
||||
flex=1,
|
||||
height="22px",
|
||||
line_height="22px",
|
||||
padding_right="18px",
|
||||
color="var(--prismui-color-2)",
|
||||
text_overflow="ellipsis",
|
||||
white_space="nowrap",
|
||||
overflow="hidden",
|
||||
),
|
||||
display="flex",
|
||||
align_items="center",
|
||||
width="100%",
|
||||
margin_bottom="8px",
|
||||
# 点击事件:设置激活任务
|
||||
on_click=lambda: TaskState.set_task(item.id),
|
||||
width="100%",
|
||||
),
|
||||
# 会话历史项的更多按钮
|
||||
# 任务更多按钮
|
||||
rx.box(
|
||||
rx.popover.root(
|
||||
rx.popover.trigger(
|
||||
|
|
@ -371,6 +361,7 @@ def sidebar() -> rx.Component:
|
|||
font_size="var(--prismui-font-size-2)",
|
||||
padding="0 0 0 10px",
|
||||
),
|
||||
task_history(),
|
||||
padding="0 12px",
|
||||
),
|
||||
align_items="flex-start",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
数据库状态
|
||||
|
||||
更新数据库方法:
|
||||
1. reflex db makemigrations
|
||||
2. reflex db migrate
|
||||
"""
|
||||
from dataclasses import asdict
|
||||
from datetime import datetime, timedelta
|
||||
|
|
@ -79,8 +83,8 @@ class TaskRecord(SQLModel, table=True):
|
|||
)
|
||||
user_id: str = Field(..., index=True, description="用户唯一标识")
|
||||
description: str = Field(default="新任务", description="任务描述")
|
||||
created_at: datetime = Field(
|
||||
default_factory=datetime.now, description="任务创建时间"
|
||||
last_run_at: datetime = Field(
|
||||
default_factory=datetime.now, description="上一次运行日期时间"
|
||||
)
|
||||
is_deleted: bool = Field(
|
||||
default=False,
|
||||
|
|
@ -222,7 +226,7 @@ class DatabaseState(rx.State):
|
|||
usage=usage_validate_json(
|
||||
record.usage
|
||||
), # 将 record.usage 由 JSON 字符串反序列化为 RunUsage
|
||||
created_at=record.created_at,
|
||||
last_run_at=record.last_run_at,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -252,10 +256,10 @@ class DatabaseState(rx.State):
|
|||
Task(
|
||||
id=task_record.id,
|
||||
description=task_record.description,
|
||||
last_run_at=task_record.last_run_at,
|
||||
usage=usage_validate_json(
|
||||
task_record.usage
|
||||
), # 将 task_record.usage 由 JSON 字符串反序列化为 RunUsage
|
||||
created_at=task_record.created_at,
|
||||
workflow=workflow_validate_json(
|
||||
task_record.workflow
|
||||
), # 将 task_record.workflow 由 JSON 字符串反序列化为 Workflow,
|
||||
|
|
@ -277,27 +281,31 @@ class DatabaseState(rx.State):
|
|||
|
||||
async def update_task_record(
|
||||
self,
|
||||
task_id: str,
|
||||
id: str,
|
||||
description: str | None = None,
|
||||
last_run_at: datetime | None = None,
|
||||
is_deleted: bool | None = None,
|
||||
usage: RunUsage | None = None,
|
||||
workflow: Workflow | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
更新任务记录
|
||||
:param task_id: 指定任务唯一标识
|
||||
:param id: 任务唯一标识
|
||||
:param description: 任务描述
|
||||
:param last_run_at: 上一次运行日期时间
|
||||
:param is_deleted: 任务已删除
|
||||
:param usage: 使用量
|
||||
:param workflow: 工作流
|
||||
:return: None
|
||||
"""
|
||||
async with rx.asession() as session:
|
||||
record = await session.get(TaskRecord, task_id)
|
||||
record = await session.get(TaskRecord, id)
|
||||
if not record:
|
||||
return
|
||||
if isinstance(description, str):
|
||||
record.description = description
|
||||
if isinstance(last_run_at, datetime):
|
||||
record.last_run_at = last_run_at
|
||||
if isinstance(is_deleted, bool):
|
||||
record.is_deleted = is_deleted
|
||||
if isinstance(usage, RunUsage):
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class Task(BaseModel):
|
|||
|
||||
id: str = Field(..., description="任务唯一标识")
|
||||
description: str = Field(..., description="任务描述")
|
||||
created_at: datetime = Field(..., description="任务创建日期时间")
|
||||
last_run_at: datetime = Field(..., description="上一次运行日期时间")
|
||||
usage: RunUsage = Field(..., description="任务使用量")
|
||||
messages: dict[str, Message] = Field(default_factory=dict, description="消息字典")
|
||||
workflow: Workflow = Field(default_factory=Workflow, description="工作,默认为对话")
|
||||
|
|
@ -105,7 +105,10 @@ class TaskHistoryItem(BaseModel):
|
|||
|
||||
id: str = Field(..., description="任务唯一标识")
|
||||
description: str = Field(..., description="任务描述")
|
||||
created_at: str = Field(..., description="任务创建日期时间")
|
||||
last_run_at: str = Field(..., description="上一次运行日期时间")
|
||||
is_running: bool = Field(
|
||||
default=False, description="正在运行,True 表示正在运行, False 表示运行结束"
|
||||
)
|
||||
|
||||
|
||||
class MessageHistoryItem(Message):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
会话状态
|
||||
任务状态
|
||||
"""
|
||||
from datetime import date as Date, datetime
|
||||
from typing import AsyncGenerator
|
||||
|
|
@ -35,20 +35,20 @@ from application.states.models import (
|
|||
from application.workshop.events import AgentRuntimeEvent
|
||||
|
||||
|
||||
def format_conversation_created_at(created_at: datetime) -> str:
|
||||
def format_datetime(datetime: datetime) -> str:
|
||||
"""
|
||||
格式化会话创建日期时间
|
||||
:param created_at: 创建日期时间
|
||||
:return: 格式化后的日期时间字符串
|
||||
格式化日期时间
|
||||
:param datetime: 日期时间
|
||||
:return: 格式化后日期时间字符串
|
||||
"""
|
||||
match (datetime.now().date() - created_at.date()).days:
|
||||
match (datetime.now().date() - datetime.date()).days:
|
||||
case 0:
|
||||
formatted_created_at = f"{created_at.strftime('%H:%M')}"
|
||||
formatted_datetime = f"{datetime.strftime('%H:%M')}"
|
||||
case 1:
|
||||
formatted_created_at = f"昨天 {created_at.strftime('%H:%M')}"
|
||||
formatted_datetime = f"昨天 {datetime.strftime('%H:%M')}"
|
||||
case _:
|
||||
formatted_created_at = created_at.strftime("%Y-%m-%d %H:%M")
|
||||
return formatted_created_at
|
||||
formatted_datetime = datetime.strftime("%Y-%m-%d %H:%M")
|
||||
return formatted_datetime
|
||||
|
||||
|
||||
class TaskState(rx.State):
|
||||
|
|
@ -127,14 +127,15 @@ class TaskState(rx.State):
|
|||
@rx.var
|
||||
def task_history(self) -> list[TaskHistoryItem]:
|
||||
"""
|
||||
获取会话历史项列表(按照会话创建日期时间降序排序)
|
||||
获取任务历史项列表(按照任务创建日期时间降序排序)
|
||||
:return: 任务历史项列表
|
||||
"""
|
||||
return [
|
||||
TaskHistoryItem(
|
||||
id=task.id,
|
||||
description=task.description,
|
||||
created_at=format_conversation_created_at(task.created_at),
|
||||
last_run_at=format_datetime(task.last_run_at),
|
||||
is_running=task.is_running,
|
||||
)
|
||||
for task in reversed(self.tasks.values())
|
||||
]
|
||||
|
|
@ -613,14 +614,19 @@ class TaskState(rx.State):
|
|||
# 若工作流类型为预定航班则设置为对话
|
||||
if task.workflow.type == WorkflowType.BOOK_FLIGHT:
|
||||
task.workflow = Workflow()
|
||||
# 将正在运行设置为否
|
||||
# 更新上一次运行日期时间
|
||||
task.last_run_at = datetime.now()
|
||||
# 更新正在运行状态
|
||||
task.is_running = False
|
||||
yield # 通知前端更新渲染
|
||||
|
||||
# 更新会话记录
|
||||
# 更新使用量
|
||||
task.usage = result.usage
|
||||
# 更新任务记录
|
||||
await db_state.update_task_record(
|
||||
task.id,
|
||||
usage=result.usage,
|
||||
id=task.id,
|
||||
last_run_at=task.last_run_at,
|
||||
usage=task.usage,
|
||||
workflow=task.workflow,
|
||||
)
|
||||
|
||||
|
|
@ -754,8 +760,8 @@ class TaskState(rx.State):
|
|||
task.workflow = workflow
|
||||
# 获取数据库状态
|
||||
db_state = await self.get_db_state()
|
||||
# 更新会话记录
|
||||
# 更新任务记录
|
||||
await db_state.update_task_record(
|
||||
task.id,
|
||||
id=task.id,
|
||||
workflow=task.workflow,
|
||||
)
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue