hailuo-cli 2026.7.31.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.
hailuo_cli/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """Hailuo CLI - AI Video Generation via AceDataCloud API."""
hailuo_cli/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Allow running as python -m hailuo_cli."""
2
+
3
+ from hailuo_cli.main import cli
4
+
5
+ cli()
@@ -0,0 +1 @@
1
+ """Commands package for Hailuo CLI."""
@@ -0,0 +1,30 @@
1
+ """Info and utility commands."""
2
+
3
+ import click
4
+
5
+ from hailuo_cli.core.config import settings
6
+ from hailuo_cli.core.output import console, print_models
7
+
8
+
9
+ @click.command()
10
+ def models() -> None:
11
+ """List available Hailuo models."""
12
+ print_models()
13
+
14
+
15
+ @click.command()
16
+ def config() -> None:
17
+ """Show current configuration."""
18
+ from rich.table import Table
19
+
20
+ table = Table(title="Hailuo CLI Configuration")
21
+ table.add_column("Setting", style="bold cyan")
22
+ table.add_column("Value")
23
+
24
+ table.add_row("API Base URL", settings.api_base_url)
25
+ table.add_row(
26
+ "API Token", f"{settings.api_token[:8]}..." if settings.api_token else "[red]Not set[/red]"
27
+ )
28
+ table.add_row("Request Timeout", f"{settings.request_timeout}s")
29
+
30
+ console.print(table)
@@ -0,0 +1,160 @@
1
+ """Task management commands."""
2
+
3
+ import time
4
+
5
+ import click
6
+
7
+ from hailuo_cli.core.client import get_client
8
+ from hailuo_cli.core.exceptions import HailuoError
9
+ from hailuo_cli.core.output import (
10
+ print_error,
11
+ print_json,
12
+ print_success,
13
+ print_task_result,
14
+ )
15
+
16
+
17
+ @click.command()
18
+ @click.argument("task_id")
19
+ @click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
20
+ @click.pass_context
21
+ def task(
22
+ ctx: click.Context,
23
+ task_id: str,
24
+ output_json: bool,
25
+ ) -> None:
26
+ """Query a single task status.
27
+
28
+ TASK_ID is the task ID returned from generate commands.
29
+
30
+ \b
31
+ Examples:
32
+ hailuo task abc123-def456
33
+ """
34
+ client = get_client(ctx.obj.get("token"))
35
+ try:
36
+ result = client.query_task(id=task_id, action="retrieve")
37
+ if output_json:
38
+ print_json(result)
39
+ else:
40
+ print_task_result(result)
41
+ except HailuoError as e:
42
+ print_error(e.message)
43
+ raise SystemExit(1) from e
44
+
45
+
46
+ @click.command("tasks")
47
+ @click.argument("task_ids", nargs=-1, required=True)
48
+ @click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
49
+ @click.pass_context
50
+ def tasks_batch(
51
+ ctx: click.Context,
52
+ task_ids: tuple[str, ...],
53
+ output_json: bool,
54
+ ) -> None:
55
+ """Query multiple tasks at once.
56
+
57
+ TASK_IDS are space-separated task IDs.
58
+
59
+ \b
60
+ Examples:
61
+ hailuo tasks abc123 def456 ghi789
62
+ """
63
+ client = get_client(ctx.obj.get("token"))
64
+ try:
65
+ result = client.query_task(ids=list(task_ids), action="retrieve_batch")
66
+ if output_json:
67
+ print_json(result)
68
+ else:
69
+ print_task_result(result)
70
+ except HailuoError as e:
71
+ print_error(e.message)
72
+ raise SystemExit(1) from e
73
+
74
+
75
+ @click.command()
76
+ @click.argument("task_id")
77
+ @click.option(
78
+ "--interval",
79
+ type=int,
80
+ default=5,
81
+ help="Polling interval in seconds (default: 5).",
82
+ )
83
+ @click.option(
84
+ "--timeout",
85
+ "max_timeout",
86
+ type=int,
87
+ default=600,
88
+ help="Maximum wait time in seconds (default: 600).",
89
+ )
90
+ @click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
91
+ @click.pass_context
92
+ def wait(
93
+ ctx: click.Context,
94
+ task_id: str,
95
+ interval: int,
96
+ max_timeout: int,
97
+ output_json: bool,
98
+ ) -> None:
99
+ """Wait for a task to complete, polling periodically.
100
+
101
+ TASK_ID is the task ID to monitor.
102
+
103
+ \b
104
+ Examples:
105
+ hailuo wait abc123
106
+ hailuo wait abc123 --interval 10 --timeout 300
107
+ """
108
+ client = get_client(ctx.obj.get("token"))
109
+ elapsed = 0
110
+
111
+ try:
112
+ while elapsed < max_timeout:
113
+ result = client.query_task(id=task_id, action="retrieve")
114
+
115
+ # Check for completion signals
116
+ data = result.get("data", result)
117
+ if isinstance(data, dict):
118
+ item = data
119
+ elif isinstance(data, list) and data:
120
+ item = data[0]
121
+ else:
122
+ item = result
123
+
124
+ state = item.get("state", item.get("status", ""))
125
+ video_url = item.get("video_url") or result.get("video_url")
126
+ error = item.get("error") or result.get("error")
127
+
128
+ if error:
129
+ if output_json:
130
+ print_json(result)
131
+ else:
132
+ print_error(f"Task {task_id} failed: {error}")
133
+ raise SystemExit(1)
134
+
135
+ if state in ("succeeded", "completed", "complete") or video_url:
136
+ if output_json:
137
+ print_json(result)
138
+ else:
139
+ print_success(f"Task {task_id} completed!")
140
+ print_task_result(result)
141
+ return
142
+
143
+ if state in ("failed", "error"):
144
+ if output_json:
145
+ print_json(result)
146
+ else:
147
+ print_error(f"Task {task_id} failed.")
148
+ raise SystemExit(1)
149
+
150
+ if not output_json:
151
+ click.echo(f"Status: {state or 'pending'} (waited {elapsed}s)...", err=True)
152
+
153
+ time.sleep(interval)
154
+ elapsed += interval
155
+
156
+ print_error(f"Timeout: task {task_id} did not complete within {max_timeout}s")
157
+ raise SystemExit(1)
158
+ except HailuoError as e:
159
+ print_error(e.message)
160
+ raise SystemExit(1) from e
@@ -0,0 +1,128 @@
1
+ """Video generation commands."""
2
+
3
+ import click
4
+
5
+ from hailuo_cli.core.client import get_client
6
+ from hailuo_cli.core.exceptions import HailuoError
7
+ from hailuo_cli.core.output import (
8
+ DEFAULT_MODEL,
9
+ HAILUO_MODELS,
10
+ print_error,
11
+ print_json,
12
+ print_video_result,
13
+ )
14
+
15
+
16
+ @click.command()
17
+ @click.argument("prompt")
18
+ @click.option(
19
+ "-m",
20
+ "--model",
21
+ type=click.Choice(HAILUO_MODELS),
22
+ default=DEFAULT_MODEL,
23
+ help="Hailuo model to use (default: minimax-t2v).",
24
+ )
25
+ @click.option("--callback-url", default=None, help="Webhook callback URL.")
26
+ @click.option(
27
+ "--async",
28
+ "async_mode",
29
+ is_flag=True,
30
+ default=False,
31
+ help="Submit asynchronously; returns a task_id to poll instead of waiting.",
32
+ )
33
+ @click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
34
+ @click.pass_context
35
+ def generate(
36
+ ctx: click.Context,
37
+ prompt: str,
38
+ model: str,
39
+ callback_url: str | None,
40
+ async_mode: bool,
41
+ output_json: bool,
42
+ ) -> None:
43
+ """Generate a video from a text prompt.
44
+
45
+ PROMPT is a detailed description of what to generate.
46
+
47
+ \b
48
+ Examples:
49
+ hailuo generate "A cat playing in the snow"
50
+ hailuo generate "Ocean waves at sunset" --model minimax-t2v
51
+ """
52
+ client = get_client(ctx.obj.get("token"))
53
+ try:
54
+ payload: dict[str, object] = {
55
+ "action": "generate",
56
+ "prompt": prompt,
57
+ "model": model,
58
+ "callback_url": callback_url,
59
+ "async": async_mode,
60
+ }
61
+
62
+ result = client.generate_video(**payload) # type: ignore[arg-type]
63
+ if output_json:
64
+ print_json(result)
65
+ else:
66
+ print_video_result(result)
67
+ except HailuoError as e:
68
+ print_error(e.message)
69
+ raise SystemExit(1) from e
70
+
71
+
72
+ @click.command("image-to-video")
73
+ @click.argument("prompt")
74
+ @click.option("--image-url", required=True, help="URL of the first frame reference image.")
75
+ @click.option(
76
+ "-m",
77
+ "--model",
78
+ type=click.Choice(["minimax-i2v", "minimax-t2v", "minimax-i2v-director"]),
79
+ default="minimax-i2v",
80
+ help="Hailuo image-to-video model (default: minimax-i2v).",
81
+ )
82
+ @click.option("--callback-url", default=None, help="Webhook callback URL.")
83
+ @click.option(
84
+ "--async",
85
+ "async_mode",
86
+ is_flag=True,
87
+ default=False,
88
+ help="Submit asynchronously; returns a task_id to poll instead of waiting.",
89
+ )
90
+ @click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
91
+ @click.pass_context
92
+ def image_to_video(
93
+ ctx: click.Context,
94
+ prompt: str,
95
+ image_url: str,
96
+ model: str,
97
+ callback_url: str | None,
98
+ async_mode: bool,
99
+ output_json: bool,
100
+ ) -> None:
101
+ """Generate a video from an image and text prompt.
102
+
103
+ PROMPT describes the desired video content.
104
+
105
+ \b
106
+ Examples:
107
+ hailuo image-to-video "Animate this scene" --image-url https://example.com/photo.jpg
108
+ hailuo image-to-video "Cinematic pan" --image-url img.jpg --model minimax-i2v-director
109
+ """
110
+ client = get_client(ctx.obj.get("token"))
111
+ try:
112
+ payload: dict[str, object] = {
113
+ "action": "generate",
114
+ "prompt": prompt,
115
+ "model": model,
116
+ "first_image_url": image_url,
117
+ "callback_url": callback_url,
118
+ "async": async_mode,
119
+ }
120
+
121
+ result = client.generate_video(**payload) # type: ignore[arg-type]
122
+ if output_json:
123
+ print_json(result)
124
+ else:
125
+ print_video_result(result)
126
+ except HailuoError as e:
127
+ print_error(e.message)
128
+ raise SystemExit(1) from e
@@ -0,0 +1 @@
1
+ """Core package for Hailuo CLI."""
@@ -0,0 +1,107 @@
1
+ """HTTP client for Hailuo API."""
2
+
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+ from hailuo_cli.core.config import settings
8
+ from hailuo_cli.core.exceptions import (
9
+ HailuoAPIError,
10
+ HailuoAuthError,
11
+ HailuoTimeoutError,
12
+ )
13
+
14
+
15
+ class HailuoClient:
16
+ """HTTP client for AceDataCloud Hailuo 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 HailuoAuthError("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 Hailuo 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 HailuoAuthError("Invalid API token")
66
+
67
+ if response.status_code == 403:
68
+ raise HailuoAuthError("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 HailuoTimeoutError(
75
+ f"Request to {endpoint} timed out after {request_timeout}s"
76
+ ) from e
77
+
78
+ except HailuoAuthError:
79
+ raise
80
+
81
+ except httpx.HTTPStatusError as e:
82
+ raise HailuoAPIError(
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, HailuoAPIError | HailuoTimeoutError):
90
+ raise
91
+ raise HailuoAPIError(message=str(e)) from e
92
+
93
+ # Convenience methods
94
+ def generate_video(self, **kwargs: Any) -> dict[str, Any]:
95
+ """Generate video using the videos endpoint."""
96
+ return self.request("/hailuo/videos", kwargs)
97
+
98
+ def query_task(self, **kwargs: Any) -> dict[str, Any]:
99
+ """Query task status using the tasks endpoint."""
100
+ return self.request("/hailuo/tasks", kwargs)
101
+
102
+
103
+ def get_client(token: str | None = None) -> HailuoClient:
104
+ """Get a HailuoClient instance, optionally overriding the token."""
105
+ if token:
106
+ return HailuoClient(api_token=token)
107
+ return HailuoClient()
@@ -0,0 +1,39 @@
1
+ """Configuration management for Hailuo 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("HAILUO_REQUEST_TIMEOUT", "1800"))
23
+ )
24
+
25
+ @property
26
+ def is_configured(self) -> bool:
27
+ """Check if the API token is configured."""
28
+ return bool(self.api_token)
29
+
30
+ def validate(self) -> None:
31
+ """Validate configuration. Raises ValueError if API token is missing."""
32
+ if not self.api_token:
33
+ raise ValueError(
34
+ "API token not configured. "
35
+ "Set ACEDATACLOUD_API_TOKEN environment variable or use --token option."
36
+ )
37
+
38
+
39
+ settings = Settings()
@@ -0,0 +1,37 @@
1
+ """Custom exceptions for Hailuo CLI."""
2
+
3
+
4
+ class HailuoError(Exception):
5
+ """Base exception for Hailuo 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 HailuoAuthError(HailuoError):
14
+ """Authentication error."""
15
+
16
+ def __init__(self, message: str = "Authentication failed"):
17
+ super().__init__(message, code="auth_error")
18
+
19
+
20
+ class HailuoAPIError(HailuoError):
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 HailuoTimeoutError(HailuoError):
34
+ """Request timeout error."""
35
+
36
+ def __init__(self, message: str = "Request timed out"):
37
+ super().__init__(message, code="timeout_error")
@@ -0,0 +1,116 @@
1
+ """Rich terminal output formatting for Hailuo 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
+ HAILUO_MODELS = [
14
+ "minimax-t2v",
15
+ "minimax-i2v",
16
+ "minimax-i2v-director",
17
+ ]
18
+
19
+ DEFAULT_MODEL = "minimax-t2v"
20
+
21
+
22
+ def print_json(data: Any) -> None:
23
+ """Print data as formatted JSON."""
24
+ console.print(json.dumps(data, indent=2, ensure_ascii=False))
25
+
26
+
27
+ def print_error(message: str) -> None:
28
+ """Print an error message."""
29
+ console.print(f"[bold red]Error:[/bold red] {message}")
30
+
31
+
32
+ def print_success(message: str) -> None:
33
+ """Print a success message."""
34
+ console.print(f"[bold green]\u2713[/bold green] {message}")
35
+
36
+
37
+ def print_video_result(data: dict[str, Any]) -> None:
38
+ """Print video generation result in a rich format."""
39
+ task_id = data.get("task_id", "N/A")
40
+ trace_id = data.get("trace_id", "N/A")
41
+
42
+ console.print(
43
+ Panel(
44
+ f"[bold]Task ID:[/bold] {task_id}\n[bold]Trace ID:[/bold] {trace_id}",
45
+ title="[bold green]Video Result[/bold green]",
46
+ border_style="green",
47
+ )
48
+ )
49
+
50
+ video_url = data.get("video_url")
51
+ if video_url:
52
+ console.print(f"[bold]Video URL:[/bold] {video_url}")
53
+ elif not data.get("task_id"):
54
+ console.print("[yellow]No video available yet. Use 'task' to check status.[/yellow]")
55
+ else:
56
+ console.print("[yellow]Video is being generated. Use 'task' to check status.[/yellow]")
57
+
58
+
59
+ def print_task_result(data: dict[str, Any]) -> None:
60
+ """Print task query result in a rich format."""
61
+ # Handle single task response
62
+ if isinstance(data.get("data"), dict):
63
+ task_data = data["data"]
64
+ table = Table(show_header=False, box=None, padding=(0, 2))
65
+ table.add_column("Field", style="bold cyan", width=15)
66
+ table.add_column("Value")
67
+ for key in ["id", "status", "state", "video_url", "model", "created_at"]:
68
+ if task_data.get(key):
69
+ table.add_row(key.replace("_", " ").title(), str(task_data[key]))
70
+ console.print(table)
71
+ return
72
+
73
+ # Handle batch response
74
+ items = data.get("data", [])
75
+ if isinstance(items, list) and items:
76
+ for item in items:
77
+ table = Table(show_header=False, box=None, padding=(0, 2))
78
+ table.add_column("Field", style="bold cyan", width=15)
79
+ table.add_column("Value")
80
+ for key in ["id", "status", "state", "video_url", "model", "created_at"]:
81
+ if item.get(key):
82
+ table.add_row(key.replace("_", " ").title(), str(item[key]))
83
+ console.print(table)
84
+ console.print()
85
+ return
86
+
87
+ # Handle direct top-level task fields
88
+ if data.get("task_id") or data.get("video_url"):
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
+ for key in ["task_id", "video_url", "model", "status", "state"]:
93
+ val = data.get(key)
94
+ if val:
95
+ table.add_row(key.replace("_", " ").title(), str(val))
96
+ console.print(table)
97
+ return
98
+
99
+ console.print("[yellow]No data available.[/yellow]")
100
+
101
+
102
+ def print_models() -> None:
103
+ """Print available Hailuo models."""
104
+ table = Table(title="Available Hailuo Models")
105
+ table.add_column("Model", style="bold cyan")
106
+ table.add_column("Type")
107
+ table.add_column("Notes")
108
+
109
+ table.add_row("minimax-t2v", "Text-to-Video", "Generate video from text prompt (default)")
110
+ table.add_row("minimax-i2v", "Image-to-Video", "Generate video from image + text")
111
+ table.add_row(
112
+ "minimax-i2v-director", "Image-to-Video", "Cinematic director mode with image reference"
113
+ )
114
+
115
+ console.print(table)
116
+ console.print(f"\n[dim]Default model: {DEFAULT_MODEL}[/dim]")
hailuo_cli/main.py ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Hailuo CLI - AI Video Generation via AceDataCloud API.
4
+
5
+ A command-line tool for generating AI videos using Hailuo (MiniMax)
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 hailuo_cli.commands.info import config, models
15
+ from hailuo_cli.commands.task import task, tasks_batch, wait
16
+ from hailuo_cli.commands.video import generate, image_to_video
17
+
18
+ load_dotenv()
19
+
20
+
21
+ def get_version() -> str:
22
+ """Get the package version."""
23
+ try:
24
+ return metadata.version("hailuo-cli")
25
+ except metadata.PackageNotFoundError:
26
+ return "dev"
27
+
28
+
29
+ @click.group()
30
+ @click.version_option(version=get_version(), prog_name="hailuo-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
+ """Hailuo CLI - AI Video Generation powered by AceDataCloud.
39
+
40
+ Generate AI videos from the command line using Hailuo (MiniMax) models.
41
+
42
+ Get your API token at https://platform.acedata.cloud
43
+
44
+ \b
45
+ Examples:
46
+ hailuo generate "A cat playing in the snow"
47
+ hailuo image-to-video "Animate this" --image-url https://example.com/img.jpg
48
+ hailuo task abc123-def456
49
+ hailuo 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(image_to_video)
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
+
67
+
68
+ if __name__ == "__main__":
69
+ cli()
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.1
2
+ Name: hailuo-cli
3
+ Version: 2026.7.31.0
4
+ Summary: CLI tool for Hailuo AI Video Generation via AceDataCloud API
5
+ Project-URL: Homepage, https://github.com/AceDataCloud/HailuoCli
6
+ Project-URL: Repository, https://github.com/AceDataCloud/HailuoCli
7
+ Project-URL: Issues, https://github.com/AceDataCloud/HailuoCli/issues
8
+ Project-URL: Changelog, https://github.com/AceDataCloud/HailuoCli/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,hailuo,minimax,video
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 :: Video
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: hailuo-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
+ # Hailuo CLI
48
+
49
+ A command-line tool for generating AI videos using [Hailuo (MiniMax)](https://platform.acedata.cloud) through the AceDataCloud platform.
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ pip install hailuo-cli
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ ```bash
60
+ export ACEDATACLOUD_API_TOKEN=your_token
61
+ ```
62
+
63
+ Or copy `.env.example` to `.env` and fill in your token.
64
+
65
+ ## Commands
66
+
67
+ ### Video Generation
68
+
69
+ | Command | Description |
70
+ |---------|-------------|
71
+ | `hailuo generate <prompt>` | Generate a video from text (minimax-t2v) |
72
+ | `hailuo image-to-video <prompt> --image-url <url>` | Generate video from image + text |
73
+
74
+ ### Task Management
75
+
76
+ | Command | Description |
77
+ |---------|-------------|
78
+ | `hailuo task <task_id>` | Query a single task status |
79
+ | `hailuo tasks <id1> <id2> [...]` | Query multiple tasks at once |
80
+ | `hailuo wait <task_id>` | Wait for task completion with polling |
81
+
82
+ ### Utilities
83
+
84
+ | Command | Description |
85
+ |---------|-------------|
86
+ | `hailuo models` | List available Hailuo models |
87
+ | `hailuo config` | Show current configuration |
88
+
89
+ ## Global Options
90
+
91
+ ```
92
+ --token TEXT API token (or set ACEDATACLOUD_API_TOKEN env var)
93
+ --version Show version
94
+ --help Show help message
95
+ ```
96
+
97
+ Most commands support:
98
+
99
+ ```
100
+ --json Output raw JSON (for piping/scripting)
101
+ --callback-url Webhook URL for async notifications
102
+ ```
103
+
104
+ ## Examples
105
+
106
+ ```bash
107
+ # Generate a video from a text prompt
108
+ hailuo generate "A cat playing in the snow"
109
+
110
+ # Generate from image reference
111
+ hailuo image-to-video "Animate the scene" --image-url https://example.com/photo.jpg
112
+
113
+ # Use a specific model
114
+ hailuo generate "Ocean waves" --model minimax-t2v
115
+
116
+ # Director model with image reference
117
+ hailuo image-to-video "Cinematic pan" --image-url img.jpg --model minimax-i2v-director
118
+
119
+ # Check task status
120
+ hailuo task abc123-def456
121
+
122
+ # Wait for completion
123
+ hailuo wait abc123 --timeout 300
124
+ ```
125
+
126
+ ## Docker
127
+
128
+ ```bash
129
+ # Pull the image
130
+ docker pull ghcr.io/acedatacloud/hailuo-cli:latest
131
+
132
+ # Run a command
133
+ docker run --rm -e ACEDATACLOUD_API_TOKEN=your_token \
134
+ ghcr.io/acedatacloud/hailuo-cli generate "A happy scene"
135
+
136
+ # Or use docker-compose
137
+ docker compose run --rm hailuo-cli generate "A happy scene"
138
+ ```
139
+
140
+ ## Project Structure
141
+
142
+ ```
143
+ HailuoCli/
144
+ ├── hailuo_cli/ # Main package
145
+ │ ├── __init__.py
146
+ │ ├── __main__.py # python -m hailuo_cli entry point
147
+ │ ├── main.py # CLI entry point
148
+ │ ├── core/ # Core modules
149
+ │ │ ├── client.py # HTTP client for Hailuo API
150
+ │ │ ├── config.py # Configuration management
151
+ │ │ ├── exceptions.py # Custom exceptions
152
+ │ │ └── output.py # Rich terminal formatting
153
+ │ └── commands/ # CLI command groups
154
+ │ ├── video.py # Video generation commands
155
+ │ ├── task.py # Task management commands
156
+ │ └── info.py # Info and utility commands
157
+ └── tests/ # Test suite
158
+ ```
159
+
160
+ ## License
161
+
162
+ MIT License — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,17 @@
1
+ hailuo_cli/__init__.py,sha256=tfyP7ia1C4E4QR6UU8MJz438_v1sJ6h37RDpreKf2Sc,61
2
+ hailuo_cli/__main__.py,sha256=iFzCKPwnD2OJCzyemVSV7CCrCHKZJTzExfJYRkhficU,85
3
+ hailuo_cli/main.py,sha256=PMdxllo8wSYwMEqSiA5rpePkOp40tFMWhheCTlDP11g,1732
4
+ hailuo_cli/commands/__init__.py,sha256=_1AM6pXttEBO3ZlftokfV_SBJ4ZqiCak2YCxaayKGNc,39
5
+ hailuo_cli/commands/info.py,sha256=PI6HW8MZJhl4Oh11bAHKwjpIjad4FyCK_slPyUgf3n4,773
6
+ hailuo_cli/commands/task.py,sha256=y8xqUZcKMcO64RMPBnX-D1RmBL0PdSq_zGnAKN_YI70,4311
7
+ hailuo_cli/commands/video.py,sha256=v15XiXT0i_hpwJdaPCFSLSQLt1pMcBimTfJ3_oUJSL4,3587
8
+ hailuo_cli/core/__init__.py,sha256=Ivx0Brt3XsJvJ-3Jj8Ix-CgwsxyMfui11PuBzJ2l8u8,35
9
+ hailuo_cli/core/client.py,sha256=6UPNsmk_kq_lrIkiJWMZf1B84ee2FEJo8qGbGRekk2c,3516
10
+ hailuo_cli/core/config.py,sha256=_9d-b8YC8cz6hkL0R3sDKESrxTvHqVm-VIOonCm-74E,1120
11
+ hailuo_cli/core/exceptions.py,sha256=uh_M8fP1h9Evntk3J9ec3__Xz9UmSsWdgf4mmyHDONE,961
12
+ hailuo_cli/core/output.py,sha256=Qs6-8hNdJ14aI85DayoUHkGhdfV1E-oHtewEdKtwRM8,3931
13
+ hailuo_cli-2026.7.31.0.dist-info/METADATA,sha256=LSUlSfH5obcJurDEuNIneNnGfhw3s2sJ04Q6nKziY2M,5020
14
+ hailuo_cli-2026.7.31.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
15
+ hailuo_cli-2026.7.31.0.dist-info/entry_points.txt,sha256=qLRpjcfXhQ_t-YmcQ--IVej3XYwEOoRnG0CWjf9NWJo,80
16
+ hailuo_cli-2026.7.31.0.dist-info/licenses/LICENSE,sha256=bxZ4efJS6INmQdLVfyxLQXtLCEaj-ORFNew2MaGiZ8E,1069
17
+ hailuo_cli-2026.7.31.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
+ hailuo = hailuo_cli.main:cli
3
+ hailuo-cli = hailuo_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.