coze-coding-dev-sdk 0.4.2__tar.gz → 0.4.4__tar.gz
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.
- {coze_coding_dev_sdk-0.4.2/coze_coding_dev_sdk.egg-info → coze_coding_dev_sdk-0.4.4}/PKG-INFO +1 -1
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/__init__.py +1 -1
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/chat.py +13 -1
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/image.py +25 -7
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/search.py +12 -2
- coze_coding_dev_sdk-0.4.4/coze_coding_dev_sdk/cli/utils.py +41 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/video.py +25 -12
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/voice.py +33 -13
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/core/__init__.py +6 -0
- coze_coding_dev_sdk-0.4.4/coze_coding_dev_sdk/core/client.py +188 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/core/config.py +6 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/image/client.py +3 -14
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/llm/client.py +16 -2
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/search/client.py +2 -1
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/video/client.py +3 -2
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/voice/asr.py +26 -25
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/voice/tts.py +25 -22
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4/coze_coding_dev_sdk.egg-info}/PKG-INFO +1 -1
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/SOURCES.txt +1 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/pyproject.toml +1 -1
- coze_coding_dev_sdk-0.4.2/coze_coding_dev_sdk/core/client.py +0 -97
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/CHANGELOG.md +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/LICENSE +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/MANIFEST.in +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/README.md +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/cli.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/constants.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/core/exceptions.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/image/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/image/models.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/llm/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/llm/models.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/search/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/search/models.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/video/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/video/models.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/voice/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/voice/models.py +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/dependency_links.txt +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/entry_points.txt +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/requires.txt +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/top_level.txt +0 -0
- {coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/setup.cfg +0 -0
{coze_coding_dev_sdk-0.4.2/coze_coding_dev_sdk.egg-info → coze_coding_dev_sdk-0.4.4}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coze-coding-dev-sdk
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Coze Coding Dev SDK - 优雅的多功能 AI SDK,支持图片生成、视频生成、语音合成、语音识别、大语言模型和联网搜索。包含命令行工具 coze-coding-ai,支持 Context 上下文追踪
|
|
5
5
|
Author-email: Coze Coding Integration Team <support@coze.com>
|
|
6
6
|
Maintainer-email: Coze Coding Integration Team <support@coze.com>
|
|
@@ -22,17 +22,29 @@ console = Console()
|
|
|
22
22
|
"--output", "-o", type=click.Path(), help="Output file path (JSON format)"
|
|
23
23
|
)
|
|
24
24
|
@click.option("--stream", is_flag=True, help="Stream the response in real-time")
|
|
25
|
+
@click.option(
|
|
26
|
+
"--header",
|
|
27
|
+
"-H",
|
|
28
|
+
multiple=True,
|
|
29
|
+
help="自定义 HTTP 请求头 (格式: 'Key: Value' 或 'Key=Value',可多次使用)",
|
|
30
|
+
)
|
|
31
|
+
@click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求日志")
|
|
25
32
|
def chat(
|
|
26
33
|
prompt: str,
|
|
27
34
|
system: Optional[str],
|
|
28
35
|
thinking: bool,
|
|
29
36
|
output: Optional[str],
|
|
30
37
|
stream: bool,
|
|
38
|
+
header: tuple,
|
|
39
|
+
verbose: bool,
|
|
31
40
|
):
|
|
32
41
|
"""Chat with AI using natural language."""
|
|
33
42
|
try:
|
|
43
|
+
from .utils import parse_headers
|
|
44
|
+
|
|
34
45
|
config = Config()
|
|
35
|
-
|
|
46
|
+
custom_headers = parse_headers(header)
|
|
47
|
+
client = LLMClient(config, custom_headers=custom_headers, verbose=verbose)
|
|
36
48
|
|
|
37
49
|
messages = []
|
|
38
50
|
if system:
|
|
@@ -4,7 +4,7 @@ import time
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
|
-
from coze_coding_utils.runtime_ctx.context import
|
|
7
|
+
from coze_coding_utils.runtime_ctx.context import new_context
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
|
|
10
10
|
from ..core.config import Config
|
|
@@ -56,22 +56,40 @@ def validate_and_normalize_size(size: str) -> str:
|
|
|
56
56
|
help="Multiple reference image URLs or paths (can be used multiple times)",
|
|
57
57
|
)
|
|
58
58
|
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
59
|
+
@click.option(
|
|
60
|
+
"--header",
|
|
61
|
+
"-H",
|
|
62
|
+
multiple=True,
|
|
63
|
+
help="自定义 HTTP 请求头 (格式: 'Key: Value' 或 'Key=Value',可多次使用)",
|
|
64
|
+
)
|
|
65
|
+
@click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求日志")
|
|
59
66
|
def image(
|
|
60
|
-
prompt: str,
|
|
67
|
+
prompt: str,
|
|
68
|
+
output: str,
|
|
69
|
+
size: str,
|
|
70
|
+
image: Optional[str],
|
|
71
|
+
images: tuple,
|
|
72
|
+
mock: bool,
|
|
73
|
+
header: tuple,
|
|
74
|
+
verbose: bool,
|
|
61
75
|
):
|
|
62
76
|
"""Generate image using AI."""
|
|
63
77
|
try:
|
|
78
|
+
from .utils import parse_headers
|
|
79
|
+
|
|
64
80
|
config = Config()
|
|
65
81
|
|
|
66
82
|
ctx = None
|
|
83
|
+
custom_headers = parse_headers(header)
|
|
84
|
+
|
|
67
85
|
if mock:
|
|
68
|
-
ctx =
|
|
69
|
-
|
|
70
|
-
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
71
|
-
)
|
|
86
|
+
ctx = new_context(method="image.generate", headers=custom_headers)
|
|
87
|
+
custom_headers[RUN_MODE_HEADER] = RUN_MODE_TEST
|
|
72
88
|
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
73
89
|
|
|
74
|
-
client = ImageGenerationClient(
|
|
90
|
+
client = ImageGenerationClient(
|
|
91
|
+
config, ctx=ctx, custom_headers=custom_headers, verbose=verbose
|
|
92
|
+
)
|
|
75
93
|
|
|
76
94
|
reference_images = None
|
|
77
95
|
if image:
|
|
@@ -121,7 +121,14 @@ def save_to_json(response, output_path: str):
|
|
|
121
121
|
@click.option("--time-range", help="发文时间范围,如: 1d, 1w, 1m (仅 web 类型)")
|
|
122
122
|
@click.option("--output", "-o", type=click.Path(), help="输出 JSON 文件路径")
|
|
123
123
|
@click.option("--format", "-f", type=click.Choice(["table", "json", "simple"]), default="table", help="输出格式")
|
|
124
|
-
|
|
124
|
+
@click.option(
|
|
125
|
+
"--header",
|
|
126
|
+
"-H",
|
|
127
|
+
multiple=True,
|
|
128
|
+
help="自定义 HTTP 请求头 (格式: 'Key: Value' 或 'Key=Value',可多次使用)",
|
|
129
|
+
)
|
|
130
|
+
@click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求日志")
|
|
131
|
+
def search(query, type, count, summary, need_content, need_url, sites, block_hosts, time_range, output, format, header, verbose):
|
|
125
132
|
"""联网搜索
|
|
126
133
|
|
|
127
134
|
支持三种搜索类型:
|
|
@@ -147,8 +154,11 @@ def search(query, type, count, summary, need_content, need_url, sites, block_hos
|
|
|
147
154
|
coze-coding-ai search "新闻" --time-range "1d" --need-url
|
|
148
155
|
"""
|
|
149
156
|
try:
|
|
157
|
+
from .utils import parse_headers
|
|
158
|
+
|
|
150
159
|
config = Config()
|
|
151
|
-
|
|
160
|
+
custom_headers = parse_headers(header)
|
|
161
|
+
client = SearchClient(config, custom_headers=custom_headers, verbose=verbose)
|
|
152
162
|
|
|
153
163
|
if type == "image":
|
|
154
164
|
console.print(f"[bold magenta]正在搜索图片:[/bold magenta] {query}")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from typing import Dict, Optional, Tuple
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def parse_headers(header_strings: Tuple[str, ...]) -> Optional[Dict[str, str]]:
|
|
5
|
+
"""
|
|
6
|
+
解析命令行传入的 header 字符串
|
|
7
|
+
|
|
8
|
+
支持格式:
|
|
9
|
+
- "Key: Value"
|
|
10
|
+
- "Key=Value"
|
|
11
|
+
|
|
12
|
+
示例:
|
|
13
|
+
--header "X-Custom: value1" --header "X-Test=value2"
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
header_strings: 命令行传入的 header 字符串元组
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Dict[str, str] or None: 解析后的 headers 字典,如果没有则返回 None
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
ValueError: 如果 header 格式不正确
|
|
23
|
+
"""
|
|
24
|
+
if not header_strings:
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
headers = {}
|
|
28
|
+
for header_str in header_strings:
|
|
29
|
+
if ": " in header_str:
|
|
30
|
+
key, value = header_str.split(": ", 1)
|
|
31
|
+
elif "=" in header_str:
|
|
32
|
+
key, value = header_str.split("=", 1)
|
|
33
|
+
else:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
f"Invalid header format: '{header_str}'. "
|
|
36
|
+
f"Use 'Key: Value' or 'Key=Value'"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
headers[key.strip()] = value.strip()
|
|
40
|
+
|
|
41
|
+
return headers if headers else None
|
|
@@ -4,7 +4,7 @@ import time
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
|
-
from coze_coding_utils.runtime_ctx.context import
|
|
7
|
+
from coze_coding_utils.runtime_ctx.context import new_context
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
10
10
|
from rich.table import Table
|
|
@@ -54,6 +54,13 @@ def parse_resolution(size: Optional[str]) -> tuple[Optional[str], Optional[str]]
|
|
|
54
54
|
@click.option("--max-polls", type=int, default=60, help="Maximum poll attempts")
|
|
55
55
|
@click.option("--output", "-o", type=click.Path(), help="Output file path (JSON)")
|
|
56
56
|
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
57
|
+
@click.option(
|
|
58
|
+
"--header",
|
|
59
|
+
"-H",
|
|
60
|
+
multiple=True,
|
|
61
|
+
help="自定义 HTTP 请求头 (格式: 'Key: Value' 或 'Key=Value',可多次使用)",
|
|
62
|
+
)
|
|
63
|
+
@click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求日志")
|
|
57
64
|
def video(
|
|
58
65
|
prompt: Optional[str],
|
|
59
66
|
image_url: Optional[str],
|
|
@@ -68,20 +75,24 @@ def video(
|
|
|
68
75
|
max_polls: int,
|
|
69
76
|
output: Optional[str],
|
|
70
77
|
mock: bool,
|
|
78
|
+
header: tuple,
|
|
79
|
+
verbose: bool,
|
|
71
80
|
):
|
|
72
81
|
"""Generate video using AI."""
|
|
73
82
|
try:
|
|
83
|
+
from .utils import parse_headers
|
|
84
|
+
|
|
74
85
|
config = Config()
|
|
75
86
|
|
|
76
87
|
ctx = None
|
|
88
|
+
custom_headers = parse_headers(header)
|
|
89
|
+
|
|
77
90
|
if mock:
|
|
78
|
-
ctx =
|
|
79
|
-
|
|
80
|
-
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
81
|
-
)
|
|
91
|
+
ctx = new_context(method="video.generate", headers=custom_headers)
|
|
92
|
+
custom_headers[RUN_MODE_HEADER] = RUN_MODE_TEST
|
|
82
93
|
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
83
94
|
|
|
84
|
-
client = VideoGenerationClient(config, ctx=ctx)
|
|
95
|
+
client = VideoGenerationClient(config, ctx=ctx, custom_headers=custom_headers, verbose=verbose)
|
|
85
96
|
|
|
86
97
|
image_urls = None
|
|
87
98
|
if image_url:
|
|
@@ -203,20 +214,22 @@ def video(
|
|
|
203
214
|
@click.argument("task_id")
|
|
204
215
|
@click.option("--output", "-o", type=click.Path(), help="Output file path (JSON)")
|
|
205
216
|
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
206
|
-
|
|
217
|
+
@click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求日志")
|
|
218
|
+
def video_status(task_id: str, output: Optional[str], mock: bool, verbose: bool):
|
|
207
219
|
"""Check video generation task status."""
|
|
208
220
|
try:
|
|
209
221
|
config = Config()
|
|
210
222
|
|
|
211
223
|
ctx = None
|
|
212
224
|
if mock:
|
|
213
|
-
ctx =
|
|
214
|
-
request_id=f"mock-req-{int(time.time())}",
|
|
215
|
-
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
216
|
-
)
|
|
225
|
+
ctx = new_context(method="video.status")
|
|
217
226
|
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
218
227
|
|
|
219
|
-
|
|
228
|
+
custom_headers = {}
|
|
229
|
+
if mock:
|
|
230
|
+
custom_headers[RUN_MODE_HEADER] = RUN_MODE_TEST
|
|
231
|
+
|
|
232
|
+
client = VideoGenerationClient(config, ctx=ctx, custom_headers=custom_headers, verbose=verbose)
|
|
220
233
|
|
|
221
234
|
task_result = client._get_task_status(task_id)
|
|
222
235
|
result = task_result.model_dump()
|
|
@@ -5,7 +5,7 @@ import time
|
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
|
-
from coze_coding_utils.runtime_ctx.context import
|
|
8
|
+
from coze_coding_utils.runtime_ctx.context import new_context
|
|
9
9
|
from rich.console import Console
|
|
10
10
|
from rich.panel import Panel
|
|
11
11
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
@@ -63,6 +63,13 @@ COMMON_SPEAKERS = {
|
|
|
63
63
|
@click.option("--loudness-rate", type=int, default=0, help="音量 (-50 到 100)")
|
|
64
64
|
@click.option("--ssml", is_flag=True, help="使用 SSML 格式")
|
|
65
65
|
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
66
|
+
@click.option(
|
|
67
|
+
"--header",
|
|
68
|
+
"-H",
|
|
69
|
+
multiple=True,
|
|
70
|
+
help="自定义 HTTP 请求头 (格式: 'Key: Value' 或 'Key=Value',可多次使用)",
|
|
71
|
+
)
|
|
72
|
+
@click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求日志")
|
|
66
73
|
def tts(
|
|
67
74
|
text,
|
|
68
75
|
output,
|
|
@@ -74,6 +81,8 @@ def tts(
|
|
|
74
81
|
loudness_rate,
|
|
75
82
|
ssml,
|
|
76
83
|
mock,
|
|
84
|
+
header,
|
|
85
|
+
verbose,
|
|
77
86
|
):
|
|
78
87
|
"""语音合成 (Text-to-Speech)
|
|
79
88
|
|
|
@@ -111,17 +120,19 @@ def tts(
|
|
|
111
120
|
coze-coding-ai tts "儿童故事" -o story.mp3 -s zh_female_xueayi_saturn_bigtts --speech-rate 20
|
|
112
121
|
"""
|
|
113
122
|
try:
|
|
123
|
+
from .utils import parse_headers
|
|
124
|
+
|
|
114
125
|
config = Config()
|
|
115
126
|
|
|
116
127
|
ctx = None
|
|
128
|
+
custom_headers = parse_headers(header)
|
|
129
|
+
|
|
117
130
|
if mock:
|
|
118
|
-
ctx =
|
|
119
|
-
|
|
120
|
-
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
121
|
-
)
|
|
131
|
+
ctx = new_context(method="tts.generate", headers=custom_headers)
|
|
132
|
+
custom_headers[RUN_MODE_HEADER] = RUN_MODE_TEST
|
|
122
133
|
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
123
134
|
|
|
124
|
-
client = TTSClient(config, ctx=ctx)
|
|
135
|
+
client = TTSClient(config, ctx=ctx, custom_headers=custom_headers, verbose=verbose)
|
|
125
136
|
|
|
126
137
|
with Progress(
|
|
127
138
|
SpinnerColumn(),
|
|
@@ -216,7 +227,14 @@ def tts(
|
|
|
216
227
|
)
|
|
217
228
|
@click.option("--base64", is_flag=True, help="将本地文件转为 base64 上传")
|
|
218
229
|
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
219
|
-
|
|
230
|
+
@click.option(
|
|
231
|
+
"--header",
|
|
232
|
+
"-H",
|
|
233
|
+
multiple=True,
|
|
234
|
+
help="自定义 HTTP 请求头 (格式: 'Key: Value' 或 'Key=Value',可多次使用)",
|
|
235
|
+
)
|
|
236
|
+
@click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求日志")
|
|
237
|
+
def asr(audio, uid, output, format, base64, mock, header, verbose):
|
|
220
238
|
"""语音识别 (Automatic Speech Recognition)
|
|
221
239
|
|
|
222
240
|
将语音音频转换为文本。
|
|
@@ -231,20 +249,22 @@ def asr(audio, uid, output, format, base64, mock):
|
|
|
231
249
|
coze-coding-ai asr https://example.com/audio.mp3
|
|
232
250
|
coze-coding-ai asr ./audio.mp3 -o result.txt
|
|
233
251
|
coze-coding-ai asr ./audio.mp3 -f json
|
|
234
|
-
coze-coding-ai asr
|
|
252
|
+
coze-coding-ai asr audio.mp3 --base64 --output result.txt
|
|
235
253
|
"""
|
|
236
254
|
try:
|
|
255
|
+
from .utils import parse_headers
|
|
256
|
+
|
|
237
257
|
config = Config()
|
|
238
258
|
|
|
239
259
|
ctx = None
|
|
260
|
+
custom_headers = parse_headers(header)
|
|
261
|
+
|
|
240
262
|
if mock:
|
|
241
|
-
ctx =
|
|
242
|
-
|
|
243
|
-
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
244
|
-
)
|
|
263
|
+
ctx = new_context(method="asr.recognize", headers=custom_headers)
|
|
264
|
+
custom_headers[RUN_MODE_HEADER] = RUN_MODE_TEST
|
|
245
265
|
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
246
266
|
|
|
247
|
-
client = ASRClient(config, ctx=ctx)
|
|
267
|
+
client = ASRClient(config, ctx=ctx, custom_headers=custom_headers, verbose=verbose)
|
|
248
268
|
|
|
249
269
|
audio_url = None
|
|
250
270
|
audio_base64 = None
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/core/__init__.py
RENAMED
|
@@ -8,6 +8,11 @@ from .exceptions import (
|
|
|
8
8
|
ValidationError
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
+
try:
|
|
12
|
+
from .. import __version__
|
|
13
|
+
except ImportError:
|
|
14
|
+
__version__ = "0.0.0"
|
|
15
|
+
|
|
11
16
|
__all__ = [
|
|
12
17
|
"BaseClient",
|
|
13
18
|
"Config",
|
|
@@ -16,4 +21,5 @@ __all__ = [
|
|
|
16
21
|
"APIError",
|
|
17
22
|
"NetworkError",
|
|
18
23
|
"ValidationError",
|
|
24
|
+
"__version__",
|
|
19
25
|
]
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
from typing import Dict, Optional
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from coze_coding_utils.runtime_ctx.context import Context, default_headers
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
from rich.syntax import Syntax
|
|
10
|
+
|
|
11
|
+
from .config import Config
|
|
12
|
+
from .exceptions import APIError, NetworkError
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BaseClient:
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
config: Optional[Config] = None,
|
|
21
|
+
ctx: Optional[Context] = None,
|
|
22
|
+
custom_headers: Optional[Dict[str, str]] = None,
|
|
23
|
+
verbose: bool = False,
|
|
24
|
+
):
|
|
25
|
+
if config is None:
|
|
26
|
+
config = Config()
|
|
27
|
+
self.config = config
|
|
28
|
+
self.ctx = ctx
|
|
29
|
+
self.custom_headers = custom_headers or {}
|
|
30
|
+
self.verbose = verbose
|
|
31
|
+
|
|
32
|
+
def _request(
|
|
33
|
+
self, method: str, url: str, headers: Optional[Dict[str, str]] = None, **kwargs
|
|
34
|
+
) -> dict:
|
|
35
|
+
request_headers = {}
|
|
36
|
+
|
|
37
|
+
if self.ctx is not None:
|
|
38
|
+
ctx_headers = default_headers(self.ctx)
|
|
39
|
+
request_headers.update(ctx_headers)
|
|
40
|
+
|
|
41
|
+
if self.custom_headers:
|
|
42
|
+
request_headers.update(self.custom_headers)
|
|
43
|
+
|
|
44
|
+
config_headers = self.config.get_headers(headers)
|
|
45
|
+
request_headers.update(config_headers)
|
|
46
|
+
|
|
47
|
+
response = self._make_request(
|
|
48
|
+
method=method, url=url, headers=request_headers, **kwargs
|
|
49
|
+
)
|
|
50
|
+
return self._handle_response(response)
|
|
51
|
+
|
|
52
|
+
def _sanitize_headers(self, headers: Dict[str, str]) -> Dict[str, str]:
|
|
53
|
+
sanitized = headers.copy()
|
|
54
|
+
if "Authorization" in sanitized:
|
|
55
|
+
token = sanitized["Authorization"]
|
|
56
|
+
if token.startswith("Bearer "):
|
|
57
|
+
token = token[7:]
|
|
58
|
+
if len(token) > 16:
|
|
59
|
+
sanitized["Authorization"] = f"Bearer {token[:8]}...{token[-4:]}"
|
|
60
|
+
else:
|
|
61
|
+
sanitized["Authorization"] = "Bearer ****"
|
|
62
|
+
return sanitized
|
|
63
|
+
|
|
64
|
+
def _log_request(self, method: str, url: str, **kwargs):
|
|
65
|
+
if not self.verbose:
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
parts = []
|
|
69
|
+
parts.append(f"[bold cyan]{method}[/bold cyan] {url}\n")
|
|
70
|
+
|
|
71
|
+
headers = kwargs.get("headers", {})
|
|
72
|
+
sanitized_headers = self._sanitize_headers(headers)
|
|
73
|
+
if sanitized_headers:
|
|
74
|
+
parts.append("[bold]Headers:[/bold]")
|
|
75
|
+
for key, value in sanitized_headers.items():
|
|
76
|
+
parts.append(f" {key}: {value}")
|
|
77
|
+
parts.append("")
|
|
78
|
+
|
|
79
|
+
if "json" in kwargs and kwargs["json"]:
|
|
80
|
+
parts.append("[bold]Body:[/bold]")
|
|
81
|
+
try:
|
|
82
|
+
json_str = json.dumps(kwargs["json"], ensure_ascii=False, indent=2)
|
|
83
|
+
parts.append("")
|
|
84
|
+
except Exception:
|
|
85
|
+
json_str = str(kwargs["json"])
|
|
86
|
+
parts.append("")
|
|
87
|
+
|
|
88
|
+
content = "\n".join(parts)
|
|
89
|
+
console.print(
|
|
90
|
+
Panel(
|
|
91
|
+
content,
|
|
92
|
+
title="[bold green]HTTP Request[/bold green]",
|
|
93
|
+
border_style="green",
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if "json" in kwargs and kwargs["json"]:
|
|
98
|
+
try:
|
|
99
|
+
json_str = json.dumps(kwargs["json"], ensure_ascii=False, indent=2)
|
|
100
|
+
console.print(
|
|
101
|
+
Syntax(json_str, "json", theme="monokai", line_numbers=False)
|
|
102
|
+
)
|
|
103
|
+
console.print()
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
def _log_response(self, response: requests.Response):
|
|
108
|
+
if not self.verbose:
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
parts = []
|
|
112
|
+
parts.append(f"[bold]Status:[/bold] {response.status_code} {response.reason}\n")
|
|
113
|
+
parts.append("[bold]Body:[/bold]")
|
|
114
|
+
|
|
115
|
+
content = "\n".join(parts)
|
|
116
|
+
console.print(
|
|
117
|
+
Panel(
|
|
118
|
+
content,
|
|
119
|
+
title="[bold blue]HTTP Response[/bold blue]",
|
|
120
|
+
border_style="blue",
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
response_data = response.json()
|
|
126
|
+
json_str = json.dumps(response_data, ensure_ascii=False, indent=2)
|
|
127
|
+
if len(json_str) > 2000:
|
|
128
|
+
json_str = json_str[:2000] + "\n... (truncated)"
|
|
129
|
+
console.print(Syntax(json_str, "json", theme="monokai", line_numbers=False))
|
|
130
|
+
except Exception:
|
|
131
|
+
body_text = response.text[:500]
|
|
132
|
+
if len(response.text) > 500:
|
|
133
|
+
body_text += "... (truncated)"
|
|
134
|
+
console.print(f" {body_text}")
|
|
135
|
+
|
|
136
|
+
console.print()
|
|
137
|
+
|
|
138
|
+
def _make_request(self, method: str, url: str, **kwargs) -> requests.Response:
|
|
139
|
+
last_error = None
|
|
140
|
+
|
|
141
|
+
for attempt in range(self.config.retry_times):
|
|
142
|
+
try:
|
|
143
|
+
if attempt == 0:
|
|
144
|
+
self._log_request(method, url, **kwargs)
|
|
145
|
+
|
|
146
|
+
response = requests.request(
|
|
147
|
+
method=method, url=url, timeout=self.config.timeout, **kwargs
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if attempt == 0:
|
|
151
|
+
self._log_response(response)
|
|
152
|
+
|
|
153
|
+
return response
|
|
154
|
+
|
|
155
|
+
except requests.exceptions.RequestException as e:
|
|
156
|
+
last_error = NetworkError(str(e), e)
|
|
157
|
+
if attempt < self.config.retry_times - 1:
|
|
158
|
+
time.sleep(self.config.retry_delay * (attempt + 1))
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
raise last_error
|
|
162
|
+
|
|
163
|
+
def _handle_response(self, response: requests.Response) -> dict:
|
|
164
|
+
try:
|
|
165
|
+
data = response.json()
|
|
166
|
+
except Exception as e:
|
|
167
|
+
raise APIError(
|
|
168
|
+
f"响应解析失败: {str(e)}, 响应内容: {response.text[:200]}",
|
|
169
|
+
status_code=response.status_code,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
response.raise_for_status()
|
|
174
|
+
except requests.exceptions.HTTPError as e:
|
|
175
|
+
error_msg = f"HTTP 错误: {str(e)}"
|
|
176
|
+
if data:
|
|
177
|
+
error_msg += f", 响应数据: {data}"
|
|
178
|
+
raise APIError(
|
|
179
|
+
error_msg, status_code=response.status_code, response_data=data
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return data
|
|
183
|
+
|
|
184
|
+
def __enter__(self):
|
|
185
|
+
return self
|
|
186
|
+
|
|
187
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
188
|
+
pass
|
|
@@ -42,9 +42,15 @@ class Config:
|
|
|
42
42
|
raise ConfigurationError("Base URL 未配置")
|
|
43
43
|
|
|
44
44
|
def get_headers(self, ctx_headers: Optional[dict] = None) -> dict:
|
|
45
|
+
try:
|
|
46
|
+
from .. import __version__
|
|
47
|
+
except ImportError:
|
|
48
|
+
__version__ = "0.0.0"
|
|
49
|
+
|
|
45
50
|
headers = {}
|
|
46
51
|
if ctx_headers:
|
|
47
52
|
headers.update(ctx_headers)
|
|
48
53
|
headers.setdefault("Content-Type", "application/json")
|
|
49
54
|
headers.setdefault("Authorization", f"Bearer {self.api_key}")
|
|
55
|
+
headers.setdefault("X-Client-Sdk", f"coze-coding-dev-sdk-python/{__version__}")
|
|
50
56
|
return headers
|
|
@@ -16,12 +16,13 @@ class ImageGenerationClient(BaseClient):
|
|
|
16
16
|
config: Optional[Config] = None,
|
|
17
17
|
ctx: Optional[Context] = None,
|
|
18
18
|
custom_headers: Optional[Dict[str, str]] = None,
|
|
19
|
+
verbose: bool = False,
|
|
19
20
|
):
|
|
20
|
-
super().__init__(config, ctx, custom_headers)
|
|
21
|
+
super().__init__(config, ctx, custom_headers, verbose)
|
|
21
22
|
self.base_url = self.config.base_url
|
|
22
23
|
self.model = ImageConfig.DEFAULT_MODEL
|
|
23
24
|
|
|
24
|
-
def
|
|
25
|
+
def extract_urls(self, response: ImageGenerationResponse) -> List[str]:
|
|
25
26
|
urls = []
|
|
26
27
|
for item in response.data:
|
|
27
28
|
if item.error:
|
|
@@ -107,15 +108,3 @@ class ImageGenerationClient(BaseClient):
|
|
|
107
108
|
sequential_image_generation,
|
|
108
109
|
sequential_image_generation_max_images,
|
|
109
110
|
)
|
|
110
|
-
|
|
111
|
-
async def batch_generate(
|
|
112
|
-
self, requests: List[Dict[str, Any]], max_concurrent: int = 5
|
|
113
|
-
) -> List[ImageGenerationResponse]:
|
|
114
|
-
semaphore = asyncio.Semaphore(max_concurrent)
|
|
115
|
-
|
|
116
|
-
async def _generate_with_semaphore(request_params: Dict[str, Any]):
|
|
117
|
-
async with semaphore:
|
|
118
|
-
return await self.generate_async(**request_params)
|
|
119
|
-
|
|
120
|
-
tasks = [_generate_with_semaphore(req) for req in requests]
|
|
121
|
-
return await asyncio.gather(*tasks, return_exceptions=False)
|
|
@@ -16,11 +16,19 @@ from .models import LLMConfig
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class LLMClient:
|
|
19
|
-
def __init__(
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
config: Optional[Config] = None,
|
|
22
|
+
ctx: Optional[Context] = None,
|
|
23
|
+
custom_headers: Optional[Dict[str, str]] = None,
|
|
24
|
+
verbose: bool = False,
|
|
25
|
+
):
|
|
20
26
|
if config is None:
|
|
21
27
|
config = Config()
|
|
22
28
|
self.config = config
|
|
23
29
|
self.ctx = ctx
|
|
30
|
+
self.custom_headers = custom_headers or {}
|
|
31
|
+
self.verbose = verbose
|
|
24
32
|
self.base_url = self.config.base_model_url
|
|
25
33
|
self.api_key = self.config.api_key
|
|
26
34
|
|
|
@@ -39,12 +47,18 @@ class LLMClient:
|
|
|
39
47
|
if llm_config.caching:
|
|
40
48
|
extra_body["caching"] = {"type": llm_config.caching}
|
|
41
49
|
|
|
42
|
-
headers =
|
|
50
|
+
headers = {}
|
|
43
51
|
|
|
44
52
|
if self.ctx is not None:
|
|
45
53
|
ctx_headers = default_headers(self.ctx)
|
|
46
54
|
headers.update(ctx_headers)
|
|
47
55
|
|
|
56
|
+
if self.custom_headers:
|
|
57
|
+
headers.update(self.custom_headers)
|
|
58
|
+
|
|
59
|
+
config_headers = self.config.get_headers(extra_headers)
|
|
60
|
+
headers.update(config_headers)
|
|
61
|
+
|
|
48
62
|
llm = ChatOpenAI(
|
|
49
63
|
model=llm_config.model,
|
|
50
64
|
api_key=self.api_key,
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/search/client.py
RENAMED
|
@@ -79,8 +79,9 @@ class SearchClient(BaseClient):
|
|
|
79
79
|
config: Optional[Config] = None,
|
|
80
80
|
ctx: Optional[Context] = None,
|
|
81
81
|
custom_headers: Optional[Dict[str, str]] = None,
|
|
82
|
+
verbose: bool = False,
|
|
82
83
|
):
|
|
83
|
-
super().__init__(config, ctx, custom_headers)
|
|
84
|
+
super().__init__(config, ctx, custom_headers, verbose)
|
|
84
85
|
self.base_url = self.config.base_url
|
|
85
86
|
|
|
86
87
|
@observe(name="web_search")
|
|
@@ -20,9 +20,10 @@ class VideoGenerationClient(BaseClient):
|
|
|
20
20
|
self,
|
|
21
21
|
config: Optional[Config] = None,
|
|
22
22
|
ctx: Optional[Context] = None,
|
|
23
|
-
custom_headers: Optional[Dict[str, str]] = None
|
|
23
|
+
custom_headers: Optional[Dict[str, str]] = None,
|
|
24
|
+
verbose: bool = False
|
|
24
25
|
):
|
|
25
|
-
super().__init__(config, ctx, custom_headers)
|
|
26
|
+
super().__init__(config, ctx, custom_headers, verbose)
|
|
26
27
|
self.base_url = self.config.base_url
|
|
27
28
|
|
|
28
29
|
@observe(name="video_generation_create_task")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from typing import Optional, Tuple
|
|
2
|
-
|
|
1
|
+
from typing import Dict, Optional, Tuple
|
|
2
|
+
|
|
3
3
|
from coze_coding_utils.runtime_ctx.context import Context
|
|
4
|
+
from cozeloop.decorator import observe
|
|
4
5
|
|
|
5
6
|
from ..core.client import BaseClient
|
|
6
7
|
from ..core.config import Config
|
|
@@ -10,50 +11,50 @@ from .models import ASRRequest, ASRResponse
|
|
|
10
11
|
|
|
11
12
|
class ASRClient(BaseClient):
|
|
12
13
|
def __init__(
|
|
13
|
-
self,
|
|
14
|
-
config: Optional[Config] = None,
|
|
14
|
+
self,
|
|
15
|
+
config: Optional[Config] = None,
|
|
15
16
|
ctx: Optional[Context] = None,
|
|
16
|
-
custom_headers: Optional[Dict[str, str]] = None
|
|
17
|
+
custom_headers: Optional[Dict[str, str]] = None,
|
|
18
|
+
verbose: bool = False,
|
|
17
19
|
):
|
|
18
|
-
super().__init__(config, ctx, custom_headers)
|
|
20
|
+
super().__init__(config, ctx, custom_headers, verbose)
|
|
19
21
|
self.base_url = self.config.base_url
|
|
22
|
+
|
|
20
23
|
@observe
|
|
21
24
|
def recognize(
|
|
22
25
|
self,
|
|
23
26
|
uid: Optional[str] = None,
|
|
24
27
|
url: Optional[str] = None,
|
|
25
|
-
base64_data: Optional[str] = None
|
|
28
|
+
base64_data: Optional[str] = None,
|
|
26
29
|
) -> Tuple[str, dict]:
|
|
27
30
|
if not (url or base64_data):
|
|
28
|
-
raise ValidationError(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
35
|
-
|
|
31
|
+
raise ValidationError(
|
|
32
|
+
"必须提供 url 或 base64_data 其中之一", field="url/base64_data"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
request = ASRRequest(uid=uid, url=url, base64_data=base64_data)
|
|
36
|
+
|
|
36
37
|
headers = self.config.get_headers()
|
|
37
38
|
response = self._make_request(
|
|
38
39
|
method="POST",
|
|
39
40
|
url=f"{self.base_url}/api/v3/auc/bigmodel/recognize/flash",
|
|
40
41
|
json=request.to_api_request(),
|
|
41
|
-
headers=headers
|
|
42
|
+
headers=headers,
|
|
42
43
|
)
|
|
43
|
-
|
|
44
|
-
status_code = response.headers.get(
|
|
45
|
-
message = response.headers.get(
|
|
46
|
-
|
|
47
|
-
if status_code !=
|
|
44
|
+
|
|
45
|
+
status_code = response.headers.get("X-Api-Status-Code", "0")
|
|
46
|
+
message = response.headers.get("X-Api-Message", "")
|
|
47
|
+
|
|
48
|
+
if status_code != "20000000":
|
|
48
49
|
raise APIError(
|
|
49
50
|
f"识别失败: {message}",
|
|
50
51
|
code=status_code,
|
|
51
|
-
status_code=response.status_code
|
|
52
|
+
status_code=response.status_code,
|
|
52
53
|
)
|
|
53
|
-
|
|
54
|
+
|
|
54
55
|
data = self._handle_response(response)
|
|
55
|
-
|
|
56
|
+
|
|
56
57
|
result = data.get("result", {})
|
|
57
58
|
text = result.get("text", "")
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
return text, data
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import base64
|
|
3
|
-
|
|
4
|
-
from
|
|
2
|
+
import json
|
|
3
|
+
from typing import Dict, Optional, Tuple
|
|
4
|
+
|
|
5
5
|
from coze_coding_utils.runtime_ctx.context import Context
|
|
6
|
+
from cozeloop.decorator import observe
|
|
6
7
|
|
|
7
8
|
from ..core.client import BaseClient
|
|
8
9
|
from ..core.config import Config
|
|
@@ -12,13 +13,15 @@ from .models import TTSConfig, TTSRequest
|
|
|
12
13
|
|
|
13
14
|
class TTSClient(BaseClient):
|
|
14
15
|
def __init__(
|
|
15
|
-
self,
|
|
16
|
-
config: Optional[Config] = None,
|
|
16
|
+
self,
|
|
17
|
+
config: Optional[Config] = None,
|
|
17
18
|
ctx: Optional[Context] = None,
|
|
18
|
-
custom_headers: Optional[Dict[str, str]] = None
|
|
19
|
+
custom_headers: Optional[Dict[str, str]] = None,
|
|
20
|
+
verbose: bool = False,
|
|
19
21
|
):
|
|
20
|
-
super().__init__(config, ctx, custom_headers)
|
|
22
|
+
super().__init__(config, ctx, custom_headers, verbose)
|
|
21
23
|
self.base_url = self.config.base_url
|
|
24
|
+
|
|
22
25
|
@observe
|
|
23
26
|
def synthesize(
|
|
24
27
|
self,
|
|
@@ -33,7 +36,7 @@ class TTSClient(BaseClient):
|
|
|
33
36
|
) -> Tuple[str, int]:
|
|
34
37
|
if not (text or ssml):
|
|
35
38
|
raise ValidationError("必须提供 text 或 ssml 其中之一", field="text/ssml")
|
|
36
|
-
|
|
39
|
+
|
|
37
40
|
request = TTSRequest(
|
|
38
41
|
uid=uid,
|
|
39
42
|
text=text,
|
|
@@ -42,49 +45,49 @@ class TTSClient(BaseClient):
|
|
|
42
45
|
audio_format=audio_format,
|
|
43
46
|
sample_rate=sample_rate,
|
|
44
47
|
speech_rate=speech_rate,
|
|
45
|
-
loudness_rate=loudness_rate
|
|
48
|
+
loudness_rate=loudness_rate,
|
|
46
49
|
)
|
|
47
|
-
|
|
50
|
+
|
|
48
51
|
headers = self.config.get_headers({"Connection": "keep-alive"})
|
|
49
52
|
response = self._make_request(
|
|
50
53
|
method="POST",
|
|
51
54
|
url=f"{self.base_url}/api/v3/tts/unidirectional",
|
|
52
55
|
json=request.to_api_request(),
|
|
53
56
|
headers=headers,
|
|
54
|
-
stream=True
|
|
57
|
+
stream=True,
|
|
55
58
|
)
|
|
56
|
-
|
|
59
|
+
|
|
57
60
|
try:
|
|
58
61
|
audio_uri = None
|
|
59
62
|
audio_data = bytearray()
|
|
60
63
|
total_audio_size = 0
|
|
61
|
-
|
|
64
|
+
|
|
62
65
|
for chunk in response.iter_lines(decode_unicode=False):
|
|
63
66
|
if not chunk:
|
|
64
67
|
continue
|
|
65
|
-
|
|
68
|
+
|
|
66
69
|
chunk_str = chunk.decode("utf-8").replace("data:", "")
|
|
67
70
|
data = json.loads(chunk_str)
|
|
68
|
-
|
|
71
|
+
|
|
69
72
|
if data.get("code", 0) == 0 and "data" in data and data["data"]:
|
|
70
73
|
chunk_audio = base64.b64decode(data["data"])
|
|
71
74
|
audio_size = len(chunk_audio)
|
|
72
75
|
total_audio_size += audio_size
|
|
73
76
|
audio_data.extend(chunk_audio)
|
|
74
|
-
|
|
77
|
+
|
|
75
78
|
elif data.get("code", 0) == 20000000:
|
|
76
|
-
if
|
|
77
|
-
audio_uri = data[
|
|
79
|
+
if "url" in data and data["url"]:
|
|
80
|
+
audio_uri = data["url"]
|
|
78
81
|
break
|
|
79
|
-
|
|
82
|
+
|
|
80
83
|
elif data.get("code", 0) > 0:
|
|
81
84
|
raise APIError(
|
|
82
85
|
f"合成音频失败: {data.get('message', '')}",
|
|
83
|
-
code=str(data.get(
|
|
86
|
+
code=str(data.get("code", 0)),
|
|
84
87
|
)
|
|
85
|
-
|
|
88
|
+
|
|
86
89
|
return audio_uri or "", total_audio_size
|
|
87
|
-
|
|
90
|
+
|
|
88
91
|
except json.JSONDecodeError as e:
|
|
89
92
|
raise APIError(f"响应解析失败: {str(e)}")
|
|
90
93
|
except Exception as e:
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4/coze_coding_dev_sdk.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coze-coding-dev-sdk
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Coze Coding Dev SDK - 优雅的多功能 AI SDK,支持图片生成、视频生成、语音合成、语音识别、大语言模型和联网搜索。包含命令行工具 coze-coding-ai,支持 Context 上下文追踪
|
|
5
5
|
Author-email: Coze Coding Integration Team <support@coze.com>
|
|
6
6
|
Maintainer-email: Coze Coding Integration Team <support@coze.com>
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/SOURCES.txt
RENAMED
|
@@ -16,6 +16,7 @@ coze_coding_dev_sdk/cli/cli.py
|
|
|
16
16
|
coze_coding_dev_sdk/cli/constants.py
|
|
17
17
|
coze_coding_dev_sdk/cli/image.py
|
|
18
18
|
coze_coding_dev_sdk/cli/search.py
|
|
19
|
+
coze_coding_dev_sdk/cli/utils.py
|
|
19
20
|
coze_coding_dev_sdk/cli/video.py
|
|
20
21
|
coze_coding_dev_sdk/cli/voice.py
|
|
21
22
|
coze_coding_dev_sdk/core/__init__.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coze-coding-dev-sdk"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.4"
|
|
8
8
|
description = "Coze Coding Dev SDK - 优雅的多功能 AI SDK,支持图片生成、视频生成、语音合成、语音识别、大语言模型和联网搜索。包含命令行工具 coze-coding-ai,支持 Context 上下文追踪"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from typing import Optional, Dict
|
|
3
|
-
import requests
|
|
4
|
-
from coze_coding_utils.runtime_ctx.context import Context, default_headers
|
|
5
|
-
|
|
6
|
-
from .config import Config
|
|
7
|
-
from .exceptions import APIError, NetworkError
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class BaseClient:
|
|
11
|
-
def __init__(
|
|
12
|
-
self,
|
|
13
|
-
config: Optional[Config] = None,
|
|
14
|
-
ctx: Optional[Context] = None,
|
|
15
|
-
custom_headers: Optional[Dict[str, str]] = None
|
|
16
|
-
):
|
|
17
|
-
if config is None:
|
|
18
|
-
config = Config()
|
|
19
|
-
self.config = config
|
|
20
|
-
self.ctx = ctx
|
|
21
|
-
self.custom_headers = custom_headers or {}
|
|
22
|
-
|
|
23
|
-
def _request(
|
|
24
|
-
self,
|
|
25
|
-
method: str,
|
|
26
|
-
url: str,
|
|
27
|
-
headers: Optional[Dict[str, str]] = None,
|
|
28
|
-
**kwargs
|
|
29
|
-
) -> dict:
|
|
30
|
-
request_headers = self.config.get_headers(headers)
|
|
31
|
-
|
|
32
|
-
if self.ctx is not None:
|
|
33
|
-
ctx_headers = default_headers(self.ctx)
|
|
34
|
-
request_headers.update(ctx_headers)
|
|
35
|
-
|
|
36
|
-
response = self._make_request(
|
|
37
|
-
method=method,
|
|
38
|
-
url=url,
|
|
39
|
-
headers=request_headers,
|
|
40
|
-
**kwargs
|
|
41
|
-
)
|
|
42
|
-
return self._handle_response(response)
|
|
43
|
-
|
|
44
|
-
def _make_request(
|
|
45
|
-
self,
|
|
46
|
-
method: str,
|
|
47
|
-
url: str,
|
|
48
|
-
**kwargs
|
|
49
|
-
) -> requests.Response:
|
|
50
|
-
last_error = None
|
|
51
|
-
|
|
52
|
-
for attempt in range(self.config.retry_times):
|
|
53
|
-
try:
|
|
54
|
-
response = requests.request(
|
|
55
|
-
method=method,
|
|
56
|
-
url=url,
|
|
57
|
-
timeout=self.config.timeout,
|
|
58
|
-
**kwargs
|
|
59
|
-
)
|
|
60
|
-
return response
|
|
61
|
-
|
|
62
|
-
except requests.exceptions.RequestException as e:
|
|
63
|
-
last_error = NetworkError(str(e), e)
|
|
64
|
-
if attempt < self.config.retry_times - 1:
|
|
65
|
-
time.sleep(self.config.retry_delay * (attempt + 1))
|
|
66
|
-
continue
|
|
67
|
-
|
|
68
|
-
raise last_error
|
|
69
|
-
|
|
70
|
-
def _handle_response(self, response: requests.Response) -> dict:
|
|
71
|
-
try:
|
|
72
|
-
data = response.json()
|
|
73
|
-
except Exception as e:
|
|
74
|
-
raise APIError(
|
|
75
|
-
f"响应解析失败: {str(e)}, 响应内容: {response.text[:200]}",
|
|
76
|
-
status_code=response.status_code
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
try:
|
|
80
|
-
response.raise_for_status()
|
|
81
|
-
except requests.exceptions.HTTPError as e:
|
|
82
|
-
error_msg = f"HTTP 错误: {str(e)}"
|
|
83
|
-
if data:
|
|
84
|
-
error_msg += f", 响应数据: {data}"
|
|
85
|
-
raise APIError(
|
|
86
|
-
error_msg,
|
|
87
|
-
status_code=response.status_code,
|
|
88
|
-
response_data=data
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
return data
|
|
92
|
-
|
|
93
|
-
def __enter__(self):
|
|
94
|
-
return self
|
|
95
|
-
|
|
96
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
97
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/cli/constants.py
RENAMED
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/core/exceptions.py
RENAMED
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/image/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/search/__init__.py
RENAMED
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/search/models.py
RENAMED
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/video/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk/voice/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/requires.txt
RENAMED
|
File without changes
|
{coze_coding_dev_sdk-0.4.2 → coze_coding_dev_sdk-0.4.4}/coze_coding_dev_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|