local-coze 0.0.1__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.
- local_coze/__init__.py +110 -0
- local_coze/cli/__init__.py +3 -0
- local_coze/cli/chat.py +126 -0
- local_coze/cli/cli.py +34 -0
- local_coze/cli/constants.py +7 -0
- local_coze/cli/db.py +81 -0
- local_coze/cli/embedding.py +193 -0
- local_coze/cli/image.py +162 -0
- local_coze/cli/knowledge.py +195 -0
- local_coze/cli/search.py +198 -0
- local_coze/cli/utils.py +41 -0
- local_coze/cli/video.py +191 -0
- local_coze/cli/video_edit.py +888 -0
- local_coze/cli/voice.py +351 -0
- local_coze/core/__init__.py +25 -0
- local_coze/core/client.py +253 -0
- local_coze/core/config.py +58 -0
- local_coze/core/exceptions.py +67 -0
- local_coze/database/__init__.py +29 -0
- local_coze/database/client.py +170 -0
- local_coze/database/migration.py +342 -0
- local_coze/embedding/__init__.py +31 -0
- local_coze/embedding/client.py +350 -0
- local_coze/embedding/models.py +130 -0
- local_coze/image/__init__.py +19 -0
- local_coze/image/client.py +110 -0
- local_coze/image/models.py +163 -0
- local_coze/knowledge/__init__.py +19 -0
- local_coze/knowledge/client.py +148 -0
- local_coze/knowledge/models.py +45 -0
- local_coze/llm/__init__.py +25 -0
- local_coze/llm/client.py +317 -0
- local_coze/llm/models.py +48 -0
- local_coze/memory/__init__.py +14 -0
- local_coze/memory/client.py +176 -0
- local_coze/s3/__init__.py +12 -0
- local_coze/s3/client.py +580 -0
- local_coze/s3/models.py +18 -0
- local_coze/search/__init__.py +19 -0
- local_coze/search/client.py +183 -0
- local_coze/search/models.py +57 -0
- local_coze/video/__init__.py +17 -0
- local_coze/video/client.py +347 -0
- local_coze/video/models.py +39 -0
- local_coze/video_edit/__init__.py +23 -0
- local_coze/video_edit/examples.py +340 -0
- local_coze/video_edit/frame_extractor.py +176 -0
- local_coze/video_edit/models.py +362 -0
- local_coze/video_edit/video_edit.py +631 -0
- local_coze/voice/__init__.py +17 -0
- local_coze/voice/asr.py +82 -0
- local_coze/voice/models.py +86 -0
- local_coze/voice/tts.py +94 -0
- local_coze-0.0.1.dist-info/METADATA +636 -0
- local_coze-0.0.1.dist-info/RECORD +58 -0
- local_coze-0.0.1.dist-info/WHEEL +4 -0
- local_coze-0.0.1.dist-info/entry_points.txt +3 -0
- local_coze-0.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import requests
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from cozeloop.decorator import observe
|
|
6
|
+
from coze_coding_utils.runtime_ctx.context import Context
|
|
7
|
+
|
|
8
|
+
from ..core.client import BaseClient
|
|
9
|
+
from ..core.config import Config
|
|
10
|
+
from ..core.exceptions import APIError
|
|
11
|
+
from .models import (
|
|
12
|
+
AddSubtitlesRequest,
|
|
13
|
+
AudioExtractRequest,
|
|
14
|
+
AudioToSubtitleRequest,
|
|
15
|
+
CompileVideoAudioRequest,
|
|
16
|
+
ConcatVideosRequest,
|
|
17
|
+
OutputSync,
|
|
18
|
+
SubtitleConfig,
|
|
19
|
+
TextItem,
|
|
20
|
+
VideoEditResponse,
|
|
21
|
+
VideoTrimRequest,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class VideoEditClient(BaseClient):
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
config: Optional[Config] = None,
|
|
29
|
+
ctx: Optional[Context] = None,
|
|
30
|
+
custom_headers: Optional[Dict[str, str]] = None,
|
|
31
|
+
verbose: bool = False,
|
|
32
|
+
):
|
|
33
|
+
super().__init__(config, ctx, custom_headers, verbose)
|
|
34
|
+
self.base_url = self.config.base_url
|
|
35
|
+
|
|
36
|
+
@observe
|
|
37
|
+
def add_subtitles(
|
|
38
|
+
self,
|
|
39
|
+
video: str,
|
|
40
|
+
subtitle_config: SubtitleConfig,
|
|
41
|
+
subtitle_url: Optional[str] = None,
|
|
42
|
+
text_list: Optional[List[TextItem]] = None,
|
|
43
|
+
url_expire: Optional[int] = None,
|
|
44
|
+
) -> VideoEditResponse:
|
|
45
|
+
"""
|
|
46
|
+
视频添加字幕:为视频添加字幕,视频支持MP4、AVI、MKV、MOV等常见格式,字幕文件支持SRT、VTT、ASS 等格式。
|
|
47
|
+
支持指定字幕样式的配置,包括字体大小、字体 ID、字体颜色及字幕显示位置和尺寸等。
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
video: 视频输入地址
|
|
51
|
+
subtitle_config: 字幕配置(字体、位置、颜色等)
|
|
52
|
+
subtitle_url: 字幕文件 url(可选)
|
|
53
|
+
text_list: 文本序列(可选)
|
|
54
|
+
url_expire: 产物url有效时间,单位秒,默认一天,最大30天
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
VideoEditResponse: 视频编辑结果响应
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
APIError: 当添加字幕失败时
|
|
61
|
+
"""
|
|
62
|
+
request_params = {
|
|
63
|
+
"video": video,
|
|
64
|
+
"subtitle_config": subtitle_config,
|
|
65
|
+
}
|
|
66
|
+
if subtitle_url is not None:
|
|
67
|
+
request_params["subtitle_url"] = subtitle_url
|
|
68
|
+
if text_list is not None:
|
|
69
|
+
request_params["text_list"] = text_list
|
|
70
|
+
if url_expire is not None:
|
|
71
|
+
request_params["url_expire"] = url_expire
|
|
72
|
+
|
|
73
|
+
request = AddSubtitlesRequest(**request_params)
|
|
74
|
+
|
|
75
|
+
response = self._request_with_response(
|
|
76
|
+
method="POST",
|
|
77
|
+
url=f"{self.base_url}/api/v1/integration/video_editing_utils?tool_name=add_subtitles",
|
|
78
|
+
json=request.to_api_request(),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
status_code = response.headers.get("X-Api-Status-Code", "0")
|
|
82
|
+
message = response.headers.get("X-Api-Message", "")
|
|
83
|
+
|
|
84
|
+
if status_code != "0":
|
|
85
|
+
raise APIError(
|
|
86
|
+
f"添加字幕失败,状态码: {status_code}, 错误信息: {message}",
|
|
87
|
+
code=status_code,
|
|
88
|
+
status_code=response.status_code,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
response.raise_for_status()
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
data = response.json()
|
|
95
|
+
except Exception as e:
|
|
96
|
+
raise APIError(
|
|
97
|
+
f"响应解析失败: {str(e)}",
|
|
98
|
+
status_code=response.status_code,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
result = VideoEditResponse(**data)
|
|
102
|
+
if not result.url:
|
|
103
|
+
raise APIError(
|
|
104
|
+
f"添加字幕失败: 返回的 URL 为空",
|
|
105
|
+
status_code=response.status_code,
|
|
106
|
+
)
|
|
107
|
+
return result
|
|
108
|
+
|
|
109
|
+
@observe
|
|
110
|
+
def concat_videos(
|
|
111
|
+
self,
|
|
112
|
+
videos: List[str],
|
|
113
|
+
transitions: Optional[List[str]] = None,
|
|
114
|
+
url_expire: Optional[int] = None,
|
|
115
|
+
) -> VideoEditResponse:
|
|
116
|
+
"""
|
|
117
|
+
视频拼接/音频拼接,支持:
|
|
118
|
+
(1)对输入的多个视频片段进行拼接,并支持添加转场。
|
|
119
|
+
(2)对输入的多个音频片段进行拼接。
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
videos: 音视频列表,每个元素为视频 URL 地址
|
|
123
|
+
transitions: 转场ID列表(可选),仅支持非交叠转场
|
|
124
|
+
url_expire: 产物有效时间,单位秒,默认一天,最长30天
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
VideoEditResponse: 视频编辑结果响应
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
APIError: 当视频拼接失败时
|
|
131
|
+
"""
|
|
132
|
+
request_params = {"videos": videos}
|
|
133
|
+
if transitions is not None:
|
|
134
|
+
request_params["transitions"] = transitions
|
|
135
|
+
if url_expire is not None:
|
|
136
|
+
request_params["url_expire"] = url_expire
|
|
137
|
+
|
|
138
|
+
request = ConcatVideosRequest(**request_params)
|
|
139
|
+
|
|
140
|
+
response = self._request_with_response(
|
|
141
|
+
method="POST",
|
|
142
|
+
url=f"{self.base_url}/api/v1/integration/video_editing_utils?tool_name=concat_videos",
|
|
143
|
+
json=request.to_api_request(),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
status_code = response.headers.get("X-Api-Status-Code", "0")
|
|
147
|
+
message = response.headers.get("X-Api-Message", "")
|
|
148
|
+
|
|
149
|
+
if status_code != "0":
|
|
150
|
+
raise APIError(
|
|
151
|
+
f"视频拼接失败,状态码: {status_code}, 错误信息: {message}",
|
|
152
|
+
code=status_code,
|
|
153
|
+
status_code=response.status_code,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
response.raise_for_status()
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
data = response.json()
|
|
160
|
+
except Exception as e:
|
|
161
|
+
raise APIError(
|
|
162
|
+
f"响应解析失败: {str(e)}",
|
|
163
|
+
status_code=response.status_code,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
result = VideoEditResponse(**data)
|
|
167
|
+
if not result.url:
|
|
168
|
+
raise APIError(
|
|
169
|
+
f"视频拼接失败: 返回的 URL 为空",
|
|
170
|
+
status_code=response.status_code,
|
|
171
|
+
)
|
|
172
|
+
return result
|
|
173
|
+
|
|
174
|
+
@observe
|
|
175
|
+
def compile_video_audio(
|
|
176
|
+
self,
|
|
177
|
+
video: str,
|
|
178
|
+
audio: str,
|
|
179
|
+
is_video_audio_sync: Optional[bool] = None,
|
|
180
|
+
output_sync: Optional[OutputSync] = None,
|
|
181
|
+
is_audio_reserve: Optional[bool] = None,
|
|
182
|
+
url_expire: Optional[int] = None,
|
|
183
|
+
) -> VideoEditResponse:
|
|
184
|
+
"""
|
|
185
|
+
音视频合成:将视频、音频叠加合成视频。
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
video: 输入视频 URL
|
|
189
|
+
audio: 输入音频 URL
|
|
190
|
+
is_video_audio_sync: 是否执行音频视频对齐,默认保持原样输出,不做音视频对齐
|
|
191
|
+
output_sync: 输出模式配置(对齐方式和基准),与 is_video_audio_sync 配合使用
|
|
192
|
+
is_audio_reserve: 是否保留原视频流中的音频
|
|
193
|
+
url_expire: 产物有效时间,单位秒,默认一天,最大30天
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
VideoEditResponse: 视频编辑结果响应
|
|
197
|
+
|
|
198
|
+
Raises:
|
|
199
|
+
APIError: 当视频音频合成失败时
|
|
200
|
+
"""
|
|
201
|
+
request_params = {
|
|
202
|
+
"video": video,
|
|
203
|
+
"audio": audio,
|
|
204
|
+
}
|
|
205
|
+
if is_video_audio_sync is not None:
|
|
206
|
+
request_params["is_video_audio_sync"] = is_video_audio_sync
|
|
207
|
+
if output_sync is not None:
|
|
208
|
+
request_params["output_sync"] = output_sync
|
|
209
|
+
if is_audio_reserve is not None:
|
|
210
|
+
request_params["is_audio_reserve"] = is_audio_reserve
|
|
211
|
+
if url_expire is not None:
|
|
212
|
+
request_params["url_expire"] = url_expire
|
|
213
|
+
|
|
214
|
+
request = CompileVideoAudioRequest(**request_params)
|
|
215
|
+
|
|
216
|
+
response = self._request_with_response(
|
|
217
|
+
method="POST",
|
|
218
|
+
url=f"{self.base_url}/api/v1/integration/video_editing_utils?tool_name=compile_video_audio",
|
|
219
|
+
json=request.to_api_request(),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
status_code = response.headers.get("X-Api-Status-Code", "0")
|
|
223
|
+
message = response.headers.get("X-Api-Message", "")
|
|
224
|
+
|
|
225
|
+
if status_code != "0":
|
|
226
|
+
raise APIError(
|
|
227
|
+
f"视频音频合成失败,状态码: {status_code}, 错误信息: {message}",
|
|
228
|
+
code=status_code,
|
|
229
|
+
status_code=response.status_code,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
response.raise_for_status()
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
data = response.json()
|
|
236
|
+
except Exception as e:
|
|
237
|
+
raise APIError(
|
|
238
|
+
f"响应解析失败: {str(e)}",
|
|
239
|
+
status_code=response.status_code,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
result = VideoEditResponse(**data)
|
|
243
|
+
if not result.url:
|
|
244
|
+
raise APIError(
|
|
245
|
+
f"音视频合成失败: 返回的 URL 为空",
|
|
246
|
+
status_code=response.status_code,
|
|
247
|
+
)
|
|
248
|
+
return result
|
|
249
|
+
|
|
250
|
+
@observe
|
|
251
|
+
def audio_to_subtitle(
|
|
252
|
+
self,
|
|
253
|
+
source: str,
|
|
254
|
+
subtitle_type: Optional[str] = None,
|
|
255
|
+
url_expire: Optional[int] = None,
|
|
256
|
+
) -> VideoEditResponse:
|
|
257
|
+
"""
|
|
258
|
+
语音转写字幕:将视频或音频中的语音内容转换为字幕文件。
|
|
259
|
+
可以组合 add_subtitles(视频添加字幕)工具使用,将字幕合成到视频中。
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
source: 音视频输入地址
|
|
263
|
+
subtitle_type: 字幕类型,可选值 ["webvtt", "srt"],默认 "srt"
|
|
264
|
+
url_expire: 产物超时时间,单位秒,默认一天,最长30天
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
VideoEditResponse: 视频编辑结果响应
|
|
268
|
+
|
|
269
|
+
Raises:
|
|
270
|
+
APIError: 当语音转字幕失败时
|
|
271
|
+
"""
|
|
272
|
+
request_params = {"source": source}
|
|
273
|
+
if subtitle_type is not None:
|
|
274
|
+
request_params["subtitle_type"] = subtitle_type
|
|
275
|
+
if url_expire is not None:
|
|
276
|
+
request_params["url_expire"] = url_expire
|
|
277
|
+
|
|
278
|
+
request = AudioToSubtitleRequest(**request_params)
|
|
279
|
+
|
|
280
|
+
response = self._request_with_response(
|
|
281
|
+
method="POST",
|
|
282
|
+
url=f"{self.base_url}/api/v1/integration/video_editing_utils?tool_name=audio_to_subtitle",
|
|
283
|
+
json=request.to_api_request(),
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
status_code = response.headers.get("X-Api-Status-Code", "0")
|
|
287
|
+
message = response.headers.get("X-Api-Message", "")
|
|
288
|
+
|
|
289
|
+
if status_code != "0":
|
|
290
|
+
raise APIError(
|
|
291
|
+
f"语音转字幕失败,状态码: {status_code}, 错误信息: {message}",
|
|
292
|
+
code=status_code,
|
|
293
|
+
status_code=response.status_code,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
response.raise_for_status()
|
|
297
|
+
|
|
298
|
+
try:
|
|
299
|
+
data = response.json()
|
|
300
|
+
except Exception as e:
|
|
301
|
+
raise APIError(
|
|
302
|
+
f"响应解析失败: {str(e)}",
|
|
303
|
+
status_code=response.status_code,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
result = VideoEditResponse(**data)
|
|
307
|
+
if not result.url:
|
|
308
|
+
raise APIError(
|
|
309
|
+
f"语音转字幕失败: 返回的 URL 为空",
|
|
310
|
+
status_code=response.status_code,
|
|
311
|
+
)
|
|
312
|
+
return result
|
|
313
|
+
|
|
314
|
+
@observe
|
|
315
|
+
def extract_audio(
|
|
316
|
+
self,
|
|
317
|
+
video: str,
|
|
318
|
+
format: Optional[str] = None,
|
|
319
|
+
url_expire: Optional[int] = None,
|
|
320
|
+
) -> VideoEditResponse:
|
|
321
|
+
"""
|
|
322
|
+
音频提取:提取视频文件中的音频。
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
video: 视频输入地址
|
|
326
|
+
format: 输出格式,可选值 ["m4a", "mp3"],默认 "m4a"
|
|
327
|
+
url_expire: 产物有效时间,单位秒,默认一天,最大30天,最小1小时
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
VideoEditResponse: 视频编辑结果响应
|
|
331
|
+
|
|
332
|
+
Raises:
|
|
333
|
+
APIError: 当音频提取失败时
|
|
334
|
+
"""
|
|
335
|
+
request_params = {"video": video}
|
|
336
|
+
if format is not None:
|
|
337
|
+
request_params["format"] = format
|
|
338
|
+
if url_expire is not None:
|
|
339
|
+
request_params["url_expire"] = url_expire
|
|
340
|
+
|
|
341
|
+
request = AudioExtractRequest(**request_params)
|
|
342
|
+
|
|
343
|
+
response = self._request_with_response(
|
|
344
|
+
method="POST",
|
|
345
|
+
url=f"{self.base_url}/api/v1/integration/video_editing_utils?tool_name=audio_extract",
|
|
346
|
+
json=request.to_api_request(),
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
status_code = response.headers.get("X-Api-Status-Code", "0")
|
|
350
|
+
message = response.headers.get("X-Api-Message", "")
|
|
351
|
+
|
|
352
|
+
if status_code != "0":
|
|
353
|
+
raise APIError(
|
|
354
|
+
f"音频提取失败,状态码: {status_code}, 错误信息: {message}",
|
|
355
|
+
code=status_code,
|
|
356
|
+
status_code=response.status_code,
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
response.raise_for_status()
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
data = response.json()
|
|
363
|
+
except Exception as e:
|
|
364
|
+
raise APIError(
|
|
365
|
+
f"响应解析失败: {str(e)}",
|
|
366
|
+
status_code=response.status_code,
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
result = VideoEditResponse(**data)
|
|
370
|
+
if not result.url:
|
|
371
|
+
raise APIError(
|
|
372
|
+
f"音频提取失败: 返回的 URL 为空",
|
|
373
|
+
status_code=response.status_code,
|
|
374
|
+
)
|
|
375
|
+
return result
|
|
376
|
+
|
|
377
|
+
@observe
|
|
378
|
+
def video_trim(
|
|
379
|
+
self,
|
|
380
|
+
video: str,
|
|
381
|
+
start_time: Optional[float] = None,
|
|
382
|
+
end_time: Optional[float] = None,
|
|
383
|
+
url_expire: Optional[int] = None,
|
|
384
|
+
) -> VideoEditResponse:
|
|
385
|
+
"""
|
|
386
|
+
音视频裁剪:对视频、音频进行片段裁剪,支持输入开始、结束时间。
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
video: 视频输入地址
|
|
390
|
+
start_time: 裁剪开始时间,单位:秒,默认为0
|
|
391
|
+
end_time: 裁剪结束时间,单位:秒;默认为片源结尾
|
|
392
|
+
url_expire: 产物有效时间,单位为秒,默认一天,最大30天
|
|
393
|
+
|
|
394
|
+
Returns:
|
|
395
|
+
VideoEditResponse: 视频编辑结果响应
|
|
396
|
+
|
|
397
|
+
Raises:
|
|
398
|
+
APIError: 当视频裁剪失败时
|
|
399
|
+
"""
|
|
400
|
+
request_params = {"video": video}
|
|
401
|
+
if start_time is not None:
|
|
402
|
+
request_params["start_time"] = start_time
|
|
403
|
+
if end_time is not None:
|
|
404
|
+
request_params["end_time"] = end_time
|
|
405
|
+
if url_expire is not None:
|
|
406
|
+
request_params["url_expire"] = url_expire
|
|
407
|
+
|
|
408
|
+
request = VideoTrimRequest(**request_params)
|
|
409
|
+
|
|
410
|
+
response = self._request_with_response(
|
|
411
|
+
method="POST",
|
|
412
|
+
url=f"{self.base_url}/api/v1/integration/video_editing_utils?tool_name=video_trim",
|
|
413
|
+
json=request.to_api_request(),
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
status_code = response.headers.get("X-Api-Status-Code", "0")
|
|
417
|
+
message = response.headers.get("X-Api-Message", "")
|
|
418
|
+
|
|
419
|
+
if status_code != "0":
|
|
420
|
+
raise APIError(
|
|
421
|
+
f"视频裁剪失败,状态码: {status_code}, 错误信息: {message}",
|
|
422
|
+
code=status_code,
|
|
423
|
+
status_code=response.status_code,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
response.raise_for_status()
|
|
427
|
+
|
|
428
|
+
try:
|
|
429
|
+
data = response.json()
|
|
430
|
+
except Exception as e:
|
|
431
|
+
raise APIError(
|
|
432
|
+
f"响应解析失败: {str(e)}",
|
|
433
|
+
status_code=response.status_code,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
result = VideoEditResponse(**data)
|
|
437
|
+
if not result.url:
|
|
438
|
+
raise APIError(
|
|
439
|
+
f"视频裁剪失败: 返回的 URL 为空",
|
|
440
|
+
status_code=response.status_code,
|
|
441
|
+
)
|
|
442
|
+
return result
|
|
443
|
+
|
|
444
|
+
async def add_subtitles_async(
|
|
445
|
+
self,
|
|
446
|
+
video: str,
|
|
447
|
+
subtitle_config: SubtitleConfig,
|
|
448
|
+
subtitle_url: Optional[str] = None,
|
|
449
|
+
text_list: Optional[List[TextItem]] = None,
|
|
450
|
+
url_expire: Optional[int] = None,
|
|
451
|
+
) -> VideoEditResponse:
|
|
452
|
+
"""
|
|
453
|
+
视频添加字幕(异步版本):为视频添加字幕,视频支持MP4、AVI、MKV、MOV等常见格式,字幕文件支持SRT、VTT、ASS 等格式。
|
|
454
|
+
支持指定字幕样式的配置,包括字体大小、字体 ID、字体颜色及字幕显示位置和尺寸等。
|
|
455
|
+
|
|
456
|
+
适用于批量为多个视频添加字幕的场景。
|
|
457
|
+
|
|
458
|
+
Args:
|
|
459
|
+
video: 视频输入地址
|
|
460
|
+
subtitle_config: 字幕配置(字体、位置、颜色等)
|
|
461
|
+
subtitle_url: 字幕文件 url(可选)
|
|
462
|
+
text_list: 文本序列(可选)
|
|
463
|
+
url_expire: 产物url有效时间,单位秒,默认一天,最大30天
|
|
464
|
+
|
|
465
|
+
Returns:
|
|
466
|
+
VideoEditResponse: 视频编辑结果响应
|
|
467
|
+
|
|
468
|
+
Raises:
|
|
469
|
+
APIError: 当添加字幕失败时
|
|
470
|
+
"""
|
|
471
|
+
loop = asyncio.get_event_loop()
|
|
472
|
+
return await loop.run_in_executor(
|
|
473
|
+
None,
|
|
474
|
+
self.add_subtitles,
|
|
475
|
+
video,
|
|
476
|
+
subtitle_config,
|
|
477
|
+
subtitle_url,
|
|
478
|
+
text_list,
|
|
479
|
+
url_expire,
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
async def concat_videos_async(
|
|
483
|
+
self,
|
|
484
|
+
videos: List[str],
|
|
485
|
+
transitions: Optional[List[str]] = None,
|
|
486
|
+
url_expire: Optional[int] = None,
|
|
487
|
+
) -> VideoEditResponse:
|
|
488
|
+
"""
|
|
489
|
+
视频拼接/音频拼接(异步版本),支持:
|
|
490
|
+
(1)对输入的多个视频片段进行拼接,并支持添加转场。
|
|
491
|
+
(2)对输入的多个音频片段进行拼接。
|
|
492
|
+
|
|
493
|
+
适用于批量处理多个视频拼接任务的场景。
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
videos: 音视频列表,每个元素为视频 URL 地址
|
|
497
|
+
transitions: 转场ID列表(可选),仅支持非交叠转场
|
|
498
|
+
url_expire: 产物有效时间,单位秒,默认一天,最长30天
|
|
499
|
+
|
|
500
|
+
Returns:
|
|
501
|
+
VideoEditResponse: 视频编辑结果响应
|
|
502
|
+
|
|
503
|
+
Raises:
|
|
504
|
+
APIError: 当视频拼接失败时
|
|
505
|
+
"""
|
|
506
|
+
loop = asyncio.get_event_loop()
|
|
507
|
+
return await loop.run_in_executor(
|
|
508
|
+
None, self.concat_videos, videos, transitions, url_expire
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
async def compile_video_audio_async(
|
|
512
|
+
self,
|
|
513
|
+
video: str,
|
|
514
|
+
audio: str,
|
|
515
|
+
is_video_audio_sync: Optional[bool] = None,
|
|
516
|
+
output_sync: Optional[OutputSync] = None,
|
|
517
|
+
is_audio_reserve: Optional[bool] = None,
|
|
518
|
+
url_expire: Optional[int] = None,
|
|
519
|
+
) -> VideoEditResponse:
|
|
520
|
+
"""
|
|
521
|
+
音视频合成(异步版本):将视频、音频叠加合成视频。
|
|
522
|
+
|
|
523
|
+
适用于批量处理视频音频合成任务的场景。
|
|
524
|
+
|
|
525
|
+
Args:
|
|
526
|
+
video: 输入视频 URL
|
|
527
|
+
audio: 输入音频 URL
|
|
528
|
+
is_video_audio_sync: 是否执行音频视频对齐,默认保持原样输出,不做音视频对齐
|
|
529
|
+
output_sync: 输出模式配置(对齐方式和基准),与 is_video_audio_sync 配合使用
|
|
530
|
+
is_audio_reserve: 是否保留原视频流中的音频
|
|
531
|
+
url_expire: 产物有效时间,单位秒,默认一天,最大30天
|
|
532
|
+
|
|
533
|
+
Returns:
|
|
534
|
+
VideoEditResponse: 视频编辑结果响应
|
|
535
|
+
|
|
536
|
+
Raises:
|
|
537
|
+
APIError: 当视频音频合成失败时
|
|
538
|
+
"""
|
|
539
|
+
loop = asyncio.get_event_loop()
|
|
540
|
+
return await loop.run_in_executor(
|
|
541
|
+
None,
|
|
542
|
+
self.compile_video_audio,
|
|
543
|
+
video,
|
|
544
|
+
audio,
|
|
545
|
+
is_video_audio_sync,
|
|
546
|
+
output_sync,
|
|
547
|
+
is_audio_reserve,
|
|
548
|
+
url_expire,
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
async def audio_to_subtitle_async(
|
|
552
|
+
self,
|
|
553
|
+
source: str,
|
|
554
|
+
subtitle_type: Optional[str] = None,
|
|
555
|
+
url_expire: Optional[int] = None,
|
|
556
|
+
) -> VideoEditResponse:
|
|
557
|
+
"""
|
|
558
|
+
语音转写字幕(异步版本):将视频或音频中的语音内容转换为字幕文件。
|
|
559
|
+
可以组合 add_subtitles(视频添加字幕)工具使用,将字幕合成到视频中。
|
|
560
|
+
|
|
561
|
+
适用于批量处理语音转字幕任务的场景。
|
|
562
|
+
|
|
563
|
+
Args:
|
|
564
|
+
source: 音视频输入地址
|
|
565
|
+
subtitle_type: 字幕类型,可选值 ["webvtt", "srt"],默认 "srt"
|
|
566
|
+
url_expire: 产物超时时间,单位秒,默认一天,最长30天
|
|
567
|
+
|
|
568
|
+
Returns:
|
|
569
|
+
VideoEditResponse: 视频编辑结果响应
|
|
570
|
+
|
|
571
|
+
Raises:
|
|
572
|
+
APIError: 当语音转字幕失败时
|
|
573
|
+
"""
|
|
574
|
+
loop = asyncio.get_event_loop()
|
|
575
|
+
return await loop.run_in_executor(
|
|
576
|
+
None, self.audio_to_subtitle, source, subtitle_type, url_expire
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
async def extract_audio_async(
|
|
580
|
+
self,
|
|
581
|
+
video: str,
|
|
582
|
+
format: Optional[str] = None,
|
|
583
|
+
url_expire: Optional[int] = None,
|
|
584
|
+
) -> VideoEditResponse:
|
|
585
|
+
"""
|
|
586
|
+
音频提取(异步版本):提取视频文件中的音频。
|
|
587
|
+
|
|
588
|
+
适用于批量从多个视频中提取音频的场景。
|
|
589
|
+
|
|
590
|
+
Args:
|
|
591
|
+
video: 视频输入地址
|
|
592
|
+
format: 输出格式,可选值 ["m4a", "mp3"],默认 "m4a"
|
|
593
|
+
url_expire: 产物有效时间,单位秒,默认一天,最大30天,最小1小时
|
|
594
|
+
|
|
595
|
+
Returns:
|
|
596
|
+
VideoEditResponse: 视频编辑结果响应
|
|
597
|
+
|
|
598
|
+
Raises:
|
|
599
|
+
APIError: 当音频提取失败时
|
|
600
|
+
"""
|
|
601
|
+
loop = asyncio.get_event_loop()
|
|
602
|
+
return await loop.run_in_executor(
|
|
603
|
+
None, self.extract_audio, video, format, url_expire
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
async def video_trim_async(
|
|
607
|
+
self,
|
|
608
|
+
video: str,
|
|
609
|
+
start_time: Optional[float] = None,
|
|
610
|
+
end_time: Optional[float] = None,
|
|
611
|
+
url_expire: Optional[int] = None,
|
|
612
|
+
) -> VideoEditResponse:
|
|
613
|
+
"""
|
|
614
|
+
音视频裁剪:对视频、音频进行片段裁剪,支持输入开始、结束时间(异步版本)
|
|
615
|
+
|
|
616
|
+
Args:
|
|
617
|
+
video: 视频输入地址
|
|
618
|
+
start_time: 裁剪开始时间,单位:秒,默认为0
|
|
619
|
+
end_time: 裁剪结束时间,单位:秒;默认为片源结尾
|
|
620
|
+
url_expire: 产物有效时间,单位为秒,默认一天,最大30天
|
|
621
|
+
|
|
622
|
+
Returns:
|
|
623
|
+
VideoEditResponse: 视频编辑结果响应
|
|
624
|
+
|
|
625
|
+
Raises:
|
|
626
|
+
APIError: 当视频裁剪失败时
|
|
627
|
+
"""
|
|
628
|
+
loop = asyncio.get_event_loop()
|
|
629
|
+
return await loop.run_in_executor(
|
|
630
|
+
None, self.video_trim, video, start_time, end_time, url_expire
|
|
631
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .tts import TTSClient
|
|
2
|
+
from .asr import ASRClient
|
|
3
|
+
from .models import (
|
|
4
|
+
TTSConfig,
|
|
5
|
+
TTSRequest,
|
|
6
|
+
ASRRequest,
|
|
7
|
+
ASRResponse
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"TTSClient",
|
|
12
|
+
"ASRClient",
|
|
13
|
+
"TTSConfig",
|
|
14
|
+
"TTSRequest",
|
|
15
|
+
"ASRRequest",
|
|
16
|
+
"ASRResponse",
|
|
17
|
+
]
|