hypercli-cli 0.8.10__tar.gz → 0.8.12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/PKG-INFO +1 -1
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/flow.py +96 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/pyproject.toml +1 -1
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/.gitignore +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/README.md +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/__init__.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/billing.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/claw.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/cli.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/comfyui.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/instances.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/jobs.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/keys.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/onboard.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/output.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/renders.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/tui/__init__.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/tui/job_monitor.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/user.py +0 -0
- {hypercli_cli-0.8.10 → hypercli_cli-0.8.12}/hypercli_cli/wallet.py +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""hyper flow commands - simplified flow interfaces"""
|
|
2
|
+
import json
|
|
2
3
|
import math
|
|
4
|
+
from datetime import datetime, timezone
|
|
3
5
|
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
|
|
4
6
|
import typer
|
|
5
7
|
from pathlib import Path
|
|
@@ -8,6 +10,8 @@ from typing import Any, Optional, List
|
|
|
8
10
|
from hypercli import HyperCLI, X402Client
|
|
9
11
|
from .output import output, console, spinner
|
|
10
12
|
|
|
13
|
+
X402_RENDERS_FILE = Path.home() / ".hypercli" / "x402_renders.jsonl"
|
|
14
|
+
|
|
11
15
|
HUMO_FPS = 25 # HuMo video_humo template frame rate
|
|
12
16
|
USDC_ATOMIC_UNITS = Decimal("1000000")
|
|
13
17
|
|
|
@@ -52,6 +56,25 @@ def _usd_to_atomic(amount_usd: float) -> int:
|
|
|
52
56
|
return int((usd * USDC_ATOMIC_UNITS).to_integral_value(rounding=ROUND_HALF_UP))
|
|
53
57
|
|
|
54
58
|
|
|
59
|
+
def _save_x402_render(flow_type: str, amount: float, x402_result) -> None:
|
|
60
|
+
"""Append x402 render info to ~/.hypercli/x402_renders.jsonl"""
|
|
61
|
+
try:
|
|
62
|
+
X402_RENDERS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
entry = {
|
|
64
|
+
"ts": datetime.now(timezone.utc).isoformat(),
|
|
65
|
+
"flow_type": flow_type,
|
|
66
|
+
"render_id": x402_result.render.render_id,
|
|
67
|
+
"amount_usd": amount,
|
|
68
|
+
"access_key": x402_result.access_key,
|
|
69
|
+
"status_url": x402_result.status_url,
|
|
70
|
+
"cancel_url": x402_result.cancel_url,
|
|
71
|
+
}
|
|
72
|
+
with open(X402_RENDERS_FILE, "a") as f:
|
|
73
|
+
f.write(json.dumps(entry) + "\n")
|
|
74
|
+
except Exception:
|
|
75
|
+
pass # best-effort, don't break the flow
|
|
76
|
+
|
|
77
|
+
|
|
55
78
|
def _create_flow_render(
|
|
56
79
|
flow_type: str,
|
|
57
80
|
payload: dict[str, Any],
|
|
@@ -90,6 +113,7 @@ def _create_flow_render(
|
|
|
90
113
|
params=clean_payload,
|
|
91
114
|
notify_url=notify_url,
|
|
92
115
|
)
|
|
116
|
+
_save_x402_render(flow_type, amount, x402_result)
|
|
93
117
|
return x402_result.render, x402_result
|
|
94
118
|
|
|
95
119
|
with spinner("Creating render..."):
|
|
@@ -139,6 +163,78 @@ OPT_AMOUNT = typer.Option(None, "--amount", help="USDC amount to spend with --x4
|
|
|
139
163
|
OPT_FMT = typer.Option("table", "--output", "-o", help="Output format: table|json")
|
|
140
164
|
|
|
141
165
|
|
|
166
|
+
@app.command("renders")
|
|
167
|
+
def list_renders(
|
|
168
|
+
limit: int = typer.Option(10, "--limit", "-n", help="Number of recent renders to show"),
|
|
169
|
+
check: bool = typer.Option(False, "--check", "-c", help="Check current status of each render"),
|
|
170
|
+
fmt: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
171
|
+
):
|
|
172
|
+
"""List saved x402 render history from ~/.hypercli/x402_renders.jsonl"""
|
|
173
|
+
if not X402_RENDERS_FILE.exists():
|
|
174
|
+
console.print("[dim]No x402 renders recorded yet.[/dim]")
|
|
175
|
+
raise typer.Exit(0)
|
|
176
|
+
|
|
177
|
+
entries = []
|
|
178
|
+
with open(X402_RENDERS_FILE) as f:
|
|
179
|
+
for line in f:
|
|
180
|
+
line = line.strip()
|
|
181
|
+
if line:
|
|
182
|
+
try:
|
|
183
|
+
entries.append(json.loads(line))
|
|
184
|
+
except json.JSONDecodeError:
|
|
185
|
+
pass
|
|
186
|
+
|
|
187
|
+
if not entries:
|
|
188
|
+
console.print("[dim]No x402 renders recorded yet.[/dim]")
|
|
189
|
+
raise typer.Exit(0)
|
|
190
|
+
|
|
191
|
+
entries = entries[-limit:]
|
|
192
|
+
|
|
193
|
+
if check:
|
|
194
|
+
import httpx
|
|
195
|
+
for entry in entries:
|
|
196
|
+
access_key = entry.get("access_key", "")
|
|
197
|
+
status_path = entry.get("status_url", "")
|
|
198
|
+
if access_key and status_path:
|
|
199
|
+
try:
|
|
200
|
+
url = f"https://api.hypercli.com/api{status_path}" if status_path.startswith("/flow") else f"https://api.hypercli.com{status_path}"
|
|
201
|
+
resp = httpx.get(url, headers={"Authorization": f"Bearer {access_key}"}, timeout=10)
|
|
202
|
+
if resp.status_code == 200:
|
|
203
|
+
data = resp.json()
|
|
204
|
+
entry["live_state"] = data.get("state", "?")
|
|
205
|
+
entry["result_url"] = data.get("result_url")
|
|
206
|
+
entry["error"] = data.get("error")
|
|
207
|
+
except Exception:
|
|
208
|
+
entry["live_state"] = "error"
|
|
209
|
+
|
|
210
|
+
if fmt == "json":
|
|
211
|
+
output(entries, "json")
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
from rich.table import Table
|
|
215
|
+
table = Table(title="x402 Renders")
|
|
216
|
+
table.add_column("Time", style="dim")
|
|
217
|
+
table.add_column("Flow")
|
|
218
|
+
table.add_column("Render ID", style="cyan")
|
|
219
|
+
table.add_column("USD", justify="right")
|
|
220
|
+
if check:
|
|
221
|
+
table.add_column("State")
|
|
222
|
+
table.add_column("Result")
|
|
223
|
+
|
|
224
|
+
for e in entries:
|
|
225
|
+
ts = e.get("ts", "?")[:19].replace("T", " ")
|
|
226
|
+
row = [ts, e.get("flow_type", "?"), e.get("render_id", "?")[:13] + "…", f"${e.get('amount_usd', 0):.2f}"]
|
|
227
|
+
if check:
|
|
228
|
+
state = e.get("live_state", "?")
|
|
229
|
+
style = "green" if state == "completed" else "red" if state == "failed" else "yellow"
|
|
230
|
+
row.append(f"[{style}]{state}[/{style}]")
|
|
231
|
+
result = e.get("result_url") or e.get("error") or ""
|
|
232
|
+
row.append(result[:60] if result else "")
|
|
233
|
+
table.add_row(*row)
|
|
234
|
+
|
|
235
|
+
console.print(table)
|
|
236
|
+
|
|
237
|
+
|
|
142
238
|
@app.command("text-to-image")
|
|
143
239
|
def text_to_image(
|
|
144
240
|
prompt: str = typer.Argument(..., help="Text description of the image"),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|