oneliai 1.2.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.
- oneliai/__init__.py +0 -0
- oneliai/client.py +930 -0
- oneliai-1.2.7.dist-info/METADATA +8 -0
- oneliai-1.2.7.dist-info/RECORD +8 -0
- oneliai-1.2.7.dist-info/WHEEL +5 -0
- oneliai-1.2.7.dist-info/top_level.txt +2 -0
- sdk/__init__.py +0 -0
- sdk/client.py +129 -0
oneliai/__init__.py
ADDED
|
File without changes
|
oneliai/client.py
ADDED
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import asyncio
|
|
3
|
+
import uuid
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import pymysql
|
|
7
|
+
import json
|
|
8
|
+
from typing import List, Dict, Any, Optional,Callable
|
|
9
|
+
from datetime import datetime, date, time, timedelta
|
|
10
|
+
import decimal
|
|
11
|
+
import jwt
|
|
12
|
+
import redis
|
|
13
|
+
URL="https://apis.oneli.chat"
|
|
14
|
+
# URL="http://localhost:8085"
|
|
15
|
+
SECRET_KEY = "your-256-bit-secret" # 生产环境应从配置读取
|
|
16
|
+
ALGORITHM = "HS256"
|
|
17
|
+
appurl="http://localhost:3000"
|
|
18
|
+
protocol="http"
|
|
19
|
+
class AIClient:
|
|
20
|
+
def __init__(self, client_id, client_secret, base_url=f'{URL}/v1/strategy',mode = "auto",callback:Callable=None):
|
|
21
|
+
self.client_id = client_id
|
|
22
|
+
self.client_secret = client_secret
|
|
23
|
+
self.base_url = base_url
|
|
24
|
+
self.access_token = self._get_access_token()
|
|
25
|
+
self.mode = mode
|
|
26
|
+
self.local=False
|
|
27
|
+
self.local_ports = [3000, 3001, 3002, 3003, 3004] # Electron 可能使用的端口
|
|
28
|
+
self.remote_port = 8001 # 远程服务固定端口
|
|
29
|
+
self.callback=callback
|
|
30
|
+
self._task_checker: Optional[asyncio.Task] = None
|
|
31
|
+
self._should_stop = False
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
# 同步Redis客户端(用于触发代码)
|
|
35
|
+
self.redis_client = redis.Redis(
|
|
36
|
+
host="124.70.82.221",
|
|
37
|
+
port=6379,
|
|
38
|
+
db=1,
|
|
39
|
+
password="cgpe34!",
|
|
40
|
+
decode_responses=True,
|
|
41
|
+
socket_connect_timeout=5,
|
|
42
|
+
socket_keepalive=True
|
|
43
|
+
)
|
|
44
|
+
# 测试连接
|
|
45
|
+
self.redis_client.ping()
|
|
46
|
+
logging.info("Redis同步客户端连接成功")
|
|
47
|
+
except redis.ConnectionError as e:
|
|
48
|
+
logging.error(f"Redis连接失败: {e}")
|
|
49
|
+
self.redis_client = None
|
|
50
|
+
raise
|
|
51
|
+
|
|
52
|
+
async def _get_userid(self):
|
|
53
|
+
payload = jwt.decode(
|
|
54
|
+
self.access_token,
|
|
55
|
+
SECRET_KEY,
|
|
56
|
+
algorithms=[ALGORITHM],
|
|
57
|
+
options={
|
|
58
|
+
"verify_signature": True,
|
|
59
|
+
"verify_exp": True,
|
|
60
|
+
"verify_aud": False # 根据需求调整
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
return payload["user_id"]
|
|
64
|
+
|
|
65
|
+
def _get_access_token(self):
|
|
66
|
+
response = requests.post(
|
|
67
|
+
f'{self.base_url}/auth/token',
|
|
68
|
+
json={
|
|
69
|
+
'client_id': self.client_id,
|
|
70
|
+
'client_secret': self.client_secret,
|
|
71
|
+
'grant_type': 'client_credentials'
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
if response.status_code == 200:
|
|
75
|
+
return response.json().get('access_token')
|
|
76
|
+
else:
|
|
77
|
+
raise Exception('Failed to get access token')
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def detect_environment(self) -> str:
|
|
81
|
+
"""自动检测运行环境"""
|
|
82
|
+
if self.mode != "auto":
|
|
83
|
+
return self.mode
|
|
84
|
+
|
|
85
|
+
# 尝试连接本地 Electron 服务
|
|
86
|
+
for port in self.local_ports:
|
|
87
|
+
try:
|
|
88
|
+
url = f"{protocol}://127.0.0.1:{port}/api/health"
|
|
89
|
+
# url = f"http://127.0.0.1:{port}/api/health"
|
|
90
|
+
response = requests.get(url, timeout=2)
|
|
91
|
+
|
|
92
|
+
if response.status_code == 200:
|
|
93
|
+
data=response.json()
|
|
94
|
+
|
|
95
|
+
print(data['status'])
|
|
96
|
+
if data['status']=="healthy":
|
|
97
|
+
logging.info(f"检测到本地 Electron 服务 (端口 {port})")
|
|
98
|
+
return "local"
|
|
99
|
+
except:
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
# 尝试连接远程服务
|
|
103
|
+
try:
|
|
104
|
+
url = f"{protocol}://127.0.0.1:{self.remote_port}/api/health"
|
|
105
|
+
response = requests.get(url, timeout=2)
|
|
106
|
+
if response.status_code == 200:
|
|
107
|
+
logging.info("检测到远程服务")
|
|
108
|
+
return "remote"
|
|
109
|
+
except:
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
logging.warning("未检测到可用服务,使用默认模式: remote")
|
|
113
|
+
return "remote"
|
|
114
|
+
|
|
115
|
+
def get_service_url(self, endpoint: str) -> str:
|
|
116
|
+
"""获取服务地址"""
|
|
117
|
+
# if self.base_url:
|
|
118
|
+
# return f"{self.base_url}{endpoint}"
|
|
119
|
+
|
|
120
|
+
mode = self.detect_environment()
|
|
121
|
+
|
|
122
|
+
if mode == "local":
|
|
123
|
+
self.local=True
|
|
124
|
+
# 动态发现 Electron 端口
|
|
125
|
+
for port in self.local_ports:
|
|
126
|
+
try:
|
|
127
|
+
health_url = f"{protocol}://127.0.0.1:{port}/api/health"
|
|
128
|
+
response = requests.get(health_url, timeout=1)
|
|
129
|
+
if response.status_code == 200:
|
|
130
|
+
return f"{protocol}://127.0.0.1:{port}{endpoint}"
|
|
131
|
+
except:
|
|
132
|
+
continue
|
|
133
|
+
# 如果没找到,使用第一个端口
|
|
134
|
+
return f"{protocol}://127.0.0.1:{self.local_ports[0]}{endpoint}"
|
|
135
|
+
else:
|
|
136
|
+
return f"{protocol}://127.0.0.1:{self.remote_port}{endpoint}"
|
|
137
|
+
|
|
138
|
+
def notify(self, action: str, params: Optional[Dict[str, Any]] = None,
|
|
139
|
+
timeout: int = 10) -> Dict[str, Any]:
|
|
140
|
+
"""
|
|
141
|
+
发送通知到 Electron
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
action: 动作类型
|
|
145
|
+
params: 参数字典
|
|
146
|
+
timeout: 超时时间
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
响应结果
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
|
|
155
|
+
url = self.get_service_url("/api/run-task")
|
|
156
|
+
print(url)
|
|
157
|
+
data = {
|
|
158
|
+
"type": action,
|
|
159
|
+
"data": params or {}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
logging.debug(f"发送通知到: {url}, 数据: {data}")
|
|
163
|
+
|
|
164
|
+
if self.local:
|
|
165
|
+
print("post")
|
|
166
|
+
response = requests.post(
|
|
167
|
+
url,
|
|
168
|
+
json=data,
|
|
169
|
+
verify=False,
|
|
170
|
+
headers={'Content-Type': 'application/json'}
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
result = response.json()
|
|
174
|
+
logging.info(f"通知发送成功: {action}, 响应: {result}")
|
|
175
|
+
return result
|
|
176
|
+
else:
|
|
177
|
+
print("Redis模式")
|
|
178
|
+
# response = requests.get(
|
|
179
|
+
# url,
|
|
180
|
+
# params={"request": json.dumps(data)}
|
|
181
|
+
# )
|
|
182
|
+
# result = response.json()
|
|
183
|
+
# Redis模式
|
|
184
|
+
if not self.redis_client:
|
|
185
|
+
raise Exception("Redis客户端未初始化")
|
|
186
|
+
|
|
187
|
+
channel = "sdk_signals"
|
|
188
|
+
message = json.dumps(data, ensure_ascii=False)
|
|
189
|
+
|
|
190
|
+
subscribers = self.redis_client.publish(channel, message)
|
|
191
|
+
|
|
192
|
+
result = {
|
|
193
|
+
"code": 200,
|
|
194
|
+
"msg": f"信号已通过Redis发布",
|
|
195
|
+
"subscribers": subscribers,
|
|
196
|
+
"channel": channel,
|
|
197
|
+
"action": action
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
logging.info(f"Redis通知发送成功,订阅者数: {subscribers}")
|
|
201
|
+
return result
|
|
202
|
+
# logging.info(f"通知发送成功: {action}, 响应: {result}")
|
|
203
|
+
# return result
|
|
204
|
+
|
|
205
|
+
except requests.exceptions.ConnectionError:
|
|
206
|
+
error_msg = "无法连接到 Electron 服务,请确保应用正在运行"
|
|
207
|
+
logging.error(error_msg)
|
|
208
|
+
return {"code": 500, "msg": error_msg}
|
|
209
|
+
except requests.exceptions.Timeout:
|
|
210
|
+
error_msg = "请求超时,请检查网络连接"
|
|
211
|
+
logging.error(error_msg)
|
|
212
|
+
return {"code": 500, "msg": error_msg}
|
|
213
|
+
except Exception as e:
|
|
214
|
+
error_msg = f"发送通知失败: {str(e)}"
|
|
215
|
+
logging.error(error_msg)
|
|
216
|
+
return {"code": 500, "msg": error_msg}
|
|
217
|
+
|
|
218
|
+
def health_check(self) -> Dict[str, Any]:
|
|
219
|
+
"""健康检查"""
|
|
220
|
+
try:
|
|
221
|
+
url = self.get_service_url("/health")
|
|
222
|
+
response = requests.get(url, timeout=5)
|
|
223
|
+
return response.json()
|
|
224
|
+
except Exception as e:
|
|
225
|
+
return {"code": 500, "msg": f"健康检查失败: {str(e)}"}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def generate_response(self, question,template_id, variables):
|
|
229
|
+
response = requests.post(
|
|
230
|
+
f'{self.base_url}/dynamic-response',
|
|
231
|
+
json={
|
|
232
|
+
'question':question,
|
|
233
|
+
'template_id': template_id,
|
|
234
|
+
'variables': variables
|
|
235
|
+
},
|
|
236
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
237
|
+
)
|
|
238
|
+
if response.status_code == 200:
|
|
239
|
+
return response.json().get('response')
|
|
240
|
+
else:
|
|
241
|
+
return response.json()
|
|
242
|
+
# raise Exception('Failed to generate response')
|
|
243
|
+
|
|
244
|
+
def query_data(self, arg, template_id):
|
|
245
|
+
response = requests.post(
|
|
246
|
+
f'{self.base_url}/query-data',
|
|
247
|
+
json={
|
|
248
|
+
'arg': arg,
|
|
249
|
+
'template_id': template_id
|
|
250
|
+
},
|
|
251
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
252
|
+
)
|
|
253
|
+
if response.status_code == 200:
|
|
254
|
+
return response.json()
|
|
255
|
+
else:
|
|
256
|
+
res=response.json()
|
|
257
|
+
raise Exception(res['error'])
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def query_intention(self, question):
|
|
261
|
+
response = requests.post(
|
|
262
|
+
f'{self.base_url}/query-intention',
|
|
263
|
+
json={
|
|
264
|
+
'question': question
|
|
265
|
+
|
|
266
|
+
},
|
|
267
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
268
|
+
)
|
|
269
|
+
if response.status_code == 200:
|
|
270
|
+
return response.json()
|
|
271
|
+
else:
|
|
272
|
+
|
|
273
|
+
raise Exception('Failed to start intention query')
|
|
274
|
+
|
|
275
|
+
def voc(self,productname,text):
|
|
276
|
+
response = requests.post(
|
|
277
|
+
f'{self.base_url}/voc',
|
|
278
|
+
json={
|
|
279
|
+
'productname': productname,
|
|
280
|
+
'text':text
|
|
281
|
+
},
|
|
282
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
283
|
+
)
|
|
284
|
+
if response.status_code == 200:
|
|
285
|
+
return response.json()
|
|
286
|
+
else:
|
|
287
|
+
raise Exception('Failed to start voc ')
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def spec(self,asin):
|
|
291
|
+
response = requests.post(
|
|
292
|
+
f'{self.base_url}/spec',
|
|
293
|
+
json={
|
|
294
|
+
'asin': asin
|
|
295
|
+
|
|
296
|
+
},
|
|
297
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
298
|
+
)
|
|
299
|
+
if response.status_code == 200:
|
|
300
|
+
return response.json()
|
|
301
|
+
else:
|
|
302
|
+
res=response.json()
|
|
303
|
+
raise Exception(f'Failed to start voc,reason:{res["error"]}')
|
|
304
|
+
|
|
305
|
+
#选品建议
|
|
306
|
+
def suggestion(self, selected_products):
|
|
307
|
+
response = requests.post(
|
|
308
|
+
f'{self.base_url}/suggestion',
|
|
309
|
+
json={
|
|
310
|
+
"final_selected_products": selected_products
|
|
311
|
+
|
|
312
|
+
},
|
|
313
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
314
|
+
)
|
|
315
|
+
if response.status_code == 200:
|
|
316
|
+
return response.json()
|
|
317
|
+
else:
|
|
318
|
+
raise Exception('Failed to start suggestion')
|
|
319
|
+
|
|
320
|
+
async def competitor_analysis(self,missionid="",asins=[]):
|
|
321
|
+
if not missionid: # Check if missionid is empty
|
|
322
|
+
missionid = str(uuid.uuid4()) # Generate a random UUID
|
|
323
|
+
|
|
324
|
+
task_id = await self.get_competitive_data(missionid,asins)
|
|
325
|
+
|
|
326
|
+
# logging.info(task_id)
|
|
327
|
+
|
|
328
|
+
if task_id:
|
|
329
|
+
|
|
330
|
+
task = await self.check_task_status(task_id)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
if task["status"] == "SUCCESS" and task['result']['code'] == 200:
|
|
334
|
+
|
|
335
|
+
ret=await self.analysis_details(missionid)
|
|
336
|
+
return ret
|
|
337
|
+
else:
|
|
338
|
+
return {'code': 400, 'data': None, 'msg':task['result']['msg']}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
async def analysis_details(self,missionid):
|
|
342
|
+
response = requests.post(
|
|
343
|
+
f'{URL}/v1/conv/analysis/getid',
|
|
344
|
+
json={
|
|
345
|
+
'missionid': missionid
|
|
346
|
+
|
|
347
|
+
},
|
|
348
|
+
headers={"Content-Type": "application/json"}
|
|
349
|
+
)
|
|
350
|
+
if response.status_code == 200:
|
|
351
|
+
return response.json()
|
|
352
|
+
else:
|
|
353
|
+
raise Exception('Failed to start analysis')
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
async def get_competitive_data(self,missionid,asins=[]):
|
|
357
|
+
|
|
358
|
+
response = requests.post(
|
|
359
|
+
f'{self.base_url}/competitor_analysis',
|
|
360
|
+
json={
|
|
361
|
+
"asins": asins,
|
|
362
|
+
"missionid":missionid
|
|
363
|
+
|
|
364
|
+
},
|
|
365
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
if response.status_code == 200:
|
|
369
|
+
|
|
370
|
+
result=response.json()
|
|
371
|
+
|
|
372
|
+
return result['data']['task_id']
|
|
373
|
+
else:
|
|
374
|
+
raise Exception('Failed to request get_competitive_data')
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
#获取所有asins
|
|
379
|
+
async def productList(self,missionid):
|
|
380
|
+
data=await self.get_token()
|
|
381
|
+
print(data['token'])
|
|
382
|
+
response = requests.post(
|
|
383
|
+
f"{URL}/v1/agent/productList",
|
|
384
|
+
json={
|
|
385
|
+
'missionid':missionid
|
|
386
|
+
},
|
|
387
|
+
headers={'Authorization': f"Bearer {data['token']}"}
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
print(response)
|
|
391
|
+
if response.status_code == 200:
|
|
392
|
+
return response.json()
|
|
393
|
+
else:
|
|
394
|
+
raise Exception('Failed to request task_status')
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
async def getTaskStatus(self,taskId):
|
|
399
|
+
data=await self.get_token()
|
|
400
|
+
|
|
401
|
+
response =requests.get(f"{URL}/v1/task/task_status/{taskId}",
|
|
402
|
+
headers={'Authorization': f"Bearer {data['token']}"})
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
# if response.status_code == 200:
|
|
406
|
+
return response.json()
|
|
407
|
+
# else:
|
|
408
|
+
# raise Exception('Failed to request task_status')
|
|
409
|
+
|
|
410
|
+
#检查竞品分析任务状态
|
|
411
|
+
async def check_task_status(self,task_id):
|
|
412
|
+
print("start")
|
|
413
|
+
|
|
414
|
+
while True:
|
|
415
|
+
try:
|
|
416
|
+
|
|
417
|
+
response = await self.getTaskStatus(task_id)
|
|
418
|
+
print(response)
|
|
419
|
+
logging.info(response)
|
|
420
|
+
status = response.get('status')
|
|
421
|
+
logging.info(f"Task status: {status}")
|
|
422
|
+
print("------------------")
|
|
423
|
+
if status == "SUCCESS":
|
|
424
|
+
return {"status": "SUCCESS", "result": response.get('result')}
|
|
425
|
+
else:
|
|
426
|
+
return {"status": "ERROR", "result": {"code":400,"msg":"竞品分析发生错误"}}
|
|
427
|
+
|
|
428
|
+
except Exception as error:
|
|
429
|
+
logging.error(f"Error checking task status: {error}")
|
|
430
|
+
|
|
431
|
+
await asyncio.sleep(1) # Sleep for 1 second
|
|
432
|
+
|
|
433
|
+
#获取asin 列表
|
|
434
|
+
async def getAsinfromAmazon(self,title,keywords):
|
|
435
|
+
missionid = str(uuid.uuid4())
|
|
436
|
+
res=await self.update_mission("app_"+missionid, title,keywords)
|
|
437
|
+
print(res)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
response=self.notify("list",{"keywords":keywords,"missionid":"app_"+missionid})
|
|
441
|
+
if self.local:
|
|
442
|
+
return response
|
|
443
|
+
else:
|
|
444
|
+
res=await self.start_checking("app_"+missionid)
|
|
445
|
+
print(res)
|
|
446
|
+
if res['status']=="Productlist_complete":
|
|
447
|
+
return {"success": True,"missionid":"app_"+missionid}
|
|
448
|
+
#获取asin 详情
|
|
449
|
+
async def getGoodinfofromAmazon(self, asins,missionid=None,filename=None):
|
|
450
|
+
if filename:
|
|
451
|
+
locafile,filename=self.upload_file(filename)
|
|
452
|
+
print(filename)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
response=self.create_asin_mission(locafile,filename)
|
|
456
|
+
asins=response['asins']
|
|
457
|
+
missionid=response['missionid']
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
if missionid is None:
|
|
462
|
+
missionid = str(uuid.uuid4())
|
|
463
|
+
res=await self.update_mission("app_"+missionid,"获取asinlist" ,"无关键词")
|
|
464
|
+
print(res)
|
|
465
|
+
|
|
466
|
+
response=self.notify("asin",{"asins": asins,"missionid":"app_"+missionid})
|
|
467
|
+
|
|
468
|
+
if self.local:
|
|
469
|
+
return response
|
|
470
|
+
else:
|
|
471
|
+
res=await self.start_checking("app_"+missionid)
|
|
472
|
+
print(res)
|
|
473
|
+
if res['status']=="Completed":
|
|
474
|
+
return {"success": True,"missionid":"app_"+missionid}
|
|
475
|
+
|
|
476
|
+
#检查任务状态
|
|
477
|
+
async def check_mission_status(self, task_id):
|
|
478
|
+
print("start")
|
|
479
|
+
|
|
480
|
+
# 重置停止标志
|
|
481
|
+
self._should_stop = False
|
|
482
|
+
|
|
483
|
+
while True:
|
|
484
|
+
# 检查是否应该停止
|
|
485
|
+
if self._should_stop:
|
|
486
|
+
print("任务检查器被停止")
|
|
487
|
+
return {"status": "stopped", "result": {"code": 400, "msg": "任务检查被手动停止"}}
|
|
488
|
+
|
|
489
|
+
try:
|
|
490
|
+
response = await self.findMissionbyid(task_id)
|
|
491
|
+
print(response)
|
|
492
|
+
logging.info(response)
|
|
493
|
+
status = response.get('task_status')
|
|
494
|
+
logging.info(f"Task status: {status}")
|
|
495
|
+
print("------------------")
|
|
496
|
+
|
|
497
|
+
if status == "Completed":
|
|
498
|
+
return {"status": status, "result": {"code": 200, "msg": "商品详情数据抓取数据成功"}}
|
|
499
|
+
elif status == "Productlist_complete":
|
|
500
|
+
return {"status": status, "result": {"code": 200, "msg": "商品列表抓取数据成功"}}
|
|
501
|
+
else:
|
|
502
|
+
pass
|
|
503
|
+
except Exception as error:
|
|
504
|
+
logging.error(f"Error checking task status: {error}")
|
|
505
|
+
|
|
506
|
+
await asyncio.sleep(1) # Sleep for 1 second
|
|
507
|
+
|
|
508
|
+
# def start_checking(self, task_id):
|
|
509
|
+
# """启动状态检查任务"""
|
|
510
|
+
# # 先停止之前的任务(如果存在)
|
|
511
|
+
# self.stop_checking()
|
|
512
|
+
|
|
513
|
+
# # 重置停止标志
|
|
514
|
+
# self._should_stop = False
|
|
515
|
+
|
|
516
|
+
# # 创建新任务
|
|
517
|
+
# self._task_checker = asyncio.create_task(self.check_mission_status(task_id))
|
|
518
|
+
# return self._task_checker
|
|
519
|
+
|
|
520
|
+
def start_checking(self, task_id):
|
|
521
|
+
"""启动状态检查任务"""
|
|
522
|
+
# 先停止之前的任务(如果存在)
|
|
523
|
+
self.stop_checking()
|
|
524
|
+
|
|
525
|
+
# 重置停止标志
|
|
526
|
+
self._should_stop = False
|
|
527
|
+
|
|
528
|
+
# 创建新任务
|
|
529
|
+
self._task_checker = asyncio.create_task(self.check_mission_status(task_id))
|
|
530
|
+
return self._task_checker
|
|
531
|
+
|
|
532
|
+
async def stop_checking(self):
|
|
533
|
+
"""停止状态检查任务"""
|
|
534
|
+
# 设置停止标志
|
|
535
|
+
self._should_stop = True
|
|
536
|
+
|
|
537
|
+
# 取消任务(如果存在)
|
|
538
|
+
if self._task_checker and not self._task_checker.done():
|
|
539
|
+
self._task_checker.cancel()
|
|
540
|
+
try:
|
|
541
|
+
await self._task_checker
|
|
542
|
+
except asyncio.CancelledError:
|
|
543
|
+
print("任务检查器已取消")
|
|
544
|
+
pass
|
|
545
|
+
self._task_checker = None
|
|
546
|
+
|
|
547
|
+
# async def check_mission_status(self,task_id):
|
|
548
|
+
# print("start")
|
|
549
|
+
|
|
550
|
+
# while True:
|
|
551
|
+
# try:
|
|
552
|
+
|
|
553
|
+
# response = await self.findMissionbyid(task_id)
|
|
554
|
+
# print(response)
|
|
555
|
+
# logging.info(response)
|
|
556
|
+
# status = response.get('task_status')
|
|
557
|
+
# logging.info(f"Task status: {status}")
|
|
558
|
+
# print("------------------")
|
|
559
|
+
# if status == "Completed":
|
|
560
|
+
# return {"status": status, "result": {"code":200,"msg":"商品详情数据抓取数据成功"}}
|
|
561
|
+
# elif status=="Productlist_complete":
|
|
562
|
+
# return {"status": status, "result": {"code":200,"msg":"商品列表抓取数据成功"}}
|
|
563
|
+
# else:
|
|
564
|
+
# pass
|
|
565
|
+
# except Exception as error:
|
|
566
|
+
# logging.error(f"Error checking task status: {error}")
|
|
567
|
+
|
|
568
|
+
# await asyncio.sleep(1) # Sleep for 1 second
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def upload_file(self,file_path):
|
|
575
|
+
url =f"{URL}/v1/task/upload"
|
|
576
|
+
file_name = os.path.basename(file_path)
|
|
577
|
+
with open(file_path, 'rb') as f:
|
|
578
|
+
files = {'file': (file_name, f)}
|
|
579
|
+
response = requests.post(url, files=files)
|
|
580
|
+
|
|
581
|
+
if response.status_code == 200:
|
|
582
|
+
data = response.json()
|
|
583
|
+
print(f"Uploaded filename: {data['filename']}")
|
|
584
|
+
return file_name,data['filename']
|
|
585
|
+
else:
|
|
586
|
+
print(f"Upload failed: {response.text}")
|
|
587
|
+
return None
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
async def create_asin_mission(self,locafile,filename):
|
|
591
|
+
# Start ASIN extraction process
|
|
592
|
+
task_id = await self.create_asin_mission_api(filename)
|
|
593
|
+
|
|
594
|
+
if task_id:
|
|
595
|
+
task = await self.check_task_status(task_id)
|
|
596
|
+
|
|
597
|
+
if task["status"] == "SUCCESS" and task["result"]["code"] == 200:
|
|
598
|
+
missionid = task["result"]["missionid"]
|
|
599
|
+
|
|
600
|
+
# Generate report title using AI
|
|
601
|
+
gentitle_prompt = f"""
|
|
602
|
+
以下是选品报告标题的关键要素
|
|
603
|
+
今天是{datetime.now()}
|
|
604
|
+
用户了提交了asin 列表,文件名称为{locafile}
|
|
605
|
+
请生成亚马逊选品分析报告的标题
|
|
606
|
+
"""
|
|
607
|
+
response_title = await self.call_ai_api([{"role": "user", "content": gentitle_prompt}])
|
|
608
|
+
title = response_title["data"]
|
|
609
|
+
|
|
610
|
+
# Update mission with generated title
|
|
611
|
+
task_res = await self.update_mission(missionid, title, "无需关键词")
|
|
612
|
+
|
|
613
|
+
if task_res["code"] == 200:
|
|
614
|
+
# Get ASIN list for the mission
|
|
615
|
+
res = await self.get_asin_list(missionid)
|
|
616
|
+
|
|
617
|
+
if res["code"] == 200:
|
|
618
|
+
asinlist = res["data"]
|
|
619
|
+
asins = [item["asin"] for item in asinlist]
|
|
620
|
+
return {"missionid": missionid, "asins": asins}
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
# Return None if any step fails
|
|
625
|
+
return None
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
# Example implementations of the required service functions
|
|
630
|
+
async def create_asin_mission_api(self,filename: str) -> str:
|
|
631
|
+
|
|
632
|
+
response = requests.post(
|
|
633
|
+
f"{URL}/task/start_task",
|
|
634
|
+
json={
|
|
635
|
+
'name':"create_asin_mission",
|
|
636
|
+
'data': {"file_name":filename},
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
)
|
|
640
|
+
"""Mock implementation - replace with actual API call"""
|
|
641
|
+
if response.status_code == 200:
|
|
642
|
+
res=response.json()
|
|
643
|
+
return res['task_id']
|
|
644
|
+
else:
|
|
645
|
+
raise Exception('Failed to request task_status')
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
# async def check_task_status(self,task_id: str) -> dict:
|
|
649
|
+
# response =requests.get(f"{URL}/task/task_status/{task_id}")
|
|
650
|
+
# if response.status_code == 200:
|
|
651
|
+
# ret= response.json()
|
|
652
|
+
# """Mock implementation - replace with actual status check"""
|
|
653
|
+
# return {
|
|
654
|
+
# "status": ret["status"],
|
|
655
|
+
# "result": {
|
|
656
|
+
# "code": 200,
|
|
657
|
+
# "missionid": ret["result"]["missionid"]
|
|
658
|
+
# }
|
|
659
|
+
# }
|
|
660
|
+
# else:
|
|
661
|
+
# raise Exception('Failed to request task_status')
|
|
662
|
+
|
|
663
|
+
async def get_token(self):
|
|
664
|
+
|
|
665
|
+
# response =requests.get(f"{appurl}/api/gettoken")
|
|
666
|
+
# if response.status_code == 200:
|
|
667
|
+
# return response.json()
|
|
668
|
+
# else:
|
|
669
|
+
# raise Exception('Failed to request task_status')
|
|
670
|
+
response =requests.get(f"{URL}/v1/selectproduct/sdklogin")
|
|
671
|
+
if response.status_code == 200:
|
|
672
|
+
return response.json()
|
|
673
|
+
else:
|
|
674
|
+
raise Exception('Failed to request task_status')
|
|
675
|
+
|
|
676
|
+
async def call_ai_api(self,messages,tools):
|
|
677
|
+
data=await self.get_token()
|
|
678
|
+
print(data)
|
|
679
|
+
response = requests.post(
|
|
680
|
+
f"{URL}/agent/fn",
|
|
681
|
+
json={"tools":tools,"messages":messages},
|
|
682
|
+
headers={'Authorization': f"Bearer {data['token']}"}
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
if response.status_code == 200:
|
|
686
|
+
return response.json()
|
|
687
|
+
else:
|
|
688
|
+
raise Exception('Failed to request task_status')
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
async def update_mission(self,missionid: str, title: str, keywords: str) :
|
|
692
|
+
data=await self.get_token()
|
|
693
|
+
print(data['token'])
|
|
694
|
+
userid=await self._get_userid()
|
|
695
|
+
print(userid)
|
|
696
|
+
response = requests.post(
|
|
697
|
+
f"{URL}/v1/agent/intertMissioinlist",
|
|
698
|
+
json={
|
|
699
|
+
'userid':userid,
|
|
700
|
+
'task_id':missionid,
|
|
701
|
+
'report_title': title,
|
|
702
|
+
'keywords': keywords,
|
|
703
|
+
'task_status':'In Progress',
|
|
704
|
+
'task_status_description':'数据采集任务开始'
|
|
705
|
+
},
|
|
706
|
+
headers={'Authorization': f"Bearer {data['token']}"}
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
if response.status_code == 200:
|
|
711
|
+
return response.json()
|
|
712
|
+
else:
|
|
713
|
+
raise Exception('Failed to request task_status')
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
async def findMissionbyid(self,missionid: str):
|
|
717
|
+
data=await self.get_token()
|
|
718
|
+
print(data['token'])
|
|
719
|
+
userid=await self._get_userid()
|
|
720
|
+
print(userid)
|
|
721
|
+
response = requests.post(
|
|
722
|
+
f"{URL}/v1/agent/findMissionbyid",
|
|
723
|
+
json={
|
|
724
|
+
'task_id':missionid,
|
|
725
|
+
'user_id':userid
|
|
726
|
+
},
|
|
727
|
+
headers={'Authorization': f"Bearer {data['token']}"}
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
print(response)
|
|
731
|
+
if response.status_code == 200:
|
|
732
|
+
result=response.json()
|
|
733
|
+
print(result)
|
|
734
|
+
if result["code"]==200:
|
|
735
|
+
return result["data"]
|
|
736
|
+
else:
|
|
737
|
+
raise Exception('Failed to request task_status')
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
async def get_asin_list(self,missionid: str):
|
|
742
|
+
response = requests.post(
|
|
743
|
+
f"{URL}/conv/getid",
|
|
744
|
+
json={
|
|
745
|
+
'missionid':missionid}
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
if response.status_code == 200:
|
|
750
|
+
return response.json()
|
|
751
|
+
else:
|
|
752
|
+
raise Exception('Failed to request task_status')
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
async def getallpageData(self,missionid: str) :
|
|
759
|
+
data=await self.get_token()
|
|
760
|
+
print(data['token'])
|
|
761
|
+
response = requests.post(
|
|
762
|
+
f"{URL}/v1/agent/test/getallpageData",
|
|
763
|
+
json={
|
|
764
|
+
'missionid':missionid
|
|
765
|
+
},
|
|
766
|
+
headers={'Authorization': f"Bearer {data['token']}"}
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
print(response)
|
|
770
|
+
if response.status_code == 200:
|
|
771
|
+
return response.json()
|
|
772
|
+
else:
|
|
773
|
+
raise Exception('Failed to request task_status')
|
|
774
|
+
|
|
775
|
+
#保存数据到云
|
|
776
|
+
async def CloudStorage(self,input_data:Any,config: dict={}) :
|
|
777
|
+
data=await self.get_token()
|
|
778
|
+
missionid=str(uuid.uuid4()) # Generate a random UUID
|
|
779
|
+
response = requests.post(
|
|
780
|
+
f"{URL}/v1/conv/analysis/save",
|
|
781
|
+
json={
|
|
782
|
+
'id':missionid,
|
|
783
|
+
'data':input_data
|
|
784
|
+
},
|
|
785
|
+
headers={'Authorization': f"Bearer {data['token']}"}
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
if response.status_code == 200:
|
|
790
|
+
return {"missionid": missionid, "msg":"已经保存完成"}
|
|
791
|
+
else:
|
|
792
|
+
raise Exception('Failed to request task_status')
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
#读取数据库
|
|
797
|
+
async def Database(self,input_data: str, config: dict={}) -> Optional[object]:
|
|
798
|
+
"""
|
|
799
|
+
执行 MySQL 查询并返回包含 database-source 属性的对象
|
|
800
|
+
只支持 SELECT 查询,自动限制最多1000条数据
|
|
801
|
+
"""
|
|
802
|
+
# 从 config 中获取参数
|
|
803
|
+
sql_query = config.get('query', '')
|
|
804
|
+
connection_string = config.get('connectionString', '')
|
|
805
|
+
|
|
806
|
+
if not sql_query:
|
|
807
|
+
print("SQL 查询语句不能为空")
|
|
808
|
+
return None
|
|
809
|
+
|
|
810
|
+
if not connection_string:
|
|
811
|
+
print("数据库连接字符串不能为空")
|
|
812
|
+
return None
|
|
813
|
+
|
|
814
|
+
# 检查是否只支持 SELECT 查询
|
|
815
|
+
sql_upper = sql_query.strip().upper()
|
|
816
|
+
if not sql_upper.startswith('SELECT'):
|
|
817
|
+
print("只支持 SELECT 查询语句")
|
|
818
|
+
return None
|
|
819
|
+
|
|
820
|
+
# 解析连接字符串
|
|
821
|
+
config_dict = {}
|
|
822
|
+
try:
|
|
823
|
+
for param in connection_string.split(';'):
|
|
824
|
+
if '=' in param:
|
|
825
|
+
key, value = param.split('=', 1)
|
|
826
|
+
config_dict[key.strip()] = value.strip()
|
|
827
|
+
except Exception as e:
|
|
828
|
+
print(f"连接字符串解析失败: {e}")
|
|
829
|
+
return None
|
|
830
|
+
|
|
831
|
+
# 建立数据库连接
|
|
832
|
+
connection = None
|
|
833
|
+
try:
|
|
834
|
+
connection = pymysql.connect(
|
|
835
|
+
host=config_dict.get('host', 'localhost'),
|
|
836
|
+
port=int(config_dict.get('port', 3306)),
|
|
837
|
+
user=config_dict.get('user', ''),
|
|
838
|
+
password=config_dict.get('password', ''),
|
|
839
|
+
database=config_dict.get('database', ''),
|
|
840
|
+
charset='utf8mb4',
|
|
841
|
+
cursorclass=pymysql.cursors.DictCursor
|
|
842
|
+
)
|
|
843
|
+
|
|
844
|
+
# 执行查询
|
|
845
|
+
with connection.cursor() as cursor:
|
|
846
|
+
# 检查查询是否已经有 LIMIT 子句
|
|
847
|
+
if 'LIMIT' not in sql_upper:
|
|
848
|
+
# 如果没有 LIMIT,自动添加 LIMIT 1000
|
|
849
|
+
modified_query = sql_query.rstrip(';') + ' LIMIT 1000'
|
|
850
|
+
print(f"自动添加 LIMIT 1000,执行查询: {modified_query}")
|
|
851
|
+
cursor.execute(modified_query)
|
|
852
|
+
else:
|
|
853
|
+
# 如果已经有 LIMIT,检查是否超过1000条
|
|
854
|
+
# 提取 LIMIT 后面的数字
|
|
855
|
+
limit_index = sql_upper.find('LIMIT')
|
|
856
|
+
limit_part = sql_upper[limit_index:].split()
|
|
857
|
+
|
|
858
|
+
if len(limit_part) >= 2:
|
|
859
|
+
try:
|
|
860
|
+
limit_value = int(limit_part[1])
|
|
861
|
+
if limit_value > 1000:
|
|
862
|
+
# 如果限制超过1000,修改为1000
|
|
863
|
+
original_limit = f"LIMIT {limit_value}"
|
|
864
|
+
new_limit = "LIMIT 1000"
|
|
865
|
+
modified_query = sql_query.replace(original_limit, new_limit)
|
|
866
|
+
print(f"限制条数从 {limit_value} 改为 1000,执行查询: {modified_query}")
|
|
867
|
+
cursor.execute(modified_query)
|
|
868
|
+
else:
|
|
869
|
+
# 如果限制在1000以内,直接执行
|
|
870
|
+
cursor.execute(sql_query)
|
|
871
|
+
except ValueError:
|
|
872
|
+
# 如果 LIMIT 参数不是数字,使用默认查询
|
|
873
|
+
cursor.execute(sql_query)
|
|
874
|
+
else:
|
|
875
|
+
# 如果 LIMIT 格式不正确,使用默认查询
|
|
876
|
+
cursor.execute(sql_query)
|
|
877
|
+
|
|
878
|
+
result = cursor.fetchall()
|
|
879
|
+
|
|
880
|
+
# 检查实际返回的数据条数
|
|
881
|
+
actual_count = len(result)
|
|
882
|
+
if actual_count == 1000:
|
|
883
|
+
print("警告:查询结果已达到1000条限制,可能有不完整数据")
|
|
884
|
+
|
|
885
|
+
# JSON 序列化器
|
|
886
|
+
def json_serializer(obj):
|
|
887
|
+
"""支持多种数据类型的 JSON 序列化器"""
|
|
888
|
+
if isinstance(obj, (datetime, date)):
|
|
889
|
+
return obj.isoformat()
|
|
890
|
+
elif isinstance(obj, decimal.Decimal):
|
|
891
|
+
return float(obj)
|
|
892
|
+
elif isinstance(obj, (bytes, bytearray)):
|
|
893
|
+
return obj.decode('utf-8', errors='ignore')
|
|
894
|
+
elif isinstance(obj, time):
|
|
895
|
+
return obj.isoformat()
|
|
896
|
+
elif isinstance(obj, timedelta):
|
|
897
|
+
return str(obj)
|
|
898
|
+
else:
|
|
899
|
+
return str(obj)
|
|
900
|
+
|
|
901
|
+
# 转换为 JSON
|
|
902
|
+
json_result = json.dumps(result, ensure_ascii=False, default=json_serializer, indent=2)
|
|
903
|
+
|
|
904
|
+
# 返回包含 database-source 属性的对象
|
|
905
|
+
class DatabaseResult:
|
|
906
|
+
def __init__(self, result):
|
|
907
|
+
self.database_source = result
|
|
908
|
+
|
|
909
|
+
return DatabaseResult(json_result)
|
|
910
|
+
|
|
911
|
+
except pymysql.Error as e:
|
|
912
|
+
print(f"数据库操作失败: {e}")
|
|
913
|
+
return None
|
|
914
|
+
except Exception as e:
|
|
915
|
+
print(f"其他错误: {e}")
|
|
916
|
+
return None
|
|
917
|
+
finally:
|
|
918
|
+
# 确保连接被关闭
|
|
919
|
+
if connection:
|
|
920
|
+
connection.close()
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
oneliai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
oneliai/client.py,sha256=I_h53HA6n8QE2y8QUSk2ffbtSaOaFhu2ReecwYKoJE0,33604
|
|
3
|
+
sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
sdk/client.py,sha256=EenoF_sh_EsovxqLCKfcs0_9mMV1LqC3GnysQupgL1g,4296
|
|
5
|
+
oneliai-1.2.7.dist-info/METADATA,sha256=gMARNnr4rVLDqcroUoeGOsTt8aPVWWoAa9umKUGcQ4I,155
|
|
6
|
+
oneliai-1.2.7.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
|
7
|
+
oneliai-1.2.7.dist-info/top_level.txt,sha256=7zBSOMx80pMmYiAfyZoqmb8S5_lloaTESpnFRO3KoYk,12
|
|
8
|
+
oneliai-1.2.7.dist-info/RECORD,,
|
sdk/__init__.py
ADDED
|
File without changes
|
sdk/client.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import jwt
|
|
3
|
+
import datetime
|
|
4
|
+
|
|
5
|
+
# URL="https://apis.oneli.chat"
|
|
6
|
+
URL="http://localhost:8085"
|
|
7
|
+
class AICustomerClient:
|
|
8
|
+
def __init__(self, client_id, client_secret, base_url=f'{URL}/v1/strategy'):
|
|
9
|
+
self.client_id = client_id
|
|
10
|
+
self.client_secret = client_secret
|
|
11
|
+
self.base_url = base_url
|
|
12
|
+
self.access_token = self._get_access_token()
|
|
13
|
+
|
|
14
|
+
def _get_access_token(self):
|
|
15
|
+
response = requests.post(
|
|
16
|
+
f'{self.base_url}/auth/token',
|
|
17
|
+
json={
|
|
18
|
+
'client_id': self.client_id,
|
|
19
|
+
'client_secret': self.client_secret,
|
|
20
|
+
'grant_type': 'client_credentials'
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
if response.status_code == 200:
|
|
24
|
+
return response.json().get('access_token')
|
|
25
|
+
else:
|
|
26
|
+
raise Exception('Failed to get access token')
|
|
27
|
+
|
|
28
|
+
def generate_response(self, template_id, variables):
|
|
29
|
+
response = requests.post(
|
|
30
|
+
f'{self.base_url}/dynamic-response',
|
|
31
|
+
json={
|
|
32
|
+
'template_id': template_id,
|
|
33
|
+
'variables': variables
|
|
34
|
+
},
|
|
35
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
36
|
+
)
|
|
37
|
+
if response.status_code == 200:
|
|
38
|
+
return response.json().get('response')
|
|
39
|
+
else:
|
|
40
|
+
return response.json()
|
|
41
|
+
# raise Exception('Failed to generate response')
|
|
42
|
+
|
|
43
|
+
def query_data(self, arg, template_id):
|
|
44
|
+
response = requests.post(
|
|
45
|
+
f'{self.base_url}/query-data',
|
|
46
|
+
json={
|
|
47
|
+
'arg': arg,
|
|
48
|
+
'template_id': template_id
|
|
49
|
+
},
|
|
50
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
51
|
+
)
|
|
52
|
+
if response.status_code == 200:
|
|
53
|
+
return response.json()
|
|
54
|
+
else:
|
|
55
|
+
res=response.json()
|
|
56
|
+
raise Exception(res['error'])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def query_intention(self, question):
|
|
60
|
+
response = requests.post(
|
|
61
|
+
f'{self.base_url}/query-intention',
|
|
62
|
+
json={
|
|
63
|
+
'question': question
|
|
64
|
+
|
|
65
|
+
},
|
|
66
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
67
|
+
)
|
|
68
|
+
if response.status_code == 200:
|
|
69
|
+
return response.json()
|
|
70
|
+
else:
|
|
71
|
+
raise Exception('Failed to start intention query')
|
|
72
|
+
|
|
73
|
+
def registEndpoint(self, name,endpointpath):
|
|
74
|
+
response = requests.post(
|
|
75
|
+
f'{self.base_url}/createEndpoints',
|
|
76
|
+
json={
|
|
77
|
+
"endpointpath": endpointpath,
|
|
78
|
+
"method": "POST",
|
|
79
|
+
"name":name
|
|
80
|
+
},
|
|
81
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
82
|
+
)
|
|
83
|
+
if response.status_code == 200:
|
|
84
|
+
return response.json()
|
|
85
|
+
else:
|
|
86
|
+
raise Exception('Failed to createEndpoints')
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def createRoles(self, role_name, description):
|
|
91
|
+
response = requests.post(
|
|
92
|
+
f'{self.base_url}/createRoles',
|
|
93
|
+
json={
|
|
94
|
+
"role_name": role_name,
|
|
95
|
+
"description":description
|
|
96
|
+
},
|
|
97
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
98
|
+
)
|
|
99
|
+
if response.status_code == 200:
|
|
100
|
+
return response.json()
|
|
101
|
+
else:
|
|
102
|
+
raise Exception('Failed to createRoles')
|
|
103
|
+
|
|
104
|
+
def roles_endpoint(self, role_id, endpoint_id):
|
|
105
|
+
response = requests.post(
|
|
106
|
+
f'{self.base_url}/roles/{role_id}/endpoints',
|
|
107
|
+
json={
|
|
108
|
+
"endpoint_id": endpoint_id
|
|
109
|
+
},
|
|
110
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
111
|
+
)
|
|
112
|
+
if response.status_code == 200:
|
|
113
|
+
return response.json()
|
|
114
|
+
else:
|
|
115
|
+
raise Exception('Failed to roles_endpoint')
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def user_roles(self, user_id, role_id):
|
|
119
|
+
response = requests.post(
|
|
120
|
+
f'{self.base_url}/users/{user_id}/roles',
|
|
121
|
+
json={
|
|
122
|
+
"role_id": role_id
|
|
123
|
+
},
|
|
124
|
+
headers={'Authorization': f'Bearer {self.access_token}'}
|
|
125
|
+
)
|
|
126
|
+
if response.status_code == 200:
|
|
127
|
+
return response.json()
|
|
128
|
+
else:
|
|
129
|
+
raise Exception('Failed to user_roles')
|