itam-assistant 0.1.1__py3-none-any.whl → 0.1.3__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.
- it_assistant/do_ai.py +443 -76
- it_assistant/intent_detail.py +4 -3
- it_assistant/openapi.py +270 -42
- itam_assistant-0.1.3.dist-info/METADATA +16 -0
- itam_assistant-0.1.3.dist-info/RECORD +19 -0
- {itam_assistant-0.1.1.dist-info → itam_assistant-0.1.3.dist-info}/WHEEL +1 -1
- main/__init__.py +0 -0
- main/ailyapp_client.py +132 -0
- main/do_ai.py +177 -0
- main/intent_detail.py +326 -0
- main/lark_client.py +159 -0
- main/logger.py +53 -0
- itam_assistant-0.1.1.dist-info/METADATA +0 -25
- itam_assistant-0.1.1.dist-info/RECORD +0 -13
- {itam_assistant-0.1.1.dist-info → itam_assistant-0.1.3.dist-info}/top_level.txt +0 -0
main/ailyapp_client.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import lark_oapi as lark
|
|
4
|
+
from lark_oapi.api.auth.v3 import *
|
|
5
|
+
from lark_oapi.api.aily.v1 import *
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# SDK 使用说明: https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/server-side-sdk/python--sdk/preparations-before-development
|
|
9
|
+
# 以下示例代码默认根据文档示例值填充,如果存在代码问题,请在 API 调试台填上相关必要参数后再复制代码使用
|
|
10
|
+
# 复制该 Demo 后, 需要将 "YOUR_APP_ID", "YOUR_APP_SECRET" 替换为自己应用的 APP_ID, APP_SECRET.
|
|
11
|
+
|
|
12
|
+
class AilyLarkClient:
|
|
13
|
+
def __init__(self):
|
|
14
|
+
"""
|
|
15
|
+
初始化 Client 实例,tenant_access_token 会在 Client 初始化时自动获取
|
|
16
|
+
"""
|
|
17
|
+
self.aily_app_id = "spring_f17d05d924__c"
|
|
18
|
+
self.app_id = "cli_a6e3aea1a13c900c"
|
|
19
|
+
self.app_secret = "J0fAPt3BL6bv4KUJV0dJMdTUdr0pv3xx"
|
|
20
|
+
# 创建 Lark-tenant tenant客户端
|
|
21
|
+
self.tlark_client = lark.Client.builder().app_id(self.app_id).app_secret(self.app_secret).build()
|
|
22
|
+
|
|
23
|
+
# 创建 Lark-tenant user 客户端
|
|
24
|
+
self.ulark_client = lark.Client.builder().enable_set_token(True).log_level(lark.LogLevel.DEBUG).build()
|
|
25
|
+
|
|
26
|
+
def get_tenant_access_token(self):
|
|
27
|
+
# 构造请求对象
|
|
28
|
+
request: InternalTenantAccessTokenRequest = InternalTenantAccessTokenRequest.builder() \
|
|
29
|
+
.request_body(InternalTenantAccessTokenRequestBody.builder()
|
|
30
|
+
.app_id(self.app_id)
|
|
31
|
+
.app_secret(self.app_secret)
|
|
32
|
+
.build()) \
|
|
33
|
+
.build()
|
|
34
|
+
|
|
35
|
+
# 发起请求
|
|
36
|
+
response: InternalTenantAccessTokenResponse = self.tlark_client.auth.v3.tenant_access_token.internal(request)
|
|
37
|
+
|
|
38
|
+
# 处理失败返回
|
|
39
|
+
if not response.success():
|
|
40
|
+
lark.logger.error(
|
|
41
|
+
f"client.auth.v3.tenant_access_token.internal failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
|
42
|
+
return
|
|
43
|
+
# 处理业务结果
|
|
44
|
+
lark.logger.info(lark.JSON.marshal(response.raw, indent=4))
|
|
45
|
+
tenant_access_token = json.loads(response.raw.content).get("tenant_access_token")
|
|
46
|
+
if tenant_access_token:
|
|
47
|
+
return tenant_access_token
|
|
48
|
+
else:
|
|
49
|
+
lark.logger.error(
|
|
50
|
+
f"client.auth.v3.tenant_access_token.internal failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
def create_ailysession(self, access_token):
|
|
54
|
+
# 创建会话
|
|
55
|
+
# 构造请求对象
|
|
56
|
+
request: CreateAilySessionRequest = CreateAilySessionRequest.builder() \
|
|
57
|
+
.request_body(CreateAilySessionRequestBody.builder()
|
|
58
|
+
.channel_context("{}")
|
|
59
|
+
.metadata("{}")
|
|
60
|
+
.build()) \
|
|
61
|
+
.build()
|
|
62
|
+
|
|
63
|
+
# 发起请求
|
|
64
|
+
option = lark.RequestOption.builder().user_access_token(access_token).build()
|
|
65
|
+
response: CreateAilySessionResponse = self.ulark_client.aily.v1.aily_session.create(request, option)
|
|
66
|
+
|
|
67
|
+
# 处理失败返回
|
|
68
|
+
if not response.success():
|
|
69
|
+
lark.logger.error(
|
|
70
|
+
f"client.aily.v1.aily_session.create failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
# 处理业务结果
|
|
74
|
+
lark.logger.info(lark.JSON.marshal(response.data, indent=4))
|
|
75
|
+
return response.data.session.id
|
|
76
|
+
|
|
77
|
+
def create_ailysessionaily_message(self, access_token, session_id, content):
|
|
78
|
+
# 发送智能伙伴消息
|
|
79
|
+
# 构造请求对象
|
|
80
|
+
request: CreateAilySessionAilyMessageRequest = CreateAilySessionAilyMessageRequest.builder() \
|
|
81
|
+
.aily_session_id(session_id) \
|
|
82
|
+
.request_body(CreateAilySessionAilyMessageRequestBody.builder()
|
|
83
|
+
.content(content)
|
|
84
|
+
.content_type("MDX")
|
|
85
|
+
.idempotent_id("idempotent_id_1")
|
|
86
|
+
.build()) \
|
|
87
|
+
.build()
|
|
88
|
+
# 发起请求
|
|
89
|
+
option = lark.RequestOption.builder().user_access_token(access_token).build()
|
|
90
|
+
response: CreateAilySessionAilyMessageResponse = self.ulark_client.aily.v1.aily_session_aily_message.create(
|
|
91
|
+
request,
|
|
92
|
+
option)
|
|
93
|
+
# 处理失败返回
|
|
94
|
+
if not response.success():
|
|
95
|
+
lark.logger.error(
|
|
96
|
+
f"client.aily.v1.aily_session_aily_message.create failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
|
97
|
+
return
|
|
98
|
+
# 处理业务结果
|
|
99
|
+
lark.logger.info(lark.JSON.marshal(response.data, indent=4))
|
|
100
|
+
return response.data.message.id
|
|
101
|
+
|
|
102
|
+
def create_ailysession_run(self, access_token, aily_session_id):
|
|
103
|
+
# 创建运行
|
|
104
|
+
# 构造请求对象
|
|
105
|
+
request: CreateAilySessionRunRequest = CreateAilySessionRunRequest.builder() \
|
|
106
|
+
.aily_session_id(aily_session_id) \
|
|
107
|
+
.request_body(CreateAilySessionRunRequestBody.builder()
|
|
108
|
+
.app_id(self.aily_app_id)
|
|
109
|
+
.build()) \
|
|
110
|
+
.build()
|
|
111
|
+
# 发起请求
|
|
112
|
+
option = lark.RequestOption.builder().user_access_token(
|
|
113
|
+
access_token).build()
|
|
114
|
+
response: CreateAilySessionRunResponse = self.ulark_client.aily.v1.aily_session_run.create(request, option)
|
|
115
|
+
# 处理失败返回
|
|
116
|
+
if not response.success():
|
|
117
|
+
lark.logger.error(
|
|
118
|
+
f"client.aily.v1.aily_session_run.create failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
|
119
|
+
return
|
|
120
|
+
|
|
121
|
+
# 处理业务结果
|
|
122
|
+
lark.logger.info(lark.JSON.marshal(response.data, indent=4))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
if __name__ == '__main__':
|
|
127
|
+
tenant_access_token = AilyLarkClient().get_tenant_access_token()
|
|
128
|
+
seseion_id = AilyLarkClient().create_ailysession(tenant_access_token)
|
|
129
|
+
print(seseion_id)
|
|
130
|
+
message_id = AilyLarkClient().create_ailysessionaily_message(tenant_access_token, seseion_id, "你好")
|
|
131
|
+
runs = AilyLarkClient().create_ailysession_run(tenant_access_token, seseion_id)
|
|
132
|
+
|
main/do_ai.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from it_assistant.ailyapp_client import AilyLarkClient
|
|
4
|
+
from it_assistant.lark_client import LarkdocsClient
|
|
5
|
+
from it_assistant.intent_detail import *
|
|
6
|
+
import datetime
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Testsuitelink = "https://bytedance.larkoffice.com/sheets/ZVzfsw4rMhkMF6tjtxmc4BdSnMb"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def do_ai_auto(Testsuitelink):
|
|
14
|
+
"""
|
|
15
|
+
自动化执行AI测试用例
|
|
16
|
+
"""
|
|
17
|
+
startAt = 0
|
|
18
|
+
try:
|
|
19
|
+
# 获取租户访问令牌
|
|
20
|
+
tenant_access_token = AilyLarkClient().get_tenant_access_token()
|
|
21
|
+
if not tenant_access_token:
|
|
22
|
+
raise ValueError("未能获取到有效的租户访问令牌")
|
|
23
|
+
# 通过文档链接获取spreadsheet_token
|
|
24
|
+
spreadsheet_token = Testsuitelink.split("/")[-1]
|
|
25
|
+
if not spreadsheet_token:
|
|
26
|
+
raise ValueError("未能从文档链接中提取到有效的spreadsheet_token")
|
|
27
|
+
# 读取表格用户输入
|
|
28
|
+
spreadsheet = LarkdocsClient().get_the_worksheet(spreadsheet_token)
|
|
29
|
+
if not spreadsheet:
|
|
30
|
+
raise ValueError("未能获取到有效的工作表数据")
|
|
31
|
+
for i in spreadsheet.sheets:
|
|
32
|
+
column_count = i.grid_properties.column_count
|
|
33
|
+
row_count = i.grid_properties.row_count
|
|
34
|
+
sheet_id = i.sheet_id
|
|
35
|
+
title = i.title
|
|
36
|
+
if title == "测试集":
|
|
37
|
+
# 构建JSON字符串
|
|
38
|
+
json_str = {"ranges": [sheet_id + "!A1:A" + str(row_count)]}
|
|
39
|
+
# 获取纯文本内容
|
|
40
|
+
test = LarkdocsClient().get_plaintextcontent(json_str, spreadsheet_token, sheet_id)
|
|
41
|
+
test = json.loads(test)
|
|
42
|
+
userinput = test['data']['value_ranges'][0]['values']
|
|
43
|
+
print(f"表头为{userinput[0]}")
|
|
44
|
+
for i in range(1, row_count):
|
|
45
|
+
if userinput[i][0]:
|
|
46
|
+
if startAt == 0:
|
|
47
|
+
startAt = int(time.time())
|
|
48
|
+
# 创建会话
|
|
49
|
+
seseion_id = AilyLarkClient().create_ailysession(tenant_access_token)
|
|
50
|
+
if not seseion_id:
|
|
51
|
+
raise ValueError("未能成功创建会话")
|
|
52
|
+
# 创建消息
|
|
53
|
+
message_id = AilyLarkClient().create_ailysessionaily_message(tenant_access_token, seseion_id,
|
|
54
|
+
userinput[i][0])
|
|
55
|
+
if not message_id:
|
|
56
|
+
raise ValueError("未能成功创建消息")
|
|
57
|
+
# 创建运行实例
|
|
58
|
+
runs = AilyLarkClient().create_ailysession_run(tenant_access_token, seseion_id)
|
|
59
|
+
#可不需等待运行实例创建完成
|
|
60
|
+
#if not runs:
|
|
61
|
+
# raise ValueError("未能成功创建运行实例")
|
|
62
|
+
time.sleep(1)
|
|
63
|
+
else:
|
|
64
|
+
return startAt, i
|
|
65
|
+
break
|
|
66
|
+
return startAt, row_count
|
|
67
|
+
break
|
|
68
|
+
except KeyError as ke:
|
|
69
|
+
print(f"KeyError 发生: 数据中缺少必要的键,错误详情: {ke}")
|
|
70
|
+
return None, None
|
|
71
|
+
except json.JSONDecodeError as jde:
|
|
72
|
+
print(f"JSON 解析错误: {jde}")
|
|
73
|
+
return None, None
|
|
74
|
+
except ValueError as ve:
|
|
75
|
+
print(f"值错误: {ve}")
|
|
76
|
+
return None, None
|
|
77
|
+
except Exception as e:
|
|
78
|
+
print(f"发生未知错误: {e}")
|
|
79
|
+
return None, None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_conversationlogs1(startAt):
|
|
83
|
+
"""
|
|
84
|
+
对话ID 技能分发 用户输入
|
|
85
|
+
res_data = {
|
|
86
|
+
'intentID': 7485259579248705537,
|
|
87
|
+
'skillLabels': ["GUI 设备/配件申请"],
|
|
88
|
+
'userInput': "我要申请一个鼠标",
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
"""
|
|
92
|
+
data = webapiClient().get_intent_detail_list(startAt)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_conversationlogs(startAt, pageSize=10):
|
|
96
|
+
"""
|
|
97
|
+
对话ID 技能分发 用户输入
|
|
98
|
+
res_data = {
|
|
99
|
+
'intentID': 7485259579248705537,
|
|
100
|
+
'skillLabels': ["GUI 设备/配件申请"],
|
|
101
|
+
'userInput': "我要申请一个鼠标",
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
# 之前提到形参 'pageSize' 未填,这里假设默认值为 10,你可按需修改
|
|
107
|
+
data = webapiClient().get_intent_detail_list(startAt, pageSize=10)
|
|
108
|
+
return data
|
|
109
|
+
except KeyError as ke:
|
|
110
|
+
print(f"KeyError 发生: 数据中缺少必要的键,错误详情: {ke}")
|
|
111
|
+
return None
|
|
112
|
+
except IndexError as ie:
|
|
113
|
+
print(f"IndexError 发生: 索引超出范围,错误详情: {ie}")
|
|
114
|
+
return None
|
|
115
|
+
except Exception as e:
|
|
116
|
+
print(f"发生未知错误: {e}")
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def write_reslut(data, Testsuitelink, title):
|
|
121
|
+
"""
|
|
122
|
+
写入表格
|
|
123
|
+
"""
|
|
124
|
+
try:
|
|
125
|
+
# 解析 spreadsheet_token
|
|
126
|
+
spreadsheet_token = Testsuitelink.split("/")[-1]
|
|
127
|
+
|
|
128
|
+
# 生成新工作表名称
|
|
129
|
+
new_sheet_title = f"{title}{datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')}"
|
|
130
|
+
sheetinfo = {"index": 0, "title": new_sheet_title}
|
|
131
|
+
|
|
132
|
+
# 创建新工作表
|
|
133
|
+
spreadsheet0 = LarkdocsClient().createsheets(spreadsheet_token, sheetinfo)
|
|
134
|
+
sheet_id = spreadsheet0['sheet_id']
|
|
135
|
+
|
|
136
|
+
# 准备表头数据
|
|
137
|
+
headers = list(data[0].keys())
|
|
138
|
+
header_data = [
|
|
139
|
+
{
|
|
140
|
+
"range": f"{sheet_id}!{chr(ord('A') + col)}1:{chr(ord('A') + col)}1",
|
|
141
|
+
"values": [[[{"text": {"text": header}, "type": "text"}]]]
|
|
142
|
+
}
|
|
143
|
+
for col, header in enumerate(headers)
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
# 写入表头
|
|
147
|
+
LarkdocsClient().writesheets(spreadsheet_token, sheet_id, {"value_ranges": header_data})
|
|
148
|
+
|
|
149
|
+
# 写入数据
|
|
150
|
+
for row, row_data in enumerate(data, start=1):
|
|
151
|
+
row_values = [
|
|
152
|
+
{
|
|
153
|
+
"range": f"{sheet_id}!{chr(ord('A') + col)}{row + 1}:{chr(ord('A') + col)}{row + 1}",
|
|
154
|
+
"values": [[[{"text": {"text": str(row_data[header])}, "type": "text"}]]]
|
|
155
|
+
}
|
|
156
|
+
for col, header in enumerate(headers)
|
|
157
|
+
]
|
|
158
|
+
LarkdocsClient().writesheets(spreadsheet_token, sheet_id, {"value_ranges": row_values})
|
|
159
|
+
|
|
160
|
+
return True
|
|
161
|
+
except KeyError as ke:
|
|
162
|
+
print(f"KeyError 发生: 数据中缺少必要的键,错误详情: {ke}")
|
|
163
|
+
return False
|
|
164
|
+
except IndexError as ie:
|
|
165
|
+
print(f"IndexError 发生: 索引超出范围,错误详情: {ie}")
|
|
166
|
+
return False
|
|
167
|
+
except Exception as e:
|
|
168
|
+
print(f"发生未知错误: {e}")
|
|
169
|
+
return False
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if __name__ == '__main__':
|
|
173
|
+
Testsuitelink = "https://bytedance.larkoffice.com/sheets/ZVzfsw4rMhkMF6tjtxmc4BdSnMb"
|
|
174
|
+
startAt, num = do_ai_auto(Testsuitelink)
|
|
175
|
+
data = webapiClient().get_intent_detail_list(startAt, num)
|
|
176
|
+
data_qqq = webapiClient().get_intent_detail_llm(data)
|
|
177
|
+
aaaa = write_reslut(data_qqq, Testsuitelink, "测试")
|
main/intent_detail.py
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import http.client
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
import requests
|
|
6
|
+
headers = {
|
|
7
|
+
'cookie':'X-Kunlun-SessionId=L%3A3b34958803f34f43a52c.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YWwiOnsidGVuYW50X2lkIjozOTAsInVzZXJfaWQiOjE3MjIxNjYwNzMxOTk2NDUsInRlbmFudF9kb21haW5fbmFtZSI6ImFwYWFzIiwic2Vzc2lvbl92ZXJzaW9uIjoidjIwMjAtMDUtMTkiLCJ3c190b2tlbiI6Ilc6OTk3Y2MwNTA3OTRlNGFmYWFkYzEiLCJsb2dpbl90b2tlbiI6IjE3MDE3ZmFlMWJlNjVlMzdzSzBhMzA0ZjY0N2MyZmFjY2QwSjRFYmNmNGVjNzAzZDgwOWYxNDVnNDY0MzY1ZjEyNWI0YmZlZDhhTmMiLCJzb3VyY2VfY2hhbm5lbCI6ImZlaXNodSIsInRlbmFudF9rZXkiOiI3MzY1ODhjOTI2MGYxNzVkIiwiZXh0ZXJuYWxfZG9tYWluX25hbWUiOiJieXRlZGFuY2UiLCJvcmlnaW5hbF90ZW5hbnRfaWQiOjAsIm9yaWdpbmFsX3VzZXJfaWQiOjAsImlkcF9jaGFubmVsIjoiIn0sImV4cCI6MTc1ODk0MTY3MH0.l9yn5zbWFhOEJml5iA69TpFwZ7qgLMzj7L0cj4Ryozc; passport_web_did=7487801556726579201; passport_trace_id=7487801556748156956; QXV0aHpDb250ZXh0=2f506053fdd544e7aa0df84c66a287f9; locale=zh-CN; landing_url=https://accounts.feishu.cn/accounts/page/login?app_id=107&no_trap=1&redirect_uri=https%3A%2F%2Fapaas.feishu.cn%2Fai%2Fspring_f17d05d924__c%2Fmanagement%2Fchat-log; _gcl_au=1.1.1249684330.1743389657; s_v_web_id=verify_m8wh6ssk_JRUTLUkb_AJsu_4Xjm_ANzV_gLPDip941iqw; __tea__ug__uid=7487801495396992562; _ga=GA1.2.1834362348.1743389657; _gid=GA1.2.758422620.1743389658; session=XN0YXJ0-4e7g6c2c-da65-4492-a6f6-6413002bd949-WVuZA; session_list=XN0YXJ0-4e7g6c2c-da65-4492-a6f6-6413002bd949-WVuZA; login_recently=1; _ga_VPYRHN104D=GS1.1.1743389657.1.1.1743389669.48.0.0; msToken=4W_kQaUJyB5jBl5FX8vjfY6SYAFcNAp7NiDqM3-QyBN0XIF24a5SyaOeTpfzIZAuNfH-cGjXK1u3tNXV3ETo8Z2ZTQFLGSTFF2KmMr35XQsODVrddz8FdHAfyJg4F7ayxiDsicO5ObKgK0Y_95Bq1d12vKKbJ99vm9IZWEpcRFLG; kunlun-session-v2=L%3A3b34958803f34f43a52c.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YWwiOnsidGVuYW50X2lkIjozOTAsInVzZXJfaWQiOjE3MjIxNjYwNzMxOTk2NDUsInRlbmFudF9kb21haW5fbmFtZSI6ImFwYWFzIiwic2Vzc2lvbl92ZXJzaW9uIjoidjIwMjAtMDUtMTkiLCJ3c190b2tlbiI6Ilc6OTk3Y2MwNTA3OTRlNGFmYWFkYzEiLCJsb2dpbl90b2tlbiI6IjE3MDE3ZmFlMWJlNjVlMzdzSzBhMzA0ZjY0N2MyZmFjY2QwSjRFYmNmNGVjNzAzZDgwOWYxNDVnNDY0MzY1ZjEyNWI0YmZlZDhhTmMiLCJzb3VyY2VfY2hhbm5lbCI6ImZlaXNodSIsInRlbmFudF9rZXkiOiI3MzY1ODhjOTI2MGYxNzVkIiwiZXh0ZXJuYWxfZG9tYWluX25hbWUiOiJieXRlZGFuY2UiLCJvcmlnaW5hbF90ZW5hbnRfaWQiOjAsIm9yaWdpbmFsX3VzZXJfaWQiOjAsImlkcF9jaGFubmVsIjoiIn0sImV4cCI6MTc1ODk0MTY3MH0.l9yn5zbWFhOEJml5iA69TpFwZ7qgLMzj7L0cj4Ryozc; kunlun-session-token=2b32fc3c28f44fb89bab94ad072a05c9f2f844c49705c95d76bae40479a189b7; _tea_utm_cache_1229=undefined; sl_session=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDM0MzI4NzEsInVuaXQiOiJldV9uYyIsInJhdyI6eyJtZXRhIjoiQVdIazBuRzhRUUFDQUFBQUFBQUFBQUZuNmdQWUFVNEFBV2ZxQTlnQlRnQUJaK29ENWRES3dBSUNLZ0VBUVVGQlFVRkJRVUZCUVVKdU5tZFFiRE40ZDBGQlp6MDkiLCJzdW0iOiJlMmM4YTIwMTcyMDcxNmVjYTFiOWRlOTQ5Yjc3OGJkNDczOGIzOTAwNWJiNTJhYTkyOTM2YTRhZWIzMGI2ZTY0IiwibG9jIjoiemhfY24iLCJhcGMiOiJSZWxlYXNlIiwiaWF0IjoxNzQzMzg5NjcxLCJzYWMiOnsiVXNlclN0YWZmU3RhdHVzIjoiMSIsIlVzZXJUeXBlIjoiNDIifSwibG9kIjpudWxsLCJjbmYiOnsiamt0IjoiYkx6aTdPRDBHS09mNllOQ0xGamtPZWtuQkNRSHM2ZFh5STdmcTVubE93VSJ9LCJucyI6ImxhcmsiLCJuc191aWQiOiI3MDUzOTk0MzAyMzAwNTUzMjE4IiwibnNfdGlkIjoiMSIsIm90IjozLCJjdCI6MTc0MzM4OTY3MCwicnQiOjE3NDMzODk2NzB9fQ.2pQlqU6fuqnw_iqtJe1sH1FfSSXBpFQ0RAoaRccxHEaHSBvqsdc9_7e4zjgcHOhTjISi3mGw3EC3EXftLj5Otw; passport_app_access_token=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDM0MzI4NzIsInVuaXQiOiJldV9uYyIsInJhdyI6eyJtX2FjY2Vzc19pbmZvIjp7IjEwNyI6eyJpYXQiOjE3NDMzODk2NzIsImFjY2VzcyI6dHJ1ZX19LCJzdW0iOiJlMmM4YTIwMTcyMDcxNmVjYTFiOWRlOTQ5Yjc3OGJkNDczOGIzOTAwNWJiNTJhYTkyOTM2YTRhZWIzMGI2ZTY0In19.jtfbxALtDnZYTJx4cb6ohPy2uDVCHTuh0x-Dg7Ui1F4vMO3aka7rvOeZTIwGJ7IlAn0b-OjBOWQEVQvHthhEwQ; swp_csrf_token=a239a297-e0f7-4820-aa3a-6349c8a04977; t_beda37=10a0c227407070710f979ef9d5b530118d080fd0ec27f2c3ce04c251a5a20d70',
|
|
8
|
+
'x-kunlun-token': '17017fae1be65e37sK0a304f647c2faccd0J4Ebcf4ec703d809f145g464365f125b4bfed8aNc',
|
|
9
|
+
'Content-Type': 'application/json'
|
|
10
|
+
}
|
|
11
|
+
itamheaders = {
|
|
12
|
+
'authorization': 'Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InYyIiwidHlwIjoiSldUIn0.eyJleHAiOjE3NDI1NDYyMTcsImp0aSI6ImJKMk9hV0dkanU5QStMMXciLCJpYXQiOjE3NDEyNTAyMTcsImlzcyI6InRhbm5hIiwic3ViIjoiMzgzMDMxOUBieXRlZGFuY2UucGVvcGxlIiwidGVuYW50X2lkIjoiYnl0ZWRhbmNlLnBlb3BsZSIsInRlbmFudF9uYW1lIjoiIiwicHJvamVjdF9rZXkiOiJjcm1TZmdIVmU1dXhIMHJyIiwidW5pdCI6ImV1X25jIiwiYXV0aF9ieSI6Mn0.eHghtX4NOnD1uD65bzqv7n1J3mtnPPXJoVKIWDwl4PMZPkqc3FisH4RMXxDqeOyDCgRHYhmam7VEenl8T0UIKpzI8ad8yMiZytvAkNhclLjCdmokLB7DdwnbO1qeDLxdqjL-S3da0KHHkOT8j-rWR94XJ0N7T_snoko4Ovsp13w',
|
|
13
|
+
'Content-Type': 'application/json'
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class webapiClient:
|
|
18
|
+
def __init__(self):
|
|
19
|
+
"""
|
|
20
|
+
初始化 Client 实例,tenant_access_token 会在 Client 初始化时自动获取
|
|
21
|
+
"""
|
|
22
|
+
self.headers = headers
|
|
23
|
+
self.itamheaders = headers
|
|
24
|
+
self.conn = http.client.HTTPSConnection("apaas.feishu.cn")
|
|
25
|
+
|
|
26
|
+
def get_intent_detail_list1(self, startAt,pageSize):
|
|
27
|
+
"""
|
|
28
|
+
outdata:
|
|
29
|
+
对话ID 技能分发 用户输入
|
|
30
|
+
res_ = {
|
|
31
|
+
'intentID': 7485259579248705537,
|
|
32
|
+
'userInput': "我要申请一个鼠标",
|
|
33
|
+
'skillLabels': ["GUI 设备/配件申请"],
|
|
34
|
+
'apply_day':"",
|
|
35
|
+
'apply_num':"",
|
|
36
|
+
'asset_name':"",
|
|
37
|
+
'device_type':""
|
|
38
|
+
}
|
|
39
|
+
"""
|
|
40
|
+
endAt = int(time.time())
|
|
41
|
+
payload = json.dumps({
|
|
42
|
+
"startAt": startAt,
|
|
43
|
+
"endAt": endAt,
|
|
44
|
+
"matchIntentID": "",
|
|
45
|
+
"matchStatus": [],
|
|
46
|
+
"pageSize": pageSize+10
|
|
47
|
+
})
|
|
48
|
+
self.conn.request("POST",
|
|
49
|
+
"/ai/api/v1/conversational_runtime/namespaces/spring_f17d05d924__c/stats/intent_detail_list",
|
|
50
|
+
payload, self.headers)
|
|
51
|
+
res = self.conn.getresponse()
|
|
52
|
+
data = res.read()
|
|
53
|
+
data = json.loads(data.decode("utf-8"))
|
|
54
|
+
res_list = []
|
|
55
|
+
|
|
56
|
+
for i in data['data']['intentDetailList']:
|
|
57
|
+
if i['channelType'] in ["LARK_OPEN_API","LARK_BOT","ANONYMOUS_CUI_SDK"]:
|
|
58
|
+
res_list.append(
|
|
59
|
+
{'对话日志/intentID': i['intentID'],
|
|
60
|
+
'用户输入/userInput': i['userInput'],
|
|
61
|
+
'数据是否有效/isdatavalid': "是",
|
|
62
|
+
'语言/language': "zh",
|
|
63
|
+
'是否 IT 问题/isITproblem': "是",
|
|
64
|
+
'业务场景/businessscenario': "NULL",
|
|
65
|
+
'分发技能/skill': i['skillLabels'],
|
|
66
|
+
'型号关键字词/asset_name': "NULL",
|
|
67
|
+
'型号类型/device_type': "NULL",
|
|
68
|
+
'匹配型号/AssetNamelist': "NULL",
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
return res_list
|
|
73
|
+
|
|
74
|
+
def get_intent_detail_list(self, startAt, pageSize):
|
|
75
|
+
"""
|
|
76
|
+
outdata:
|
|
77
|
+
对话ID 技能分发 用户输入
|
|
78
|
+
res_ = {
|
|
79
|
+
'intentID': 7485259579248705537,
|
|
80
|
+
'userInput': "我要申请一个鼠标",
|
|
81
|
+
'skillLabels': ["GUI 设备/配件申请"],
|
|
82
|
+
'apply_day':"",
|
|
83
|
+
'apply_num':"",
|
|
84
|
+
'asset_name':"",
|
|
85
|
+
'device_type':""
|
|
86
|
+
}
|
|
87
|
+
"""
|
|
88
|
+
# 输入参数类型和范围检查
|
|
89
|
+
if not isinstance(startAt, int) or startAt < 0:
|
|
90
|
+
raise ValueError("startAt 必须是一个非负整数")
|
|
91
|
+
if not isinstance(pageSize, int) or pageSize < 0:
|
|
92
|
+
raise ValueError("pageSize 必须是一个非负整数")
|
|
93
|
+
|
|
94
|
+
endAt = int(time.time())
|
|
95
|
+
payload = json.dumps({
|
|
96
|
+
"startAt": startAt,
|
|
97
|
+
"endAt": endAt,
|
|
98
|
+
"matchIntentID": "",
|
|
99
|
+
"matchStatus": [],
|
|
100
|
+
"pageSize": pageSize + 10
|
|
101
|
+
})
|
|
102
|
+
try:
|
|
103
|
+
self.conn.request("POST",
|
|
104
|
+
"/ai/api/v1/conversational_runtime/namespaces/spring_f17d05d924__c/stats/intent_detail_list",
|
|
105
|
+
payload, self.headers)
|
|
106
|
+
res = self.conn.getresponse()
|
|
107
|
+
|
|
108
|
+
# 检查响应状态码
|
|
109
|
+
if res.status != 200:
|
|
110
|
+
raise http.client.HTTPException(f"请求失败,状态码: {res.status}, 原因: {res.reason}")
|
|
111
|
+
|
|
112
|
+
data = res.read()
|
|
113
|
+
try:
|
|
114
|
+
data = json.loads(data.decode("utf-8"))
|
|
115
|
+
except json.JSONDecodeError:
|
|
116
|
+
raise ValueError("无法将响应数据解析为 JSON 格式")
|
|
117
|
+
|
|
118
|
+
# 检查响应数据结构
|
|
119
|
+
if 'data' not in data or 'intentDetailList' not in data['data']:
|
|
120
|
+
raise ValueError("响应数据缺少必要的字段 'data' 或 'intentDetailList'")
|
|
121
|
+
|
|
122
|
+
res_list = []
|
|
123
|
+
for i in data['data']['intentDetailList']:
|
|
124
|
+
if i['channelType'] in ["LARK_OPEN_API", "LARK_BOT", "ANONYMOUS_CUI_SDK"]:
|
|
125
|
+
res_list.append({
|
|
126
|
+
'对话日志/intentID': i['intentID'],
|
|
127
|
+
'用户输入/userInput': i['userInput'],
|
|
128
|
+
'数据是否有效/isdatavalid': "是",
|
|
129
|
+
'语言/language': "zh",
|
|
130
|
+
'是否 IT 问题/isITproblem': "是",
|
|
131
|
+
'业务场景/businessscenario': "NULL",
|
|
132
|
+
'分发技能/skill': i['skillLabels'],
|
|
133
|
+
'型号关键字词/asset_name': "NULL",
|
|
134
|
+
'型号类型/device_type': "NULL",
|
|
135
|
+
'匹配型号/AssetNamelist': "NULL",
|
|
136
|
+
})
|
|
137
|
+
return res_list
|
|
138
|
+
except http.client.HTTPException as http_err:
|
|
139
|
+
print(f"HTTP 请求错误: {http_err}")
|
|
140
|
+
return []
|
|
141
|
+
except ValueError as value_err:
|
|
142
|
+
print(f"值错误: {value_err}")
|
|
143
|
+
return []
|
|
144
|
+
except Exception as general_err:
|
|
145
|
+
print(f"发生未知错误: {general_err}")
|
|
146
|
+
return []
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def get_intent_detail_llm0(self, res_list):
|
|
152
|
+
"""
|
|
153
|
+
提取关键词
|
|
154
|
+
'apply_day': "",'apply_num': "",'asset_name': "",'device_type': ""'对话日志/intentID': 7485264011232886786,
|
|
155
|
+
'用户输入/userInput': "我要申请一个鼠标",
|
|
156
|
+
'数据是否有效/isdatavalid': "是",
|
|
157
|
+
'语言/language': "zh",
|
|
158
|
+
'是否 IT 问题/isITproblem': "是",
|
|
159
|
+
'业务场景/businessscenario': "NULL",
|
|
160
|
+
'分发技能/skill': "NULL",
|
|
161
|
+
'型号关键字词/asset_name': "NULL", #显示器
|
|
162
|
+
'型号类型/device_type': "NULL", # 设备 配件 软件
|
|
163
|
+
'匹配型号/AssetNamelist': "NULL",
|
|
164
|
+
"""
|
|
165
|
+
payload = ''
|
|
166
|
+
for i in res_list:
|
|
167
|
+
intentID = i['对话日志/intentID']
|
|
168
|
+
urlintentID = f'https://apaas.feishu.cn/ai/api/v1/conversational_runtime/namespaces/spring_f17d05d924__c/intent/{intentID}?pageSize=20&statusFilter=%5B%5D&fieldFilter=_node_id&fieldFilter=status&fieldFilter=usages&fieldFilter=_node_name&fieldFilter=_node_type&fieldFilter=title_for_maker&fieldFilter=associate_id'
|
|
169
|
+
response = requests.request("GET", urlintentID, headers=self.headers, data=payload)
|
|
170
|
+
response = json.loads(response.text)
|
|
171
|
+
for j in response['data']['steps']:
|
|
172
|
+
if j['titleForMaker'] in ["槽位抽取","LLM 2"]:
|
|
173
|
+
nodeid = j['nodeID']
|
|
174
|
+
urlnodeid = f'https://apaas.feishu.cn/ai/api/v1/conversational_runtime/namespaces/spring_f17d05d924__c/association/{intentID}/node/{nodeid}?intentID={intentID}'
|
|
175
|
+
response = requests.request("GET", urlnodeid, headers=self.headers, data=payload)
|
|
176
|
+
data_nodeid = json.loads(response.text)
|
|
177
|
+
nodeid_output = json.loads(data_nodeid['data']['step']['output'])
|
|
178
|
+
if nodeid_output is not None and nodeid_output['response'] is not None:
|
|
179
|
+
# 判断是否为json格式
|
|
180
|
+
if not isinstance(nodeid_output['response'], dict):
|
|
181
|
+
nodeid_output['response'] = json.loads(nodeid_output['response'])
|
|
182
|
+
#i['apply_day'] = nodeid_output['response'].get('apply_day', 'NULL')
|
|
183
|
+
#i['apply_num'] = nodeid_output['response'].get('apply_num', 'NULL')
|
|
184
|
+
|
|
185
|
+
i['型号关键字词/asset_name'] = nodeid_output['response'].get('asset_name', 'NULL')
|
|
186
|
+
i['型号类型/device_type'] = nodeid_output['response'].get('device_type', 'NULL')
|
|
187
|
+
return res_list
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def get_intent_detail_llm(self, res_list):
|
|
191
|
+
"""
|
|
192
|
+
提取关键词:
|
|
193
|
+
槽位提取:'apply_day': "",'apply_num': "",'asset_name': "",'device_type': ""
|
|
194
|
+
表头字段:
|
|
195
|
+
'对话日志/intentID': 7485264011232886786,
|
|
196
|
+
'用户输入/userInput': "我要申请一个鼠标",
|
|
197
|
+
'数据是否有效/isdatavalid': "是",
|
|
198
|
+
'语言/language': "zh",
|
|
199
|
+
'是否 IT 问题/isITproblem': "是",
|
|
200
|
+
'业务场景/businessscenario': "NULL",
|
|
201
|
+
'分发技能/skill': "NULL",
|
|
202
|
+
'型号关键字词/asset_name': "NULL", #显示器
|
|
203
|
+
'型号类型/device_type': "NULL", # 设备 配件 软件
|
|
204
|
+
'匹配型号/AssetNamelist': "NULL",
|
|
205
|
+
"""
|
|
206
|
+
try:
|
|
207
|
+
# 检查 res_list 是否为空
|
|
208
|
+
if not res_list:
|
|
209
|
+
print("输入的 res_list 为空")
|
|
210
|
+
return []
|
|
211
|
+
|
|
212
|
+
payload = ''
|
|
213
|
+
for i in res_list:
|
|
214
|
+
intentID = i['对话日志/intentID']
|
|
215
|
+
urlintentID = f'https://apaas.feishu.cn/ai/api/v1/conversational_runtime/namespaces/spring_f17d05d924__c/intent/{intentID}?pageSize=20&statusFilter=%5B%5D&fieldFilter=_node_id&fieldFilter=status&fieldFilter=usages&fieldFilter=_node_name&fieldFilter=_node_type&fieldFilter=title_for_maker&fieldFilter=associate_id'
|
|
216
|
+
response = requests.request("GET", urlintentID, headers=self.headers, data=payload)
|
|
217
|
+
|
|
218
|
+
# 检查响应状态码
|
|
219
|
+
response.raise_for_status()
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
response = response.json()
|
|
223
|
+
except json.JSONDecodeError:
|
|
224
|
+
print(f"无法解析来自 {urlintentID} 的响应为 JSON 格式")
|
|
225
|
+
continue
|
|
226
|
+
|
|
227
|
+
# 检查响应数据结构
|
|
228
|
+
if 'data' not in response or 'steps' not in response['data']:
|
|
229
|
+
print(f"来自 {urlintentID} 的响应缺少必要的字段 'data' 或 'steps'")
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
for j in response['data']['steps']:
|
|
233
|
+
if j['titleForMaker'] in ["槽位抽取", "LLM 2"]:
|
|
234
|
+
nodeid = j['nodeID']
|
|
235
|
+
urlnodeid = f'https://apaas.feishu.cn/ai/api/v1/conversational_runtime/namespaces/spring_f17d05d924__c/association/{intentID}/node/{nodeid}?intentID={intentID}'
|
|
236
|
+
response_nodeid = requests.request("GET", urlnodeid, headers=self.headers, data=payload)
|
|
237
|
+
|
|
238
|
+
# 检查响应状态码
|
|
239
|
+
response_nodeid.raise_for_status()
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
data_nodeid = response_nodeid.json()
|
|
243
|
+
except json.JSONDecodeError:
|
|
244
|
+
print(f"无法解析来自 {urlnodeid} 的响应为 JSON 格式")
|
|
245
|
+
continue
|
|
246
|
+
|
|
247
|
+
# 检查响应数据结构
|
|
248
|
+
if 'data' not in data_nodeid or 'step' not in data_nodeid['data'] or 'output' not in data_nodeid['data']['step']:
|
|
249
|
+
print(f"来自 {urlnodeid} 的响应缺少必要的字段 'data'、'step' 或 'output'")
|
|
250
|
+
continue
|
|
251
|
+
|
|
252
|
+
nodeid_output = json.loads(data_nodeid['data']['step']['output'])
|
|
253
|
+
if nodeid_output is not None and nodeid_output.get('response') is not None:
|
|
254
|
+
# 判断是否为 json 格式
|
|
255
|
+
if not isinstance(nodeid_output['response'], dict):
|
|
256
|
+
try:
|
|
257
|
+
nodeid_output['response'] = json.loads(nodeid_output['response'])
|
|
258
|
+
except json.JSONDecodeError:
|
|
259
|
+
print(f"无法解析 {urlnodeid} 响应中的 'response' 字段为 JSON 格式")
|
|
260
|
+
continue
|
|
261
|
+
i['型号关键字词/asset_name'] = nodeid_output['response'].get('asset_name', 'NULL')
|
|
262
|
+
i['型号类型/device_type'] = nodeid_output['response'].get('device_type', 'NULL')
|
|
263
|
+
|
|
264
|
+
return res_list
|
|
265
|
+
except requests.RequestException as req_err:
|
|
266
|
+
print(f"请求错误: {req_err}")
|
|
267
|
+
return []
|
|
268
|
+
except Exception as general_err:
|
|
269
|
+
print(f"发生未知错误: {general_err}")
|
|
270
|
+
return []
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def get_bestmatchitemforreturn(self,keyword):
|
|
275
|
+
"""
|
|
276
|
+
mock数据,获取最佳匹配的sku/spu
|
|
277
|
+
mock数据:公用配件列表、设备列表、软件列表
|
|
278
|
+
todo:mock数据表格为飞书文档或者其他?
|
|
279
|
+
"""
|
|
280
|
+
_urlGetBestMatchItemForReturn = "https://asset-mig-pre.bytedance.net/aily/api/itservice/ai/GetBestMatchItemForReturn"
|
|
281
|
+
|
|
282
|
+
payload = json.dumps({
|
|
283
|
+
"SearchKey": keyword,
|
|
284
|
+
"AiUseType": 1,
|
|
285
|
+
"ListReturnableAccessoryRequest": {
|
|
286
|
+
"IsAll": True,
|
|
287
|
+
"Page": {
|
|
288
|
+
"PageNum": 1,
|
|
289
|
+
"PageSize": 30
|
|
290
|
+
},
|
|
291
|
+
"OwnerUserID": "",
|
|
292
|
+
"AccessoryApplyTypeList": []
|
|
293
|
+
},
|
|
294
|
+
"GetAssetListRequest": {
|
|
295
|
+
"Status": 6,
|
|
296
|
+
"Search": "",
|
|
297
|
+
"IsAll": True,
|
|
298
|
+
"SubStatusList": [
|
|
299
|
+
12,
|
|
300
|
+
18,
|
|
301
|
+
19
|
|
302
|
+
],
|
|
303
|
+
"Page": {
|
|
304
|
+
"PageNum": 1,
|
|
305
|
+
"PageSize": 30
|
|
306
|
+
},
|
|
307
|
+
"OrganizationalUnitID": 1
|
|
308
|
+
}
|
|
309
|
+
})
|
|
310
|
+
response = requests.request("GET", _urlGetBestMatchItemForReturn, headers=self.headers, data=payload)
|
|
311
|
+
response = json.loads(response.text)
|
|
312
|
+
|
|
313
|
+
def get_segsearchcandidates(self, res_list):
|
|
314
|
+
#获取分数值
|
|
315
|
+
### 读取设备&配件的信息并拼接到text里面
|
|
316
|
+
### 遍历res_list中的device_name
|
|
317
|
+
###判断是否在asset.json里面
|
|
318
|
+
###调用算法接口获取设备&配件的分数值
|
|
319
|
+
pass
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
if __name__ == '__main__':
|
|
324
|
+
data = webapiClient().get_intent_detail_list(1742832000,10)
|
|
325
|
+
data_qqq = webapiClient().get_intent_detail_llm(data)
|
|
326
|
+
print("成都")
|