Add stream command for streaming recipes
- artdag stream <recipe.sexp> runs streaming recipes - Supports --duration, --fps, --sources, --audio options - --wait flag polls for completion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
100
artdag.py
100
artdag.py
@@ -2245,5 +2245,105 @@ def run_status_v2(run_id):
|
|||||||
click.echo(f"Error: {run['error']}")
|
click.echo(f"Error: {run['error']}")
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command("stream")
|
||||||
|
@click.argument("recipe_file", type=click.Path(exists=True))
|
||||||
|
@click.option("--output", "-o", default="output.mp4", help="Output filename")
|
||||||
|
@click.option("--duration", "-d", type=float, help="Duration in seconds")
|
||||||
|
@click.option("--fps", type=float, help="FPS override")
|
||||||
|
@click.option("--sources", type=click.Path(exists=True), help="Sources config .sexp file")
|
||||||
|
@click.option("--audio", type=click.Path(exists=True), help="Audio config .sexp file")
|
||||||
|
@click.option("--wait", "-w", is_flag=True, help="Wait for completion")
|
||||||
|
def run_stream(recipe_file, output, duration, fps, sources, audio, wait):
|
||||||
|
"""Run a streaming S-expression recipe. Requires login.
|
||||||
|
|
||||||
|
RECIPE_FILE: Path to the recipe .sexp file
|
||||||
|
|
||||||
|
Example: artdag stream effects/my_effect.sexp --duration 10 --fps 30 -w
|
||||||
|
"""
|
||||||
|
token_data = load_token()
|
||||||
|
if not token_data.get("access_token"):
|
||||||
|
click.echo("Not logged in. Please run: artdag login <username>", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Read recipe file
|
||||||
|
recipe_path = Path(recipe_file)
|
||||||
|
recipe_sexp = recipe_path.read_text()
|
||||||
|
|
||||||
|
# Read optional config files
|
||||||
|
sources_sexp = None
|
||||||
|
if sources:
|
||||||
|
sources_sexp = Path(sources).read_text()
|
||||||
|
|
||||||
|
audio_sexp = None
|
||||||
|
if audio:
|
||||||
|
audio_sexp = Path(audio).read_text()
|
||||||
|
|
||||||
|
# Build request
|
||||||
|
request_data = {
|
||||||
|
"recipe_sexp": recipe_sexp,
|
||||||
|
"output_name": output,
|
||||||
|
}
|
||||||
|
if duration:
|
||||||
|
request_data["duration"] = duration
|
||||||
|
if fps:
|
||||||
|
request_data["fps"] = fps
|
||||||
|
if sources_sexp:
|
||||||
|
request_data["sources_sexp"] = sources_sexp
|
||||||
|
if audio_sexp:
|
||||||
|
request_data["audio_sexp"] = audio_sexp
|
||||||
|
|
||||||
|
# Submit
|
||||||
|
try:
|
||||||
|
headers = get_auth_header(require_token=True)
|
||||||
|
resp = requests.post(
|
||||||
|
f"{get_server()}/runs/stream",
|
||||||
|
json=request_data,
|
||||||
|
headers=headers
|
||||||
|
)
|
||||||
|
if resp.status_code == 401:
|
||||||
|
click.echo("Authentication failed. Please login again.", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
if resp.status_code == 400:
|
||||||
|
error = resp.json().get("detail", "Bad request")
|
||||||
|
click.echo(f"Error: {error}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
resp.raise_for_status()
|
||||||
|
result = resp.json()
|
||||||
|
except requests.RequestException as e:
|
||||||
|
click.echo(f"Stream failed: {e}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
run_id = result["run_id"]
|
||||||
|
click.echo(f"Stream started: {run_id}")
|
||||||
|
click.echo(f"Task ID: {result.get('celery_task_id', 'N/A')}")
|
||||||
|
click.echo(f"Status: {result.get('status', 'pending')}")
|
||||||
|
|
||||||
|
if wait:
|
||||||
|
click.echo("Waiting for completion...")
|
||||||
|
while True:
|
||||||
|
time.sleep(2)
|
||||||
|
try:
|
||||||
|
resp = requests.get(
|
||||||
|
f"{get_server()}/runs/{run_id}",
|
||||||
|
headers=get_auth_header()
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
run = resp.json()
|
||||||
|
except requests.RequestException:
|
||||||
|
continue
|
||||||
|
|
||||||
|
status = run.get("status")
|
||||||
|
if status == "completed":
|
||||||
|
click.echo(f"\nCompleted!")
|
||||||
|
if run.get("output_cid"):
|
||||||
|
click.echo(f"Output CID: {run['output_cid']}")
|
||||||
|
break
|
||||||
|
elif status == "failed":
|
||||||
|
click.echo(f"\nFailed: {run.get('error', 'Unknown error')}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
click.echo(".", nl=False)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli()
|
cli()
|
||||||
|
|||||||
Reference in New Issue
Block a user