Skip to content

Commit 5f758c8

Browse files
committed
增加了DifySite,重新生成了注释
1 parent aae03f2 commit 5f758c8

File tree

9 files changed

+681
-3240
lines changed

9 files changed

+681
-3240
lines changed

README.md

Lines changed: 158 additions & 416 deletions
Large diffs are not rendered by default.

examples/agent_example.py

Lines changed: 0 additions & 625 deletions
This file was deleted.

examples/chatbot_example.py

Lines changed: 0 additions & 577 deletions
This file was deleted.

examples/chatflow_example.py

Lines changed: 0 additions & 603 deletions
This file was deleted.

examples/text_generation_example.py

Lines changed: 0 additions & 520 deletions
This file was deleted.

examples/workflow_example.py

Lines changed: 0 additions & 498 deletions
This file was deleted.

pydify/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def create_client(type: str, base_url: str, api_key: str) -> DifyBaseClient:
2828
raise ValueError(f"Invalid client type: {type}")
2929

3030

31-
__version__ = "2.1.0"
31+
__version__ = "2.2.0"
3232
__all__ = [
3333
"WorkflowClient",
3434
"ChatbotClient",

pydify/site.py

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
"""
2+
Pydify - Dify 网站API交互
3+
4+
此模块提供与Dify网站API交互的工具。
5+
"""
6+
import requests
7+
import webbrowser
8+
9+
# Dify应用模式的枚举类,用于创建应用时指定应用类型
10+
class DifyAppMode:
11+
"""
12+
Dify应用模式的枚举类,定义了Dify支持的所有应用类型
13+
"""
14+
CHAT = "chat" # 聊天助手chatbot
15+
AGENT_CHAT = "agent-chat" # Agent - 代理模式
16+
COMPLETION = "completion" # 文本生成应用
17+
ADVANCED_CHAT = "advanced-chat" # Chatflow - 高级聊天流
18+
WORKFLOW = "workflow" # 工作流应用
19+
20+
class DifySite:
21+
"""
22+
Dify网站API交互类,提供与Dify平台管理API的交互功能
23+
24+
此类封装了Dify平台的所有管理API,包括登录认证、应用管理、API密钥管理等功能。
25+
初始化时会自动登录并获取访问令牌,后续所有API调用都会使用此令牌进行认证。
26+
"""
27+
28+
def __init__(self, base_url, email, password):
29+
"""
30+
初始化DifySite实例并自动登录获取访问令牌
31+
32+
Args:
33+
base_url (str): Dify平台的基础URL,例如 "http://sandanapp.com:11080"
34+
email (str): 登录邮箱账号
35+
password (str): 登录密码
36+
37+
Raises:
38+
Exception: 登录失败时抛出异常,包含错误信息
39+
"""
40+
self.base_url = base_url
41+
self.email = email
42+
self.password = password
43+
self.access_token = None
44+
self.refresh_token = None
45+
46+
# 自动登录并获取访问令牌
47+
self._login()
48+
49+
def _login(self):
50+
"""
51+
登录Dify平台并获取访问令牌
52+
53+
Raises:
54+
Exception: 登录失败时抛出异常,包含错误信息
55+
"""
56+
url = f"{self.base_url}/console/api/login"
57+
data = {
58+
"email": self.email,
59+
"language": "zh-CN",
60+
"password": self.password,
61+
"remember_me": True
62+
}
63+
response = requests.post(url, json=data)
64+
if response.status_code != 200:
65+
raise Exception(f"登录失败: {response.text}")
66+
67+
response_data = response.json()['data']
68+
self.access_token = response_data['access_token']
69+
self.refresh_token = response_data['refresh_token']
70+
71+
def fetch_apps(self, page=1, limit=100, name="", is_created_by_me=False, keywords="", tagIDs=[]):
72+
"""
73+
获取Dify平台中的应用列表,支持分页和过滤条件
74+
75+
Args:
76+
page (int, optional): 页码,从1开始. 默认为1.
77+
limit (int, optional): 每页返回的应用数量上限. 默认为100.
78+
name (str, optional): 按应用名称过滤. 默认为空字符串,不过滤.
79+
is_created_by_me (bool, optional): 是否只查询当前用户创建的应用. 默认为False(查询所有).
80+
keywords (str, optional): 关键词搜索. 默认为空字符串,不过滤.
81+
tagIDs (list, optional): 标签ID列表,按标签过滤. 默认为空列表,不过滤.
82+
83+
Raises:
84+
Exception: 获取应用列表失败时抛出异常,包含错误信息
85+
86+
Returns:
87+
dict: 应用列表的响应数据,包含以下字段:
88+
- page (int): 当前页码
89+
- limit (int): 每页数量
90+
- total (int): 应用总数
91+
- has_more (bool): 是否有更多页
92+
- data (list): 应用列表,每个应用包含以下字段:
93+
- id (str): 应用ID
94+
- name (str): 应用名称
95+
- description (str): 应用描述
96+
- mode (str): 应用模式,如chat、completion、workflow、agent-chat等
97+
- icon_type (str): 图标类型
98+
- icon (str): 图标
99+
- icon_background (str): 图标背景色
100+
- icon_url (str): 图标URL
101+
- model_config (dict): 模型配置
102+
- workflow (dict): 工作流配置
103+
- created_by (str): 创建者ID
104+
- created_at (int): 创建时间戳
105+
- updated_by (str): 更新者ID
106+
- updated_at (int): 更新时间戳
107+
- tags (list): 标签列表
108+
"""
109+
# 处理关键词中的空格,转换为URL编码
110+
keywords = keywords.replace(" ", "+")
111+
# 处理标签ID列表,转换为分号分隔的字符串
112+
tagIDs = "%3B".join(tagIDs)
113+
114+
# 构建URL参数
115+
params = []
116+
if page: params.append(f"page={page}")
117+
if limit: params.append(f"limit={limit}")
118+
if name: params.append(f"name={name}")
119+
if is_created_by_me: params.append(f"is_created_by_me={is_created_by_me}")
120+
if keywords: params.append(f"keywords={keywords}")
121+
if tagIDs: params.append(f"tagIDs={tagIDs}")
122+
123+
# 构建完整的API URL
124+
url = f"{self.base_url}/console/api/apps?" + "&".join(params)
125+
126+
# 发送请求
127+
response = requests.get(url, headers={"Authorization": f"Bearer {self.access_token}"})
128+
if response.status_code != 200:
129+
raise Exception(f"获取应用失败: {response.text}")
130+
return response.json()
131+
132+
def fetch_all_apps(self):
133+
"""
134+
获取Dify平台中的所有应用列表
135+
136+
Returns:
137+
list: 所有应用的列表,每个应用包含详细信息
138+
"""
139+
all_apps = []
140+
for page in range(1, 100):
141+
resp = self.fetch_apps(page=page, limit=100)
142+
all_apps.extend(resp['data'])
143+
if not resp['has_more']:
144+
break
145+
return all_apps
146+
147+
def fetch_app_dsl(self, app_id):
148+
"""
149+
获取指定应用的DSL配置
150+
151+
Args:
152+
app_id (str): 要获取DSL的应用ID
153+
154+
Raises:
155+
Exception: 获取DSL失败时抛出异常,包含错误信息
156+
157+
Returns:
158+
str: YAML格式的DSL内容
159+
"""
160+
export_url = f"{self.base_url}/console/api/apps/{app_id}/export?include_secret=false"
161+
response = requests.get(export_url, headers={"Authorization": f"Bearer {self.access_token}"})
162+
if response.status_code != 200:
163+
raise Exception(f"获取DSL失败: {response.text}")
164+
return response.json()['data']
165+
166+
def import_app_dsl(self, dsl, app_id=None):
167+
"""
168+
将DSL配置导入为新应用
169+
170+
Args:
171+
dsl (str): YAML格式的DSL配置内容
172+
app_id (str, optional): 要导入DSL的应用ID. 默认为None(创建新应用).
173+
174+
Raises:
175+
Exception: 导入DSL失败时抛出异常,包含错误信息
176+
177+
Returns:
178+
dict: 导入成功后的响应数据,包含新创建应用的信息:
179+
新创建的应用信息,包含id、name等字段
180+
"""
181+
import_url = f"{self.base_url}/console/api/apps/imports"
182+
payload = {
183+
'mode': 'yaml-content',
184+
'yaml_content': dsl
185+
}
186+
187+
if app_id:
188+
payload['app_id'] = app_id
189+
response = requests.post(import_url, headers={"Authorization": f"Bearer {self.access_token}"}, json=payload)
190+
if response.status_code != 200:
191+
raise Exception(f"导入DSL失败: {response.text}")
192+
return response.json()
193+
194+
def create_app(self, name, description, mode):
195+
"""
196+
创建新的Dify应用
197+
198+
Args:
199+
name (str): 应用名称
200+
description (str): 应用描述
201+
mode (str): 应用模式,从DifyAppMode类中选择,如DifyAppMode.CHAT
202+
203+
Raises:
204+
Exception: 创建应用失败时抛出异常,包含错误信息
205+
206+
Returns:
207+
dict: 创建应用成功后的响应,包含以下字段:
208+
- id (str): 应用ID,如"8aa70316-9c2e-4d6e-8588-617ed91b6b5c"
209+
- name (str): 应用名称
210+
- description (str): 应用描述
211+
- mode (str): 应用模式
212+
- icon (str): 应用图标
213+
- icon_background (str): 图标背景色
214+
- status (str): 应用状态
215+
- api_status (str): API状态
216+
- api_rpm (int): API每分钟请求数限制
217+
- api_rph (int): API每小时请求数限制
218+
- is_demo (bool): 是否为演示应用
219+
- created_at (int): 创建时间戳
220+
"""
221+
create_url = f"{self.base_url}/console/api/apps"
222+
payload = {
223+
'name': name,
224+
'description': description,
225+
'mode': mode,
226+
'icon': '🤖',
227+
'icon_background': '#FFEAD5',
228+
'icon_type': 'emoji',
229+
}
230+
response = requests.post(create_url, headers={"Authorization": f"Bearer {self.access_token}"}, json=payload)
231+
if response.status_code != 201:
232+
raise Exception(f"创建应用失败: {response.text}")
233+
return response.json()
234+
235+
def fetch_app(self, app_id):
236+
"""
237+
获取指定应用的详细信息
238+
239+
Args:
240+
app_id (str): 要获取的应用ID
241+
242+
Raises:
243+
Exception: 获取应用信息失败时抛出异常,包含错误信息
244+
245+
Returns:
246+
dict: 应用的详细信息,包含以下字段:
247+
- id (str): 应用ID
248+
- name (str): 应用名称
249+
- description (str): 应用描述
250+
- mode (str): 应用模式(chat, completion, workflow等)
251+
- icon_type (str): 图标类型
252+
- icon (str): 图标内容
253+
- icon_background (str): 图标背景色
254+
- icon_url (str): 图标URL
255+
- enable_site (bool): 是否启用网站
256+
- enable_api (bool): 是否启用API
257+
- model_config (dict): 模型配置
258+
- workflow (dict): 工作流配置(仅workflow模式)
259+
- site (dict): 网站配置
260+
- api_base_url (str): API基础URL
261+
- use_icon_as_answer_icon (bool): 是否使用应用图标作为回答图标
262+
- created_by (str): 创建者ID
263+
- created_at (int): 创建时间戳
264+
- updated_by (str): 更新者ID
265+
- updated_at (int): 更新时间戳
266+
- deleted_tools (list): 已删除的工具列表
267+
"""
268+
get_url = f"{self.base_url}/console/api/apps/{app_id}"
269+
response = requests.get(get_url, headers={"Authorization": f"Bearer {self.access_token}"})
270+
271+
if response.status_code != 200:
272+
raise Exception(f"获取应用信息失败: {response.text}")
273+
274+
return response.json()
275+
276+
def create_app_api_key(self, app_id):
277+
"""
278+
为指定应用创建API密钥
279+
280+
Args:
281+
app_id (str): 要创建API密钥的应用ID
282+
283+
Raises:
284+
Exception: 创建API密钥失败时抛出异常,包含错误信息
285+
286+
Returns:
287+
dict: 创建的API密钥信息,包含以下字段:
288+
- id (str): API密钥ID
289+
- type (str): 密钥类型,通常为"app"
290+
- token (str): API密钥令牌,例如"app-QGNv5nH4Zk9gKPCDwRklvlkp"
291+
- last_used_at (str|null): 最后使用时间,首次创建为null
292+
- created_at (int): 创建时间戳
293+
"""
294+
create_url = f"{self.base_url}/console/api/apps/{app_id}/api-keys"
295+
response = requests.post(create_url, headers={"Authorization": f"Bearer {self.access_token}"})
296+
if response.status_code != 201:
297+
raise Exception(f"创建API密钥失败: {response.text}")
298+
return response.json()
299+
300+
def fetch_app_api_keys(self, app_id):
301+
"""
302+
获取指定应用的所有API密钥列表
303+
304+
Args:
305+
app_id (str): 要获取API密钥的应用ID
306+
307+
Raises:
308+
Exception: 获取API密钥列表失败时抛出异常,包含错误信息
309+
310+
Returns:
311+
list: API密钥列表,每个密钥包含以下字段:
312+
- id (str): API密钥ID
313+
- type (str): 密钥类型,通常为"app"
314+
- token (str): API密钥令牌
315+
- last_used_at (str|null): 最后使用时间,如果未使用过则为null
316+
- created_at (int): 创建时间戳
317+
"""
318+
get_url = f"{self.base_url}/console/api/apps/{app_id}/api-keys"
319+
response = requests.get(get_url, headers={"Authorization": f"Bearer {self.access_token}"})
320+
if response.status_code != 200:
321+
raise Exception(f"获取API密钥列表失败: {response.text}")
322+
return response.json()['data']
323+
324+
def delete_app_api_key(self, app_id, api_key_id):
325+
"""
326+
删除指定应用的API密钥
327+
328+
Args:
329+
app_id (str): 应用ID
330+
api_key_id (str): 要删除的API密钥ID
331+
332+
Raises:
333+
Exception: 删除API密钥失败时抛出异常,包含错误信息
334+
335+
Returns:
336+
dict: 删除操作的响应数据,如果删除成功,通常返回空对象{}
337+
"""
338+
delete_url = f"{self.base_url}/console/api/apps/{app_id}/api-keys/{api_key_id}"
339+
response = requests.delete(delete_url, headers={"Authorization": f"Bearer {self.access_token}"})
340+
if response.status_code != 204:
341+
raise Exception(f"删除API密钥失败: {response.text}")
342+
return response.json()
343+
344+
def jump_to_app(self, app_id, app_mode):
345+
"""
346+
在浏览器中打开指定应用的控制台页面
347+
348+
Args:
349+
app_id (str): 要打开的应用ID
350+
app_mode (str): 应用模式,应与应用创建时的模式一致
351+
"""
352+
url = f"{self.base_url}/console/apps/{app_id}/{app_mode}"
353+
# 使用默认浏览器打开
354+
webbrowser.open(url)
355+
356+
def delete_app(self, app_id):
357+
"""
358+
删除指定应用
359+
360+
Args:
361+
app_id (str): 要删除的应用ID
362+
363+
Raises:
364+
Exception: 删除应用失败时抛出异常,包含错误信息
365+
366+
Returns:
367+
dict: 删除操作的响应数据,如果删除成功,通常返回空对象{}
368+
"""
369+
delete_url = f"{self.base_url}/console/api/apps/{app_id}"
370+
response = requests.delete(delete_url, headers={"Authorization": f"Bearer {self.access_token}"})
371+
if response.status_code != 204:
372+
raise Exception(f"删除应用失败: {response.text}")
373+
return response.json()
374+

0 commit comments

Comments
 (0)