Skip to content

Commit b73cb6e

Browse files
committed
rebuild
1 parent 31d1dd3 commit b73cb6e

File tree

9 files changed

+698
-849
lines changed

9 files changed

+698
-849
lines changed

pydify/README.md

Whitespace-only changes.

pydify/__init__.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
包括对话、文本生成、工作流、文件上传等。
66
"""
77

8-
from .agent import AgentClient
9-
from .chatbot import ChatbotClient
10-
from .chatflow import ChatflowClient
8+
from .agent import AgentClient, AgentEvent
9+
from .chatbot import ChatbotClient, ChatbotEvent
10+
from .chatflow import ChatflowClient, ChatflowEvent
1111
from .common import DifyBaseClient, DifyType
12-
from .text_generation import TextGenerationClient
13-
from .workflow import WorkflowClient
12+
from .text_generation import TextGenerationClient, TextGenerationEvent
13+
from .workflow import WorkflowClient, WorkflowEvent
1414

1515

1616
def create_client(type: str, base_url: str, api_key: str) -> DifyBaseClient:
@@ -36,4 +36,7 @@ def create_client(type: str, base_url: str, api_key: str) -> DifyBaseClient:
3636
"AgentClient",
3737
"TextGenerationClient",
3838
"create_client",
39+
"DifyType",
40+
"ChatbotEvent",
41+
"WorkflowEvent",
3942
]

pydify/agent.py

Lines changed: 28 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,38 @@
1111
from typing import Any, BinaryIO, Dict, Generator, List, Optional, Tuple, Union
1212

1313
from .common import DifyBaseClient, DifyType
14+
from .chatbot import ChatbotClient
15+
class AgentEvent:
16+
"""事件类型枚举
1417
18+
定义了Dify Agent API中可能的事件类型,用于处理流式响应中的事件。
19+
"""
1520

16-
class AgentClient(DifyBaseClient):
21+
MESSAGE = "message" # LLM返回文本块事件,包含分块输出的文本内容
22+
AGENT_MESSAGE = "agent_message" # Agent模式下返回文本块事件,包含分块输出的文本内容
23+
AGENT_THOUGHT = "agent_thought" # Agent思考步骤事件,包含工具调用相关信息
24+
MESSAGE_FILE = "message_file" # 文件事件,表示有新文件需要展示
25+
MESSAGE_END = "message_end" # 消息结束事件,表示流式返回结束
26+
TTS_MESSAGE = "tts_message" # TTS音频流事件,包含base64编码的音频块
27+
TTS_MESSAGE_END = "tts_message_end" # TTS音频流结束事件
28+
MESSAGE_REPLACE = "message_replace" # 消息内容替换事件,用于内容审查后的替换
29+
ERROR = "error" # 流式输出过程中出现的异常事件
30+
PING = "ping" # 保持连接存活的ping事件,每10秒一次
31+
32+
33+
class AgentClient(ChatbotClient):
1734
"""Dify Agent应用客户端类。
1835
1936
提供与Dify Agent应用API交互的方法,包括发送消息、获取历史消息、管理会话、
2037
上传文件、语音转文字、文字转语音等功能。Agent应用支持迭代式规划推理和自主工具调用。
2138
"""
2239

2340
type = DifyType.Agent
24-
41+
42+
def __init__(self, *args, **kwargs):
43+
super().__init__(*args, **kwargs)
44+
self.task_id = None
45+
2546
def send_message(
2647
self,
2748
query: str,
@@ -32,7 +53,7 @@ def send_message(
3253
files: List[Dict[str, Any]] = None,
3354
auto_generate_name: bool = True,
3455
**kwargs, # 添加kwargs参数,用于接收额外的请求参数
35-
) -> Generator[Dict[str, Any], None, None]:
56+
) -> Generator[Dict[str, Any], None, None] | Dict[str, Any]:
3657
"""
3758
发送对话消息,创建会话消息。在Agent模式下,只支持streaming流式模式。
3859
@@ -55,7 +76,7 @@ def send_message(
5576
"""
5677
if response_mode != "streaming":
5778
raise ValueError("Agent mode only supports streaming response mode")
58-
79+
5980
payload = {
6081
"query": query,
6182
"user": user,
@@ -74,7 +95,7 @@ def send_message(
7495

7596
return self.post_stream(endpoint, json_data=payload, **kwargs) # 传递额外参数
7697

77-
def stop_response(self, task_id: str, user: str) -> Dict[str, Any]:
98+
def stop_task(self, task_id: str, user: str) -> Dict[str, Any]:
7899
"""
79100
停止正在进行的响应流。此方法仅在流式模式下有效。
80101
@@ -95,7 +116,7 @@ def stop_response(self, task_id: str, user: str) -> Dict[str, Any]:
95116
endpoint = f"chat-messages/{task_id}/stop"
96117
payload = {"user": user}
97118
return self.post(endpoint, json_data=payload)
98-
119+
99120
def get_meta(self) -> Dict[str, Any]:
100121
"""
101122
获取应用Meta信息,用于获取工具icon等。
@@ -107,171 +128,4 @@ def get_meta(self) -> Dict[str, Any]:
107128
requests.HTTPError: 当API请求失败时
108129
"""
109130
return self.get("meta")
110-
111-
def process_streaming_response(
112-
self,
113-
stream_generator: Generator[Dict[str, Any], None, None],
114-
handle_message=None,
115-
handle_agent_message=None,
116-
handle_agent_thought=None,
117-
handle_message_file=None,
118-
handle_message_end=None,
119-
handle_tts_message=None,
120-
handle_tts_message_end=None,
121-
handle_message_replace=None,
122-
handle_error=None,
123-
handle_ping=None,
124-
break_on_error=True,
125-
) -> Dict[str, Any]:
126-
"""
127-
处理流式响应,调用相应事件处理器。
128-
129-
Args:
130-
stream_generator: 流式响应生成器
131-
handle_message: LLM返回文本块事件处理函数
132-
handle_agent_message: Agent模式下返回文本块事件处理函数
133-
handle_agent_thought: Agent模式下思考步骤事件处理函数
134-
handle_message_file: 文件事件处理函数
135-
handle_message_end: 消息结束事件处理函数
136-
handle_tts_message: TTS音频流事件处理函数
137-
handle_tts_message_end: TTS音频流结束事件处理函数
138-
handle_message_replace: 消息内容替换事件处理函数
139-
handle_error: 错误事件处理函数
140-
handle_ping: ping事件处理函数
141-
break_on_error: 当遇到错误时是否中断处理,默认为True
142-
143-
Returns:
144-
Dict[str, Any]: 处理结果,包含消息ID、会话ID等信息
145-
146-
示例:
147-
```python
148-
def on_agent_message(chunk):
149-
# 打印Agent返回的文本块
150-
print(f"{chunk['answer']}")
151-
152-
def on_agent_thought(chunk):
153-
print(f"Agent思考: {chunk['thought']}")
154-
print(f"使用工具: {chunk['tool']}")
155-
print(f"工具输入: {chunk['tool_input']}")
156-
print(f"观察结果: {chunk['observation']}")
157-
158-
def on_message_end(chunk):
159-
print(f"消息结束: ID={chunk['message_id']}")
160-
161-
client = AgentClient(api_key)
162-
stream = client.send_message(
163-
query="帮我分析最近的股市走势",
164-
user="user123"
165-
)
166-
result = client.process_streaming_response(
167-
stream,
168-
handle_agent_message=on_agent_message,
169-
handle_agent_thought=on_agent_thought,
170-
handle_message_end=on_message_end
171-
)
172-
```
173-
"""
174-
result = {"agent_thoughts": []}
175-
answer_chunks = []
176-
177-
for chunk in stream_generator:
178-
event = chunk.get("event")
179-
180-
if event == "message" and handle_message:
181-
handle_message(chunk)
182-
# 累积回答内容
183-
if "answer" in chunk:
184-
answer_chunks.append(chunk["answer"])
185-
# 保存消息和会话ID
186-
if "message_id" in chunk and not result.get("message_id"):
187-
result["message_id"] = chunk["message_id"]
188-
if "conversation_id" in chunk and not result.get("conversation_id"):
189-
result["conversation_id"] = chunk["conversation_id"]
190-
if "task_id" in chunk and not result.get("task_id"):
191-
result["task_id"] = chunk["task_id"]
192-
193-
elif event == "agent_message" and handle_agent_message:
194-
handle_agent_message(chunk)
195-
# 累积回答内容
196-
if "answer" in chunk:
197-
answer_chunks.append(chunk["answer"])
198-
# 保存消息和会话ID
199-
if "message_id" in chunk and not result.get("message_id"):
200-
result["message_id"] = chunk["message_id"]
201-
if "conversation_id" in chunk and not result.get("conversation_id"):
202-
result["conversation_id"] = chunk["conversation_id"]
203-
if "task_id" in chunk and not result.get("task_id"):
204-
result["task_id"] = chunk["task_id"]
205-
206-
elif event == "agent_thought" and handle_agent_thought:
207-
if handle_agent_thought:
208-
handle_agent_thought(chunk)
209-
# 保存Agent思考内容
210-
thought_data = {
211-
"id": chunk.get("id"),
212-
"position": chunk.get("position"),
213-
"thought": chunk.get("thought"),
214-
"observation": chunk.get("observation"),
215-
"tool": chunk.get("tool"),
216-
"tool_input": chunk.get("tool_input"),
217-
"message_files": chunk.get("message_files", []),
218-
"created_at": chunk.get("created_at"),
219-
}
220-
result["agent_thoughts"].append(thought_data)
221-
222-
elif event == "message_file" and handle_message_file:
223-
handle_message_file(chunk)
224-
# 保存文件信息
225-
if not result.get("files"):
226-
result["files"] = []
227-
result["files"].append(
228-
{
229-
"id": chunk.get("id"),
230-
"type": chunk.get("type"),
231-
"belongs_to": chunk.get("belongs_to"),
232-
"url": chunk.get("url"),
233-
}
234-
)
235-
236-
elif event == "message_end" and handle_message_end:
237-
if handle_message_end:
238-
handle_message_end(chunk)
239-
# 保存元数据
240-
if "metadata" in chunk:
241-
result["metadata"] = chunk["metadata"]
242-
if "message_id" in chunk and not result.get("message_id"):
243-
result["message_id"] = chunk["message_id"]
244-
if "conversation_id" in chunk and not result.get("conversation_id"):
245-
result["conversation_id"] = chunk["conversation_id"]
246-
247-
elif event == "tts_message" and handle_tts_message:
248-
handle_tts_message(chunk)
249-
250-
elif event == "tts_message_end" and handle_tts_message_end:
251-
handle_tts_message_end(chunk)
252-
253-
elif event == "message_replace" and handle_message_replace:
254-
handle_message_replace(chunk)
255-
# 替换回答内容
256-
if "answer" in chunk:
257-
answer_chunks = [chunk["answer"]]
258-
259-
elif event == "error" and handle_error:
260-
handle_error(chunk)
261-
if break_on_error:
262-
# 添加错误信息到结果中
263-
result["error"] = {
264-
"status": chunk.get("status"),
265-
"code": chunk.get("code"),
266-
"message": chunk.get("message"),
267-
}
268-
break
269-
270-
elif event == "ping" and handle_ping:
271-
handle_ping(chunk)
272-
273-
# 合并所有回答块
274-
if answer_chunks:
275-
result["answer"] = "".join(answer_chunks)
276-
277-
return result
131+

0 commit comments

Comments
 (0)