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.
@@ -0,0 +1 @@
1
+ """Seedream CLI - AI Seedream Image Generation via AceDataCloud API."""
@@ -0,0 +1,5 @@
1
+ """Allow running as python -m seedream_cli."""
2
+
3
+ from seedream_cli.main import cli
4
+
5
+ cli()
@@ -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
+ [![PyPI version](https://img.shields.io/pypi/v/seedream-cli.svg)](https://pypi.org/project/seedream-cli/)
50
+ [![PyPI downloads](https://img.shields.io/pypi/dm/seedream-cli.svg)](https://pypi.org/project/seedream-cli/)
51
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
52
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
53
+ [![CI](https://github.com/AceDataCloud/SeedreamCli/actions/workflows/ci.yaml/badge.svg)](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,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.21.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ seedream = seedream_cli.main:cli
3
+ seedream-cli = seedream_cli.main:cli
@@ -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.