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.
Files changed (58) hide show
  1. local_coze/__init__.py +110 -0
  2. local_coze/cli/__init__.py +3 -0
  3. local_coze/cli/chat.py +126 -0
  4. local_coze/cli/cli.py +34 -0
  5. local_coze/cli/constants.py +7 -0
  6. local_coze/cli/db.py +81 -0
  7. local_coze/cli/embedding.py +193 -0
  8. local_coze/cli/image.py +162 -0
  9. local_coze/cli/knowledge.py +195 -0
  10. local_coze/cli/search.py +198 -0
  11. local_coze/cli/utils.py +41 -0
  12. local_coze/cli/video.py +191 -0
  13. local_coze/cli/video_edit.py +888 -0
  14. local_coze/cli/voice.py +351 -0
  15. local_coze/core/__init__.py +25 -0
  16. local_coze/core/client.py +253 -0
  17. local_coze/core/config.py +58 -0
  18. local_coze/core/exceptions.py +67 -0
  19. local_coze/database/__init__.py +29 -0
  20. local_coze/database/client.py +170 -0
  21. local_coze/database/migration.py +342 -0
  22. local_coze/embedding/__init__.py +31 -0
  23. local_coze/embedding/client.py +350 -0
  24. local_coze/embedding/models.py +130 -0
  25. local_coze/image/__init__.py +19 -0
  26. local_coze/image/client.py +110 -0
  27. local_coze/image/models.py +163 -0
  28. local_coze/knowledge/__init__.py +19 -0
  29. local_coze/knowledge/client.py +148 -0
  30. local_coze/knowledge/models.py +45 -0
  31. local_coze/llm/__init__.py +25 -0
  32. local_coze/llm/client.py +317 -0
  33. local_coze/llm/models.py +48 -0
  34. local_coze/memory/__init__.py +14 -0
  35. local_coze/memory/client.py +176 -0
  36. local_coze/s3/__init__.py +12 -0
  37. local_coze/s3/client.py +580 -0
  38. local_coze/s3/models.py +18 -0
  39. local_coze/search/__init__.py +19 -0
  40. local_coze/search/client.py +183 -0
  41. local_coze/search/models.py +57 -0
  42. local_coze/video/__init__.py +17 -0
  43. local_coze/video/client.py +347 -0
  44. local_coze/video/models.py +39 -0
  45. local_coze/video_edit/__init__.py +23 -0
  46. local_coze/video_edit/examples.py +340 -0
  47. local_coze/video_edit/frame_extractor.py +176 -0
  48. local_coze/video_edit/models.py +362 -0
  49. local_coze/video_edit/video_edit.py +631 -0
  50. local_coze/voice/__init__.py +17 -0
  51. local_coze/voice/asr.py +82 -0
  52. local_coze/voice/models.py +86 -0
  53. local_coze/voice/tts.py +94 -0
  54. local_coze-0.0.1.dist-info/METADATA +636 -0
  55. local_coze-0.0.1.dist-info/RECORD +58 -0
  56. local_coze-0.0.1.dist-info/WHEEL +4 -0
  57. local_coze-0.0.1.dist-info/entry_points.txt +3 -0
  58. local_coze-0.0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,362 @@
