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.
Files changed (60) hide show
  1. bytedance/__init__.py +4 -0
  2. bytedance/jeddak_secure_channel/__init__.py +28 -0
  3. bytedance/jeddak_secure_channel/client.py +305 -0
  4. bytedance/jeddak_secure_channel/config.py +171 -0
  5. bytedance/jeddak_secure_channel/consts.py +5 -0
  6. bytedance/jeddak_secure_channel/crypto/__init__.py +14 -0
  7. bytedance/jeddak_secure_channel/crypto/aes.py +174 -0
  8. bytedance/jeddak_secure_channel/crypto/envelope.py +395 -0
  9. bytedance/jeddak_secure_channel/crypto/rsa.py +164 -0
  10. bytedance/jeddak_secure_channel/error.py +131 -0
  11. bytedance/jeddak_secure_channel/log/__init__.py +23 -0
  12. bytedance/jeddak_secure_channel/log/config.py +31 -0
  13. bytedance/jeddak_secure_channel/log/logger.py +88 -0
  14. bytedance/jeddak_secure_channel/logger_factory.py +134 -0
  15. bytedance/jeddak_secure_channel/ra.py +772 -0
  16. bytedance/jeddak_secure_channel/server.py +745 -0
  17. bytedance/jeddak_secure_channel/service/__init__.py +16 -0
  18. bytedance/jeddak_secure_channel/service/eps.py +133 -0
  19. bytedance/jeddak_secure_channel/service/eps_models.py +47 -0
  20. bytedance/jeddak_secure_channel/service/ras.py +88 -0
  21. bytedance/jeddak_secure_channel/service/tks.py +51 -0
  22. bytedance/jeddak_secure_channel/service/tks_models.py +334 -0
  23. bytedance/jeddak_secure_channel/utils.py +469 -0
  24. bytedance/jeddak_secure_model/model_automation_tool.py +181 -0
  25. bytedance/jeddak_secure_model/model_encryption.py +416 -0
  26. bytedance/jeddak_secure_model/model_hub_admin.py +116 -0
  27. bytedance/jeddak_secure_model/pcc_utils.py +279 -0
  28. bytedance/jeddak_secure_model/rds_utils.py +63 -0
  29. bytedance/tks/attester.py +41 -0
  30. bytedance/tks/client.py +629 -0
  31. bytedance/tks/consts.py +122 -0
  32. bytedance/tks/crypto/aes.py +47 -0
  33. bytedance/tks/crypto/ec.py +39 -0
  34. bytedance/tks/exceptions.py +22 -0
  35. bytedance/volcengine_aicc_sdk/__init__.py +14 -0
  36. bytedance/volcengine_aicc_sdk/aicc_client.py +277 -0
  37. bytedance/volcengine_aicc_sdk/aicc_inference.py +64 -0
  38. bytedance/volcengine_aicc_sdk/ark_inference_client.py +343 -0
  39. bytedance/volcengine_aicc_sdk/asr_inference_client.py +158 -0
  40. bytedance/volcengine_aicc_sdk/asr_websocket_client.py +705 -0
  41. bytedance/volcengine_aicc_sdk/auc_inference_client.py +305 -0
  42. bytedance/volcengine_aicc_sdk/common/__init__.py +0 -0
  43. bytedance/volcengine_aicc_sdk/common/aes.py +136 -0
  44. bytedance/volcengine_aicc_sdk/common/constant.py +4 -0
  45. bytedance/volcengine_aicc_sdk/common/error.py +21 -0
  46. bytedance/volcengine_aicc_sdk/common/log/__init__.py +24 -0
  47. bytedance/volcengine_aicc_sdk/common/log/config.py +31 -0
  48. bytedance/volcengine_aicc_sdk/common/log/logger.py +88 -0
  49. bytedance/volcengine_aicc_sdk/common/tos_utils.py +341 -0
  50. bytedance/volcengine_aicc_sdk/common/utils.py +45 -0
  51. bytedance/volcengine_aicc_sdk/cu_inference_client.py +292 -0
  52. bytedance/volcengine_aicc_sdk/deepseek_inference_client.py +501 -0
  53. bytedance/volcengine_aicc_sdk/secure_http_client.py +406 -0
  54. bytedance/volcengine_aicc_sdk/seedance_inference_client.py +500 -0
  55. bytedance/volcengine_aicc_sdk/seedream_inference_client.py +213 -0
  56. volcengine_python_sdk_aicc-0.0.41.dist-info/METADATA +79 -0
  57. volcengine_python_sdk_aicc-0.0.41.dist-info/RECORD +60 -0
  58. volcengine_python_sdk_aicc-0.0.41.dist-info/WHEEL +5 -0
  59. volcengine_python_sdk_aicc-0.0.41.dist-info/licenses/LICENSE +202 -0
  60. 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