gohumanloop 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gohumanloop/__init__.py +6 -8
- gohumanloop/adapters/__init__.py +6 -6
- gohumanloop/adapters/base_adapter.py +838 -0
- gohumanloop/adapters/langgraph_adapter.py +140 -632
- gohumanloop/cli/main.py +4 -1
- gohumanloop/core/interface.py +194 -217
- gohumanloop/core/manager.py +375 -266
- gohumanloop/manager/ghl_manager.py +223 -185
- gohumanloop/models/api_model.py +32 -7
- gohumanloop/models/glh_model.py +15 -11
- gohumanloop/providers/api_provider.py +233 -189
- gohumanloop/providers/base.py +179 -172
- gohumanloop/providers/email_provider.py +386 -325
- gohumanloop/providers/ghl_provider.py +19 -17
- gohumanloop/providers/terminal_provider.py +111 -92
- gohumanloop/utils/__init__.py +7 -1
- gohumanloop/utils/context_formatter.py +20 -15
- gohumanloop/utils/threadsafedict.py +64 -56
- gohumanloop/utils/utils.py +28 -28
- gohumanloop-0.0.7.dist-info/METADATA +298 -0
- gohumanloop-0.0.7.dist-info/RECORD +31 -0
- {gohumanloop-0.0.5.dist-info → gohumanloop-0.0.7.dist-info}/WHEEL +1 -1
- gohumanloop-0.0.5.dist-info/METADATA +0 -35
- gohumanloop-0.0.5.dist-info/RECORD +0 -30
- {gohumanloop-0.0.5.dist-info → gohumanloop-0.0.7.dist-info}/entry_points.txt +0 -0
- {gohumanloop-0.0.5.dist-info → gohumanloop-0.0.7.dist-info}/licenses/LICENSE +0 -0
- {gohumanloop-0.0.5.dist-info → gohumanloop-0.0.7.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
|
|
1
|
-
from typing import Dict, Any, Optional, List,
|
1
|
+
from typing import Dict, Any, Optional, List, Type
|
2
|
+
from types import TracebackType
|
2
3
|
import os
|
3
4
|
import asyncio
|
4
5
|
import aiohttp
|
@@ -8,21 +9,27 @@ from datetime import datetime
|
|
8
9
|
|
9
10
|
from gohumanloop.core.manager import DefaultHumanLoopManager
|
10
11
|
from gohumanloop.providers.ghl_provider import GoHumanLoopProvider
|
11
|
-
from gohumanloop.core.interface import
|
12
|
+
from gohumanloop.core.interface import (
|
13
|
+
HumanLoopProvider,
|
14
|
+
HumanLoopStatus,
|
15
|
+
HumanLoopResult,
|
16
|
+
)
|
12
17
|
from gohumanloop.utils import get_secret_from_env
|
13
18
|
from gohumanloop.models.glh_model import GoHumanLoopConfig
|
14
19
|
|
20
|
+
|
15
21
|
class GoHumanLoopManager(DefaultHumanLoopManager):
|
16
22
|
"""
|
17
23
|
GoHumanLoop 官方平台的人机交互管理器
|
18
|
-
|
24
|
+
|
19
25
|
这个管理器专门使用 GoHumanLoopProvider 作为提供者,用于将交互过程数据传输到 GoHumanLoop 平台。
|
20
26
|
它是 DefaultHumanLoopManager 的一个特殊实现,简化了与 GoHumanLoop 平台的集成。
|
21
|
-
|
27
|
+
|
22
28
|
主要职责:
|
23
29
|
1. 管理整个人机交互任务
|
24
30
|
2. 将交互任务数据统一传输到 GoHumanLoop 平台
|
25
31
|
"""
|
32
|
+
|
26
33
|
def __init__(
|
27
34
|
self,
|
28
35
|
request_timeout: int = 60,
|
@@ -30,12 +37,12 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
30
37
|
max_retries: int = 3,
|
31
38
|
sync_interval: int = 60, # 数据同步间隔(秒)
|
32
39
|
additional_providers: Optional[List[HumanLoopProvider]] = None,
|
33
|
-
auto_start_sync: bool = True,
|
40
|
+
auto_start_sync: bool = True, # 是否自动启动数据同步任务
|
34
41
|
config: Optional[Dict[str, Any]] = None,
|
35
42
|
):
|
36
43
|
"""
|
37
44
|
初始化 GoHumanLoop 管理器
|
38
|
-
|
45
|
+
|
39
46
|
Args:
|
40
47
|
request_timeout: API 请求超时时间(秒),默认60秒
|
41
48
|
poll_interval: 轮询检查请求状态的时间间隔(秒),默认5秒
|
@@ -45,18 +52,20 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
45
52
|
auto_start_sync: 是否在初始化时自动启动数据同步任务,默认为True
|
46
53
|
config: 附加配置参数字典,可选
|
47
54
|
"""
|
48
|
-
|
55
|
+
# Get API key from environment variables (if not provided)
|
49
56
|
api_key = get_secret_from_env("GOHUMANLOOP_API_KEY")
|
50
|
-
|
57
|
+
|
58
|
+
if api_key is None:
|
59
|
+
raise ValueError("GOHUMANLOOP_API_KEY environment variable is not set!")
|
60
|
+
|
51
61
|
# Get API base URL from environment variables (if not provided)
|
52
|
-
api_base_url = os.environ.get(
|
53
|
-
|
54
|
-
# Validate configuration using pydantic model
|
55
|
-
self.ghl_config = GoHumanLoopConfig(
|
56
|
-
api_key=api_key,
|
57
|
-
api_base_url=api_base_url
|
62
|
+
api_base_url = os.environ.get(
|
63
|
+
"GOHUMANLOOP_API_BASE_URL", "https://www.gohumanloop.com"
|
58
64
|
)
|
59
|
-
|
65
|
+
|
66
|
+
# Validate configuration using pydantic model
|
67
|
+
self.ghl_config = GoHumanLoopConfig(api_key=api_key, api_base_url=api_base_url)
|
68
|
+
|
60
69
|
self.name = "GoHumanLoop"
|
61
70
|
# 创建 GoHumanLoop 提供者
|
62
71
|
ghl_provider = GoHumanLoopProvider(
|
@@ -64,36 +73,38 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
64
73
|
request_timeout=request_timeout,
|
65
74
|
poll_interval=poll_interval,
|
66
75
|
max_retries=max_retries,
|
67
|
-
config=config
|
76
|
+
config=config,
|
68
77
|
)
|
69
|
-
|
78
|
+
|
70
79
|
# 初始化提供者列表
|
71
|
-
providers = [ghl_provider]
|
80
|
+
providers: List[HumanLoopProvider] = [ghl_provider]
|
72
81
|
if additional_providers:
|
73
82
|
providers.extend(additional_providers)
|
74
|
-
|
83
|
+
|
75
84
|
# 调用父类初始化方法
|
76
85
|
super().__init__(initial_providers=providers)
|
77
|
-
|
86
|
+
|
78
87
|
# 设置 GoHumanLoop 提供者为默认提供者
|
79
88
|
self.default_provider_id = self.name
|
80
|
-
|
89
|
+
|
81
90
|
# 存储最近同步时间
|
82
91
|
self._last_sync_time = time.time()
|
83
|
-
|
92
|
+
|
84
93
|
# 同步间隔
|
85
94
|
self.sync_interval = sync_interval
|
86
|
-
|
95
|
+
|
87
96
|
# 存储已取消的请求和对话信息
|
88
|
-
self._cancelled_conversations
|
89
|
-
|
90
|
-
#
|
91
|
-
|
92
|
-
|
97
|
+
self._cancelled_conversations: Dict[
|
98
|
+
str, Dict[str, Any]
|
99
|
+
] = {} # conversation_id -> 取消信息
|
100
|
+
|
101
|
+
# 数据同步任务引用
|
102
|
+
self._sync_task: asyncio.Task[None] | None = None
|
103
|
+
|
93
104
|
# 同步模式相关属性
|
94
|
-
self._sync_thread = None
|
105
|
+
self._sync_thread: threading.Thread | None = None
|
95
106
|
self._sync_thread_stop_event = threading.Event()
|
96
|
-
|
107
|
+
|
97
108
|
# 启动数据同步任务
|
98
109
|
if auto_start_sync:
|
99
110
|
# 判断是否处在异步环境
|
@@ -102,23 +113,24 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
102
113
|
else:
|
103
114
|
self.start_sync_task()
|
104
115
|
|
105
|
-
|
106
116
|
async def async_get_ghl_provider(self) -> GoHumanLoopProvider:
|
107
117
|
"""
|
108
118
|
获取 GoHumanLoop 提供者实例
|
109
|
-
|
119
|
+
|
110
120
|
Returns:
|
111
121
|
GoHumanLoopProvider: GoHumanLoop 提供者实例
|
112
122
|
"""
|
113
123
|
provider = await self.async_get_provider(self.default_provider_id)
|
124
|
+
# 添加类型转换确保返回正确类型
|
125
|
+
assert isinstance(provider, GoHumanLoopProvider)
|
114
126
|
return provider
|
115
|
-
|
116
|
-
async def async_start_sync_task(self):
|
127
|
+
|
128
|
+
async def async_start_sync_task(self) -> None:
|
117
129
|
"""启动数据同步任务"""
|
118
130
|
if self._sync_task is None or self._sync_task.done():
|
119
131
|
self._sync_task = asyncio.create_task(self._async_data_periodically())
|
120
|
-
|
121
|
-
async def _async_data_periodically(self):
|
132
|
+
|
133
|
+
async def _async_data_periodically(self) -> None:
|
122
134
|
"""定期同步数据到 GoHumanLoop 平台"""
|
123
135
|
while True:
|
124
136
|
try:
|
@@ -134,18 +146,17 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
134
146
|
except Exception as e:
|
135
147
|
print(f"最终数据同步错误: {str(e)}")
|
136
148
|
raise # 重新抛出取消异常
|
137
|
-
|
138
|
-
def start_sync_task(self):
|
149
|
+
|
150
|
+
def start_sync_task(self) -> None:
|
139
151
|
"""启动同步版本的数据同步任务"""
|
140
152
|
if self._sync_thread is None or not self._sync_thread.is_alive():
|
141
153
|
self._sync_thread_stop_event.clear()
|
142
154
|
self._sync_thread = threading.Thread(
|
143
|
-
target=self._sync_data_periodically,
|
144
|
-
daemon=True
|
155
|
+
target=self._sync_data_periodically, daemon=True
|
145
156
|
)
|
146
157
|
self._sync_thread.start()
|
147
|
-
|
148
|
-
def _sync_data_periodically(self):
|
158
|
+
|
159
|
+
def _sync_data_periodically(self) -> None:
|
149
160
|
"""同步版本:定期同步数据到 GoHumanLoop 平台"""
|
150
161
|
while not self._sync_thread_stop_event.is_set():
|
151
162
|
try:
|
@@ -155,207 +166,227 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
155
166
|
except Exception as e:
|
156
167
|
# 记录错误但不中断同步循环
|
157
168
|
print(f"同步数据同步错误: {str(e)}")
|
158
|
-
|
169
|
+
|
159
170
|
# 线程结束前执行最后一次同步
|
160
171
|
try:
|
161
172
|
self.sync_data_to_platform()
|
162
173
|
except Exception as e:
|
163
174
|
print(f"最终同步数据同步错误: {str(e)}")
|
164
|
-
|
165
|
-
async def async_data_to_platform(self):
|
175
|
+
|
176
|
+
async def async_data_to_platform(self) -> None:
|
166
177
|
"""
|
167
178
|
同步数据到 GoHumanLoop 平台
|
168
|
-
|
179
|
+
|
169
180
|
此方法收集所有任务的数据,并通过 API 发送到 GoHumanLoop 平台
|
170
181
|
"""
|
171
182
|
current_time = time.time()
|
172
|
-
|
183
|
+
|
173
184
|
# 获取所有任务ID
|
174
185
|
task_ids = list(self._task_conversations.keys())
|
175
|
-
|
186
|
+
|
176
187
|
# 对每个任务进行数据同步
|
177
188
|
for task_id in task_ids:
|
178
189
|
# 获取任务相关的所有对话
|
179
190
|
conversations = await self.async_get_task_conversations(task_id)
|
180
|
-
|
191
|
+
|
181
192
|
# 收集任务数据
|
182
|
-
task_data = {
|
193
|
+
task_data: Dict[str, Any] = {
|
183
194
|
"task_id": task_id,
|
184
195
|
"conversations": [],
|
185
|
-
"timestamp": datetime.now().isoformat()
|
196
|
+
"timestamp": datetime.now().isoformat(),
|
186
197
|
}
|
187
|
-
|
198
|
+
|
188
199
|
# 收集每个对话的数据
|
189
200
|
for conversation_id in conversations:
|
190
201
|
# 获取对话中的所有请求
|
191
|
-
request_ids = await self.async_get_conversation_requests(
|
192
|
-
|
193
|
-
|
202
|
+
request_ids = await self.async_get_conversation_requests(
|
203
|
+
conversation_id
|
204
|
+
)
|
205
|
+
|
206
|
+
conversation_data: Dict[str, Any] = {
|
194
207
|
"conversation_id": conversation_id,
|
195
208
|
"provider_id": self._conversation_provider.get(conversation_id),
|
196
|
-
"requests": []
|
209
|
+
"requests": [],
|
197
210
|
}
|
198
|
-
|
211
|
+
|
199
212
|
# 收集每个请求的数据
|
200
213
|
for request_id in request_ids:
|
201
|
-
result = await self._async_get_request_status(
|
202
|
-
|
214
|
+
result = await self._async_get_request_status(
|
215
|
+
conversation_id, request_id
|
216
|
+
)
|
217
|
+
|
203
218
|
# 添加请求数据
|
204
|
-
conversation_data["requests"].append(
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
219
|
+
conversation_data["requests"].append(
|
220
|
+
{
|
221
|
+
"request_id": request_id,
|
222
|
+
"status": result.status.value,
|
223
|
+
"loop_type": result.loop_type.value,
|
224
|
+
"response": result.response,
|
225
|
+
"feedback": result.feedback,
|
226
|
+
"responded_by": result.responded_by,
|
227
|
+
"responded_at": result.responded_at,
|
228
|
+
"error": result.error,
|
229
|
+
}
|
230
|
+
)
|
231
|
+
|
215
232
|
# 添加对话数据
|
216
233
|
task_data["conversations"].append(conversation_data)
|
217
|
-
|
234
|
+
|
218
235
|
# 检查是否有已取消的对话需要添加
|
219
236
|
for conv_id, cancel_info in self._cancelled_conversations.items():
|
220
237
|
if conv_id not in conversations:
|
221
238
|
# 创建已取消对话的数据
|
222
|
-
cancelled_conv_data = {
|
239
|
+
cancelled_conv_data: Dict[str, Any] = {
|
223
240
|
"conversation_id": conv_id,
|
224
241
|
"provider_id": cancel_info.get("provider_id"),
|
225
|
-
"requests": []
|
242
|
+
"requests": [],
|
226
243
|
}
|
227
|
-
|
244
|
+
|
228
245
|
# 添加此对话中的已取消请求
|
229
246
|
for request_id in cancel_info.get("request_ids", []):
|
230
|
-
result = await self._async_get_request_status(
|
231
|
-
|
247
|
+
result = await self._async_get_request_status(
|
248
|
+
conv_id, request_id, cancel_info.get("provider_id")
|
249
|
+
)
|
250
|
+
|
232
251
|
# 添加请求数据
|
233
|
-
cancelled_conv_data["requests"].append(
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
252
|
+
cancelled_conv_data["requests"].append(
|
253
|
+
{
|
254
|
+
"request_id": request_id,
|
255
|
+
"status": result.status.value,
|
256
|
+
"loop_type": result.loop_type.value,
|
257
|
+
"response": result.response,
|
258
|
+
"feedback": result.feedback,
|
259
|
+
"responded_by": result.responded_by,
|
260
|
+
"responded_at": result.responded_at,
|
261
|
+
"error": result.error,
|
262
|
+
}
|
263
|
+
)
|
264
|
+
|
244
265
|
# 添加已取消的对话
|
245
266
|
task_data["conversations"].append(cancelled_conv_data)
|
246
|
-
|
267
|
+
|
247
268
|
# 发送数据到平台
|
248
269
|
await self._async_send_task_data_to_platform(task_data)
|
249
|
-
|
270
|
+
|
250
271
|
# 更新最后同步时间
|
251
272
|
self._last_sync_time = current_time
|
252
|
-
|
253
|
-
def sync_data_to_platform(self):
|
273
|
+
|
274
|
+
def sync_data_to_platform(self) -> None:
|
254
275
|
"""
|
255
276
|
同步版本:同步数据到 GoHumanLoop 平台
|
256
|
-
|
277
|
+
|
257
278
|
此方法收集所有任务的数据,并通过 API 发送到 GoHumanLoop 平台
|
258
279
|
"""
|
259
280
|
current_time = time.time()
|
260
|
-
|
281
|
+
|
261
282
|
# 获取所有任务ID
|
262
283
|
task_ids = list(self._task_conversations.keys())
|
263
|
-
|
284
|
+
|
264
285
|
# 对每个任务进行数据同步
|
265
286
|
for task_id in task_ids:
|
266
287
|
# 获取任务相关的所有对话
|
267
288
|
# 使用同步方式运行异步方法
|
268
289
|
loop = asyncio.new_event_loop()
|
269
290
|
conversations = self.get_task_conversations(task_id)
|
270
|
-
|
291
|
+
|
271
292
|
# 收集任务数据
|
272
|
-
task_data = {
|
293
|
+
task_data: Dict[str, Any] = {
|
273
294
|
"task_id": task_id,
|
274
295
|
"conversations": [],
|
275
|
-
"timestamp": datetime.now().isoformat()
|
296
|
+
"timestamp": datetime.now().isoformat(),
|
276
297
|
}
|
277
|
-
|
298
|
+
|
278
299
|
# 收集每个对话的数据
|
279
300
|
for conversation_id in conversations:
|
280
301
|
# 获取对话中的所有请求
|
281
302
|
request_ids = self.get_conversation_requests(conversation_id)
|
282
|
-
|
283
|
-
conversation_data = {
|
303
|
+
|
304
|
+
conversation_data: Dict[str, Any] = {
|
284
305
|
"conversation_id": conversation_id,
|
285
306
|
"provider_id": self._conversation_provider.get(conversation_id),
|
286
|
-
"requests": []
|
307
|
+
"requests": [],
|
287
308
|
}
|
288
|
-
|
309
|
+
|
289
310
|
# 收集每个请求的数据
|
290
311
|
for request_id in request_ids:
|
291
|
-
result = loop.run_until_complete(
|
292
|
-
|
312
|
+
result = loop.run_until_complete(
|
313
|
+
self._async_get_request_status(conversation_id, request_id)
|
314
|
+
)
|
315
|
+
|
293
316
|
# 添加请求数据
|
294
|
-
conversation_data["requests"].append(
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
317
|
+
conversation_data["requests"].append(
|
318
|
+
{
|
319
|
+
"request_id": request_id,
|
320
|
+
"status": result.status.value,
|
321
|
+
"loop_type": result.loop_type.value,
|
322
|
+
"response": result.response,
|
323
|
+
"feedback": result.feedback,
|
324
|
+
"responded_by": result.responded_by,
|
325
|
+
"responded_at": result.responded_at,
|
326
|
+
"error": result.error,
|
327
|
+
}
|
328
|
+
)
|
329
|
+
|
305
330
|
# 添加对话数据
|
306
331
|
task_data["conversations"].append(conversation_data)
|
307
|
-
|
332
|
+
|
308
333
|
# 检查是否有已取消的对话需要添加
|
309
334
|
for conv_id, cancel_info in self._cancelled_conversations.items():
|
310
335
|
if conv_id not in conversations:
|
311
336
|
# 创建已取消对话的数据
|
312
|
-
cancelled_conv_data = {
|
337
|
+
cancelled_conv_data: Dict[str, Any] = {
|
313
338
|
"conversation_id": conv_id,
|
314
339
|
"provider_id": cancel_info.get("provider_id"),
|
315
|
-
"requests": []
|
340
|
+
"requests": [],
|
316
341
|
}
|
317
|
-
|
342
|
+
|
318
343
|
# 添加此对话中的已取消请求
|
319
344
|
for request_id in cancel_info.get("request_ids", []):
|
320
345
|
result = loop.run_until_complete(
|
321
|
-
self._async_get_request_status(
|
346
|
+
self._async_get_request_status(
|
347
|
+
conv_id, request_id, cancel_info.get("provider_id")
|
348
|
+
)
|
322
349
|
)
|
323
|
-
|
350
|
+
|
324
351
|
# 添加请求数据
|
325
|
-
cancelled_conv_data["requests"].append(
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
352
|
+
cancelled_conv_data["requests"].append(
|
353
|
+
{
|
354
|
+
"request_id": request_id,
|
355
|
+
"status": result.status.value,
|
356
|
+
"loop_type": result.loop_type.value,
|
357
|
+
"response": result.response,
|
358
|
+
"feedback": result.feedback,
|
359
|
+
"responded_by": result.responded_by,
|
360
|
+
"responded_at": result.responded_at,
|
361
|
+
"error": result.error,
|
362
|
+
}
|
363
|
+
)
|
364
|
+
|
336
365
|
# 添加已取消的对话
|
337
366
|
task_data["conversations"].append(cancelled_conv_data)
|
338
|
-
|
367
|
+
|
339
368
|
# 发送数据到平台
|
340
369
|
loop.run_until_complete(self._async_send_task_data_to_platform(task_data))
|
341
370
|
loop.close()
|
342
|
-
|
371
|
+
|
343
372
|
# 更新最后同步时间
|
344
373
|
self._last_sync_time = current_time
|
345
|
-
|
346
|
-
async def _async_send_task_data_to_platform(
|
374
|
+
|
375
|
+
async def _async_send_task_data_to_platform(
|
376
|
+
self, task_data: Dict[str, Any]
|
377
|
+
) -> None:
|
347
378
|
"""发送任务数据到 GoHumanLoop 平台"""
|
348
379
|
try:
|
349
380
|
# 构建 API 请求 URL
|
350
381
|
api_base_url = self.ghl_config.api_base_url
|
351
382
|
url = f"{api_base_url}/v1/humanloop/tasks/sync"
|
352
|
-
|
383
|
+
|
353
384
|
# 构建请求头
|
354
385
|
headers = {
|
355
386
|
"Content-Type": "application/json",
|
356
|
-
"Authorization": f"Bearer {self.ghl_config.api_key.get_secret_value()}"
|
387
|
+
"Authorization": f"Bearer {self.ghl_config.api_key.get_secret_value()}",
|
357
388
|
}
|
358
|
-
|
389
|
+
|
359
390
|
# 使用 aiohttp 直接发送请求,而不依赖于 provider
|
360
391
|
async with aiohttp.ClientSession() as session:
|
361
392
|
try:
|
@@ -363,7 +394,7 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
363
394
|
url=url,
|
364
395
|
headers=headers,
|
365
396
|
json=task_data,
|
366
|
-
timeout=30 # 设置合理的超时时间
|
397
|
+
timeout=30, # 设置合理的超时时间
|
367
398
|
) as response:
|
368
399
|
# 处理 404 错误
|
369
400
|
if response.status == 404:
|
@@ -371,16 +402,18 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
371
402
|
return
|
372
403
|
# 处理 401 错误
|
373
404
|
elif response.status == 401:
|
374
|
-
print(
|
405
|
+
print("同步任务数据失败: 认证失败 - 请检查 API 密钥")
|
375
406
|
return
|
376
|
-
|
407
|
+
|
377
408
|
# 处理其他错误状态码
|
378
409
|
if not response.ok:
|
379
|
-
print(
|
410
|
+
print(
|
411
|
+
f"同步任务数据失败: HTTP {response.status} - {response.reason}"
|
412
|
+
)
|
380
413
|
return
|
381
|
-
|
414
|
+
|
382
415
|
response_data = await response.json()
|
383
|
-
|
416
|
+
|
384
417
|
if not response_data.get("success", False):
|
385
418
|
error_msg = response_data.get("error", "未知错误")
|
386
419
|
print(f"同步任务数据失败: {error_msg}")
|
@@ -389,66 +422,57 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
389
422
|
except Exception as e:
|
390
423
|
print(f"发送任务数据到平台异常: {str(e)}")
|
391
424
|
|
392
|
-
|
393
425
|
async def async_cancel_conversation(
|
394
|
-
self,
|
395
|
-
conversation_id: str,
|
396
|
-
provider_id: Optional[str] = None
|
426
|
+
self, conversation_id: str, provider_id: Optional[str] = None
|
397
427
|
) -> bool:
|
398
428
|
"""
|
399
429
|
取消整个对话,并保存取消信息用于后续同步
|
400
|
-
|
430
|
+
|
401
431
|
重写父类方法,在调用父类方法前保存对话信息
|
402
432
|
"""
|
403
433
|
# 获取对话关联的provider_id
|
404
434
|
if provider_id is None:
|
405
435
|
provider_id = self._conversation_provider.get(conversation_id)
|
406
|
-
|
436
|
+
|
407
437
|
# 保存对话取消信息,包括provider_id
|
408
438
|
self._cancelled_conversations[conversation_id] = {
|
409
439
|
"request_ids": list(self._conversation_requests.get(conversation_id, [])),
|
410
|
-
"provider_id": provider_id
|
440
|
+
"provider_id": provider_id,
|
411
441
|
}
|
412
|
-
|
442
|
+
|
413
443
|
# 调用父类方法执行实际取消操作
|
414
444
|
return await super().async_cancel_conversation(conversation_id, provider_id)
|
415
|
-
|
445
|
+
|
416
446
|
def __str__(self) -> str:
|
417
447
|
"""返回此实例的字符串描述"""
|
418
448
|
return f"GoHumanLoop(default_provider={self.default_provider_id}, providers={len(self.providers)})"
|
419
|
-
|
449
|
+
|
420
450
|
async def _async_get_request_status(
|
421
|
-
self,
|
422
|
-
conversation_id: str,
|
423
|
-
request_id: str,
|
424
|
-
provider_id: Optional[str] = None
|
451
|
+
self, conversation_id: str, request_id: str, provider_id: Optional[str] = None
|
425
452
|
) -> HumanLoopResult:
|
426
453
|
"""
|
427
454
|
获取请求状态的辅助方法
|
428
|
-
|
455
|
+
|
429
456
|
Args:
|
430
457
|
conversation_id: 对话ID
|
431
458
|
request_id: 请求ID
|
432
459
|
provider_id: 提供者ID(可选)
|
433
|
-
|
460
|
+
|
434
461
|
Returns:
|
435
462
|
HumanLoopResult: 请求状态结果
|
436
463
|
"""
|
437
464
|
# check_request_status
|
438
465
|
if provider_id is None:
|
439
466
|
provider_id = self._conversation_provider.get(conversation_id)
|
440
|
-
|
467
|
+
|
441
468
|
if not provider_id or provider_id not in self.providers:
|
442
469
|
raise ValueError(f"Provider '{provider_id}' not found")
|
443
|
-
|
470
|
+
|
444
471
|
provider = self.providers[provider_id]
|
445
472
|
return await provider.async_check_request_status(conversation_id, request_id)
|
446
473
|
|
447
474
|
async def async_check_request_status(
|
448
|
-
self,
|
449
|
-
conversation_id: str,
|
450
|
-
request_id: str,
|
451
|
-
provider_id: Optional[str] = None
|
475
|
+
self, conversation_id: str, request_id: str, provider_id: Optional[str] = None
|
452
476
|
) -> HumanLoopResult:
|
453
477
|
"""
|
454
478
|
重写父类方法,增加数据同步操作
|
@@ -457,34 +481,36 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
457
481
|
if provider_id is None:
|
458
482
|
stored_provider_id = self._conversation_provider.get(conversation_id)
|
459
483
|
provider_id = stored_provider_id or self.default_provider_id
|
460
|
-
|
484
|
+
|
461
485
|
if not provider_id or provider_id not in self.providers:
|
462
486
|
raise ValueError(f"Provider '{provider_id}' not found")
|
463
|
-
|
487
|
+
|
464
488
|
provider = self.providers[provider_id]
|
465
489
|
result = await provider.async_check_request_status(conversation_id, request_id)
|
466
|
-
|
490
|
+
|
467
491
|
# 如果有回调且状态不是等待或进行中
|
468
492
|
if result.status not in [HumanLoopStatus.PENDING]:
|
469
493
|
# 同步数据到平台
|
470
494
|
await self.async_data_to_platform()
|
471
495
|
# 触发状态更新回调
|
472
496
|
if (conversation_id, request_id) in self._callbacks:
|
473
|
-
await self._async_trigger_update_callback(
|
497
|
+
await self._async_trigger_update_callback(
|
498
|
+
conversation_id, request_id, provider, result
|
499
|
+
)
|
474
500
|
|
475
501
|
return result
|
476
|
-
|
477
|
-
def shutdown(self):
|
502
|
+
|
503
|
+
def shutdown(self) -> None:
|
478
504
|
"""
|
479
505
|
关闭管理器并确保数据同步(同步版本)
|
480
|
-
|
506
|
+
|
481
507
|
在程序退出前调用此方法,确保所有数据都被同步到平台
|
482
508
|
"""
|
483
509
|
# 停止同步线程
|
484
510
|
if self._sync_thread and self._sync_thread.is_alive():
|
485
511
|
self._sync_thread_stop_event.set()
|
486
512
|
self._sync_thread.join(timeout=5) # 等待线程结束,最多5秒
|
487
|
-
|
513
|
+
|
488
514
|
# 执行最后一次同步数据同步
|
489
515
|
try:
|
490
516
|
self.sync_data_to_platform()
|
@@ -492,10 +518,10 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
492
518
|
except Exception as e:
|
493
519
|
print(f"最终同步数据同步失败: {str(e)}")
|
494
520
|
|
495
|
-
async def async_shutdown(self):
|
521
|
+
async def async_shutdown(self) -> None:
|
496
522
|
"""
|
497
523
|
关闭管理器并确保数据同步(异步版本)
|
498
|
-
|
524
|
+
|
499
525
|
在程序退出前调用此方法,确保所有数据都被同步到平台
|
500
526
|
"""
|
501
527
|
# 取消周期性同步任务
|
@@ -511,22 +537,34 @@ class GoHumanLoopManager(DefaultHumanLoopManager):
|
|
511
537
|
print("最终异步数据同步完成")
|
512
538
|
except Exception as e:
|
513
539
|
print(f"最终异步数据同步失败: {str(e)}")
|
514
|
-
|
515
|
-
async def __aenter__(self):
|
540
|
+
|
541
|
+
async def __aenter__(self) -> "GoHumanLoopManager":
|
516
542
|
"""实现异步上下文管理器协议的进入方法"""
|
517
543
|
await self.async_start_sync_task()
|
518
544
|
return self
|
519
|
-
|
520
|
-
async def __aexit__(
|
545
|
+
|
546
|
+
async def __aexit__(
|
547
|
+
self,
|
548
|
+
exc_type: Optional[Type[BaseException]],
|
549
|
+
exc_val: Optional[BaseException],
|
550
|
+
exc_tb: Optional[TracebackType],
|
551
|
+
) -> Optional[bool]:
|
521
552
|
"""实现异步上下文管理器协议的退出方法"""
|
522
553
|
await self.async_shutdown()
|
523
|
-
|
524
|
-
|
554
|
+
return None
|
555
|
+
|
556
|
+
def __enter__(self) -> "GoHumanLoopManager":
|
525
557
|
"""实现同步上下文管理器协议的进入方法"""
|
526
558
|
# 使用同步模式
|
527
559
|
self.start_sync_task()
|
528
560
|
return self
|
529
|
-
|
530
|
-
def __exit__(
|
561
|
+
|
562
|
+
def __exit__(
|
563
|
+
self,
|
564
|
+
exc_type: Optional[Type[BaseException]],
|
565
|
+
exc_val: Optional[BaseException],
|
566
|
+
exc_tb: Optional[TracebackType],
|
567
|
+
) -> Optional[bool]:
|
531
568
|
"""实现同步上下文管理器协议的退出方法"""
|
532
569
|
self.shutdown()
|
570
|
+
return None
|