This commit is contained in:
parent
3dde59d8be
commit
8c8fda3da6
|
|
@ -13,11 +13,11 @@ from application.states.models import (
|
|||
from application.states import ConversationState, AuthState
|
||||
|
||||
|
||||
def conversation_history_item_showing(
|
||||
def conversation_history_item(
|
||||
item: Tuple[str, Conversation],
|
||||
) -> rx.Component:
|
||||
"""
|
||||
会话历史项展示
|
||||
会话历史项
|
||||
:param item: 会话历史项
|
||||
:return: Component
|
||||
"""
|
||||
|
|
@ -25,7 +25,8 @@ def conversation_history_item_showing(
|
|||
|
||||
# 高亮:若为当前会话或显示更多则高亮
|
||||
highlight: bool = (
|
||||
conversation.id == ConversationState.is_conversation_history_item_more_button_shown
|
||||
conversation.id
|
||||
== ConversationState.is_conversation_history_item_more_button_shown
|
||||
) | (conversation.id == ConversationState.conversation_id)
|
||||
|
||||
return rx.list.item(
|
||||
|
|
@ -172,12 +173,12 @@ def conversation_history_item_showing(
|
|||
)
|
||||
|
||||
|
||||
def conversation_history_items_showing(
|
||||
is_conversation_history_shown: bool,
|
||||
def conversation_history(
|
||||
is_shown: bool,
|
||||
) -> rx.Component:
|
||||
"""
|
||||
会话历史列表展示
|
||||
:param is_conversation_history_shown: 会话历史展示状态
|
||||
会话历史
|
||||
:param is_shown: 展示 / 隐藏
|
||||
:return: Component
|
||||
"""
|
||||
return rx.box(
|
||||
|
|
@ -195,8 +196,8 @@ def conversation_history_items_showing(
|
|||
),
|
||||
rx.auto_scroll(
|
||||
rx.foreach(
|
||||
ConversationState.conversations,
|
||||
conversation_history_item_showing,
|
||||
ConversationState.conversation_history,
|
||||
conversation_history_item,
|
||||
),
|
||||
flex="1",
|
||||
align_items="stretch",
|
||||
|
|
@ -217,9 +218,9 @@ def conversation_history_items_showing(
|
|||
backdrop_filter="blur(50px)",
|
||||
gap="12px",
|
||||
),
|
||||
width=rx.cond(is_conversation_history_shown, "25%", "0px"),
|
||||
min_width=rx.cond(is_conversation_history_shown, "240px", "0px"),
|
||||
max_width=rx.cond(is_conversation_history_shown, "380px", "0px"),
|
||||
width=rx.cond(is_shown, "25%", "0px"),
|
||||
min_width=rx.cond(is_shown, "240px", "0px"),
|
||||
max_width=rx.cond(is_shown, "380px", "0px"),
|
||||
height="100%",
|
||||
transition="all 0.18s ease-in-out",
|
||||
overflow="hidden",
|
||||
|
|
@ -864,21 +865,22 @@ def conversation_history_collapse_button(
|
|||
)
|
||||
|
||||
|
||||
def conversation() -> rx.Component:
|
||||
def conversation_page() -> rx.Component:
|
||||
"""
|
||||
会话页面:布局参考 MetaChat,左侧为折叠面板,右侧为工作区。其中,工作区包含展示区和操作区。若对话历史为空则展示欢迎文案,否则展示对话历史
|
||||
会话页面:布局参考 MetaChat,从左到右分别为会话历史和工作区。其中,工作区从上到下分别为对话历史和用户提示词输入框。
|
||||
"""
|
||||
# 会话历史展示状态
|
||||
is_conversation_history_shown = ConversationState.is_conversation_history_shown
|
||||
is_shown = ConversationState.is_conversation_history_shown
|
||||
|
||||
return rx.box(
|
||||
rx.hstack(
|
||||
# 会话历史列表展示
|
||||
conversation_history_items_showing(is_conversation_history_shown),
|
||||
# 会话历史
|
||||
conversation_history(is_shown),
|
||||
# 工作区
|
||||
rx.box(
|
||||
# 对话历史
|
||||
rx.vstack(
|
||||
# 对话列表展示
|
||||
dialog_items_showing(),
|
||||
dialog_history(),
|
||||
width="100%",
|
||||
height="100%",
|
||||
gap="8px",
|
||||
|
|
@ -903,7 +905,7 @@ def conversation() -> rx.Component:
|
|||
transition="all 0.18s ease-in-out",
|
||||
),
|
||||
# 会话历史折叠面板按钮
|
||||
conversation_history_collapse_button(is_conversation_history_shown),
|
||||
conversation_history_collapse_button(is_shown),
|
||||
# 挂载事件:恢复会话状态
|
||||
on_mount=AuthState.resume_conversation_state,
|
||||
position="relative",
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ from application.states.models import (
|
|||
Message,
|
||||
MessageType,
|
||||
Work,
|
||||
WorkType,
|
||||
ConversationHistoryItem,
|
||||
usage_to_dict,
|
||||
usage_validate_python,
|
||||
)
|
||||
from application.tasks import run_stream_events
|
||||
|
||||
|
||||
def format_conversation_created_at(created_at: datetime) -> str:
|
||||
|
|
@ -69,9 +69,6 @@ class ConversationState(rx.State):
|
|||
# 会话历史项显示悬停气泡,True 表示显示,False 表示隐藏
|
||||
is_conversation_history_item_popover_shown: bool = False
|
||||
|
||||
# 当前工作实例
|
||||
work: Work | None = None
|
||||
|
||||
# 当前数据库状态(私有变量)
|
||||
# 私有变量:reflex 约定以 _ 开头的变量为私有变量,后端不序列化,前端不可使用
|
||||
_db_state: DatabaseState | None = None
|
||||
|
|
@ -117,7 +114,7 @@ class ConversationState(rx.State):
|
|||
self.is_conversation_history_shown = not self.is_conversation_history_shown
|
||||
|
||||
@rx.var
|
||||
def conversation_history_items(self) -> list[ConversationHistoryItem]:
|
||||
def conversation_history(self) -> list[ConversationHistoryItem]:
|
||||
"""
|
||||
获取会话历史项列表(按照会话创建日期时间降序排序)
|
||||
:return: 会话历史项列表
|
||||
|
|
@ -240,182 +237,220 @@ class ConversationState(rx.State):
|
|||
conversation.is_running = True
|
||||
# 构建用户提示词消息实例
|
||||
message = Message(
|
||||
type=MessageType.USER_PROMPT, content=conversation.user_prompt
|
||||
type=MessageType.USER_PROMPT,
|
||||
content=(user_prompt := conversation.user_prompt),
|
||||
)
|
||||
# 添加至消息字典
|
||||
conversation.messages[message.id] = message
|
||||
# 清空用户提示词
|
||||
conversation.user_prompt = ""
|
||||
# 添加至消息字典
|
||||
user_prompt = conversation.messages.setdefault(message.id, message)
|
||||
yield # 通知前端更新渲染
|
||||
|
||||
# 获取数据库状态
|
||||
db_state = await self.get_db_state()
|
||||
|
||||
# 初始化片段索引映射为消息实例唯一标识字典
|
||||
index_map_to_message_id: dict[int, str] = {}
|
||||
# 获取运行流式输出事件
|
||||
async for event in run_stream_events(
|
||||
work=self.work,
|
||||
user_prompt=user_prompt,
|
||||
message_history=await db_state.get_message_history(
|
||||
# 初始化工具调用唯一标识集合
|
||||
tool_call_ids: set[str] = set()
|
||||
try:
|
||||
# 获取数据库状态
|
||||
db_state = await self.get_db_state()
|
||||
# 获取消息历史列表
|
||||
message_history = await db_state.get_message_history(
|
||||
conversation_id=self.actived_conversation_id
|
||||
),
|
||||
):
|
||||
match event:
|
||||
# ========== 开始事件 ==========
|
||||
case PartStartEvent(
|
||||
index=index,
|
||||
part=part,
|
||||
previous_part_kind=previous_part_kind,
|
||||
):
|
||||
match part:
|
||||
# 思考分片开始事件
|
||||
case ThinkingPart(content=content):
|
||||
message = Message(type=MessageType.THINKING)
|
||||
# 将消息实例唯一标识与片段索引映射
|
||||
message_id_map_to_index[index] = message.id
|
||||
# 若上一分片种类为空则将正在思考设置为是
|
||||
if not previous_part_kind:
|
||||
)
|
||||
usage = usage_validate_python(conversation.usage)
|
||||
# 匹配工作类型
|
||||
match conversation.work:
|
||||
# 预定航班
|
||||
case WorkType.BOOK_FLIGHT:
|
||||
from application.workshop.book_flight import run_stream_events
|
||||
|
||||
stream_events = run_stream_events(
|
||||
work=conversation.work,
|
||||
user_prompt=user_prompt,
|
||||
message_history=message_history,
|
||||
usage=usage,
|
||||
)
|
||||
|
||||
# 非结构化对话
|
||||
case _:
|
||||
from application.workshop.unstructured_dialogue import (
|
||||
run_stream_events,
|
||||
)
|
||||
|
||||
stream_events = run_stream_events(
|
||||
user_prompt=user_prompt,
|
||||
message_history=message_history,
|
||||
usage=usage,
|
||||
)
|
||||
|
||||
# 获取运行流式输出事件
|
||||
async for event in stream_events:
|
||||
match event:
|
||||
# ========== 开始事件 ==========
|
||||
case PartStartEvent(
|
||||
index=index,
|
||||
part=part,
|
||||
):
|
||||
match part:
|
||||
# 思考分片开始事件
|
||||
case ThinkingPart(content=content):
|
||||
# 构建消息实例
|
||||
message.is_thinking = True
|
||||
message.content = content
|
||||
message = Message(
|
||||
type=MessageType.THINKING,
|
||||
title="正在思考",
|
||||
content=content,
|
||||
is_running=True,
|
||||
)
|
||||
# 添加至消息字典
|
||||
conversation.messages[message.id] = message
|
||||
# 将消息实例唯一标识与片段索引映射
|
||||
index_map_to_message_id[index] = message.id
|
||||
|
||||
# 工具检索分片开始事件
|
||||
case ToolSearchCallPart(tool_call_id=tool_call_id):
|
||||
# 创建工具调用唯一标识与片段索引映射
|
||||
tool_call_ids[tool_call_id] = index
|
||||
# 工具调用分片开始事件
|
||||
case ToolCallPart(
|
||||
tool_name=tool_name, tool_call_id=tool_call_id
|
||||
):
|
||||
# 构建消息实例
|
||||
message = Message(
|
||||
type=MessageType.TOOL_CALL,
|
||||
title=tool_name,
|
||||
content=",",
|
||||
is_running=True,
|
||||
)
|
||||
tool_call_ids.add(tool_call_id)
|
||||
# 添加至消息字典
|
||||
dialog.thoughts[index] = Thought(
|
||||
type="tool_call",
|
||||
content="正在生成调用参数",
|
||||
)
|
||||
|
||||
dialog.thoughts[index] = Thought(
|
||||
type="tool_search",
|
||||
content="正在生成检索关键词",
|
||||
)
|
||||
# 文本分片开始事件
|
||||
case TextPart(content=content):
|
||||
# 构建消息实例
|
||||
message = Message(type=MessageType.RESULT_OUTPUT)
|
||||
message.content = content
|
||||
# 添加至消息字典
|
||||
conversation.messages[message.id] = message
|
||||
# 将消息实例唯一标识与片段索引映射
|
||||
index_map_to_message_id[index] = message.id
|
||||
|
||||
# 能力加载分片开始事件
|
||||
case LoadCapabilityCallPart(tool_call_id=tool_call_id):
|
||||
tool_call_ids[tool_call_id] = index
|
||||
# ========== 增量事件 ==========
|
||||
case PartDeltaEvent(index=index, delta=delta):
|
||||
match delta:
|
||||
# 思考分片增量事件
|
||||
case ThinkingPartDelta(
|
||||
content_delta=content_delta,
|
||||
):
|
||||
# 若内容增量不为空则增量更新
|
||||
if content_delta:
|
||||
conversation.messages[
|
||||
index_map_to_message_id[index]
|
||||
].content += content_delta
|
||||
|
||||
dialog.thoughts[index] = Thought(
|
||||
type="capability_load",
|
||||
content="正在生成加载参数",
|
||||
)
|
||||
# 文本分片增量事件
|
||||
case TextPartDelta(
|
||||
content_delta=content_delta,
|
||||
):
|
||||
# 增量更新
|
||||
conversation.messages[
|
||||
index_map_to_message_id[index]
|
||||
].content += content_delta
|
||||
|
||||
# 工具调用分片开始事件
|
||||
case ToolCallPart(tool_call_id=tool_call_id):
|
||||
tool_call_ids[tool_call_id] = index
|
||||
# ========== 结束事件 ==========
|
||||
case PartEndEvent(
|
||||
index=index,
|
||||
part=part,
|
||||
):
|
||||
match part:
|
||||
# 思考分片结束事件
|
||||
case ThinkingPart(content=content):
|
||||
# 获取消息实例
|
||||
message = conversation.messages[
|
||||
index_map_to_message_id[index]
|
||||
]
|
||||
message.is_running = False
|
||||
message.title = "思考完成"
|
||||
|
||||
dialog.thoughts[index] = Thought(
|
||||
type="tool_call",
|
||||
content="正在生成调用参数",
|
||||
)
|
||||
# ========== 函数工具调用事件 ==========
|
||||
case FunctionToolCallEvent(tool_call_id=tool_call_id, part=part):
|
||||
# 获取分片索引
|
||||
index = tool_call_ids[tool_call_id]
|
||||
match dialog.thoughts[index].type:
|
||||
# 工具检索
|
||||
case "tool_search":
|
||||
dialog.thoughts[index].content = (
|
||||
f"正在检索 {part.args_as_json_str()}"
|
||||
)
|
||||
|
||||
# 文本分片开始事件
|
||||
case TextPart(content=content):
|
||||
dialog.result_output = content
|
||||
# 能力加载
|
||||
case "capability_load":
|
||||
dialog.thoughts[index].content = (
|
||||
f"正在加载能力 {part.tool_name}"
|
||||
)
|
||||
|
||||
# ========== 增量事件 ==========
|
||||
case PartDeltaEvent(index=index, delta=delta):
|
||||
match delta:
|
||||
# 思考分片增量事件
|
||||
case ThinkingPartDelta(
|
||||
content_delta=content_delta,
|
||||
):
|
||||
dialog.thoughts[index].content += content_delta or ""
|
||||
# 工具调用
|
||||
case "tool_call":
|
||||
dialog.thoughts[index].content = (
|
||||
f"正在调用工具 {part.tool_name}"
|
||||
)
|
||||
|
||||
# 文本分片增量事件
|
||||
case TextPartDelta(
|
||||
content_delta=content_delta,
|
||||
):
|
||||
dialog.result_output += content_delta
|
||||
# ========== 函数工具结果事件 ==========
|
||||
case FunctionToolResultEvent(
|
||||
tool_call_id=tool_call_id,
|
||||
content=content,
|
||||
):
|
||||
index = tool_call_ids[tool_call_id]
|
||||
match dialog.thoughts[index].type:
|
||||
# 工具检索
|
||||
case "tool_search":
|
||||
dialog.thoughts[index].content = (
|
||||
content if isinstance(content, str) else ""
|
||||
) # 暂仅考虑文本内容
|
||||
|
||||
# ========== 结束事件 ==========
|
||||
case PartEndEvent(
|
||||
index=index,
|
||||
part=part,
|
||||
next_part_kind=next_part_kind,
|
||||
):
|
||||
match part:
|
||||
# 思考分片结束事件
|
||||
case ThinkingPart(content=content):
|
||||
# 若下一分片种类为文本则将思考状态设置为思考完成
|
||||
if next_part_kind == "text":
|
||||
dialog.is_thinking = False
|
||||
# 能力加载
|
||||
case "capability_load":
|
||||
dialog.thoughts[index].content = f"已加载 {content}"
|
||||
|
||||
# ========== 函数工具调用事件 ==========
|
||||
case FunctionToolCallEvent(tool_call_id=tool_call_id, part=part):
|
||||
# 获取分片索引
|
||||
index = tool_call_ids[tool_call_id]
|
||||
match dialog.thoughts[index].type:
|
||||
# 工具检索
|
||||
case "tool_search":
|
||||
dialog.thoughts[index].content = (
|
||||
f"正在检索 {part.args_as_json_str()}"
|
||||
)
|
||||
# 工具调用
|
||||
case "tool_call":
|
||||
dialog.thoughts[index].content = f"已调用 {content}"
|
||||
|
||||
# 能力加载
|
||||
case "capability_load":
|
||||
dialog.thoughts[index].content = (
|
||||
f"正在加载能力 {part.tool_name}"
|
||||
)
|
||||
case TaskNodeResultEvent(task=task, content=content):
|
||||
# 更新任务
|
||||
conversation.task = task
|
||||
dialog.result_output += content
|
||||
|
||||
# 工具调用
|
||||
case "tool_call":
|
||||
dialog.thoughts[index].content = (
|
||||
f"正在调用工具 {part.tool_name}"
|
||||
)
|
||||
# ========== 智能体运行结果事件 ==========
|
||||
case AgentRunResultEvent(result=result):
|
||||
# 创建对话记录
|
||||
await db_state.create_dialog_record(
|
||||
conversation_id=self.conversation_id,
|
||||
id=dialog.id,
|
||||
user_prompt=dialog.user_prompt,
|
||||
thoughts=thoughts_to_dict(dialog.thoughts),
|
||||
result_output=dialog.result_output,
|
||||
usage=usage_to_dict(result.usage),
|
||||
)
|
||||
# 创建结果记录
|
||||
await db_state.create_result_record(
|
||||
conversation_id=self.conversation_id,
|
||||
_id=dialog.id,
|
||||
new_messages=result.new_messages(),
|
||||
)
|
||||
|
||||
# ========== 函数工具结果事件 ==========
|
||||
case FunctionToolResultEvent(
|
||||
tool_call_id=tool_call_id,
|
||||
content=content,
|
||||
):
|
||||
index = tool_call_ids[tool_call_id]
|
||||
match dialog.thoughts[index].type:
|
||||
# 工具检索
|
||||
case "tool_search":
|
||||
dialog.thoughts[index].content = (
|
||||
content if isinstance(content, str) else ""
|
||||
) # 暂仅考虑文本内容
|
||||
# 强制更新会话并推送前端
|
||||
self.conversations[self.actived_conversation_id] = conversation
|
||||
yield
|
||||
|
||||
# 能力加载
|
||||
case "capability_load":
|
||||
dialog.thoughts[index].content = f"已加载 {content}"
|
||||
except Exception as e:
|
||||
...
|
||||
finally:
|
||||
# 将正在运行设置为否
|
||||
conversation.is_running = False
|
||||
|
||||
# 工具调用
|
||||
case "tool_call":
|
||||
dialog.thoughts[index].content = f"已调用 {content}"
|
||||
|
||||
case TaskNodeResultEvent(task=task, content=content):
|
||||
# 更新任务
|
||||
conversation.task = task
|
||||
dialog.result_output += content
|
||||
|
||||
# ========== 智能体运行结果事件 ==========
|
||||
case AgentRunResultEvent(result=result):
|
||||
# 创建对话记录
|
||||
await db_state.create_dialog_record(
|
||||
conversation_id=self.conversation_id,
|
||||
id=dialog.id,
|
||||
user_prompt=dialog.user_prompt,
|
||||
thoughts=thoughts_to_dict(dialog.thoughts),
|
||||
result_output=dialog.result_output,
|
||||
usage=usage_to_dict(result.usage),
|
||||
)
|
||||
# 创建结果记录
|
||||
await db_state.create_result_record(
|
||||
conversation_id=self.conversation_id,
|
||||
dialog_id=dialog.id,
|
||||
new_messages=result.new_messages(),
|
||||
)
|
||||
|
||||
# 强制更新会话并推送前端
|
||||
self.conversations[self.conversation_id] = conversation
|
||||
self.conversations[self.actived_conversation_id] = conversation
|
||||
yield
|
||||
|
||||
# 将正在运行设置为否
|
||||
conversation.is_running = False
|
||||
self.conversations[self.conversation_id] = conversation
|
||||
yield
|
||||
|
||||
@rx.event
|
||||
async def generate_prd(self) -> None:
|
||||
"""
|
||||
|
|
@ -430,10 +465,12 @@ class ConversationState(rx.State):
|
|||
self.user_prompt = f"帮我找一班从 {conversation.task.deps.origin} 到 {conversation.task.deps.destination} 在 {conversation.task.deps.date} 的航班"
|
||||
|
||||
@rx.event
|
||||
def toggle_collapse(self, dialog_id: str) -> None:
|
||||
def toggle_message_collapse(self, message_id: str) -> None:
|
||||
"""
|
||||
展开/折叠思考折叠面板
|
||||
展开/折叠消息组件
|
||||
"""
|
||||
# 指定运行
|
||||
dialog = self.conversations[self.conversation_id].dialogs[dialog_id]
|
||||
dialog.is_expanded = not dialog.is_expanded
|
||||
# 当前会话
|
||||
conversation = self.conversations.get(self.actived_conversation_id)
|
||||
if not conversation:
|
||||
return
|
||||
conversation.messages[message_id].is_expanded ^= True
|
||||
|
|
|
|||
|
|
@ -14,11 +14,9 @@ from sqlmodel import Field, JSON, SQLModel, select, update
|
|||
|
||||
from application.states.models import (
|
||||
Conversation,
|
||||
TaskType,
|
||||
TaskStatus,
|
||||
RunStatus,
|
||||
MessageType,
|
||||
Task,
|
||||
Run,
|
||||
Message,
|
||||
deps_to_object,
|
||||
|
|
@ -109,7 +107,7 @@ class MessageRecord(SQLModel, table=True, table_name="message"):
|
|||
content: str = Field(default="", description="消息内容")
|
||||
|
||||
|
||||
class RunRecord(SQLModel, table=True, table_name="run_result"):
|
||||
class RunRecord(SQLModel, table=True, table_name="run"):
|
||||
"""
|
||||
运行记录
|
||||
"""
|
||||
|
|
@ -333,9 +331,9 @@ class DatabaseState(rx.State):
|
|||
)
|
||||
for run in result.all():
|
||||
message_history.extend(
|
||||
ModelMessagesTypeAdapter.validate_python(
|
||||
ModelMessagesTypeAdapter.validate_json(
|
||||
run.new_messages
|
||||
) # 将 run.new_messages 由 Python 类型反序列化为 List[ModelMessage]
|
||||
) # 将 run.new_messages 由 JSON 字符串反序列化为 List[ModelMessage]
|
||||
)
|
||||
return message_history
|
||||
|
||||
|
|
@ -357,9 +355,9 @@ class DatabaseState(rx.State):
|
|||
RunRecord(
|
||||
id=id,
|
||||
conversation_id=conversation_id,
|
||||
new_messages=ModelMessagesTypeAdapter.dump_python(
|
||||
new_messages=ModelMessagesTypeAdapter.dump_json(
|
||||
new_messages
|
||||
), # 将 messages 由 List[ModelMessage] 序列化为 Python 类型
|
||||
).decode(), # 将 messages 由 List[ModelMessage] 序列化为 JSON 字符串
|
||||
)
|
||||
)
|
||||
await session.commit()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ class MessageType(StrEnum):
|
|||
|
||||
USER_PROMPT = "user_prompt"
|
||||
THINKING = "thinking"
|
||||
AGENT_RUN_RESULT_OUTPUT = "agent_run_result_output"
|
||||
TOOL_CALL = "tool_call"
|
||||
RESULT_OUTPUT = "result_output"
|
||||
|
||||
|
||||
|
||||
class Message(BaseModel):
|
||||
|
|
@ -31,8 +33,8 @@ class Message(BaseModel):
|
|||
type: MessageType = Field(..., description="消息类型")
|
||||
title: str = Field(default="", description="消息标题")
|
||||
content: str = Field(default="", description="消息内容")
|
||||
is_thinking: bool = Field(
|
||||
default=False, description="正在思考,True 表示正在思考,False 表示思考完成"
|
||||
is_running: bool = Field(
|
||||
default=False, description="正在运行,True 表示正在运行,False 表示运行完成"
|
||||
)
|
||||
is_expanded: bool = Field(
|
||||
default=False, description="展开组件,True 表示展开,False 表示折叠"
|
||||
|
|
@ -109,11 +111,11 @@ class Conversation(BaseModel):
|
|||
|
||||
id: str = Field(..., description="会话唯一标识")
|
||||
description: str = Field(..., description="会话描述")
|
||||
work: Work | None = Field(default=None, description="绑定工作实例")
|
||||
user_prompt: str = Field(default="", description="用户提示词")
|
||||
usage: dict[str, Any] = Field(..., description="会话使用量")
|
||||
messages: dict[str, Message] = Field(..., description="消息字典")
|
||||
created_at: datetime = Field(..., description="会话创建日期时间")
|
||||
|
||||
is_running: bool = Field(
|
||||
default=False, description="正在运行,True 表示正在运行, False 表示运行结束"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
任务模块
|
||||
"""
|
||||
from typing import AsyncGenerator, List
|
||||
|
||||
from pydantic_ai import Agent, ModelMessage
|
||||
from pydantic_ai.messages import AgentStreamEvent
|
||||
from pydantic_ai.run import AgentRunResultEvent
|
||||
|
||||
from application.states.models import TaskNodeResultEvent, TaskType, Task, Message
|
||||
from application.tasks.models import DEEPSEEK_V4_FLASH_MODEL
|
||||
|
||||
|
||||
instruction = """
|
||||
# 角色
|
||||
专业友好AI助手,结构化解答各类问题。
|
||||
|
||||
# 输出硬性规则
|
||||
1. 全文强制标准Markdown,禁止纯文本;不要额外说明排版格式,直接输出内容;
|
||||
2. 层级使用 `#/##/###`,列表用 `-` 无序列表或数字有序列表;
|
||||
3. 代码块用 ```语言名``` 包裹;
|
||||
4. 重点内容标注 **粗体**/*斜体*;
|
||||
5. 思考、工具日志仅输出文本,适配前端折叠面板,禁止输出HTML标签;
|
||||
6. 内容分点拆分,排版整洁适配前端Markdown渲染。
|
||||
|
||||
# 行文要求
|
||||
语言通俗,逻辑完整简洁,无多余废话。
|
||||
"""
|
||||
|
||||
|
||||
async def run_stream_events(
|
||||
work: Work | None,
|
||||
user_prompt: Message,
|
||||
message_history: List[ModelMessage],
|
||||
) -> AsyncGenerator[AgentStreamEvent | AgentRunResultEvent | TaskNodeResultEvent, None]:
|
||||
"""
|
||||
以流式事件模式运行
|
||||
"""
|
||||
if task:
|
||||
match task.type:
|
||||
case TaskType.BOOK_FLIGHT:
|
||||
from application.tasks.book_flight import run_stream_events
|
||||
|
||||
async for event in run_stream_events(
|
||||
task=task,
|
||||
user_prompt=user_prompt,
|
||||
message_history=message_history,
|
||||
):
|
||||
print(event)
|
||||
yield event
|
||||
|
||||
else:
|
||||
agent = Agent(
|
||||
model=DEEPSEEK_V4_FLASH_MODEL,
|
||||
instructions=instruction,
|
||||
)
|
||||
async with agent.run_stream_events(
|
||||
user_prompt=user_prompt,
|
||||
message_history=message_history,
|
||||
) as events:
|
||||
async for event in events:
|
||||
yield event
|
||||
|
|
@ -0,0 +1 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
预定航班任务
|
||||
预定航班
|
||||
"""
|
||||
import datetime
|
||||
from typing import AsyncGenerator, Literal
|
||||
|
|
@ -181,9 +181,11 @@ def init_task() -> Task:
|
|||
|
||||
|
||||
async def run_stream_events(
|
||||
task: Task | None,
|
||||
usage: RunUsage,
|
||||
user_prompt: str,
|
||||
message_history: list[ModelMessage],
|
||||
work: WorkType | None = None,
|
||||
|
||||
) -> AsyncGenerator:
|
||||
result = None
|
||||
while True:
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
非结构化对话
|
||||
"""
|
||||
from typing import AsyncGenerator
|
||||
|
||||
from pydantic_ai import Agent, ModelMessage, RunUsage
|
||||
from pydantic_ai.messages import AgentStreamEvent
|
||||
from pydantic_ai.run import AgentRunResultEvent
|
||||
|
||||
from application.workshop.models import DEEPSEEK_V4_FLASH_MODEL
|
||||
|
||||
|
||||
instruction = """
|
||||
# 角色
|
||||
专业友好AI助手,结构化解答各类问题。
|
||||
|
||||
# 输出硬性规则
|
||||
1. 全文强制标准Markdown,禁止纯文本;不要额外说明排版格式,直接输出内容;
|
||||
2. 层级使用 `#/##/###`,列表用 `-` 无序列表或数字有序列表;
|
||||
3. 代码块用 ```语言名``` 包裹;
|
||||
4. 重点内容标注 **粗体**/*斜体*;
|
||||
5. 思考、工具日志仅输出文本,适配前端折叠面板,禁止输出HTML标签;
|
||||
6. 内容分点拆分,排版整洁适配前端Markdown渲染。
|
||||
|
||||
# 行文要求
|
||||
语言通俗,逻辑完整简洁,无多余废话。
|
||||
"""
|
||||
|
||||
agent = Agent(
|
||||
model=DEEPSEEK_V4_FLASH_MODEL,
|
||||
instructions=instruction,
|
||||
)
|
||||
|
||||
|
||||
async def run_stream_events(
|
||||
user_prompt: str,
|
||||
message_history: list[ModelMessage],
|
||||
usage: RunUsage,
|
||||
) -> AsyncGenerator[AgentStreamEvent | AgentRunResultEvent, None]:
|
||||
"""
|
||||
运行并流式输出事件
|
||||
:param user_prompt: 用户提示词
|
||||
:param message_history: 消息历史
|
||||
:param usage: 使用量
|
||||
:return: AsyncGenerator
|
||||
"""
|
||||
async with agent.run_stream_events(
|
||||
user_prompt=user_prompt,
|
||||
message_history=message_history,
|
||||
usage=usage,
|
||||
) as events:
|
||||
async for event in events:
|
||||
yield event
|
||||
Loading…
Reference in New Issue