seedream-cli 2026.3.17.0__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.
- seedream_cli/__init__.py +1 -0
- seedream_cli/__main__.py +5 -0
- seedream_cli/commands/__init__.py +1 -0
- seedream_cli/commands/image.py +123 -0
- seedream_cli/commands/info.py +48 -0
- seedream_cli/commands/task.py +142 -0
- seedream_cli/core/__init__.py +1 -0
- seedream_cli/core/client.py +111 -0
- seedream_cli/core/config.py +42 -0
- seedream_cli/core/exceptions.py +37 -0
- seedream_cli/core/output.py +140 -0
- seedream_cli/main.py +70 -0
- seedream_cli-2026.3.17.0.dist-info/METADATA +266 -0
- seedream_cli-2026.3.17.0.dist-info/RECORD +17 -0
- seedream_cli-2026.3.17.0.dist-info/WHEEL +4 -0
- seedream_cli-2026.3.17.0.dist-info/entry_points.txt +3 -0
- seedream_cli-2026.3.17.0.dist-info/licenses/LICENSE +21 -0
seedream_cli/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Seedream CLI - AI Seedream Image Generation via AceDataCloud API."""
|
seedream_cli/__main__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Seedream CLI command modules."""
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Image generation commands."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from seedream_cli.core.client import get_client
|
|
6
|
+
from seedream_cli.core.exceptions import SeedreamError
|
|
7
|
+
from seedream_cli.core.output import (
|
|
8
|
+
SEEDREAM_MODELS, DEFAULT_MODEL, print_error, print_json, print_image_result, RESOLUTIONS, DEFAULT_RESOLUTION,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.command()
|
|
13
|
+
@click.argument("prompt")
|
|
14
|
+
@click.option(
|
|
15
|
+
"-m",
|
|
16
|
+
"--model",
|
|
17
|
+
type=click.Choice(SEEDREAM_MODELS),
|
|
18
|
+
default=DEFAULT_MODEL,
|
|
19
|
+
help="Seedream model version.",
|
|
20
|
+
)
|
|
21
|
+
@click.option(
|
|
22
|
+
"-r",
|
|
23
|
+
"--resolution",
|
|
24
|
+
type=click.Choice(RESOLUTIONS),
|
|
25
|
+
default=None,
|
|
26
|
+
help="Output resolution.",
|
|
27
|
+
)
|
|
28
|
+
@click.option("--callback-url", default=None, help="Webhook callback URL.")
|
|
29
|
+
@click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
|
|
30
|
+
@click.pass_context
|
|
31
|
+
def generate(
|
|
32
|
+
ctx: click.Context,
|
|
33
|
+
prompt: str,
|
|
34
|
+
model: str,
|
|
35
|
+
resolution: str | None,
|
|
36
|
+
callback_url: str | None,
|
|
37
|
+
output_json: bool,
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Generate an image from a text prompt.
|
|
40
|
+
|
|
41
|
+
PROMPT is a detailed description of what to generate.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
|
|
45
|
+
seedream generate "A beautiful landscape painting"
|
|
46
|
+
|
|
47
|
+
seedream generate "A product photo" -m doubao-seedream-4-5-251128
|
|
48
|
+
"""
|
|
49
|
+
client = get_client(ctx.obj.get("token"))
|
|
50
|
+
try:
|
|
51
|
+
payload: dict[str, object] = {
|
|
52
|
+
"prompt": prompt,
|
|
53
|
+
"model": model,
|
|
54
|
+
"callback_url": callback_url,
|
|
55
|
+
}
|
|
56
|
+
if resolution:
|
|
57
|
+
payload["resolution"] = resolution
|
|
58
|
+
|
|
59
|
+
result = client.generate_image(**payload) # type: ignore[arg-type]
|
|
60
|
+
if output_json:
|
|
61
|
+
print_json(result)
|
|
62
|
+
else:
|
|
63
|
+
print_image_result(result)
|
|
64
|
+
except SeedreamError as e:
|
|
65
|
+
print_error(e.message)
|
|
66
|
+
raise SystemExit(1) from e
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@click.command()
|
|
70
|
+
@click.argument("prompt")
|
|
71
|
+
@click.option(
|
|
72
|
+
"-i",
|
|
73
|
+
"--image-url",
|
|
74
|
+
"image_urls",
|
|
75
|
+
required=True,
|
|
76
|
+
multiple=True,
|
|
77
|
+
help="Image URL(s) to edit. Can be specified multiple times.",
|
|
78
|
+
)
|
|
79
|
+
@click.option(
|
|
80
|
+
"-m",
|
|
81
|
+
"--model",
|
|
82
|
+
type=click.Choice(SEEDREAM_MODELS),
|
|
83
|
+
default=DEFAULT_MODEL,
|
|
84
|
+
help="Seedream model version.",
|
|
85
|
+
)
|
|
86
|
+
@click.option("--callback-url", default=None, help="Webhook callback URL.")
|
|
87
|
+
@click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
|
|
88
|
+
@click.pass_context
|
|
89
|
+
def edit(
|
|
90
|
+
ctx: click.Context,
|
|
91
|
+
prompt: str,
|
|
92
|
+
image_urls: tuple[str, ...],
|
|
93
|
+
model: str,
|
|
94
|
+
callback_url: str | None,
|
|
95
|
+
output_json: bool,
|
|
96
|
+
) -> None:
|
|
97
|
+
"""Edit or combine images using AI.
|
|
98
|
+
|
|
99
|
+
PROMPT describes the desired edit. Use with one or more image URLs.
|
|
100
|
+
|
|
101
|
+
Examples:
|
|
102
|
+
|
|
103
|
+
seedream edit "Convert to anime style" -i https://example.com/photo.jpg
|
|
104
|
+
|
|
105
|
+
seedream edit "Virtual try-on" -i person.jpg -i shirt.jpg
|
|
106
|
+
"""
|
|
107
|
+
client = get_client(ctx.obj.get("token"))
|
|
108
|
+
try:
|
|
109
|
+
result = client.edit_image(
|
|
110
|
+
action="edit",
|
|
111
|
+
prompt=prompt,
|
|
112
|
+
image_urls=list(image_urls),
|
|
113
|
+
model=model,
|
|
114
|
+
callback_url=callback_url,
|
|
115
|
+
)
|
|
116
|
+
if output_json:
|
|
117
|
+
print_json(result)
|
|
118
|
+
else:
|
|
119
|
+
print_image_result(result)
|
|
120
|
+
except SeedreamError as e:
|
|
121
|
+
print_error(e.message)
|
|
122
|
+
raise SystemExit(1) from e
|
|
123
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Info and utility commands."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from seedream_cli.core.config import settings
|
|
6
|
+
from seedream_cli.core.output import console, print_models
|
|
7
|
+
from seedream_cli.core.output import RESOLUTIONS
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.command()
|
|
11
|
+
def models() -> None:
|
|
12
|
+
"""List available Seedream models."""
|
|
13
|
+
print_models()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.command()
|
|
17
|
+
def resolutions() -> None:
|
|
18
|
+
"""List available output resolutions."""
|
|
19
|
+
from rich.table import Table
|
|
20
|
+
|
|
21
|
+
table = Table(title="Available Resolutions")
|
|
22
|
+
table.add_column("Resolution", style="bold cyan")
|
|
23
|
+
table.add_column("Description")
|
|
24
|
+
|
|
25
|
+
desc_map = {"480p": "Standard", "720p": "HD", "1080p": "Full HD", "1K": "Default", "2K": "High resolution", "4K": "Ultra-high resolution"}
|
|
26
|
+
for r in RESOLUTIONS:
|
|
27
|
+
table.add_row(r, desc_map.get(r, r))
|
|
28
|
+
|
|
29
|
+
console.print(table)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@click.command()
|
|
33
|
+
def config() -> None:
|
|
34
|
+
"""Show current configuration."""
|
|
35
|
+
from rich.table import Table
|
|
36
|
+
|
|
37
|
+
table = Table(title="Seedream CLI Configuration")
|
|
38
|
+
table.add_column("Setting", style="bold cyan")
|
|
39
|
+
table.add_column("Value")
|
|
40
|
+
|
|
41
|
+
table.add_row("API Base URL", settings.api_base_url)
|
|
42
|
+
table.add_row(
|
|
43
|
+
"API Token", f"{settings.api_token[:8]}..." if settings.api_token else "[red]Not set[/red]"
|
|
44
|
+
)
|
|
45
|
+
table.add_row("Default Model", settings.default_model)
|
|
46
|
+
table.add_row("Request Timeout", f"{settings.request_timeout}s")
|
|
47
|
+
|
|
48
|
+
console.print(table)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Task management commands."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from seedream_cli.core.client import get_client
|
|
8
|
+
from seedream_cli.core.exceptions import SeedreamError
|
|
9
|
+
from seedream_cli.core.output import print_error, print_json, print_success, print_task_result
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.command()
|
|
13
|
+
@click.argument("task_id")
|
|
14
|
+
@click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
|
|
15
|
+
@click.pass_context
|
|
16
|
+
def task(
|
|
17
|
+
ctx: click.Context,
|
|
18
|
+
task_id: str,
|
|
19
|
+
output_json: bool,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Query a single task status.
|
|
22
|
+
|
|
23
|
+
TASK_ID is the task ID returned from generate commands.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
|
|
27
|
+
seedream task abc123-def456
|
|
28
|
+
"""
|
|
29
|
+
client = get_client(ctx.obj.get("token"))
|
|
30
|
+
try:
|
|
31
|
+
result = client.query_task(id=task_id, action="retrieve")
|
|
32
|
+
if output_json:
|
|
33
|
+
print_json(result)
|
|
34
|
+
else:
|
|
35
|
+
print_task_result(result)
|
|
36
|
+
except SeedreamError as e:
|
|
37
|
+
print_error(e.message)
|
|
38
|
+
raise SystemExit(1) from e
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@click.command("tasks")
|
|
42
|
+
@click.argument("task_ids", nargs=-1, required=True)
|
|
43
|
+
@click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
|
|
44
|
+
@click.pass_context
|
|
45
|
+
def tasks_batch(
|
|
46
|
+
ctx: click.Context,
|
|
47
|
+
task_ids: tuple[str, ...],
|
|
48
|
+
output_json: bool,
|
|
49
|
+
) -> None:
|
|
50
|
+
"""Query multiple tasks at once.
|
|
51
|
+
|
|
52
|
+
TASK_IDS are space-separated task IDs.
|
|
53
|
+
|
|
54
|
+
Examples:
|
|
55
|
+
|
|
56
|
+
seedream tasks abc123 def456 ghi789
|
|
57
|
+
"""
|
|
58
|
+
client = get_client(ctx.obj.get("token"))
|
|
59
|
+
try:
|
|
60
|
+
result = client.query_task(ids=list(task_ids), action="retrieve_batch")
|
|
61
|
+
if output_json:
|
|
62
|
+
print_json(result)
|
|
63
|
+
else:
|
|
64
|
+
print_task_result(result)
|
|
65
|
+
except SeedreamError as e:
|
|
66
|
+
print_error(e.message)
|
|
67
|
+
raise SystemExit(1) from e
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@click.command()
|
|
71
|
+
@click.argument("task_id")
|
|
72
|
+
@click.option(
|
|
73
|
+
"--interval",
|
|
74
|
+
type=int,
|
|
75
|
+
default=5,
|
|
76
|
+
help="Polling interval in seconds (default: 5).",
|
|
77
|
+
)
|
|
78
|
+
@click.option(
|
|
79
|
+
"--timeout",
|
|
80
|
+
"max_timeout",
|
|
81
|
+
type=int,
|
|
82
|
+
default=600,
|
|
83
|
+
help="Maximum wait time in seconds (default: 600).",
|
|
84
|
+
)
|
|
85
|
+
@click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
|
|
86
|
+
@click.pass_context
|
|
87
|
+
def wait(
|
|
88
|
+
ctx: click.Context,
|
|
89
|
+
task_id: str,
|
|
90
|
+
interval: int,
|
|
91
|
+
max_timeout: int,
|
|
92
|
+
output_json: bool,
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Wait for a task to complete, polling periodically.
|
|
95
|
+
|
|
96
|
+
TASK_ID is the task ID to monitor.
|
|
97
|
+
|
|
98
|
+
Examples:
|
|
99
|
+
|
|
100
|
+
seedream wait abc123
|
|
101
|
+
|
|
102
|
+
seedream wait abc123 --interval 10 --timeout 300
|
|
103
|
+
"""
|
|
104
|
+
client = get_client(ctx.obj.get("token"))
|
|
105
|
+
elapsed = 0
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
while elapsed < max_timeout:
|
|
109
|
+
result = client.query_task(id=task_id, action="retrieve")
|
|
110
|
+
data = result.get("data", {})
|
|
111
|
+
|
|
112
|
+
# Check completion - handle both list and dict responses
|
|
113
|
+
if isinstance(data, list) and data:
|
|
114
|
+
item = data[0]
|
|
115
|
+
elif isinstance(data, dict):
|
|
116
|
+
item = data
|
|
117
|
+
else:
|
|
118
|
+
item = {}
|
|
119
|
+
|
|
120
|
+
state = item.get("state", item.get("status", ""))
|
|
121
|
+
if state in ("succeeded", "completed", "complete", "failed", "error"):
|
|
122
|
+
if output_json:
|
|
123
|
+
print_json(result)
|
|
124
|
+
else:
|
|
125
|
+
if state in ("failed", "error"):
|
|
126
|
+
print_error(f"Task {task_id} failed.")
|
|
127
|
+
else:
|
|
128
|
+
print_success(f"Task {task_id} completed!")
|
|
129
|
+
print_task_result(result)
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
if not output_json:
|
|
133
|
+
click.echo(f"Status: {state or 'pending'} (waited {elapsed}s)...", err=True)
|
|
134
|
+
|
|
135
|
+
time.sleep(interval)
|
|
136
|
+
elapsed += interval
|
|
137
|
+
|
|
138
|
+
print_error(f"Timeout: task {task_id} did not complete within {max_timeout}s")
|
|
139
|
+
raise SystemExit(1)
|
|
140
|
+
except SeedreamError as e:
|
|
141
|
+
print_error(e.message)
|
|
142
|
+
raise SystemExit(1) from e
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Seedream CLI core modules."""
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""HTTP client for Seedream API."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from seedream_cli.core.config import settings
|
|
8
|
+
from seedream_cli.core.exceptions import (
|
|
9
|
+
SeedreamAPIError,
|
|
10
|
+
SeedreamAuthError,
|
|
11
|
+
SeedreamTimeoutError,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SeedreamClient:
|
|
16
|
+
"""HTTP client for AceDataCloud Seedream API."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, api_token: str | None = None, base_url: str | None = None):
|
|
19
|
+
self.api_token = api_token if api_token is not None else settings.api_token
|
|
20
|
+
self.base_url = base_url or settings.api_base_url
|
|
21
|
+
self.timeout = settings.request_timeout
|
|
22
|
+
|
|
23
|
+
def _get_headers(self) -> dict[str, str]:
|
|
24
|
+
"""Get request headers with authentication."""
|
|
25
|
+
if not self.api_token:
|
|
26
|
+
raise SeedreamAuthError("API token not configured")
|
|
27
|
+
return {
|
|
28
|
+
"accept": "application/json",
|
|
29
|
+
"authorization": f"Bearer {self.api_token}",
|
|
30
|
+
"content-type": "application/json",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
def request(
|
|
34
|
+
self,
|
|
35
|
+
endpoint: str,
|
|
36
|
+
payload: dict[str, Any],
|
|
37
|
+
timeout: float | None = None,
|
|
38
|
+
) -> dict[str, Any]:
|
|
39
|
+
"""Make a POST request to the Seedream API.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
endpoint: API endpoint path
|
|
43
|
+
payload: Request body as dictionary
|
|
44
|
+
timeout: Optional timeout override
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
API response as dictionary
|
|
48
|
+
"""
|
|
49
|
+
url = f"{self.base_url}{endpoint}"
|
|
50
|
+
request_timeout = timeout or self.timeout
|
|
51
|
+
|
|
52
|
+
# Remove None values from payload
|
|
53
|
+
payload = {k: v for k, v in payload.items() if v is not None}
|
|
54
|
+
|
|
55
|
+
with httpx.Client() as http_client:
|
|
56
|
+
try:
|
|
57
|
+
response = http_client.post(
|
|
58
|
+
url,
|
|
59
|
+
json=payload,
|
|
60
|
+
headers=self._get_headers(),
|
|
61
|
+
timeout=request_timeout,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if response.status_code == 401:
|
|
65
|
+
raise SeedreamAuthError("Invalid API token")
|
|
66
|
+
|
|
67
|
+
if response.status_code == 403:
|
|
68
|
+
raise SeedreamAuthError("Access denied. Check your API permissions.")
|
|
69
|
+
|
|
70
|
+
response.raise_for_status()
|
|
71
|
+
return response.json() # type: ignore[no-any-return]
|
|
72
|
+
|
|
73
|
+
except httpx.TimeoutException as e:
|
|
74
|
+
raise SeedreamTimeoutError(
|
|
75
|
+
f"Request to {endpoint} timed out after {request_timeout}s"
|
|
76
|
+
) from e
|
|
77
|
+
|
|
78
|
+
except SeedreamAuthError:
|
|
79
|
+
raise
|
|
80
|
+
|
|
81
|
+
except httpx.HTTPStatusError as e:
|
|
82
|
+
raise SeedreamAPIError(
|
|
83
|
+
message=e.response.text,
|
|
84
|
+
code=f"http_{e.response.status_code}",
|
|
85
|
+
status_code=e.response.status_code,
|
|
86
|
+
) from e
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
if isinstance(e, (SeedreamAPIError, SeedreamTimeoutError)):
|
|
90
|
+
raise
|
|
91
|
+
raise SeedreamAPIError(message=str(e)) from e
|
|
92
|
+
|
|
93
|
+
# Convenience methods
|
|
94
|
+
def generate_image(self, **kwargs: Any) -> dict[str, Any]:
|
|
95
|
+
"""Generate image using the main endpoint."""
|
|
96
|
+
return self.request("/seedream/images", kwargs)
|
|
97
|
+
|
|
98
|
+
def edit_image(self, **kwargs: Any) -> dict[str, Any]:
|
|
99
|
+
"""Edit an image using the main endpoint."""
|
|
100
|
+
return self.request("/seedream/images", kwargs)
|
|
101
|
+
|
|
102
|
+
def query_task(self, **kwargs: Any) -> dict[str, Any]:
|
|
103
|
+
"""Query task status using the tasks endpoint."""
|
|
104
|
+
return self.request("/seedream/tasks", kwargs)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def get_client(token: str | None = None) -> SeedreamClient:
|
|
108
|
+
"""Get a SeedreamClient instance, optionally overriding the token."""
|
|
109
|
+
if token:
|
|
110
|
+
return SeedreamClient(api_token=token)
|
|
111
|
+
return SeedreamClient()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Configuration management for Seedream CLI."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
from dotenv import load_dotenv
|
|
7
|
+
|
|
8
|
+
load_dotenv()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class Settings:
|
|
13
|
+
"""Application settings loaded from environment variables."""
|
|
14
|
+
|
|
15
|
+
api_base_url: str = field(
|
|
16
|
+
default_factory=lambda: os.environ.get(
|
|
17
|
+
"ACEDATACLOUD_API_BASE_URL", "https://api.acedata.cloud"
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
api_token: str = field(default_factory=lambda: os.environ.get("ACEDATACLOUD_API_TOKEN", ""))
|
|
21
|
+
request_timeout: float = field(
|
|
22
|
+
default_factory=lambda: float(os.environ.get("SEEDREAM_REQUEST_TIMEOUT", "1800"))
|
|
23
|
+
)
|
|
24
|
+
default_model: str = field(
|
|
25
|
+
default_factory=lambda: os.environ.get("SEEDREAM_DEFAULT_MODEL", "doubao-seedream-4-0-250828")
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def is_configured(self) -> bool:
|
|
30
|
+
"""Check if the API token is configured."""
|
|
31
|
+
return bool(self.api_token)
|
|
32
|
+
|
|
33
|
+
def validate(self) -> None:
|
|
34
|
+
"""Validate configuration. Raises ValueError if API token is missing."""
|
|
35
|
+
if not self.api_token:
|
|
36
|
+
raise ValueError(
|
|
37
|
+
"API token not configured. "
|
|
38
|
+
"Set ACEDATACLOUD_API_TOKEN environment variable or use --token option."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
settings = Settings()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Custom exceptions for Seedream CLI."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SeedreamError(Exception):
|
|
5
|
+
"""Base exception for Seedream CLI."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, message: str, code: str = "unknown"):
|
|
8
|
+
self.message = message
|
|
9
|
+
self.code = code
|
|
10
|
+
super().__init__(message)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SeedreamAuthError(SeedreamError):
|
|
14
|
+
"""Authentication error."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, message: str = "Authentication failed"):
|
|
17
|
+
super().__init__(message, code="auth_error")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SeedreamAPIError(SeedreamError):
|
|
21
|
+
"""API error with HTTP status code."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
message: str = "API request failed",
|
|
26
|
+
code: str = "api_error",
|
|
27
|
+
status_code: int | None = None,
|
|
28
|
+
):
|
|
29
|
+
self.status_code = status_code
|
|
30
|
+
super().__init__(message, code)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SeedreamTimeoutError(SeedreamError):
|
|
34
|
+
"""Request timeout error."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, message: str = "Request timed out"):
|
|
37
|
+
super().__init__(message, code="timeout_error")
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Rich terminal output formatting for Seedream CLI."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
12
|
+
# Available models
|
|
13
|
+
SEEDREAM_MODELS = [
|
|
14
|
+
"doubao-seedream-4-5-251128",
|
|
15
|
+
"doubao-seedream-4-0-250828",
|
|
16
|
+
"doubao-seedream-3-0-t2i-250415",
|
|
17
|
+
"doubao-seededit-3-0-i2i-250628",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
DEFAULT_MODEL = "doubao-seedream-4-0-250828"
|
|
21
|
+
|
|
22
|
+
# Available resolutions
|
|
23
|
+
RESOLUTIONS = [
|
|
24
|
+
"1K",
|
|
25
|
+
"2K",
|
|
26
|
+
"4K",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
DEFAULT_RESOLUTION = "1K"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def print_json(data: Any) -> None:
|
|
33
|
+
"""Print data as formatted JSON."""
|
|
34
|
+
console.print(json.dumps(data, indent=2, ensure_ascii=False))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def print_error(message: str) -> None:
|
|
38
|
+
"""Print an error message."""
|
|
39
|
+
console.print(f"[bold red]Error:[/bold red] {message}")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def print_success(message: str) -> None:
|
|
43
|
+
"""Print a success message."""
|
|
44
|
+
console.print(f"[bold green]✓[/bold green] {message}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def print_image_result(data: dict[str, Any]) -> None:
|
|
48
|
+
"""Print image generation result in a rich format."""
|
|
49
|
+
task_id = data.get("task_id", "N/A")
|
|
50
|
+
trace_id = data.get("trace_id", "N/A")
|
|
51
|
+
items = data.get("data", [])
|
|
52
|
+
|
|
53
|
+
console.print(
|
|
54
|
+
Panel(
|
|
55
|
+
f"[bold]Task ID:[/bold] {task_id}\n[bold]Trace ID:[/bold] {trace_id}",
|
|
56
|
+
title="[bold green]Image Result[/bold green]",
|
|
57
|
+
border_style="green",
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if not items:
|
|
62
|
+
console.print("[yellow]No data available yet. Use 'task' to check status.[/yellow]")
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
if isinstance(items, list):
|
|
66
|
+
for i, item in enumerate(items, 1):
|
|
67
|
+
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
68
|
+
table.add_column("Field", style="bold cyan", width=15)
|
|
69
|
+
table.add_column("Value")
|
|
70
|
+
table.add_row("Image", f"#{i}")
|
|
71
|
+
if item.get("image_url"):
|
|
72
|
+
table.add_row("URL", item["image_url"])
|
|
73
|
+
if item.get("state"):
|
|
74
|
+
table.add_row("State", item["state"])
|
|
75
|
+
if item.get("model_name"):
|
|
76
|
+
table.add_row("Model", item["model_name"])
|
|
77
|
+
if item.get("created_at"):
|
|
78
|
+
table.add_row("Created", item["created_at"])
|
|
79
|
+
console.print(table)
|
|
80
|
+
console.print()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def print_task_result(data: dict[str, Any]) -> None:
|
|
84
|
+
"""Print task query result in a rich format."""
|
|
85
|
+
tasks = data.get("data", [])
|
|
86
|
+
|
|
87
|
+
if isinstance(tasks, list):
|
|
88
|
+
for task_data in tasks:
|
|
89
|
+
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
90
|
+
table.add_column("Field", style="bold cyan", width=15)
|
|
91
|
+
table.add_column("Value")
|
|
92
|
+
|
|
93
|
+
for key in ["id", "status", "state", "image_url", "model_name", "created_at"]:
|
|
94
|
+
if task_data.get(key):
|
|
95
|
+
table.add_row(key.replace("_", " ").title(), str(task_data[key]))
|
|
96
|
+
|
|
97
|
+
console.print(table)
|
|
98
|
+
console.print()
|
|
99
|
+
elif isinstance(tasks, dict):
|
|
100
|
+
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
101
|
+
table.add_column("Field", style="bold cyan", width=15)
|
|
102
|
+
table.add_column("Value")
|
|
103
|
+
|
|
104
|
+
for key in ["id", "status", "state", "image_url", "model_name", "created_at"]:
|
|
105
|
+
if tasks.get(key):
|
|
106
|
+
table.add_row(key.replace("_", " ").title(), str(tasks[key]))
|
|
107
|
+
|
|
108
|
+
console.print(table)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def print_models() -> None:
|
|
112
|
+
"""Print available Seedream models."""
|
|
113
|
+
table = Table(title="Available Seedream Models")
|
|
114
|
+
table.add_column("Model", style="bold cyan")
|
|
115
|
+
table.add_column("Version", style="bold")
|
|
116
|
+
table.add_column("Notes")
|
|
117
|
+
|
|
118
|
+
table.add_row(
|
|
119
|
+
"doubao-seedream-4-5-251128",
|
|
120
|
+
"V4.5",
|
|
121
|
+
"Flagship model, best quality",
|
|
122
|
+
)
|
|
123
|
+
table.add_row(
|
|
124
|
+
"doubao-seedream-4-0-250828",
|
|
125
|
+
"V4.0",
|
|
126
|
+
"Standard quality (default)",
|
|
127
|
+
)
|
|
128
|
+
table.add_row(
|
|
129
|
+
"doubao-seedream-3-0-t2i-250415",
|
|
130
|
+
"V3.0 T2I",
|
|
131
|
+
"Text-to-image generation",
|
|
132
|
+
)
|
|
133
|
+
table.add_row(
|
|
134
|
+
"doubao-seededit-3-0-i2i-250628",
|
|
135
|
+
"V3.0 I2I",
|
|
136
|
+
"Image-to-image editing",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
console.print(table)
|
|
140
|
+
console.print(f"\n[dim]Default model: {DEFAULT_MODEL}[/dim]")
|
seedream_cli/main.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Seedream CLI - AI Seedream Image Generation via AceDataCloud API.
|
|
4
|
+
|
|
5
|
+
A command-line tool for generating AI images using Seedream
|
|
6
|
+
through the AceDataCloud platform.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from importlib import metadata
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from dotenv import load_dotenv
|
|
13
|
+
|
|
14
|
+
from seedream_cli.commands.image import edit, generate
|
|
15
|
+
from seedream_cli.commands.task import task, tasks_batch, wait
|
|
16
|
+
from seedream_cli.commands.info import models, config, resolutions
|
|
17
|
+
|
|
18
|
+
load_dotenv()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_version() -> str:
|
|
22
|
+
"""Get the package version."""
|
|
23
|
+
try:
|
|
24
|
+
return metadata.version("seedream-cli")
|
|
25
|
+
except metadata.PackageNotFoundError:
|
|
26
|
+
return "dev"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@click.group()
|
|
30
|
+
@click.version_option(version=get_version(), prog_name="seedream-cli")
|
|
31
|
+
@click.option(
|
|
32
|
+
"--token",
|
|
33
|
+
envvar="ACEDATACLOUD_API_TOKEN",
|
|
34
|
+
help="API token (or set ACEDATACLOUD_API_TOKEN env var).",
|
|
35
|
+
)
|
|
36
|
+
@click.pass_context
|
|
37
|
+
def cli(ctx: click.Context, token: str | None) -> None:
|
|
38
|
+
"""Seedream CLI - AI Image Generation powered by AceDataCloud.
|
|
39
|
+
|
|
40
|
+
Generate AI images from the command line.
|
|
41
|
+
|
|
42
|
+
Get your API token at https://platform.acedata.cloud
|
|
43
|
+
|
|
44
|
+
\b
|
|
45
|
+
Examples:
|
|
46
|
+
seedream generate "A beautiful landscape painting"
|
|
47
|
+
seedream edit "Make it look like a painting" -i photo.jpg
|
|
48
|
+
seedream task abc123-def456
|
|
49
|
+
seedream wait abc123 --interval 5
|
|
50
|
+
|
|
51
|
+
Set your token:
|
|
52
|
+
export ACEDATACLOUD_API_TOKEN=your_token
|
|
53
|
+
"""
|
|
54
|
+
ctx.ensure_object(dict)
|
|
55
|
+
ctx.obj["token"] = token
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Register commands
|
|
59
|
+
cli.add_command(generate)
|
|
60
|
+
cli.add_command(edit)
|
|
61
|
+
cli.add_command(task)
|
|
62
|
+
cli.add_command(tasks_batch)
|
|
63
|
+
cli.add_command(wait)
|
|
64
|
+
cli.add_command(models)
|
|
65
|
+
cli.add_command(config)
|
|
66
|
+
cli.add_command(resolutions)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
cli()
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: seedream-cli
|
|
3
|
+
Version: 2026.3.17.0
|
|
4
|
+
Summary: CLI tool for Seedream AI Image Generation via AceDataCloud API
|
|
5
|
+
Project-URL: Homepage, https://github.com/AceDataCloud/SeedreamCli
|
|
6
|
+
Project-URL: Repository, https://github.com/AceDataCloud/SeedreamCli
|
|
7
|
+
Project-URL: Issues, https://github.com/AceDataCloud/SeedreamCli/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/AceDataCloud/SeedreamCli/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: AceDataCloud <support@acedata.cloud>
|
|
10
|
+
Maintainer-email: AceDataCloud <support@acedata.cloud>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: acedata,ai,cli,command-line,generation,image,seedream
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: click>=8.1.0
|
|
27
|
+
Requires-Dist: httpx>=0.27.0
|
|
28
|
+
Requires-Dist: pydantic>=2.0.0
|
|
29
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
30
|
+
Requires-Dist: rich>=13.0.0
|
|
31
|
+
Provides-Extra: all
|
|
32
|
+
Requires-Dist: seedream-cli[dev,release,test]; extra == 'all'
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
37
|
+
Provides-Extra: release
|
|
38
|
+
Requires-Dist: build>=1.2.0; extra == 'release'
|
|
39
|
+
Requires-Dist: twine>=6.1.0; extra == 'release'
|
|
40
|
+
Provides-Extra: test
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
|
|
42
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
|
|
43
|
+
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
44
|
+
Requires-Dist: respx>=0.21.0; extra == 'test'
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
# Seedream CLI
|
|
48
|
+
|
|
49
|
+
[](https://pypi.org/project/seedream-cli/)
|
|
50
|
+
[](https://pypi.org/project/seedream-cli/)
|
|
51
|
+
[](https://www.python.org/downloads/)
|
|
52
|
+
[](https://opensource.org/licenses/MIT)
|
|
53
|
+
[](https://github.com/AceDataCloud/SeedreamCli/actions/workflows/ci.yaml)
|
|
54
|
+
|
|
55
|
+
A command-line tool for AI image generation using [Seedream](https://platform.acedata.cloud/) through the [AceDataCloud API](https://platform.acedata.cloud/).
|
|
56
|
+
|
|
57
|
+
Generate AI images directly from your terminal — no MCP client required.
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
- **Image Generation** — Generate images from text prompts with multiple models
|
|
62
|
+
- **Image Editing** — Edit, combine, and transform images with AI
|
|
63
|
+
- **Multiple Models** — doubao-seedream-4-5-251128, doubao-seedream-4-0-250828, doubao-seedream-3-0-t2i-250415, doubao-seededit-3-0-i2i-250628
|
|
64
|
+
- **Task Management** — Query tasks, batch query, wait with polling
|
|
65
|
+
- **Rich Output** — Beautiful terminal tables and panels via Rich
|
|
66
|
+
- **JSON Mode** — Machine-readable output with `--json` for piping
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
### 1. Get API Token
|
|
71
|
+
|
|
72
|
+
Get your API token from [AceDataCloud Platform](https://platform.acedata.cloud/):
|
|
73
|
+
|
|
74
|
+
1. Sign up or log in
|
|
75
|
+
2. Navigate to the Seedream API page
|
|
76
|
+
3. Click "Acquire" to get your token
|
|
77
|
+
|
|
78
|
+
### 2. Install
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Install with pip
|
|
82
|
+
pip install seedream-cli
|
|
83
|
+
|
|
84
|
+
# Or with uv (recommended)
|
|
85
|
+
uv pip install seedream-cli
|
|
86
|
+
|
|
87
|
+
# Or from source
|
|
88
|
+
git clone https://github.com/AceDataCloud/SeedreamCli.git
|
|
89
|
+
cd SeedreamCli
|
|
90
|
+
pip install -e .
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Configure
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Set your API token
|
|
97
|
+
export ACEDATACLOUD_API_TOKEN=your_token_here
|
|
98
|
+
|
|
99
|
+
# Or use .env file
|
|
100
|
+
cp .env.example .env
|
|
101
|
+
# Edit .env with your token
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 4. Use
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Generate an image
|
|
108
|
+
seedream generate "A test image"
|
|
109
|
+
|
|
110
|
+
# Edit an image
|
|
111
|
+
seedream edit "Make it look like a painting" -i https://example.com/photo.jpg
|
|
112
|
+
|
|
113
|
+
# Check task status
|
|
114
|
+
seedream task <task-id>
|
|
115
|
+
|
|
116
|
+
# Wait for completion
|
|
117
|
+
seedream wait <task-id> --interval 5
|
|
118
|
+
|
|
119
|
+
# List available models
|
|
120
|
+
seedream models
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Commands
|
|
124
|
+
|
|
125
|
+
| Command | Description |
|
|
126
|
+
|---------|-------------|
|
|
127
|
+
| `seedream generate <prompt>` | Generate an image from a text prompt |
|
|
128
|
+
| `seedream edit <prompt> -i <url>...` | Edit or combine images using AI |
|
|
129
|
+
| `seedream task <task_id>` | Query a single task status |
|
|
130
|
+
| `seedream tasks <id1> <id2>...` | Query multiple tasks at once |
|
|
131
|
+
| `seedream wait <task_id>` | Wait for task completion with polling |
|
|
132
|
+
| `seedream models` | List available Seedream models |
|
|
133
|
+
| `seedream config` | Show current configuration |
|
|
134
|
+
| `seedream resolutions` | List available output resolutions |
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
## Global Options
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
--token TEXT API token (or set ACEDATACLOUD_API_TOKEN env var)
|
|
141
|
+
--version Show version
|
|
142
|
+
--help Show help message
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Most commands support:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
--json Output raw JSON (for piping/scripting)
|
|
149
|
+
--model TEXT Seedream model version (default: doubao-seedream-4-0-250828)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Available Models
|
|
153
|
+
|
|
154
|
+
| Model | Version | Notes |
|
|
155
|
+
|-------|---------|-------|
|
|
156
|
+
| `doubao-seedream-4-5-251128` | V4.5 | Flagship model, best quality |
|
|
157
|
+
| `doubao-seedream-4-0-250828` | V4.0 | Standard quality (default) |
|
|
158
|
+
| `doubao-seedream-3-0-t2i-250415` | V3.0 T2I | Text-to-image generation |
|
|
159
|
+
| `doubao-seededit-3-0-i2i-250628` | V3.0 I2I | Image-to-image editing |
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
### Environment Variables
|
|
165
|
+
|
|
166
|
+
| Variable | Description | Default |
|
|
167
|
+
|----------|-------------|---------|
|
|
168
|
+
| `ACEDATACLOUD_API_TOKEN` | API token from AceDataCloud | *Required* |
|
|
169
|
+
| `ACEDATACLOUD_API_BASE_URL` | API base URL | `https://api.acedata.cloud` |
|
|
170
|
+
| `SEEDREAM_DEFAULT_MODEL` | Default model | `doubao-seedream-4-0-250828` |
|
|
171
|
+
| `SEEDREAM_REQUEST_TIMEOUT` | Timeout in seconds | `1800` |
|
|
172
|
+
|
|
173
|
+
## Development
|
|
174
|
+
|
|
175
|
+
### Setup Development Environment
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
git clone https://github.com/AceDataCloud/SeedreamCli.git
|
|
179
|
+
cd SeedreamCli
|
|
180
|
+
python -m venv .venv
|
|
181
|
+
source .venv/bin/activate
|
|
182
|
+
pip install -e ".[dev,test]"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Run Tests
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
pytest
|
|
189
|
+
pytest --cov=seedream_cli
|
|
190
|
+
pytest tests/test_integration.py -m integration
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Code Quality
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
ruff format .
|
|
197
|
+
ruff check .
|
|
198
|
+
mypy seedream_cli
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Docker
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
docker pull ghcr.io/acedatacloud/seedream-cli:latest
|
|
205
|
+
docker run --rm -e ACEDATACLOUD_API_TOKEN=your_token \
|
|
206
|
+
ghcr.io/acedatacloud/seedream-cli generate "A test image"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Project Structure
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
SeedreamCli/
|
|
213
|
+
├── seedream_cli/ # Main package
|
|
214
|
+
│ ├── __init__.py
|
|
215
|
+
│ ├── __main__.py # python -m seedream_cli entry point
|
|
216
|
+
│ ├── main.py # CLI entry point
|
|
217
|
+
│ ├── core/ # Core modules
|
|
218
|
+
│ │ ├── client.py # HTTP client for Seedream API
|
|
219
|
+
│ │ ├── config.py # Configuration management
|
|
220
|
+
│ │ ├── exceptions.py # Custom exceptions
|
|
221
|
+
│ │ └── output.py # Rich terminal formatting
|
|
222
|
+
│ └── commands/ # CLI command groups
|
|
223
|
+
│ ├── image.py # Image generation commands
|
|
224
|
+
│ ├── task.py # Task management commands
|
|
225
|
+
│ └── info.py # Info & utility commands
|
|
226
|
+
├── tests/ # Test suite
|
|
227
|
+
├── .github/workflows/ # CI/CD (lint, test, publish to PyPI)
|
|
228
|
+
├── Dockerfile # Container image
|
|
229
|
+
├── deploy/ # Kubernetes deployment configs
|
|
230
|
+
├── .env.example # Environment template
|
|
231
|
+
├── pyproject.toml # Project configuration
|
|
232
|
+
└── README.md
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Seedream CLI vs MCP Seedream
|
|
236
|
+
|
|
237
|
+
| Feature | Seedream CLI | MCP Seedream |
|
|
238
|
+
|---------|-----------|-----------|
|
|
239
|
+
| Interface | Terminal commands | MCP protocol |
|
|
240
|
+
| Usage | Direct shell, scripts, CI/CD | Claude, VS Code, MCP clients |
|
|
241
|
+
| Output | Rich tables / JSON | Structured MCP responses |
|
|
242
|
+
| Automation | Shell scripts, piping | AI agent workflows |
|
|
243
|
+
| Install | `pip install seedream-cli` | `pip install mcp-seedream` |
|
|
244
|
+
|
|
245
|
+
Both tools use the same AceDataCloud API and share the same API token.
|
|
246
|
+
|
|
247
|
+
## Contributing
|
|
248
|
+
|
|
249
|
+
Contributions are welcome! Please:
|
|
250
|
+
|
|
251
|
+
1. Fork the repository
|
|
252
|
+
2. Create a feature branch (`git checkout -b feature/amazing`)
|
|
253
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
254
|
+
4. Push to the branch (`git push origin feature/amazing`)
|
|
255
|
+
5. Open a Pull Request
|
|
256
|
+
|
|
257
|
+
### Development Requirements
|
|
258
|
+
|
|
259
|
+
- Python 3.10+
|
|
260
|
+
- Dependencies: `pip install -e ".[all]"`
|
|
261
|
+
- Lint: `ruff check . && ruff format --check .`
|
|
262
|
+
- Test: `pytest`
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
seedream_cli/__init__.py,sha256=5xdUANJJr9OW5WiBo4YPaUEJ2Ez1rNKvT-QnZGNDBkI,72
|
|
2
|
+
seedream_cli/__main__.py,sha256=t0BOcDkNiauczAA1ew8OCLjuM1IBuf_Ci3UO4mlx6T0,89
|
|
3
|
+
seedream_cli/main.py,sha256=4ZjqK5B81TPN48Thf4LdAONDhiApKGW3V5Evuj3j4Yk,1731
|
|
4
|
+
seedream_cli/commands/__init__.py,sha256=MWNlas-BWL_-94n1vx3XTdE-iX4undsECbwSFfyzHsY,36
|
|
5
|
+
seedream_cli/commands/image.py,sha256=zMcD3YRhlek0uVniUC-vqBP0lsYGLohnE99y5dl_YxY,3222
|
|
6
|
+
seedream_cli/commands/info.py,sha256=-mlpRRjcweacTiFW_JFM6po08gb_skgPDoRqxUaqfNc,1394
|
|
7
|
+
seedream_cli/commands/task.py,sha256=sFtQLjP_L5eziYdjGLYq3Z3NaeObRT39ksnbL3QOWHs,3877
|
|
8
|
+
seedream_cli/core/__init__.py,sha256=zyGhr4_lJcLwZIZl7ChZVUroNiWnmKNuQ7DwfBqZVns,33
|
|
9
|
+
seedream_cli/core/client.py,sha256=Ls4Q6xtBJ6KqNyaTLOBWxhKrrOa9pFOW67v5GNIkT9s,3732
|
|
10
|
+
seedream_cli/core/config.py,sha256=1rQvWrwTtn_V66DvwBtTD4cQLbteHarqMzYEFKYWTug,1265
|
|
11
|
+
seedream_cli/core/exceptions.py,sha256=IgmIepFLIfzwoUp5a5KcwmCAKozo9-CVgCb7B6ytEac,979
|
|
12
|
+
seedream_cli/core/output.py,sha256=p4S9CHoEikPlIRryXc-7LVT2PMqsitsDiVY_uGSYLtc,4186
|
|
13
|
+
seedream_cli-2026.3.17.0.dist-info/METADATA,sha256=nuWVxzDNqrb1329J8ysowvlDGmNzvOlfKVFp1llBcIo,8797
|
|
14
|
+
seedream_cli-2026.3.17.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
|
|
15
|
+
seedream_cli-2026.3.17.0.dist-info/entry_points.txt,sha256=zVLkxIXbBE_IMWYQHnc06U9JAXnfhqsAV1W6zmjeYSg,88
|
|
16
|
+
seedream_cli-2026.3.17.0.dist-info/licenses/LICENSE,sha256=bxZ4efJS6INmQdLVfyxLQXtLCEaj-ORFNew2MaGiZ8E,1069
|
|
17
|
+
seedream_cli-2026.3.17.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AceDataCloud
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|