volcengine-python-sdk-aicc 0.0.41__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.
- bytedance/__init__.py +4 -0
- bytedance/jeddak_secure_channel/__init__.py +28 -0
- bytedance/jeddak_secure_channel/client.py +305 -0
- bytedance/jeddak_secure_channel/config.py +171 -0
- bytedance/jeddak_secure_channel/consts.py +5 -0
- bytedance/jeddak_secure_channel/crypto/__init__.py +14 -0
- bytedance/jeddak_secure_channel/crypto/aes.py +174 -0
- bytedance/jeddak_secure_channel/crypto/envelope.py +395 -0
- bytedance/jeddak_secure_channel/crypto/rsa.py +164 -0
- bytedance/jeddak_secure_channel/error.py +131 -0
- bytedance/jeddak_secure_channel/log/__init__.py +23 -0
- bytedance/jeddak_secure_channel/log/config.py +31 -0
- bytedance/jeddak_secure_channel/log/logger.py +88 -0
- bytedance/jeddak_secure_channel/logger_factory.py +134 -0
- bytedance/jeddak_secure_channel/ra.py +772 -0
- bytedance/jeddak_secure_channel/server.py +745 -0
- bytedance/jeddak_secure_channel/service/__init__.py +16 -0
- bytedance/jeddak_secure_channel/service/eps.py +133 -0
- bytedance/jeddak_secure_channel/service/eps_models.py +47 -0
- bytedance/jeddak_secure_channel/service/ras.py +88 -0
- bytedance/jeddak_secure_channel/service/tks.py +51 -0
- bytedance/jeddak_secure_channel/service/tks_models.py +334 -0
- bytedance/jeddak_secure_channel/utils.py +469 -0
- bytedance/jeddak_secure_model/model_automation_tool.py +181 -0
- bytedance/jeddak_secure_model/model_encryption.py +416 -0
- bytedance/jeddak_secure_model/model_hub_admin.py +116 -0
- bytedance/jeddak_secure_model/pcc_utils.py +279 -0
- bytedance/jeddak_secure_model/rds_utils.py +63 -0
- bytedance/tks/attester.py +41 -0
- bytedance/tks/client.py +629 -0
- bytedance/tks/consts.py +122 -0
- bytedance/tks/crypto/aes.py +47 -0
- bytedance/tks/crypto/ec.py +39 -0
- bytedance/tks/exceptions.py +22 -0
- bytedance/volcengine_aicc_sdk/__init__.py +14 -0
- bytedance/volcengine_aicc_sdk/aicc_client.py +277 -0
- bytedance/volcengine_aicc_sdk/aicc_inference.py +64 -0
- bytedance/volcengine_aicc_sdk/ark_inference_client.py +343 -0
- bytedance/volcengine_aicc_sdk/asr_inference_client.py +158 -0
- bytedance/volcengine_aicc_sdk/asr_websocket_client.py +705 -0
- bytedance/volcengine_aicc_sdk/auc_inference_client.py +305 -0
- bytedance/volcengine_aicc_sdk/common/__init__.py +0 -0
- bytedance/volcengine_aicc_sdk/common/aes.py +136 -0
- bytedance/volcengine_aicc_sdk/common/constant.py +4 -0
- bytedance/volcengine_aicc_sdk/common/error.py +21 -0
- bytedance/volcengine_aicc_sdk/common/log/__init__.py +24 -0
- bytedance/volcengine_aicc_sdk/common/log/config.py +31 -0
- bytedance/volcengine_aicc_sdk/common/log/logger.py +88 -0
- bytedance/volcengine_aicc_sdk/common/tos_utils.py +341 -0
- bytedance/volcengine_aicc_sdk/common/utils.py +45 -0
- bytedance/volcengine_aicc_sdk/cu_inference_client.py +292 -0
- bytedance/volcengine_aicc_sdk/deepseek_inference_client.py +501 -0
- bytedance/volcengine_aicc_sdk/secure_http_client.py +406 -0
- bytedance/volcengine_aicc_sdk/seedance_inference_client.py +500 -0
- bytedance/volcengine_aicc_sdk/seedream_inference_client.py +213 -0
- volcengine_python_sdk_aicc-0.0.41.dist-info/METADATA +79 -0
- volcengine_python_sdk_aicc-0.0.41.dist-info/RECORD +60 -0
- volcengine_python_sdk_aicc-0.0.41.dist-info/WHEEL +5 -0
- volcengine_python_sdk_aicc-0.0.41.dist-info/licenses/LICENSE +202 -0
- volcengine_python_sdk_aicc-0.0.41.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DeepSeek机密推理客户端
|
|
3
|
+
"""
|
|
4
|
+
__all__ = ["DeepSeekClient"]
|
|
5
|
+
|
|
6
|
+
import base64
|
|
7
|
+
import copy
|
|
8
|
+
import json
|
|
9
|
+
import time
|
|
10
|
+
import requests
|
|
11
|
+
import pickle
|
|
12
|
+
import bytedance.jeddak_secure_channel as jsc
|
|
13
|
+
from typing import IO, Union
|
|
14
|
+
|
|
15
|
+
from openai.types.chat import ChatCompletionMessage, ChatCompletionChunk
|
|
16
|
+
|
|
17
|
+
from .aicc_inference import AICCInference
|
|
18
|
+
from .common.constant import Constants
|
|
19
|
+
from .common.error import AICCException
|
|
20
|
+
from .common.log import logger
|
|
21
|
+
from openai import OpenAI
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DeepSeekClient(AICCInference):
|
|
25
|
+
"""
|
|
26
|
+
DeepSeek机密推理客户端.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self,
|
|
30
|
+
base_url: str = None,
|
|
31
|
+
api_key: str = None,
|
|
32
|
+
ep: str = None,
|
|
33
|
+
aicc_service_name: str = None,
|
|
34
|
+
policy_id: str = None,
|
|
35
|
+
is_openai: bool = True,
|
|
36
|
+
is_secure: bool = True,
|
|
37
|
+
ak: str = None,
|
|
38
|
+
sk: str = None,
|
|
39
|
+
region: str = "cn-beijing",
|
|
40
|
+
**kwargs):
|
|
41
|
+
if not base_url or not api_key or not aicc_service_name or not policy_id or not ak or not sk:
|
|
42
|
+
raise AICCException("New deepseek client failed, params error")
|
|
43
|
+
|
|
44
|
+
super().__init__(base_url, is_openai, is_secure, ak, sk, region)
|
|
45
|
+
|
|
46
|
+
self.api_key = api_key
|
|
47
|
+
self.ep = ep
|
|
48
|
+
self.aicc_service_name = aicc_service_name
|
|
49
|
+
self.policy_id = policy_id
|
|
50
|
+
|
|
51
|
+
self.kwargs = kwargs
|
|
52
|
+
|
|
53
|
+
self.dp_version = self.kwargs.get("dp_version", "3.1")
|
|
54
|
+
self.jsc_client = None
|
|
55
|
+
self.max_retries = 3
|
|
56
|
+
|
|
57
|
+
if is_secure:
|
|
58
|
+
jsc_config = dict()
|
|
59
|
+
jsc_config["ra_service_name"] = aicc_service_name
|
|
60
|
+
jsc_config["ra_policy_id"] = policy_id
|
|
61
|
+
jsc_config["bytedance_top_info"] = dict()
|
|
62
|
+
jsc_config["bytedance_top_info"]["ak"] = ak
|
|
63
|
+
jsc_config["bytedance_top_info"]["sk"] = sk
|
|
64
|
+
jsc_config["bytedance_top_info"]["region"] = region
|
|
65
|
+
jsc_config["bytedance_top_info"]["url"] = self.kwargs.get("top_url", "open.volcengineapi.com")
|
|
66
|
+
jsc_config["bytedance_top_info"]["service"] = self.kwargs.get("top_service", "pcc")
|
|
67
|
+
jsc_config["log_config"] = self.kwargs.get("log_config", Constants.LOG_CONFIG)
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
secure_channel_config = jsc.ClientConfig.from_dict(jsc_config)
|
|
71
|
+
self.jsc_client = jsc.Client(secure_channel_config)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.error(f"Error init jsc: {e}")
|
|
74
|
+
raise AICCException("New deepseek client failed")
|
|
75
|
+
|
|
76
|
+
def _encrypt_prompt_with_jsc(self, messages: list) -> object:
|
|
77
|
+
"""
|
|
78
|
+
使用端云互信SDK对prompt进行加密
|
|
79
|
+
:param messages:
|
|
80
|
+
:return: 返回对称解密密钥(多密钥时返回 role user 的content加密 密钥)
|
|
81
|
+
"""
|
|
82
|
+
if not messages or not self.jsc_client:
|
|
83
|
+
logger.error(f"messages is NULL")
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
ret_encrypt_key = None
|
|
87
|
+
for i in range(len(messages)):
|
|
88
|
+
messages[i]["content"], encrypt_key = self.jsc_client.encrypt_with_response(
|
|
89
|
+
json.dumps(messages[i].get("content")))
|
|
90
|
+
if messages[i].get("role") == "user":
|
|
91
|
+
ret_encrypt_key = encrypt_key
|
|
92
|
+
|
|
93
|
+
return ret_encrypt_key
|
|
94
|
+
|
|
95
|
+
def _chat_completion_message_to_str(self, chat_message: ChatCompletionMessage) -> str:
|
|
96
|
+
ret = dict()
|
|
97
|
+
ret["role"] = chat_message.role
|
|
98
|
+
ret["content"] = chat_message.content
|
|
99
|
+
ret["reasoning_content"] = chat_message.reasoning_content
|
|
100
|
+
ret["tool_calls"] = chat_message.tool_calls
|
|
101
|
+
ret["refusal"] = chat_message.refusal
|
|
102
|
+
ret["annotations"] = chat_message.annotations
|
|
103
|
+
ret["audio"] = chat_message.audio
|
|
104
|
+
ret["function_call"] = chat_message.function_call
|
|
105
|
+
return json.dumps(ret)
|
|
106
|
+
|
|
107
|
+
def _chat_completion_chunk_to_str(self, chat_completion_chunk: ChatCompletionChunk) -> str:
|
|
108
|
+
ret = dict()
|
|
109
|
+
ret["id"] = chat_completion_chunk.id
|
|
110
|
+
ret["object"] = chat_completion_chunk.object
|
|
111
|
+
ret["created"] = chat_completion_chunk.created
|
|
112
|
+
ret["model"] = chat_completion_chunk.model
|
|
113
|
+
|
|
114
|
+
if chat_completion_chunk.usage:
|
|
115
|
+
ret["usage"] = dict()
|
|
116
|
+
ret["usage"]["completion_tokens"] = chat_completion_chunk.usage.completion_tokens
|
|
117
|
+
ret["usage"]["prompt_tokens"] = chat_completion_chunk.usage.prompt_tokens
|
|
118
|
+
ret["usage"]["total_tokens"] = chat_completion_chunk.usage.total_tokens
|
|
119
|
+
ret["usage"]["completion_tokens_details"] = chat_completion_chunk.usage.completion_tokens_details
|
|
120
|
+
ret["usage"]["prompt_tokens_details"] = chat_completion_chunk.usage.prompt_tokens_details
|
|
121
|
+
ret["usage"]["reasoning_tokens"] = chat_completion_chunk.usage.reasoning_tokens
|
|
122
|
+
else:
|
|
123
|
+
ret["usage"] = None
|
|
124
|
+
|
|
125
|
+
ret["choices"] = list()
|
|
126
|
+
|
|
127
|
+
for choice in chat_completion_chunk.choices:
|
|
128
|
+
choice_info = dict()
|
|
129
|
+
choice_info["index"] = choice.index
|
|
130
|
+
choice_info["logprobs"] = choice.logprobs
|
|
131
|
+
choice_info["finish_reason"] = choice.finish_reason
|
|
132
|
+
choice_info["matched_stop"] = choice.matched_stop
|
|
133
|
+
choice_info["delta"] = dict()
|
|
134
|
+
choice_info["delta"]["content"] = choice.delta.content
|
|
135
|
+
choice_info["delta"]["function_call"] = choice.delta.function_call
|
|
136
|
+
choice_info["delta"]["refusal"] = choice.delta.refusal
|
|
137
|
+
choice_info["delta"]["role"] = choice.delta.role
|
|
138
|
+
choice_info["delta"]["tool_calls"] = choice.delta.tool_calls
|
|
139
|
+
choice_info["delta"]["reasoning_content"] = choice.delta.reasoning_content
|
|
140
|
+
|
|
141
|
+
ret["choices"].append(choice_info)
|
|
142
|
+
|
|
143
|
+
return json.dumps(ret)
|
|
144
|
+
|
|
145
|
+
def chat_completions(self, messages: list, output_stream: IO = None) -> Union[str, None]:
|
|
146
|
+
"""
|
|
147
|
+
生成聊天补全
|
|
148
|
+
:param messages:
|
|
149
|
+
:param output_stream:
|
|
150
|
+
:return:
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
if not messages:
|
|
154
|
+
raise AICCException("DeepSeek chat_completions Messages cannot be empty")
|
|
155
|
+
|
|
156
|
+
# DeepSeek目前仅3.1支持openai的方式
|
|
157
|
+
if self.dp_version < "3.1" and self.is_openai:
|
|
158
|
+
error_info = f"Sorry, DeepSeek{self.dp_version} not support is_openai={self.is_openai}"
|
|
159
|
+
logger.error(error_info)
|
|
160
|
+
raise AICCException(error_info)
|
|
161
|
+
|
|
162
|
+
if self.is_secure:
|
|
163
|
+
# V3.1用V4, V3.0用V2
|
|
164
|
+
if self.dp_version < "3.1":
|
|
165
|
+
url = f"{self.base_url}/v2/chat/completions"
|
|
166
|
+
else:
|
|
167
|
+
url = f"{self.base_url}/v4/chat/completions"
|
|
168
|
+
else:
|
|
169
|
+
url = f"{self.base_url}/v1/chat/completions"
|
|
170
|
+
|
|
171
|
+
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}"}
|
|
172
|
+
payload = {
|
|
173
|
+
"messages": messages,
|
|
174
|
+
"max_tokens": int(self.kwargs.get("max_tokens", 100)),
|
|
175
|
+
"temperature": float(self.kwargs.get("temperature", 1.0)),
|
|
176
|
+
"chat_template_kwargs": {"thinking": self.kwargs.get("thinking", True)},
|
|
177
|
+
"separate_reasoning": True
|
|
178
|
+
}
|
|
179
|
+
if output_stream:
|
|
180
|
+
payload["stream"] = True
|
|
181
|
+
payload["stop"] = "<|im_end|>"
|
|
182
|
+
payload["eos_token"] = "<|im_end|>"
|
|
183
|
+
|
|
184
|
+
if self.is_openai:
|
|
185
|
+
openai_messages = copy.deepcopy(messages)
|
|
186
|
+
encrypt_key = None
|
|
187
|
+
if self.is_secure:
|
|
188
|
+
encrypt_key = self._encrypt_prompt_with_jsc(openai_messages)
|
|
189
|
+
if not encrypt_key:
|
|
190
|
+
raise AICCException("Error during openai encrypt")
|
|
191
|
+
|
|
192
|
+
url = url.rstrip("/chat/completions")
|
|
193
|
+
openai_client = OpenAI(base_url=url, api_key=self.api_key)
|
|
194
|
+
|
|
195
|
+
resp = openai_client.chat.completions.create(
|
|
196
|
+
model=self.ep if self.ep else "",
|
|
197
|
+
messages=openai_messages,
|
|
198
|
+
temperature=payload.get("temperature"),
|
|
199
|
+
max_tokens=payload.get("max_tokens"),
|
|
200
|
+
stream=True if output_stream else False,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
if output_stream:
|
|
204
|
+
for chunk in resp:
|
|
205
|
+
if self.is_secure and encrypt_key:
|
|
206
|
+
if chunk.content:
|
|
207
|
+
data = encrypt_key.decrypt(base64.b64decode(chunk.content)).decode("utf-8")
|
|
208
|
+
if data.startswith("data:"):
|
|
209
|
+
data = data.strip("data:").strip()
|
|
210
|
+
output_stream.write(f"{data}\n")
|
|
211
|
+
else:
|
|
212
|
+
cont = self._chat_completion_chunk_to_str(chunk)
|
|
213
|
+
output_stream.write(f"{cont}\n")
|
|
214
|
+
return
|
|
215
|
+
else:
|
|
216
|
+
resp_msg = resp.choices[0].message
|
|
217
|
+
if self.is_secure and encrypt_key:
|
|
218
|
+
resp_msg = encrypt_key.decrypt(resp_msg).decode("utf-8")
|
|
219
|
+
return resp_msg
|
|
220
|
+
else:
|
|
221
|
+
return self._chat_completion_message_to_str(resp_msg)
|
|
222
|
+
|
|
223
|
+
encrypt_key = None
|
|
224
|
+
if self.is_secure:
|
|
225
|
+
# 加密数据并发送
|
|
226
|
+
try:
|
|
227
|
+
if self.dp_version < "3.1":
|
|
228
|
+
encrypted_messages, encrypt_key = \
|
|
229
|
+
self.jsc_client.encrypt_with_response(pickle.dumps(payload["messages"]))
|
|
230
|
+
else:
|
|
231
|
+
encrypted_messages, encrypt_key = \
|
|
232
|
+
self.jsc_client.encrypt_with_response(json.dumps(payload["messages"]))
|
|
233
|
+
|
|
234
|
+
payload["messages"] = encrypted_messages # 敏感字段
|
|
235
|
+
except Exception as e:
|
|
236
|
+
logger.error(f"Error during encrypt: {e}")
|
|
237
|
+
raise AICCException("Error during encrypt")
|
|
238
|
+
|
|
239
|
+
if output_stream:
|
|
240
|
+
try:
|
|
241
|
+
with requests.post(url, json=payload, headers=headers, stream=True) as response:
|
|
242
|
+
response.raise_for_status()
|
|
243
|
+
for chunk in response.iter_lines():
|
|
244
|
+
if chunk:
|
|
245
|
+
if self.is_secure and encrypt_key:
|
|
246
|
+
if self.dp_version < "3.1":
|
|
247
|
+
data = encrypt_key.decrypt(base64.b64decode(chunk)).decode("utf-8")
|
|
248
|
+
output_stream.write(f"{data}\n")
|
|
249
|
+
else:
|
|
250
|
+
chunk_str = chunk.decode("utf-8")
|
|
251
|
+
if chunk_str.startswith("data:"):
|
|
252
|
+
chunk_str = chunk_str.strip("data:").strip()
|
|
253
|
+
if chunk_str == "[DONE]":
|
|
254
|
+
output_stream.write(chunk_str + "\n")
|
|
255
|
+
else:
|
|
256
|
+
content = json.loads(chunk_str).get("content")
|
|
257
|
+
data = encrypt_key.decrypt(base64.b64decode(content)).decode("utf-8")
|
|
258
|
+
output_stream.write(f"{data}\n")
|
|
259
|
+
else:
|
|
260
|
+
chunk_str = chunk.decode("utf-8")
|
|
261
|
+
if chunk_str.startswith("data:"):
|
|
262
|
+
chunk_str = chunk_str.strip("data:").strip()
|
|
263
|
+
output_stream.write(f"{chunk_str}\n")
|
|
264
|
+
except Exception as e:
|
|
265
|
+
logger.error(f"call AICC DeepSeek service chat_completions error:{e}")
|
|
266
|
+
raise AICCException("DeepSeek chat_completions_stream error")
|
|
267
|
+
else:
|
|
268
|
+
for attempt in range(self.max_retries):
|
|
269
|
+
try:
|
|
270
|
+
response = requests.post(url, json=payload, headers=headers)
|
|
271
|
+
response.raise_for_status()
|
|
272
|
+
data = response.json()
|
|
273
|
+
|
|
274
|
+
if self.is_secure and encrypt_key:
|
|
275
|
+
for elm in data['choices']:
|
|
276
|
+
if self.dp_version < "3.1":
|
|
277
|
+
elm['message'] = pickle.loads(encrypt_key.decrypt(elm['message']))
|
|
278
|
+
else:
|
|
279
|
+
elm['message'] = json.loads(encrypt_key.decrypt(elm['message']))
|
|
280
|
+
|
|
281
|
+
return json.dumps(data)
|
|
282
|
+
except Exception as e:
|
|
283
|
+
if attempt == self.max_retries - 1:
|
|
284
|
+
logger.error(f"call AICC DeepSeek service chat_completions error:{e}")
|
|
285
|
+
raise AICCException("DeepSeek chat_completions error")
|
|
286
|
+
else:
|
|
287
|
+
logger.error(f"call AICC DeepSeek service chat_completions error:{e}, try again....")
|
|
288
|
+
time.sleep(1)
|
|
289
|
+
except AICCException as e:
|
|
290
|
+
raise e
|
|
291
|
+
except Exception as e:
|
|
292
|
+
logger.error(f"call AICC deepseek service chat_completions error: {e}")
|
|
293
|
+
raise AICCException("AICC deepseek service chat_completions error")
|
|
294
|
+
|
|
295
|
+
def chat_completions_stream(self, messages: list, output_stream: IO) -> Union[str, None]:
|
|
296
|
+
return self.chat_completions(messages, output_stream)
|
|
297
|
+
|
|
298
|
+
def chat_completions_stream_yield(self, messages: list):
|
|
299
|
+
"""
|
|
300
|
+
生成聊天补全
|
|
301
|
+
:param messages:
|
|
302
|
+
:return:
|
|
303
|
+
"""
|
|
304
|
+
try:
|
|
305
|
+
if not messages:
|
|
306
|
+
raise AICCException("DeepSeek chat_completions Messages cannot be empty")
|
|
307
|
+
|
|
308
|
+
# DeepSeek目前仅3.1支持openai的方式
|
|
309
|
+
if self.dp_version < "3.1" and self.is_openai:
|
|
310
|
+
error_info = f"Sorry, DeepSeek{self.dp_version} not support is_openai={self.is_openai}"
|
|
311
|
+
logger.error(error_info)
|
|
312
|
+
raise AICCException(error_info)
|
|
313
|
+
|
|
314
|
+
if self.is_secure:
|
|
315
|
+
# V3.1用V4, V3.0用V2
|
|
316
|
+
if self.dp_version < "3.1":
|
|
317
|
+
url = f"{self.base_url}/v2/chat/completions"
|
|
318
|
+
else:
|
|
319
|
+
url = f"{self.base_url}/v4/chat/completions"
|
|
320
|
+
else:
|
|
321
|
+
url = f"{self.base_url}/v1/chat/completions"
|
|
322
|
+
|
|
323
|
+
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}"}
|
|
324
|
+
payload = {
|
|
325
|
+
"messages": messages,
|
|
326
|
+
"max_tokens": int(self.kwargs.get("max_tokens", 100)),
|
|
327
|
+
"temperature": float(self.kwargs.get("temperature", 1.0)),
|
|
328
|
+
"chat_template_kwargs": {"thinking": self.kwargs.get("thinking", True)},
|
|
329
|
+
"separate_reasoning": True,
|
|
330
|
+
"stream": True,
|
|
331
|
+
"stop": "<|im_end|>",
|
|
332
|
+
"eos_token": "<|im_end|>"
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if self.is_openai:
|
|
336
|
+
openai_messages = copy.deepcopy(messages)
|
|
337
|
+
encrypt_key = None
|
|
338
|
+
if self.is_secure:
|
|
339
|
+
encrypt_key = self._encrypt_prompt_with_jsc(openai_messages)
|
|
340
|
+
if not encrypt_key:
|
|
341
|
+
raise AICCException("Error during openai encrypt")
|
|
342
|
+
|
|
343
|
+
url = url.rstrip("/chat/completions")
|
|
344
|
+
openai_client = OpenAI(base_url=url, api_key=self.api_key)
|
|
345
|
+
|
|
346
|
+
resp = openai_client.chat.completions.create(
|
|
347
|
+
model=self.ep if self.ep else "",
|
|
348
|
+
messages=openai_messages,
|
|
349
|
+
temperature=payload.get("temperature"),
|
|
350
|
+
max_tokens=payload.get("max_tokens"),
|
|
351
|
+
stream=True,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
for chunk in resp:
|
|
355
|
+
if self.is_secure and encrypt_key:
|
|
356
|
+
if chunk.content:
|
|
357
|
+
data = encrypt_key.decrypt(base64.b64decode(chunk.content)).decode("utf-8")
|
|
358
|
+
if data.startswith("data:"):
|
|
359
|
+
data = data.strip("data:").strip()
|
|
360
|
+
yield data
|
|
361
|
+
else:
|
|
362
|
+
cont = self._chat_completion_chunk_to_str(chunk)
|
|
363
|
+
yield cont
|
|
364
|
+
else:
|
|
365
|
+
encrypt_key = None
|
|
366
|
+
if self.is_secure:
|
|
367
|
+
# 加密数据并发送
|
|
368
|
+
try:
|
|
369
|
+
if self.dp_version < "3.1":
|
|
370
|
+
encrypted_messages, encrypt_key = \
|
|
371
|
+
self.jsc_client.encrypt_with_response(pickle.dumps(payload["messages"]))
|
|
372
|
+
else:
|
|
373
|
+
encrypted_messages, encrypt_key = \
|
|
374
|
+
self.jsc_client.encrypt_with_response(json.dumps(payload["messages"]))
|
|
375
|
+
|
|
376
|
+
payload["messages"] = encrypted_messages # 敏感字段
|
|
377
|
+
except Exception as e:
|
|
378
|
+
logger.error(f"Error during encrypt: {e}")
|
|
379
|
+
raise AICCException("Error during encrypt")
|
|
380
|
+
|
|
381
|
+
try:
|
|
382
|
+
with requests.post(url, json=payload, headers=headers, stream=True) as response:
|
|
383
|
+
response.raise_for_status()
|
|
384
|
+
for chunk in response.iter_lines():
|
|
385
|
+
if chunk:
|
|
386
|
+
if self.is_secure and encrypt_key:
|
|
387
|
+
chunk_str = chunk.decode("utf-8")
|
|
388
|
+
if chunk_str.startswith("data:"):
|
|
389
|
+
chunk_str = chunk_str.strip("data:").strip()
|
|
390
|
+
if chunk_str == "[DONE]":
|
|
391
|
+
yield chunk_str
|
|
392
|
+
else:
|
|
393
|
+
if self.dp_version < "3.1":
|
|
394
|
+
data = encrypt_key.decrypt(base64.b64decode(chunk_str)).decode("utf-8")
|
|
395
|
+
else:
|
|
396
|
+
content = json.loads(chunk_str).get("content")
|
|
397
|
+
data = encrypt_key.decrypt(base64.b64decode(content)).decode("utf-8")
|
|
398
|
+
yield data
|
|
399
|
+
else:
|
|
400
|
+
chunk_str = chunk.decode("utf-8")
|
|
401
|
+
if chunk_str.startswith("data:"):
|
|
402
|
+
chunk_str = chunk_str.strip("data:").strip()
|
|
403
|
+
yield chunk_str
|
|
404
|
+
except Exception as e:
|
|
405
|
+
logger.error(f"call AICC DeepSeek service chat_completions_stream_yield error:{e}")
|
|
406
|
+
raise AICCException("DeepSeek chat_completions_stream_yield error")
|
|
407
|
+
except AICCException as e:
|
|
408
|
+
raise e
|
|
409
|
+
except Exception as e:
|
|
410
|
+
logger.error(f"call AICC deepseek service chat_completions_stream_yield error: {e}")
|
|
411
|
+
raise AICCException("AICC deepseek service chat_completions_stream_yield error")
|
|
412
|
+
|
|
413
|
+
def function_call(self, messages: list, tools: list, output_stream: IO = None) -> str:
|
|
414
|
+
"""
|
|
415
|
+
:param messages:
|
|
416
|
+
:param tools:
|
|
417
|
+
:param output_stream:
|
|
418
|
+
:return:
|
|
419
|
+
"""
|
|
420
|
+
if not messages or not tools:
|
|
421
|
+
raise AICCException("DeepSeek function_call params cannot be empty")
|
|
422
|
+
|
|
423
|
+
try:
|
|
424
|
+
# DeepSeek目前仅支持通过openai的方式使用function_call
|
|
425
|
+
if not self.is_openai:
|
|
426
|
+
error_info = f"Sorry, DeepSeek is_openai={self.is_openai} not support function_call."
|
|
427
|
+
logger.error(error_info)
|
|
428
|
+
raise AICCException(error_info)
|
|
429
|
+
|
|
430
|
+
# DeepSeek function_call目前仅支持密文访问
|
|
431
|
+
if not self.is_secure:
|
|
432
|
+
error_info = f"Sorry, DeepSeek secure={self.is_secure} not support function_call."
|
|
433
|
+
logger.error(error_info)
|
|
434
|
+
raise AICCException(error_info)
|
|
435
|
+
|
|
436
|
+
if self.is_secure:
|
|
437
|
+
url = f"{self.base_url}/v4"
|
|
438
|
+
else:
|
|
439
|
+
url = f"{self.base_url}/v1"
|
|
440
|
+
|
|
441
|
+
openai_client = OpenAI(base_url=url, api_key=self.api_key)
|
|
442
|
+
|
|
443
|
+
openai_messages = copy.deepcopy(messages)
|
|
444
|
+
encrypt_key = None
|
|
445
|
+
if self.is_secure:
|
|
446
|
+
encrypt_key = self._encrypt_prompt_with_jsc(openai_messages)
|
|
447
|
+
if not encrypt_key:
|
|
448
|
+
raise AICCException("Error during openai encrypt")
|
|
449
|
+
|
|
450
|
+
if self.is_secure:
|
|
451
|
+
if self.dp_version < "3.1":
|
|
452
|
+
encrypted_tools, _ = self.jsc_client.encrypt_with_response(pickle.dumps(tools))
|
|
453
|
+
else:
|
|
454
|
+
encrypted_tools, _ = self.jsc_client.encrypt_with_response(json.dumps(tools))
|
|
455
|
+
else:
|
|
456
|
+
encrypted_tools = tools
|
|
457
|
+
|
|
458
|
+
extra_fields = {
|
|
459
|
+
"aicc_enc_tools": encrypted_tools
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
completion = openai_client.chat.completions.create(
|
|
463
|
+
model=self.ep,
|
|
464
|
+
messages=openai_messages,
|
|
465
|
+
tool_choice="required",
|
|
466
|
+
extra_body=extra_fields,
|
|
467
|
+
stream=True if output_stream else False,
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
if output_stream:
|
|
471
|
+
for chunk in completion:
|
|
472
|
+
if not hasattr(chunk, 'content') or chunk.content is None:
|
|
473
|
+
continue
|
|
474
|
+
if chunk.content == "[DONE]":
|
|
475
|
+
output_stream.write("[DONE]\n")
|
|
476
|
+
if self.is_secure and encrypt_key:
|
|
477
|
+
decrypted_data = encrypt_key.decrypt(base64.b64decode(chunk.content)).decode("utf-8")
|
|
478
|
+
if decrypted_data.startswith("data:"):
|
|
479
|
+
decrypted_data = decrypted_data.strip("data:").strip()
|
|
480
|
+
output_stream.write(f"{decrypted_data}\n")
|
|
481
|
+
else:
|
|
482
|
+
output_stream.write(f"{chunk.content}\n")
|
|
483
|
+
else:
|
|
484
|
+
resp_msg = completion.choices[0].message
|
|
485
|
+
if self.is_secure and encrypt_key:
|
|
486
|
+
resp_msg = encrypt_key.decrypt(resp_msg).decode("utf-8")
|
|
487
|
+
|
|
488
|
+
return resp_msg
|
|
489
|
+
except AICCException as e:
|
|
490
|
+
raise e
|
|
491
|
+
except Exception as e:
|
|
492
|
+
logger.error(f"call AICC deepseek service chat_completions error: {e}")
|
|
493
|
+
raise AICCException("AICC deepseek service chat_completions error")
|
|
494
|
+
|
|
495
|
+
def function_call_stream(self, messages: list, tools: list, output_stream: IO) -> str:
|
|
496
|
+
return self.function_call(messages, tools, output_stream)
|
|
497
|
+
|
|
498
|
+
def asr_recognize(self, file_name: str) -> str:
|
|
499
|
+
error_info = "Sorry, this version does not support asr at this time."
|
|
500
|
+
logger.error(error_info)
|
|
501
|
+
return error_info
|