coze-coding-dev-sdk 0.4.1__tar.gz → 0.4.2__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.1/coze_coding_dev_sdk.egg-info → coze_coding_dev_sdk-0.4.2}/PKG-INFO +5 -1
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/README.md +4 -0
- coze_coding_dev_sdk-0.4.2/coze_coding_dev_sdk/cli/constants.py +7 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/cli/image.py +69 -33
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/cli/video.py +90 -51
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/cli/voice.py +136 -66
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/core/client.py +7 -1
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/image/client.py +30 -28
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/search/client.py +31 -39
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/video/client.py +8 -3
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/voice/asr.py +8 -3
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/voice/tts.py +8 -3
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2/coze_coding_dev_sdk.egg-info}/PKG-INFO +5 -1
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk.egg-info/SOURCES.txt +1 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/pyproject.toml +1 -1
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/CHANGELOG.md +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/LICENSE +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/MANIFEST.in +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/cli/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/cli/chat.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/cli/cli.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/cli/search.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/core/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/core/config.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/core/exceptions.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/image/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/image/models.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/llm/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/llm/client.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/llm/models.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/search/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/search/models.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/video/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/video/models.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/voice/__init__.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk/voice/models.py +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk.egg-info/dependency_links.txt +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk.egg-info/entry_points.txt +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk.egg-info/requires.txt +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/coze_coding_dev_sdk.egg-info/top_level.txt +0 -0
- {coze_coding_dev_sdk-0.4.1 → coze_coding_dev_sdk-0.4.2}/setup.cfg +0 -0
{coze_coding_dev_sdk-0.4.1/coze_coding_dev_sdk.egg-info → coze_coding_dev_sdk-0.4.2}/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.2
|
|
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>
|
|
@@ -513,6 +513,10 @@ coze-coding-ai video \
|
|
|
513
513
|
|
|
514
514
|
# 查询任务状态
|
|
515
515
|
coze-coding-ai video-status <task-id>
|
|
516
|
+
|
|
517
|
+
# Mock 模式(测试运行,不消耗配额)
|
|
518
|
+
coze-coding-ai video -p "Test video" --mock --poll
|
|
519
|
+
coze-coding-ai video-status <task-id> --mock
|
|
516
520
|
```
|
|
517
521
|
|
|
518
522
|
### Chat 对话
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import base64
|
|
2
|
+
import os
|
|
3
|
+
import time
|
|
3
4
|
from typing import Optional
|
|
5
|
+
|
|
4
6
|
import click
|
|
7
|
+
from coze_coding_utils.runtime_ctx.context import Context
|
|
5
8
|
from rich.console import Console
|
|
6
9
|
|
|
7
|
-
from ..image import ImageGenerationClient
|
|
8
10
|
from ..core.config import Config
|
|
11
|
+
from ..image import ImageGenerationClient
|
|
12
|
+
from .constants import RUN_MODE_HEADER, RUN_MODE_TEST
|
|
9
13
|
|
|
10
14
|
console = Console()
|
|
11
15
|
|
|
@@ -13,41 +17,70 @@ console = Console()
|
|
|
13
17
|
def validate_and_normalize_size(size: str) -> str:
|
|
14
18
|
if size in ["2K", "4K"]:
|
|
15
19
|
return size
|
|
16
|
-
|
|
20
|
+
|
|
17
21
|
try:
|
|
18
|
-
width, height = size.split(
|
|
22
|
+
width, height = size.split("x")
|
|
19
23
|
w, h = int(width), int(height)
|
|
20
|
-
|
|
24
|
+
|
|
21
25
|
if 2560 <= w <= 4096 and 1440 <= h <= 4096:
|
|
22
26
|
return size
|
|
23
27
|
else:
|
|
24
|
-
console.print(
|
|
28
|
+
console.print(
|
|
29
|
+
f"[yellow]Warning: Size {size} is out of range [2560x1440, 4096x4096], using default 2K[/yellow]"
|
|
30
|
+
)
|
|
25
31
|
return "2K"
|
|
26
32
|
except (ValueError, AttributeError):
|
|
27
|
-
console.print(
|
|
33
|
+
console.print(
|
|
34
|
+
f"[yellow]Warning: Invalid size format {size}, using default 2K[/yellow]"
|
|
35
|
+
)
|
|
28
36
|
return "2K"
|
|
29
37
|
|
|
30
38
|
|
|
31
39
|
@click.command()
|
|
32
40
|
@click.option("--prompt", "-p", required=True, help="Text description of the image")
|
|
33
|
-
@click.option(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@click.option(
|
|
37
|
-
|
|
41
|
+
@click.option(
|
|
42
|
+
"--output", "-o", required=True, type=click.Path(), help="Output file path"
|
|
43
|
+
)
|
|
44
|
+
@click.option(
|
|
45
|
+
"--size",
|
|
46
|
+
"-s",
|
|
47
|
+
default="2K",
|
|
48
|
+
help="Image size (2K, 4K, or WIDTHxHEIGHT in range [2560x1440, 4096x4096])",
|
|
49
|
+
)
|
|
50
|
+
@click.option(
|
|
51
|
+
"--image", "-i", help="Reference image URL or path (for image-to-image generation)"
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"--images",
|
|
55
|
+
multiple=True,
|
|
56
|
+
help="Multiple reference image URLs or paths (can be used multiple times)",
|
|
57
|
+
)
|
|
58
|
+
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
59
|
+
def image(
|
|
60
|
+
prompt: str, output: str, size: str, image: Optional[str], images: tuple, mock: bool
|
|
61
|
+
):
|
|
38
62
|
"""Generate image using AI."""
|
|
39
63
|
try:
|
|
40
64
|
config = Config()
|
|
41
|
-
|
|
42
|
-
|
|
65
|
+
|
|
66
|
+
ctx = None
|
|
67
|
+
if mock:
|
|
68
|
+
ctx = Context(
|
|
69
|
+
request_id=f"mock-req-{int(time.time())}",
|
|
70
|
+
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
71
|
+
)
|
|
72
|
+
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
73
|
+
|
|
74
|
+
client = ImageGenerationClient(config, ctx=ctx)
|
|
75
|
+
|
|
43
76
|
reference_images = None
|
|
44
77
|
if image:
|
|
45
78
|
reference_images = image
|
|
46
79
|
elif images:
|
|
47
80
|
reference_images = list(images)
|
|
48
|
-
|
|
81
|
+
|
|
49
82
|
validated_size = validate_and_normalize_size(size)
|
|
50
|
-
|
|
83
|
+
|
|
51
84
|
console.print(f"[bold cyan]Generating image...[/bold cyan]")
|
|
52
85
|
console.print(f"Prompt: [yellow]{prompt}[/yellow]")
|
|
53
86
|
console.print(f"Size: [yellow]{validated_size}[/yellow]")
|
|
@@ -55,48 +88,51 @@ def image(prompt: str, output: str, size: str, image: Optional[str], images: tup
|
|
|
55
88
|
if isinstance(reference_images, str):
|
|
56
89
|
console.print(f"Reference image: [blue]{reference_images}[/blue]")
|
|
57
90
|
else:
|
|
58
|
-
console.print(
|
|
59
|
-
|
|
91
|
+
console.print(
|
|
92
|
+
f"Reference images: [blue]{len(reference_images)} images[/blue]"
|
|
93
|
+
)
|
|
94
|
+
|
|
60
95
|
response = client.generate(
|
|
61
96
|
prompt=prompt,
|
|
62
97
|
size=validated_size,
|
|
63
98
|
image=reference_images,
|
|
64
|
-
response_format="b64_json"
|
|
99
|
+
response_format="b64_json",
|
|
65
100
|
)
|
|
66
|
-
|
|
101
|
+
|
|
67
102
|
if not response.data or len(response.data) == 0:
|
|
68
103
|
raise ValueError("No image data returned")
|
|
69
|
-
|
|
104
|
+
|
|
70
105
|
image_data = response.data[0]
|
|
71
|
-
|
|
106
|
+
|
|
72
107
|
if image_data.error:
|
|
73
|
-
error_msg = image_data.error.get(
|
|
108
|
+
error_msg = image_data.error.get("message", "Unknown error")
|
|
74
109
|
raise Exception(f"Image generation failed: {error_msg}")
|
|
75
|
-
|
|
110
|
+
|
|
76
111
|
if image_data.b64_json:
|
|
77
112
|
image_bytes = base64.b64decode(image_data.b64_json)
|
|
78
|
-
|
|
113
|
+
|
|
79
114
|
os.makedirs(os.path.dirname(os.path.abspath(output)), exist_ok=True)
|
|
80
|
-
|
|
81
|
-
with open(output,
|
|
115
|
+
|
|
116
|
+
with open(output, "wb") as f:
|
|
82
117
|
f.write(image_bytes)
|
|
83
|
-
|
|
118
|
+
|
|
84
119
|
console.print(f"[green]✓[/green] Image saved to: [bold]{output}[/bold]")
|
|
85
120
|
elif image_data.url:
|
|
86
121
|
import requests
|
|
122
|
+
|
|
87
123
|
img_response = requests.get(image_data.url)
|
|
88
124
|
img_response.raise_for_status()
|
|
89
|
-
|
|
125
|
+
|
|
90
126
|
os.makedirs(os.path.dirname(os.path.abspath(output)), exist_ok=True)
|
|
91
|
-
|
|
92
|
-
with open(output,
|
|
127
|
+
|
|
128
|
+
with open(output, "wb") as f:
|
|
93
129
|
f.write(img_response.content)
|
|
94
|
-
|
|
130
|
+
|
|
95
131
|
console.print(f"[green]✓[/green] Image saved to: [bold]{output}[/bold]")
|
|
96
132
|
console.print(f"Original URL: [blue]{image_data.url}[/blue]")
|
|
97
133
|
else:
|
|
98
134
|
raise ValueError("No image data (b64_json or url) in response")
|
|
99
|
-
|
|
135
|
+
|
|
100
136
|
except Exception as e:
|
|
101
137
|
console.print(f"[red]✗ Error: {str(e)}[/red]")
|
|
102
138
|
raise click.Abort()
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import time
|
|
2
1
|
import json
|
|
3
2
|
import os
|
|
3
|
+
import time
|
|
4
4
|
from typing import Optional
|
|
5
|
+
|
|
5
6
|
import click
|
|
7
|
+
from coze_coding_utils.runtime_ctx.context import Context
|
|
6
8
|
from rich.console import Console
|
|
7
9
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
8
10
|
from rich.table import Table
|
|
9
11
|
|
|
10
|
-
from ..video import VideoGenerationClient, VideoConfig
|
|
11
12
|
from ..core.config import Config
|
|
12
13
|
from ..core.exceptions import APIError
|
|
14
|
+
from ..video import VideoConfig, VideoGenerationClient
|
|
15
|
+
from .constants import RUN_MODE_HEADER, RUN_MODE_TEST
|
|
13
16
|
|
|
14
17
|
console = Console()
|
|
15
18
|
|
|
@@ -17,10 +20,10 @@ console = Console()
|
|
|
17
20
|
def parse_resolution(size: Optional[str]) -> tuple[Optional[str], Optional[str]]:
|
|
18
21
|
if not size:
|
|
19
22
|
return None, None
|
|
20
|
-
|
|
21
|
-
width, height = size.split(
|
|
23
|
+
|
|
24
|
+
width, height = size.split("x")
|
|
22
25
|
w, h = int(width), int(height)
|
|
23
|
-
|
|
26
|
+
|
|
24
27
|
if w == h:
|
|
25
28
|
return "1:1", "720p" if w <= 1024 else "1080p"
|
|
26
29
|
elif w > h:
|
|
@@ -32,16 +35,25 @@ def parse_resolution(size: Optional[str]) -> tuple[Optional[str], Optional[str]]
|
|
|
32
35
|
@click.command()
|
|
33
36
|
@click.option("--prompt", "-p", help="Text description of the video")
|
|
34
37
|
@click.option("--image-url", "-i", help="Image URL (single or comma-separated pair)")
|
|
35
|
-
@click.option(
|
|
38
|
+
@click.option(
|
|
39
|
+
"--quality",
|
|
40
|
+
"-q",
|
|
41
|
+
type=click.Choice(["speed", "quality"]),
|
|
42
|
+
default="speed",
|
|
43
|
+
help="Output mode",
|
|
44
|
+
)
|
|
36
45
|
@click.option("--with-audio", is_flag=True, help="Generate AI audio effects")
|
|
37
46
|
@click.option("--size", "-s", help="Video resolution (e.g., 1920x1080)")
|
|
38
47
|
@click.option("--fps", type=int, help="Frame rate (30 or 60)")
|
|
39
48
|
@click.option("--duration", "-d", type=int, help="Duration in seconds (5 or 10)")
|
|
40
49
|
@click.option("--model", "-m", help="Model name to use")
|
|
41
50
|
@click.option("--poll", is_flag=True, help="Auto-poll until task completes")
|
|
42
|
-
@click.option(
|
|
51
|
+
@click.option(
|
|
52
|
+
"--poll-interval", type=int, default=5, help="Polling interval in seconds"
|
|
53
|
+
)
|
|
43
54
|
@click.option("--max-polls", type=int, default=60, help="Maximum poll attempts")
|
|
44
55
|
@click.option("--output", "-o", type=click.Path(), help="Output file path (JSON)")
|
|
56
|
+
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
45
57
|
def video(
|
|
46
58
|
prompt: Optional[str],
|
|
47
59
|
image_url: Optional[str],
|
|
@@ -54,38 +66,48 @@ def video(
|
|
|
54
66
|
poll: bool,
|
|
55
67
|
poll_interval: int,
|
|
56
68
|
max_polls: int,
|
|
57
|
-
output: Optional[str]
|
|
69
|
+
output: Optional[str],
|
|
70
|
+
mock: bool,
|
|
58
71
|
):
|
|
59
72
|
"""Generate video using AI."""
|
|
60
73
|
try:
|
|
61
74
|
config = Config()
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
|
|
76
|
+
ctx = None
|
|
77
|
+
if mock:
|
|
78
|
+
ctx = Context(
|
|
79
|
+
request_id=f"mock-req-{int(time.time())}",
|
|
80
|
+
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
81
|
+
)
|
|
82
|
+
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
83
|
+
|
|
84
|
+
client = VideoGenerationClient(config, ctx=ctx)
|
|
85
|
+
|
|
64
86
|
image_urls = None
|
|
65
87
|
if image_url:
|
|
66
88
|
image_urls = [url.strip() for url in image_url.split(",")]
|
|
67
|
-
|
|
89
|
+
|
|
68
90
|
ratio, resolution = parse_resolution(size)
|
|
69
|
-
|
|
91
|
+
|
|
70
92
|
video_config = VideoConfig(
|
|
71
93
|
resolution=resolution or "720p",
|
|
72
94
|
ratio=ratio or "16:9",
|
|
73
|
-
duration=duration or 5
|
|
95
|
+
duration=duration or 5,
|
|
74
96
|
)
|
|
75
|
-
|
|
97
|
+
|
|
76
98
|
console.print("[bold cyan]Creating video generation task...[/bold cyan]")
|
|
77
|
-
|
|
99
|
+
|
|
78
100
|
model_name = model or "doubao-seedance-1-0-pro-250528"
|
|
79
|
-
|
|
101
|
+
|
|
80
102
|
if image_urls:
|
|
81
103
|
if len(image_urls) == 1:
|
|
82
104
|
task_id = client._create_task(
|
|
83
105
|
model=model_name,
|
|
84
106
|
content=[
|
|
85
107
|
{"type": "text", "text": prompt or ""},
|
|
86
|
-
{"type": "image_url", "image_url": {"url": image_urls[0]}}
|
|
108
|
+
{"type": "image_url", "image_url": {"url": image_urls[0]}},
|
|
87
109
|
],
|
|
88
|
-
config=video_config
|
|
110
|
+
config=video_config,
|
|
89
111
|
)
|
|
90
112
|
elif len(image_urls) == 2:
|
|
91
113
|
task_id = client._create_task(
|
|
@@ -93,78 +115,85 @@ def video(
|
|
|
93
115
|
content=[
|
|
94
116
|
{"type": "text", "text": prompt or ""},
|
|
95
117
|
{"type": "image_url", "image_url": {"url": image_urls[0]}},
|
|
96
|
-
{"type": "image_url", "image_url": {"url": image_urls[1]}}
|
|
118
|
+
{"type": "image_url", "image_url": {"url": image_urls[1]}},
|
|
97
119
|
],
|
|
98
|
-
config=video_config
|
|
120
|
+
config=video_config,
|
|
99
121
|
)
|
|
100
122
|
else:
|
|
101
123
|
raise ValueError("Only 1 or 2 images are supported")
|
|
102
124
|
else:
|
|
103
125
|
if not prompt:
|
|
104
126
|
raise ValueError("Either --prompt or --image-url must be provided")
|
|
105
|
-
|
|
127
|
+
|
|
106
128
|
task_id = client._create_task(
|
|
107
129
|
model=model_name,
|
|
108
130
|
content=[{"type": "text", "text": prompt}],
|
|
109
|
-
config=video_config
|
|
131
|
+
config=video_config,
|
|
110
132
|
)
|
|
111
|
-
|
|
133
|
+
|
|
112
134
|
console.print(f"[green]✓[/green] Task created: [bold]{task_id}[/bold]")
|
|
113
|
-
|
|
135
|
+
|
|
114
136
|
result = {"id": task_id, "status": "processing"}
|
|
115
|
-
|
|
137
|
+
|
|
116
138
|
if poll:
|
|
117
139
|
with Progress(
|
|
118
140
|
SpinnerColumn(),
|
|
119
141
|
TextColumn("[progress.description]{task.description}"),
|
|
120
|
-
console=console
|
|
142
|
+
console=console,
|
|
121
143
|
) as progress:
|
|
122
144
|
task = progress.add_task(
|
|
123
|
-
f"[cyan]Generating video (Task ID: {task_id})...",
|
|
124
|
-
total=None
|
|
145
|
+
f"[cyan]Generating video (Task ID: {task_id})...", total=None
|
|
125
146
|
)
|
|
126
|
-
|
|
147
|
+
|
|
127
148
|
max_wait_time = poll_interval * max_polls
|
|
128
149
|
start_time = time.time()
|
|
129
|
-
|
|
150
|
+
|
|
130
151
|
while time.time() - start_time < max_wait_time:
|
|
131
152
|
task_result = client._get_task_status(task_id)
|
|
132
|
-
|
|
153
|
+
|
|
133
154
|
if task_result.status == "completed":
|
|
134
|
-
progress.update(
|
|
155
|
+
progress.update(
|
|
156
|
+
task, description="[green]✓ Video generation completed!"
|
|
157
|
+
)
|
|
135
158
|
result = task_result.model_dump()
|
|
136
159
|
break
|
|
137
160
|
elif task_result.status == "failed":
|
|
138
|
-
progress.update(
|
|
161
|
+
progress.update(
|
|
162
|
+
task, description=f"[red]✗ Video generation failed"
|
|
163
|
+
)
|
|
139
164
|
result = task_result.model_dump()
|
|
140
165
|
break
|
|
141
|
-
|
|
166
|
+
|
|
142
167
|
time.sleep(poll_interval)
|
|
143
168
|
else:
|
|
144
|
-
raise TimeoutError(
|
|
145
|
-
|
|
169
|
+
raise TimeoutError(
|
|
170
|
+
f"Task did not complete within {max_wait_time} seconds"
|
|
171
|
+
)
|
|
172
|
+
|
|
146
173
|
table = Table(title="Video Generation Result")
|
|
147
174
|
table.add_column("Field", style="cyan")
|
|
148
175
|
table.add_column("Value", style="green")
|
|
149
|
-
|
|
176
|
+
|
|
150
177
|
table.add_row("Task ID", result.get("id", ""))
|
|
151
178
|
table.add_row("Status", result.get("status", ""))
|
|
152
|
-
|
|
179
|
+
|
|
153
180
|
if result.get("video_url"):
|
|
154
181
|
table.add_row("Video URL", result.get("video_url"))
|
|
155
182
|
if result.get("error_message"):
|
|
156
183
|
table.add_row("Error", result.get("error_message"))
|
|
157
|
-
|
|
184
|
+
|
|
158
185
|
console.print(table)
|
|
159
186
|
else:
|
|
160
|
-
console.print(
|
|
187
|
+
console.print(
|
|
188
|
+
f"\n[yellow]Use the following command to check status:[/yellow]"
|
|
189
|
+
)
|
|
161
190
|
console.print(f"coze-coding-ai video-status {task_id}")
|
|
162
|
-
|
|
191
|
+
|
|
163
192
|
if output:
|
|
164
193
|
with open(output, "w") as f:
|
|
165
194
|
json.dump(result, f, indent=2)
|
|
166
195
|
console.print(f"\n[green]✓[/green] Result saved to: {output}")
|
|
167
|
-
|
|
196
|
+
|
|
168
197
|
except Exception as e:
|
|
169
198
|
console.print(f"[red]✗ Error: {str(e)}[/red]")
|
|
170
199
|
raise click.Abort()
|
|
@@ -173,34 +202,44 @@ def video(
|
|
|
173
202
|
@click.command()
|
|
174
203
|
@click.argument("task_id")
|
|
175
204
|
@click.option("--output", "-o", type=click.Path(), help="Output file path (JSON)")
|
|
176
|
-
|
|
205
|
+
@click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行)")
|
|
206
|
+
def video_status(task_id: str, output: Optional[str], mock: bool):
|
|
177
207
|
"""Check video generation task status."""
|
|
178
208
|
try:
|
|
179
209
|
config = Config()
|
|
180
|
-
|
|
181
|
-
|
|
210
|
+
|
|
211
|
+
ctx = None
|
|
212
|
+
if mock:
|
|
213
|
+
ctx = Context(
|
|
214
|
+
request_id=f"mock-req-{int(time.time())}",
|
|
215
|
+
headers={RUN_MODE_HEADER: RUN_MODE_TEST},
|
|
216
|
+
)
|
|
217
|
+
console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
|
|
218
|
+
|
|
219
|
+
client = VideoGenerationClient(config, ctx=ctx)
|
|
220
|
+
|
|
182
221
|
task_result = client._get_task_status(task_id)
|
|
183
222
|
result = task_result.model_dump()
|
|
184
|
-
|
|
223
|
+
|
|
185
224
|
table = Table(title=f"Task Status: {task_id}")
|
|
186
225
|
table.add_column("Field", style="cyan")
|
|
187
226
|
table.add_column("Value", style="green")
|
|
188
|
-
|
|
227
|
+
|
|
189
228
|
table.add_row("Task ID", result.get("id", ""))
|
|
190
229
|
table.add_row("Status", result.get("status", ""))
|
|
191
|
-
|
|
230
|
+
|
|
192
231
|
if result.get("video_url"):
|
|
193
232
|
table.add_row("Video URL", result.get("video_url"))
|
|
194
233
|
if result.get("error_message"):
|
|
195
234
|
table.add_row("Error", result.get("error_message"))
|
|
196
|
-
|
|
235
|
+
|
|
197
236
|
console.print(table)
|
|
198
|
-
|
|
237
|
+
|
|
199
238
|
if output:
|
|
200
239
|
with open(output, "w") as f:
|
|
201
240
|
json.dump(result, f, indent=2)
|
|
202
241
|
console.print(f"\n[green]✓[/green] Result saved to: {output}")
|
|
203
|
-
|
|
242
|
+
|
|
204
243
|
except Exception as e:
|
|
205
244
|
console.print(f"[red]✗ Error: {str(e)}[/red]")
|
|
206
245
|
raise click.Abort()
|