1
+ from typing import List, Optional, Literal
2
+ from pydantic import BaseModel, Field, field_validator
3
+
4
+ from ..core.exceptions import ValidationError
5
+
6
+
7
+ class FrameExtractor(BaseModel):
8
+ url: str = Field(..., description="视频 URL 链接")
9
+
10
+
11
+ class FrameExtractorByKeyFrameRequest(FrameExtractor):
12
+ def to_api_request(self) -> dict:
13
+ return {"url": self.url}
14
+
15
+
16
+ class FrameExtractorByIntervalRequest(FrameExtractor):
17
+ interval_ms: int = Field(..., description="间隔抽帧时间,单位: ms")
18
+
19
+ def to_api_request(self) -> dict:
20
+ return {"url": self.url, "interval_ms": self.interval_ms}
21
+
22
+
23
+ class FrameExtractorByInterval(FrameExtractor):
24
+ count: int = Field(..., description="抽取多少个帧")
25
+
26
+ def to_api_request(self) -> dict:
27
+ return {"url": self.url, "count": self.count}
28
+
29
+
30
+ class FrameChunk(BaseModel):
31
+ index: int = Field(..., description="抽帧结果索引")
32
+ screenshot: str = Field(..., description="抽帧结果 URL 链接")
33
+ timestamp_ms: int = Field(..., description="抽帧在视频中的相对时间,单位: ms")
34
+
35
+
36
+ class FrameExtractorData(BaseModel):
37
+ chunks: List[FrameChunk] = Field(..., description="抽帧结果列表")
38
+
39
+
40
+ class FrameExtractorResponse(BaseModel):
41
+ code: int = Field(..., description="状态码")
42
+ msg: str = Field(..., description="状态描述")
43
+ log_id: str = Field(..., description="日志 ID")
44
+ data: FrameExtractorData = Field(..., description="抽帧返回结果")
45
+
46
+
47
+ class FontPosConfig(BaseModel):
48
+ height: Optional[str] = Field(default="10%", description="字幕显示高度,支持设置为百分比(相对于视频高度)或具体像素值")
49
+ pos_x: Optional[str] = Field(default="0", description="字幕在水平方向(X 轴)的位置,以视频正上方居中位置为原点,单位:像素。例如值为 0 时,表示字幕在水平位置居中;值为 - 100 时,表示字幕向左移动 100 像素;值为 100 时,表示字幕向右移动 100 像素。")
50
+ pos_y: Optional[str] = Field(default="90%", description="字幕在垂直方向(Y 轴)的位置,以视频正上方居中位置为原点,单位:像素。例如值为 0 时,表示字幕在视频顶部;值为 100 时,表示字幕向下移动 100 像素。")
51
+ width: Optional[str] = Field(default="100%", description="字幕显示宽度,支持设置为百分比(相对于视频宽度)或具体像素值")
52
+
53
+
54
+ class SubtitleConfig(BaseModel):
55
+ background_border_width: Optional[int] = Field(default=0, description="字幕背景边框大小。默认值为 0")
56
+ font_type: Optional[str] = Field(default="1525745", description="字幕字体设置, 默认值方正雅宋")
57
+ border_width: Optional[int] = Field(default=None, description="描边宽度")
58
+ font_color: Optional[str] = Field(default="#FFFFFFFF", description="字幕字体颜色,默认为白色")
59
+ font_pos_config: FontPosConfig = Field(..., description="字幕位置设置")
60
+ font_size: Optional[int] = Field(default=36, description="字幕字体大小")
61
+ background_color: Optional[str] = Field(default="#00000000", description="字幕背景颜色,默认为无色")
62
+ border_color: Optional[str] = Field(default=None, description="描边颜色")
63
+
64
+
65
+ class TextItem(BaseModel):
66
+ end_time: float = Field(..., description="文本结束时间,单位s")
67
+ start_time: float = Field(..., description="文本开始时间,单位s")
68
+ text: str = Field(..., description="输入文本")
69
+
70
+
71
+ class AddSubtitlesRequest(BaseModel):
72
+ video: str = Field(..., description="视频输入地址")
73
+ subtitle_config: SubtitleConfig = Field(..., description="字幕描述")
74
+ subtitle_url: Optional[str] = Field(default=None, description="字幕地址")
75
+ text_list: Optional[List[TextItem]] = Field(default=None, description="文本序列")
76
+ url_expire: Optional[int] = Field(default=86400, description="产物地址有效时间,单位秒,默认一天,最大30天")
77
+
78
+ @field_validator('url_expire')
79
+ @classmethod
80
+ def validate_url_expire(cls, v: Optional[int]) -> int:
81
+ if v is None:
82
+ return 86400
83
+ if v < 1 or v > 2592000:
84
+ raise ValidationError(
85
+ "url_expire 必须在 [1, 2592000] 范围内(最大30天)",
86
+ field="url_expire",
87
+ value=v
88
+ )
89
+ return v
90
+
91
+ def to_api_request(self) -> dict:
92
+ request_data = {
93
+ "video": self.video,
94
+ "subtitle_config": {
95
+ "background_border_width": self.subtitle_config.background_border_width,
96
+ "font_type": self.subtitle_config.font_type,
97
+ "font_pos_config": {
98
+ "height": self.subtitle_config.font_pos_config.height,
99
+ "pos_x": self.subtitle_config.font_pos_config.pos_x,
100
+ "pos_y": self.subtitle_config.font_pos_config.pos_y,
101
+ "width": self.subtitle_config.font_pos_config.width,
102
+ }
103
+ },
104
+ "url_expire": self.url_expire,
105
+ }
106
+
107
+ if self.subtitle_config.border_width is not None:
108
+ request_data["subtitle_config"]["border_width"] = self.subtitle_config.border_width
109
+ if self.subtitle_config.font_color is not None:
110
+ request_data["subtitle_config"]["font_color"] = self.subtitle_config.font_color
111
+ if self.subtitle_config.font_size is not None:
112
+ request_data["subtitle_config"]["font_size"] = self.subtitle_config.font_size
113
+ if self.subtitle_config.background_color is not None:
114
+ request_data["subtitle_config"]["background_color"] = self.subtitle_config.background_color
115
+ if self.subtitle_config.border_color is not None:
116
+ request_data["subtitle_config"]["border_color"] = self.subtitle_config.border_color
117
+
118
+ if self.subtitle_url is not None:
119
+ request_data["subtitle_url"] = self.subtitle_url
120
+
121
+ if self.text_list is not None:
122
+ request_data["text_list"] = [
123
+ {
124
+ "end_time": item.end_time,
125
+ "start_time": item.start_time,
126
+ "text": item.text,
127
+ }
128
+ for item in self.text_list
129
+ ]
130
+
131
+ return request_data
132
+
133
+
134
+ class ConcatVideosRequest(BaseModel):
135
+ videos: List[str] = Field(..., description="视频列表,每个元素为视频 URL 地址")
136
+ transitions: Optional[List[str]] = Field(default=None,
137
+ description="转场ID列表,已支持转场见官网文档(本插件只支持非交叠转场)")
138
+ url_expire: Optional[int] = Field(default=86400, description="产物有效时间,单位秒,默认一天,最长30天")
139
+
140
+ @field_validator('url_expire')
141
+ @classmethod
142
+ def validate_url_expire(cls, v: Optional[int]) -> int:
143
+ if v is None:
144
+ return 86400
145
+ if v < 1 or v > 2592000:
146
+ raise ValidationError(
147
+ "url_expire 必须在 [1, 2592000] 范围内(最大30天)",
148
+ field="url_expire",
149
+ value=v
150
+ )
151
+ return v
152
+
153
+ @field_validator('videos')
154
+ @classmethod
155
+ def validate_videos(cls, v: List[str]) -> List[str]:
156
+ if not v or len(v) == 0:
157
+ raise ValidationError(
158
+ "videos 列表不能为空",
159
+ field="videos",
160
+ value=v
161
+ )
162
+ return v
163
+
164
+ def to_api_request(self) -> dict:
165
+ request_data = {
166
+ "videos": self.videos,
167
+ "url_expire": self.url_expire,
168
+ }
169
+
170
+ if self.transitions is not None and len(self.transitions) > 0:
171
+ request_data["transitions"] = self.transitions
172
+
173
+ return request_data
174
+
175
+
176
+ class OutputSync(BaseModel):
177
+ sync_method: Optional[Literal["speed", "trim"]] = Field(default="trim",
178
+ description="对齐方式,裁剪 or 倍速,参数取值范围是 'speed'、'trim',默认值 trim")
179
+ sync_mode: Optional[Literal["video", "audio"]] = Field(default="video",
180
+ description="输出基准,音频 or 视频,参数取值范围是 'video'、'audio',默认值 video")
181
+
182
+
183
+ class CompileVideoAudioRequest(BaseModel):
184
+ video: str = Field(..., description="输入视频 URL")
185
+ audio: str = Field(..., description="输入音频 URL")
186
+ is_video_audio_sync: Optional[bool] = Field(default=False,
187
+ description="是否执行音频视频对齐,默认保持原样输出,不做音视频对齐")
188
+ output_sync: Optional[OutputSync] = Field(default=None, description="输出模式,与 is_video_audio_sync 配合使用")
189
+ is_audio_reserve: Optional[bool] = Field(default=False, description="是否保留原视频流中的音频")
190
+ url_expire: Optional[int] = Field(default=86400, description="产物有效时间,单位秒,默认一天,最大30天")
191
+
192
+ @field_validator('url_expire')
193
+ @classmethod
194
+ def validate_url_expire(cls, v: Optional[int]) -> int:
195
+ if v is None:
196
+ return 86400
197
+ if v < 1 or v > 2592000:
198
+ raise ValidationError(
199
+ "url_expire 必须在 [1, 2592000] 范围内(最大30天)",
200
+ field="url_expire",
201
+ value=v
202
+ )
203
+ return v
204
+
205
+ def to_api_request(self) -> dict:
206
+ request_data = {
207
+ "video": self.video,
208
+ "audio": self.audio,
209
+ "url_expire": self.url_expire,
210
+ }
211
+
212
+ if self.is_video_audio_sync is not None:
213
+ request_data["is_video_audio_sync"] = self.is_video_audio_sync
214
+
215
+ if self.output_sync is not None:
216
+ request_data["output_sync"] = {
217
+ "sync_method": self.output_sync.sync_method,
218
+ "sync_mode": self.output_sync.sync_mode,
219
+ }
220
+
221
+ if self.is_audio_reserve is not None:
222
+ request_data["is_audio_reserve"] = self.is_audio_reserve
223
+
224
+ return request_data
225
+
226
+
227
+ class AudioToSubtitleRequest(BaseModel):
228
+ source: str = Field(..., description="输入视频 URL")
229
+ subtitle_type: Optional[Literal["webvtt", "srt"]] = Field(default="srt",
230
+ description="字幕类型,可选值 [webvtt, srt]")
231
+ url_expire: Optional[int] = Field(default=86400, description="产物超时时间,单位秒,默认一天,最长30天")
232
+
233
+ @field_validator('url_expire')
234
+ @classmethod
235
+ def validate_url_expire(cls, v: Optional[int]) -> int:
236
+ if v is None:
237
+ return 86400
238
+ if v < 1 or v > 2592000:
239
+ raise ValidationError(
240
+ "url_expire 必须在 [1, 2592000] 范围内(最大30天)",
241
+ field="url_expire",
242
+ value=v
243
+ )
244
+ return v
245
+
246
+ def to_api_request(self) -> dict:
247
+ request_data = {
248
+ "source": self.source,
249
+ "url_expire": self.url_expire,
250
+ }
251
+
252
+ if self.subtitle_type is not None:
253
+ request_data["subtitle_type"] = self.subtitle_type
254
+
255
+ return request_data
256
+
257
+
258
+ class AudioExtractRequest(BaseModel):
259
+ video: str = Field(..., description="输入视频 URL")
260
+ format: Optional[Literal["m4a", "mp3"]] = Field(default="m4a", description="输出格式,默认 m4a,可选值 [m4a, mp3]")
261
+ url_expire: Optional[int] = Field(default=86400, description="产物有效时间,单位秒,默认一天,最大30天,最小1小时")
262
+
263
+ @field_validator('url_expire')
264
+ @classmethod
265
+ def validate_url_expire(cls, v: Optional[int]) -> int:
266
+ if v is None:
267
+ return 86400
268
+ if v < 3600 or v > 2592000:
269
+ raise ValidationError(
270
+ "url_expire 必须在 [3600, 2592000] 范围内(最小1小时,最大30天)",
271
+ field="url_expire",
272
+ value=v
273
+ )
274
+ return v
275
+
276
+ def to_api_request(self) -> dict:
277
+ request_data = {
278
+ "video": self.video,
279
+ "url_expire": self.url_expire,
280
+ }
281
+
282
+ if self.format is not None:
283
+ request_data["format"] = self.format
284
+
285
+ return request_data
286
+
287
+
288
+ class VideoTrimRequest(BaseModel):
289
+ video: str = Field(..., description="视频输入地址")
290
+ start_time: Optional[float] = Field(default=0, description="裁剪开始时间,单位:秒,默认为0")
291
+ end_time: Optional[float] = Field(default=None, description="裁剪结束时间,单位:秒;默认为片源结尾")
292
+ url_expire: Optional[int] = Field(default=86400, description="产物有效时间,单位为秒,默认一天,最大30天")
293
+
294
+ @field_validator('url_expire')
295
+ @classmethod
296
+ def validate_url_expire(cls, v: Optional[int]) -> int:
297
+ if v is None:
298
+ return 86400
299
+ if v < 1 or v > 2592000:
300
+ raise ValidationError(
301
+ "url_expire 必须在 [1, 2592000] 范围内(最大30天)",
302
+ field="url_expire",
303
+ value=v
304
+ )
305
+ return v
306
+
307
+ @field_validator('start_time')
308
+ @classmethod
309
+ def validate_start_time(cls, v: Optional[float]) -> float:
310
+ if v is None:
311
+ return 0
312
+ if v < 0:
313
+ raise ValidationError(
314
+ "start_time 必须大于等于 0",
315
+ field="start_time",
316
+ value=v
317
+ )
318
+ return v
319
+
320
+ @field_validator('end_time')
321
+ @classmethod
322
+ def validate_end_time(cls, v: Optional[float]) -> Optional[float]:
323
+ if v is not None and v < 0:
324
+ raise ValidationError(
325
+ "end_time 必须大于等于 0",
326
+ field="end_time",
327
+ value=v
328
+ )
329
+ return v
330
+
331
+ def to_api_request(self) -> dict:
332
+ request_data = {
333
+ "video": self.video,
334
+ "url_expire": self.url_expire,
335
+ }
336
+
337
+ if self.start_time is not None:
338
+ request_data["start_time"] = self.start_time
339
+
340
+ if self.end_time is not None:
341
+ request_data["end_time"] = self.end_time
342
+
343
+ return request_data
344
+
345
+
346
+ class VideoMeta(BaseModel):
347
+ duration: float = Field(..., description="音视频时长,单位s")
348
+ resolution: str = Field(..., description="视频分辨率,若为音频则为 'unknown'")
349
+ type: str = Field(..., description="输出结果的类型,[video, audio]")
350
+
351
+
352
+ class BillInfo(BaseModel):
353
+ duration: float = Field(..., description="处理的音视频时长,单位s")
354
+ ratio: float = Field(..., description="计费的抵扣系数")
355
+
356
+
357
+ class VideoEditResponse(BaseModel):
358
+ req_id: str = Field(..., description="请求 ID")
359
+ url: str = Field(..., description="处理后的视频/字幕/音频 URL。URL 有效期为 1 ~ 30 天,由输入参数 url_expire 决定。")
360
+ message: Optional[str] = Field(default=None, description="执行插件时的状态描述或错误提示信息")
361
+ video_meta: Optional[VideoMeta] = Field(default=None, description="视频/音频元数据")
362
+ bill_info: Optional[BillInfo] = Field(default=None, description="计费参考信息")