VibesAI-api 1.3.2__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.
- server/__init__.py +3 -0
- server/app.py +332 -0
- vibes_api/__init__.py +121 -0
- vibes_api/cli.py +852 -0
- vibes_api/client.py +3972 -0
- vibes_api/composition.py +852 -0
- vibes_api/ingredients.py +206 -0
- vibes_api/models.py +165 -0
- vibesai_api-1.3.2.dist-info/METADATA +600 -0
- vibesai_api-1.3.2.dist-info/RECORD +14 -0
- vibesai_api-1.3.2.dist-info/WHEEL +5 -0
- vibesai_api-1.3.2.dist-info/entry_points.txt +2 -0
- vibesai_api-1.3.2.dist-info/licenses/LICENSE +28 -0
- vibesai_api-1.3.2.dist-info/top_level.txt +2 -0
vibes_api/cli.py
ADDED
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
"""CLI entrypoint for the Vibes API client.
|
|
2
|
+
|
|
3
|
+
Usage
|
|
4
|
+
-----
|
|
5
|
+
vibes-api --cookie <meta_session> me
|
|
6
|
+
vibes-api --cookie <meta_session> projects list
|
|
7
|
+
vibes-api --cookie <meta_session> projects create --name "My Video"
|
|
8
|
+
vibes-api --cookie <meta_session> videos generate \\
|
|
9
|
+
--project-id <id> \\
|
|
10
|
+
--prompt "sunset over ocean" \\
|
|
11
|
+
--aspect-ratio 16:9 \\
|
|
12
|
+
--resolution 720p \\
|
|
13
|
+
--variations 4 \\
|
|
14
|
+
--download-dir ./out
|
|
15
|
+
vibes-api --cookie <meta_session> images generate \\
|
|
16
|
+
--project-id <id> --prompt "cyberpunk city"
|
|
17
|
+
vibes-api --cookie <meta_session> voices list
|
|
18
|
+
vibes-api --cookie <meta_session> tts --voice play_ai_Marisol \\
|
|
19
|
+
--text "Hello world" --out hello.mp3
|
|
20
|
+
vibes-api --cookie <meta_session> media list
|
|
21
|
+
vibes-api --cookie <meta_session> media download --id <id> --out video.mp4
|
|
22
|
+
vibes-api --cookie <meta_session> prompts enhance --prompt "a cat"
|
|
23
|
+
vibes-api --cookie <meta_session> ingredients list
|
|
24
|
+
vibes-api --cookie <meta_session> share create --entity-type project --entity-id <id>
|
|
25
|
+
|
|
26
|
+
You can also set VIBES_META_SESSION env var instead of --cookie.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import argparse
|
|
32
|
+
import json
|
|
33
|
+
import os
|
|
34
|
+
import sys
|
|
35
|
+
from typing import Any
|
|
36
|
+
|
|
37
|
+
from .client import VibesClient, VibesAPIError
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _client(args: argparse.Namespace) -> VibesClient:
|
|
41
|
+
cookie = args.cookie or os.environ.get("VIBES_META_SESSION")
|
|
42
|
+
if not cookie:
|
|
43
|
+
sys.exit("error: --cookie is required (or set VIBES_META_SESSION env var)")
|
|
44
|
+
return VibesClient(meta_session=cookie)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _print(obj: Any) -> None:
|
|
48
|
+
if isinstance(obj, (dict, list)):
|
|
49
|
+
print(json.dumps(obj, indent=2, default=str))
|
|
50
|
+
else:
|
|
51
|
+
print(obj)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def cmd_me(client: VibesClient, args: argparse.Namespace) -> None:
|
|
55
|
+
_print(client.get_me())
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def cmd_projects_list(client: VibesClient, args: argparse.Namespace) -> None:
|
|
59
|
+
_print(client.list_projects(limit=args.limit, offset=args.offset, search=args.search))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def cmd_projects_create(client: VibesClient, args: argparse.Namespace) -> None:
|
|
63
|
+
_print(client.create_project(name=args.name))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def cmd_projects_get(client: VibesClient, args: argparse.Namespace) -> None:
|
|
67
|
+
_print(client.get_project(args.project_id))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def cmd_projects_delete(client: VibesClient, args: argparse.Namespace) -> None:
|
|
71
|
+
client.delete_project(args.project_id, delete_assets=args.delete_assets)
|
|
72
|
+
print(f"Deleted project {args.project_id}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def cmd_videos_generate(client: VibesClient, args: argparse.Namespace) -> None:
|
|
76
|
+
print(f"Generating {args.variations} video variation(s)...", file=sys.stderr)
|
|
77
|
+
result = client.generate_video(
|
|
78
|
+
project_id=args.project_id,
|
|
79
|
+
prompt=args.prompt,
|
|
80
|
+
aspect_ratio=args.aspect_ratio,
|
|
81
|
+
resolution=args.resolution,
|
|
82
|
+
variations=args.variations,
|
|
83
|
+
poll=not args.no_poll,
|
|
84
|
+
)
|
|
85
|
+
if args.no_poll:
|
|
86
|
+
_print(result)
|
|
87
|
+
return
|
|
88
|
+
# Summarize
|
|
89
|
+
videos = [
|
|
90
|
+
{"id": c.get("id"), "videoUrl": c.get("videoUrl"),
|
|
91
|
+
"imageUrl": c.get("imageUrl"), "prompt": c.get("prompt")}
|
|
92
|
+
for c in result.get("content", []) if c.get("videoUrl")
|
|
93
|
+
]
|
|
94
|
+
print(f"Generated {len(videos)} video(s):", file=sys.stderr)
|
|
95
|
+
for v in videos:
|
|
96
|
+
print(f" - id={v['id']}", file=sys.stderr)
|
|
97
|
+
print(f" videoUrl={v['videoUrl'][:80]}..." if v["videoUrl"] else "", file=sys.stderr)
|
|
98
|
+
if args.download_dir:
|
|
99
|
+
os.makedirs(args.download_dir, exist_ok=True)
|
|
100
|
+
for i, v in enumerate(videos):
|
|
101
|
+
out = os.path.join(args.download_dir, f"video_{i}.mp4")
|
|
102
|
+
try:
|
|
103
|
+
client.download_video(v["id"], out)
|
|
104
|
+
print(f" downloaded → {out}", file=sys.stderr)
|
|
105
|
+
except Exception as e:
|
|
106
|
+
print(f" download failed: {e}", file=sys.stderr)
|
|
107
|
+
_print({"videos": videos, "batch_id": result.get("id")})
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def cmd_images_generate(client: VibesClient, args: argparse.Namespace) -> None:
|
|
111
|
+
print(f"Generating {args.variations} image(s)...", file=sys.stderr)
|
|
112
|
+
resp = client.generate_image(
|
|
113
|
+
project_id=args.project_id,
|
|
114
|
+
prompt=args.prompt,
|
|
115
|
+
aspect_ratio=args.aspect_ratio,
|
|
116
|
+
variations=args.variations,
|
|
117
|
+
)
|
|
118
|
+
images = [
|
|
119
|
+
{"url": d.get("url"), "prompt": d.get("prompt"),
|
|
120
|
+
"imageEntId": d.get("imageEntId"), "dimensions": d.get("dimensions")}
|
|
121
|
+
for d in resp.get("data", [])
|
|
122
|
+
]
|
|
123
|
+
print(f"Generated {len(images)} image(s):", file=sys.stderr)
|
|
124
|
+
for im in images:
|
|
125
|
+
print(f" - {im['url'][:80]}...", file=sys.stderr)
|
|
126
|
+
if args.download_dir:
|
|
127
|
+
os.makedirs(args.download_dir, exist_ok=True)
|
|
128
|
+
for i, im in enumerate(images):
|
|
129
|
+
out = os.path.join(args.download_dir, f"image_{i}.png")
|
|
130
|
+
try:
|
|
131
|
+
# Download via direct URL
|
|
132
|
+
import requests
|
|
133
|
+
r = requests.get(im["url"], timeout=60)
|
|
134
|
+
r.raise_for_status()
|
|
135
|
+
with open(out, "wb") as f:
|
|
136
|
+
f.write(r.content)
|
|
137
|
+
print(f" downloaded → {out}", file=sys.stderr)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
print(f" download failed: {e}", file=sys.stderr)
|
|
140
|
+
_print({"images": images, "batch": resp.get("updatedBatch", {}).get("id")})
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def cmd_voices_list(client: VibesClient, args: argparse.Namespace) -> None:
|
|
144
|
+
voices = client.list_voices()
|
|
145
|
+
print(f"{len(voices)} voice(s) available:\n", file=sys.stderr)
|
|
146
|
+
for v in voices:
|
|
147
|
+
print(f" {v['id']:35s} {v['name']:20s} {v.get('description','')}", file=sys.stderr)
|
|
148
|
+
_print(voices)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def cmd_tts(client: VibesClient, args: argparse.Namespace) -> None:
|
|
152
|
+
print(f"Synthesizing with voice '{args.voice}'...", file=sys.stderr)
|
|
153
|
+
resp = client.tts(text=args.text, voice=args.voice, language=args.language)
|
|
154
|
+
if "audioBase64" not in resp:
|
|
155
|
+
_print(resp)
|
|
156
|
+
return
|
|
157
|
+
client.save_tts_audio(resp, args.out)
|
|
158
|
+
print(f"saved → {args.out}", file=sys.stderr)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def cmd_media_list(client: VibesClient, args: argparse.Namespace) -> None:
|
|
162
|
+
_print(client.list_media(limit=args.limit, offset=args.offset, type=args.type))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def cmd_media_download(client: VibesClient, args: argparse.Namespace) -> None:
|
|
166
|
+
if args.type == "image":
|
|
167
|
+
client.download_image(args.id, args.out)
|
|
168
|
+
else:
|
|
169
|
+
client.download_video(args.id, args.out)
|
|
170
|
+
print(f"saved → {args.out}", file=sys.stderr)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def cmd_media_delete(client: VibesClient, args: argparse.Namespace) -> None:
|
|
174
|
+
client.delete_content_items(args.ids)
|
|
175
|
+
print(f"deleted {len(args.ids)} item(s)")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def cmd_prompts_enhance(client: VibesClient, args: argparse.Namespace) -> None:
|
|
179
|
+
variations = client.enhance_prompt(prompt=args.prompt, batch_type=args.batch_type)
|
|
180
|
+
print(f"{len(variations)} variation(s):", file=sys.stderr)
|
|
181
|
+
_print(variations)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def cmd_ingredients_list(client: VibesClient, args: argparse.Namespace) -> None:
|
|
185
|
+
items = client.list_ingredients(owner_filter=args.owner_filter)
|
|
186
|
+
print(f"{len(items)} ingredient(s):", file=sys.stderr)
|
|
187
|
+
for it in items:
|
|
188
|
+
print(f" [{it.get('ingredientType')}] {it.get('name')} (id={it.get('ingredientId')})", file=sys.stderr)
|
|
189
|
+
_print(items)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def cmd_share_create(client: VibesClient, args: argparse.Namespace) -> None:
|
|
193
|
+
link = client.create_share_link(args.entity_type, args.entity_id)
|
|
194
|
+
print(f"Share URL: {link.get('url')}", file=sys.stderr)
|
|
195
|
+
_print(link)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def cmd_share_list(client: VibesClient, args: argparse.Namespace) -> None:
|
|
199
|
+
_print(client.list_share_links(args.entity_type, args.entity_id))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def cmd_share_revoke(client: VibesClient, args: argparse.Namespace) -> None:
|
|
203
|
+
client.revoke_share_link(args.share_link_id)
|
|
204
|
+
print(f"revoked {args.share_link_id}")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def cmd_batches_list(client: VibesClient, args: argparse.Namespace) -> None:
|
|
208
|
+
_print(client.list_batches(limit=args.limit, offset=args.offset, project_id=args.project_id))
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def cmd_batches_get(client: VibesClient, args: argparse.Namespace) -> None:
|
|
212
|
+
_print(client.get_batch(args.batch_id))
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def cmd_batches_poll(client: VibesClient, args: argparse.Namespace) -> None:
|
|
216
|
+
print(f"Polling batch {args.batch_id} (timeout {args.timeout}s)...", file=sys.stderr)
|
|
217
|
+
batch = client.poll_batch(args.batch_id, timeout=args.timeout)
|
|
218
|
+
_print(batch)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def cmd_music_search(client: VibesClient, args: argparse.Namespace) -> None:
|
|
222
|
+
_print(client.search_music(query=args.query, limit=args.limit))
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def cmd_timeline_chat(client: VibesClient, args: argparse.Namespace) -> None:
|
|
226
|
+
print(f"Streaming timeline chat for: {args.input}", file=sys.stderr)
|
|
227
|
+
for event in client.timeline_chat(args.input):
|
|
228
|
+
etype = event.get("type")
|
|
229
|
+
if etype == "message_delta":
|
|
230
|
+
print(event.get("delta", ""), end="", flush=True)
|
|
231
|
+
elif etype == "message_done":
|
|
232
|
+
print()
|
|
233
|
+
elif etype == "tool_call":
|
|
234
|
+
print(f"\n[tool_call] {event.get('name')}({event.get('arguments_buffer','')[:200]})",
|
|
235
|
+
file=sys.stderr)
|
|
236
|
+
elif etype == "error":
|
|
237
|
+
print(f"\n[error] {event.get('code')}: {event.get('message')}", file=sys.stderr)
|
|
238
|
+
elif etype == "completed":
|
|
239
|
+
print(f"\n[completed] conversation_id={event.get('conversation_id')}", file=sys.stderr)
|
|
240
|
+
else:
|
|
241
|
+
_print(event)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def cmd_one_shot(client: VibesClient, args: argparse.Namespace) -> None:
|
|
245
|
+
print(f"Creating end-to-end video for: {args.prompt}", file=sys.stderr)
|
|
246
|
+
result = client.create_video_from_prompt(
|
|
247
|
+
prompt=args.prompt,
|
|
248
|
+
project_name=args.name,
|
|
249
|
+
aspect_ratio=args.aspect_ratio,
|
|
250
|
+
resolution=args.resolution,
|
|
251
|
+
variations=args.variations,
|
|
252
|
+
download_dir=args.download_dir,
|
|
253
|
+
)
|
|
254
|
+
_print(result)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# ----- NEW COMMANDS: extend, edit_video, animate, regenerate, ingredient CRUD, sync -----
|
|
258
|
+
|
|
259
|
+
def cmd_videos_extend(client: VibesClient, args: argparse.Namespace) -> None:
|
|
260
|
+
"""Extend a video (auto or manual)."""
|
|
261
|
+
# Fetch the source content item from the batch
|
|
262
|
+
batch = client.get_batch(args.batch_id)
|
|
263
|
+
source = None
|
|
264
|
+
for c in batch.get("content", []):
|
|
265
|
+
if c["id"] == args.content_id:
|
|
266
|
+
source = c
|
|
267
|
+
break
|
|
268
|
+
if not source:
|
|
269
|
+
# Try to use the first content item
|
|
270
|
+
if batch.get("content"):
|
|
271
|
+
source = batch["content"][0]
|
|
272
|
+
else:
|
|
273
|
+
sys.exit(f"Content item {args.content_id} not found in batch {args.batch_id}")
|
|
274
|
+
mode = "manual" if args.prompt else "auto"
|
|
275
|
+
print(f"Extend ({mode}) on {source['id']}...", file=sys.stderr)
|
|
276
|
+
result = client.extend_video(
|
|
277
|
+
project_id=args.project_id,
|
|
278
|
+
source_video=source,
|
|
279
|
+
prompt=args.prompt,
|
|
280
|
+
poll=not args.no_poll,
|
|
281
|
+
)
|
|
282
|
+
if args.no_poll:
|
|
283
|
+
_print(result)
|
|
284
|
+
return
|
|
285
|
+
videos = [{"id": c.get("id"), "videoUrl": c.get("videoUrl")}
|
|
286
|
+
for c in result.get("content", []) if c.get("videoUrl")]
|
|
287
|
+
print(f"Extended: {len(videos)} video(s)", file=sys.stderr)
|
|
288
|
+
for v in videos:
|
|
289
|
+
print(f" - {v['id']}: {v['videoUrl'][:80]}...", file=sys.stderr)
|
|
290
|
+
_print({"videos": videos, "batch_id": result.get("id")})
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def cmd_videos_edit(client: VibesClient, args: argparse.Namespace) -> None:
|
|
294
|
+
"""Video-to-video edit (re-render with a directive)."""
|
|
295
|
+
batch = client.get_batch(args.batch_id)
|
|
296
|
+
source = None
|
|
297
|
+
for c in batch.get("content", []):
|
|
298
|
+
if c["id"] == args.content_id:
|
|
299
|
+
source = c
|
|
300
|
+
break
|
|
301
|
+
if not source:
|
|
302
|
+
if batch.get("content"):
|
|
303
|
+
source = batch["content"][0]
|
|
304
|
+
else:
|
|
305
|
+
sys.exit(f"Content item not found in batch {args.batch_id}")
|
|
306
|
+
print(f"Editing video {source['id']} with prompt: {args.prompt}", file=sys.stderr)
|
|
307
|
+
result = client.edit_video(
|
|
308
|
+
project_id=args.project_id,
|
|
309
|
+
source_video=source,
|
|
310
|
+
prompt=args.prompt,
|
|
311
|
+
poll=not args.no_poll,
|
|
312
|
+
)
|
|
313
|
+
_print(result if args.no_poll else {
|
|
314
|
+
"batch_id": result.get("id"),
|
|
315
|
+
"videos": [{"id": c.get("id"), "videoUrl": c.get("videoUrl")}
|
|
316
|
+
for c in result.get("content", []) if c.get("videoUrl")],
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def cmd_images_animate(client: VibesClient, args: argparse.Namespace) -> None:
|
|
321
|
+
"""Animate an image (auto or manual)."""
|
|
322
|
+
# Image content items are in image batches; we need to fetch them.
|
|
323
|
+
# Use the media library to find the source image.
|
|
324
|
+
media = client.list_media(limit=100)
|
|
325
|
+
source = None
|
|
326
|
+
for item in media["items"]:
|
|
327
|
+
if item["id"] == args.content_id:
|
|
328
|
+
# Reconstruct a content-item-shaped dict
|
|
329
|
+
source = {
|
|
330
|
+
"id": item["id"],
|
|
331
|
+
"imageUrl": item.get("thumbnailUrl") or item.get("fullUrl"),
|
|
332
|
+
"prompt": item.get("prompt", ""),
|
|
333
|
+
"type": "images",
|
|
334
|
+
}
|
|
335
|
+
break
|
|
336
|
+
if not source:
|
|
337
|
+
sys.exit(f"Content item {args.content_id} not found in media library")
|
|
338
|
+
mode = "manual" if args.prompt else "auto"
|
|
339
|
+
print(f"Animate ({mode}) on {source['id']}...", file=sys.stderr)
|
|
340
|
+
result = client.animate_image(
|
|
341
|
+
project_id=args.project_id,
|
|
342
|
+
source_image=source,
|
|
343
|
+
prompt=args.prompt,
|
|
344
|
+
poll=not args.no_poll,
|
|
345
|
+
)
|
|
346
|
+
_print(result if args.no_poll else {
|
|
347
|
+
"batch_id": result.get("id"),
|
|
348
|
+
"videos": [{"id": c.get("id"), "videoUrl": c.get("videoUrl")}
|
|
349
|
+
for c in result.get("content", []) if c.get("videoUrl")],
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def cmd_batches_regenerate(client: VibesClient, args: argparse.Namespace) -> None:
|
|
354
|
+
"""Regenerate a batch (re-roll)."""
|
|
355
|
+
print(f"Regenerating batch {args.batch_id}...", file=sys.stderr)
|
|
356
|
+
result = client.regenerate_batch(
|
|
357
|
+
project_id=args.project_id,
|
|
358
|
+
batch_id=args.batch_id,
|
|
359
|
+
prompt=args.prompt,
|
|
360
|
+
poll=not args.no_poll,
|
|
361
|
+
)
|
|
362
|
+
_print(result if args.no_poll else {
|
|
363
|
+
"batch_id": result.get("id"),
|
|
364
|
+
"isComplete": result.get("isComplete"),
|
|
365
|
+
"content_count": len(result.get("content", [])),
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def cmd_ingredients_create(client: VibesClient, args: argparse.Namespace) -> None:
|
|
370
|
+
"""Create a new ingredient."""
|
|
371
|
+
result = client.create_ingredient(
|
|
372
|
+
name=args.name,
|
|
373
|
+
ingredient_type=args.type,
|
|
374
|
+
source_image_ent_id=args.image_ent_id,
|
|
375
|
+
image_url=args.image_url,
|
|
376
|
+
description=args.description,
|
|
377
|
+
)
|
|
378
|
+
print(f"Created ingredient: {result.get('ingredient', {}).get('ingredientId')}", file=sys.stderr)
|
|
379
|
+
if result.get("usedExistingName"):
|
|
380
|
+
print("(used existing name — ingredient with this name already existed)", file=sys.stderr)
|
|
381
|
+
_print(result)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def cmd_ingredients_delete(client: VibesClient, args: argparse.Namespace) -> None:
|
|
385
|
+
"""Delete an ingredient."""
|
|
386
|
+
client.delete_ingredient(args.ingredient_id)
|
|
387
|
+
print(f"Deleted ingredient {args.ingredient_id}", file=sys.stderr)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def cmd_sync_status(client: VibesClient, args: argparse.Namespace) -> None:
|
|
391
|
+
"""Get sync status for an entity."""
|
|
392
|
+
result = client.get_sync_status(args.entity_type, args.entity_id)
|
|
393
|
+
_print(result)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def cmd_sync_stream(client: VibesClient, args: argparse.Namespace) -> None:
|
|
397
|
+
"""Stream sync updates (Ctrl+C to stop)."""
|
|
398
|
+
print(f"Streaming updates for {args.entity_type} {args.entity_id} (Ctrl+C to stop)...",
|
|
399
|
+
file=sys.stderr)
|
|
400
|
+
try:
|
|
401
|
+
for event in client.stream_sync_updates(args.entity_type, args.entity_id):
|
|
402
|
+
_print(event)
|
|
403
|
+
except KeyboardInterrupt:
|
|
404
|
+
print("\nStopped.", file=sys.stderr)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def cmd_quota(client: VibesClient, args: argparse.Namespace) -> None:
|
|
408
|
+
"""Get quota upsell info."""
|
|
409
|
+
result = client.get_quota_upsell()
|
|
410
|
+
if result is None:
|
|
411
|
+
print("No upsell info available (user not eligible or endpoint failed).")
|
|
412
|
+
else:
|
|
413
|
+
_print(result)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
# ----- v1.2.0 commands -----
|
|
417
|
+
|
|
418
|
+
def cmd_publish(client: VibesClient, args: argparse.Namespace) -> None:
|
|
419
|
+
"""Publish a content item to Vibes."""
|
|
420
|
+
print(f"Publishing content item {args.content_id}...", file=sys.stderr)
|
|
421
|
+
result = client.publish_to_vibes(
|
|
422
|
+
content_item_id=args.content_id,
|
|
423
|
+
batch_id=args.batch_id,
|
|
424
|
+
caption=args.caption,
|
|
425
|
+
prompt=args.prompt,
|
|
426
|
+
image_prompt=args.image_prompt,
|
|
427
|
+
video_prompt=args.video_prompt,
|
|
428
|
+
)
|
|
429
|
+
_print(result)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def cmd_moodboard_update(client: VibesClient, args: argparse.Namespace) -> None:
|
|
433
|
+
"""Update a moodboard (rename / add / remove images)."""
|
|
434
|
+
result = client.update_moodboard(
|
|
435
|
+
moodboard_id=args.moodboard_id,
|
|
436
|
+
name=args.name,
|
|
437
|
+
)
|
|
438
|
+
_print(result)
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def cmd_moodboard_lookup(client: VibesClient, args: argparse.Namespace) -> None:
|
|
442
|
+
"""Look up a moodboard ID by code."""
|
|
443
|
+
moodboard_id = client.lookup_moodboard_by_code(args.code)
|
|
444
|
+
if moodboard_id:
|
|
445
|
+
print(moodboard_id)
|
|
446
|
+
else:
|
|
447
|
+
print(f"No moodboard found with code '{args.code}'", file=sys.stderr)
|
|
448
|
+
sys.exit(1)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def cmd_share_reset(client: VibesClient, args: argparse.Namespace) -> None:
|
|
452
|
+
"""Reset share link (revoke existing + create new)."""
|
|
453
|
+
print(f"Resetting share link for {args.entity_type} {args.entity_id}...", file=sys.stderr)
|
|
454
|
+
result = client.reset_share_link(args.entity_type, args.entity_id)
|
|
455
|
+
print(f"New share URL: {result.get('url')}", file=sys.stderr)
|
|
456
|
+
_print(result)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def cmd_playables_list(client: VibesClient, args: argparse.Namespace) -> None:
|
|
460
|
+
"""List playables."""
|
|
461
|
+
_print(client.list_playables(limit=args.limit, offset=args.offset, status=args.status))
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def cmd_playables_get(client: VibesClient, args: argparse.Namespace) -> None:
|
|
465
|
+
"""Get a playable."""
|
|
466
|
+
_print(client.get_playable(args.playable_id))
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def cmd_playables_delete(client: VibesClient, args: argparse.Namespace) -> None:
|
|
470
|
+
"""Delete a playable."""
|
|
471
|
+
client.delete_playable(args.playable_id)
|
|
472
|
+
print(f"Deleted playable {args.playable_id}", file=sys.stderr)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def cmd_ingredients_update(client: VibesClient, args: argparse.Namespace) -> None:
|
|
476
|
+
"""Update an ingredient."""
|
|
477
|
+
result = client.update_ingredient(
|
|
478
|
+
ingredient_id=args.ingredient_id,
|
|
479
|
+
name=args.name,
|
|
480
|
+
description=args.description,
|
|
481
|
+
personality=args.personality,
|
|
482
|
+
backstory=args.backstory,
|
|
483
|
+
core_beliefs=args.core_beliefs,
|
|
484
|
+
)
|
|
485
|
+
_print(result)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def cmd_audio_resolve(client: VibesClient, args: argparse.Namespace) -> None:
|
|
489
|
+
"""Resolve audio URLs for a list of audio cluster IDs."""
|
|
490
|
+
result = client.resolve_audio_urls(args.ids)
|
|
491
|
+
_print(result)
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def cmd_audio_proxy(client: VibesClient, args: argparse.Namespace) -> None:
|
|
495
|
+
"""Build a proxy audio URL."""
|
|
496
|
+
url = client.proxy_audio_url(args.audio_id, title=args.title)
|
|
497
|
+
print(url)
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def cmd_check_token(client: VibesClient, args: argparse.Namespace) -> None:
|
|
501
|
+
"""Check if the current session token is valid."""
|
|
502
|
+
if client.check_token():
|
|
503
|
+
print("✓ Token is valid")
|
|
504
|
+
else:
|
|
505
|
+
print("✗ Token is INVALID (session expired)")
|
|
506
|
+
sys.exit(1)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def cmd_rate_limit(client: VibesClient, args: argparse.Namespace) -> None:
|
|
510
|
+
"""Show current rate limit status."""
|
|
511
|
+
_print(client.get_rate_limit_status())
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def cmd_pending_export(client: VibesClient, args: argparse.Namespace) -> None:
|
|
515
|
+
"""Check if a project has a pending export."""
|
|
516
|
+
result = client.get_pending_export(args.project_id)
|
|
517
|
+
if result:
|
|
518
|
+
print("Pending export found:", file=sys.stderr)
|
|
519
|
+
_print(result)
|
|
520
|
+
else:
|
|
521
|
+
print("No pending export.", file=sys.stderr)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def cmd_parse_midjourney(client: VibesClient, args: argparse.Namespace) -> None:
|
|
525
|
+
"""Parse Midjourney parameters from a prompt."""
|
|
526
|
+
result = VibesClient.parse_midjourney_params(args.prompt)
|
|
527
|
+
_print(result)
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def cmd_validate_prompt(client: VibesClient, args: argparse.Namespace) -> None:
|
|
531
|
+
"""Validate a prompt's length."""
|
|
532
|
+
result = VibesClient.validate_prompt_length(args.prompt)
|
|
533
|
+
if result["success"]:
|
|
534
|
+
print(f"✓ Valid ({len(result['value'])} chars)")
|
|
535
|
+
else:
|
|
536
|
+
print(f"✗ {result['error']}")
|
|
537
|
+
sys.exit(1)
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
541
|
+
p = argparse.ArgumentParser(prog="vibes-api", description="Vibes.ai API CLI")
|
|
542
|
+
p.add_argument("--cookie", help="meta_session cookie value (or set VIBES_META_SESSION env var)")
|
|
543
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
544
|
+
|
|
545
|
+
# me
|
|
546
|
+
sub.add_parser("me", help="Get current user").set_defaults(func=cmd_me)
|
|
547
|
+
|
|
548
|
+
# projects
|
|
549
|
+
proj = sub.add_parser("projects", help="Project management")
|
|
550
|
+
proj_sub = proj.add_subparsers(dest="subcmd", required=True)
|
|
551
|
+
proj_list = proj_sub.add_parser("list", help="List projects")
|
|
552
|
+
proj_list.add_argument("--limit", type=int, default=25)
|
|
553
|
+
proj_list.add_argument("--offset", type=int, default=0)
|
|
554
|
+
proj_list.add_argument("--search", type=str)
|
|
555
|
+
proj_list.set_defaults(func=cmd_projects_list)
|
|
556
|
+
proj_create = proj_sub.add_parser("create", help="Create a project")
|
|
557
|
+
proj_create.add_argument("--name", default="Untitled")
|
|
558
|
+
proj_create.set_defaults(func=cmd_projects_create)
|
|
559
|
+
proj_get = proj_sub.add_parser("get", help="Get a project")
|
|
560
|
+
proj_get.add_argument("project_id")
|
|
561
|
+
proj_get.set_defaults(func=cmd_projects_get)
|
|
562
|
+
proj_del = proj_sub.add_parser("delete", help="Delete a project")
|
|
563
|
+
proj_del.add_argument("project_id")
|
|
564
|
+
proj_del.add_argument("--delete-assets", action="store_true")
|
|
565
|
+
proj_del.set_defaults(func=cmd_projects_delete)
|
|
566
|
+
|
|
567
|
+
# videos
|
|
568
|
+
vid = sub.add_parser("videos", help="Video generation")
|
|
569
|
+
vid_sub = vid.add_subparsers(dest="subcmd", required=True)
|
|
570
|
+
vid_gen = vid_sub.add_parser("generate", help="Generate videos from a prompt")
|
|
571
|
+
vid_gen.add_argument("--project-id", required=True)
|
|
572
|
+
vid_gen.add_argument("--prompt", required=True)
|
|
573
|
+
vid_gen.add_argument("--aspect-ratio", default="9:16", choices=["1:1","9:16","16:9","4:5","3:2","2:3"])
|
|
574
|
+
vid_gen.add_argument("--resolution", default="480p", choices=["480p","720p"])
|
|
575
|
+
vid_gen.add_argument("--variations", type=int, default=4)
|
|
576
|
+
vid_gen.add_argument("--download-dir", help="If set, download MP4s to this dir")
|
|
577
|
+
vid_gen.add_argument("--no-poll", action="store_true", help="Return immediately without waiting")
|
|
578
|
+
vid_gen.set_defaults(func=cmd_videos_generate)
|
|
579
|
+
|
|
580
|
+
# videos extend (auto/manual)
|
|
581
|
+
vid_ext = vid_sub.add_parser("extend", help="Extend a video (auto or manual)")
|
|
582
|
+
vid_ext.add_argument("--project-id", required=True)
|
|
583
|
+
vid_ext.add_argument("--batch-id", required=True, help="Batch containing the source video")
|
|
584
|
+
vid_ext.add_argument("--content-id", help="Specific content item ID (default: first)")
|
|
585
|
+
vid_ext.add_argument("--prompt", help="Manual extend directive (omit for auto extend)")
|
|
586
|
+
vid_ext.add_argument("--no-poll", action="store_true")
|
|
587
|
+
vid_ext.set_defaults(func=cmd_videos_extend)
|
|
588
|
+
|
|
589
|
+
# videos edit (v2v)
|
|
590
|
+
vid_edit = vid_sub.add_parser("edit", help="Edit a video with a prompt (v2v)")
|
|
591
|
+
vid_edit.add_argument("--project-id", required=True)
|
|
592
|
+
vid_edit.add_argument("--batch-id", required=True)
|
|
593
|
+
vid_edit.add_argument("--content-id")
|
|
594
|
+
vid_edit.add_argument("--prompt", required=True, help="Edit directive")
|
|
595
|
+
vid_edit.add_argument("--no-poll", action="store_true")
|
|
596
|
+
vid_edit.set_defaults(func=cmd_videos_edit)
|
|
597
|
+
|
|
598
|
+
# images
|
|
599
|
+
img = sub.add_parser("images", help="Image generation")
|
|
600
|
+
img_sub = img.add_subparsers(dest="subcmd", required=True)
|
|
601
|
+
img_gen = img_sub.add_parser("generate", help="Generate images from a prompt")
|
|
602
|
+
img_gen.add_argument("--project-id", required=True)
|
|
603
|
+
img_gen.add_argument("--prompt", required=True)
|
|
604
|
+
img_gen.add_argument("--aspect-ratio", default="1:1", choices=["1:1","9:16","16:9","4:5","3:2","2:3"])
|
|
605
|
+
img_gen.add_argument("--variations", type=int, default=1)
|
|
606
|
+
img_gen.add_argument("--download-dir")
|
|
607
|
+
img_gen.set_defaults(func=cmd_images_generate)
|
|
608
|
+
|
|
609
|
+
# images animate (auto/manual)
|
|
610
|
+
img_anim = img_sub.add_parser("animate", help="Animate an image (auto or manual)")
|
|
611
|
+
img_anim.add_argument("--project-id", required=True)
|
|
612
|
+
img_anim.add_argument("--content-id", required=True, help="Image content item ID")
|
|
613
|
+
img_anim.add_argument("--prompt", help="Manual animate directive (omit for auto)")
|
|
614
|
+
img_anim.add_argument("--no-poll", action="store_true")
|
|
615
|
+
img_anim.set_defaults(func=cmd_images_animate)
|
|
616
|
+
|
|
617
|
+
# voices / tts
|
|
618
|
+
sub.add_parser("voices", help="List TTS voices").set_defaults(func=cmd_voices_list)
|
|
619
|
+
tts = sub.add_parser("tts", help="Text-to-speech")
|
|
620
|
+
tts.add_argument("--voice", required=True)
|
|
621
|
+
tts.add_argument("--text", required=True)
|
|
622
|
+
tts.add_argument("--out", required=True, help="Output mp3 path")
|
|
623
|
+
tts.add_argument("--language")
|
|
624
|
+
tts.set_defaults(func=cmd_tts)
|
|
625
|
+
|
|
626
|
+
# media
|
|
627
|
+
med = sub.add_parser("media", help="Media library")
|
|
628
|
+
med_sub = med.add_subparsers(dest="subcmd", required=True)
|
|
629
|
+
med_list = med_sub.add_parser("list", help="List media items")
|
|
630
|
+
med_list.add_argument("--limit", type=int, default=50)
|
|
631
|
+
med_list.add_argument("--offset", type=int, default=0)
|
|
632
|
+
med_list.add_argument("--type", choices=["video","image","audio"])
|
|
633
|
+
med_list.set_defaults(func=cmd_media_list)
|
|
634
|
+
med_dl = med_sub.add_parser("download", help="Download a media item")
|
|
635
|
+
med_dl.add_argument("--id", required=True)
|
|
636
|
+
med_dl.add_argument("--out", required=True)
|
|
637
|
+
med_dl.add_argument("--type", default="video", choices=["video","image"])
|
|
638
|
+
med_dl.set_defaults(func=cmd_media_download)
|
|
639
|
+
med_del = med_sub.add_parser("delete", help="Delete media items")
|
|
640
|
+
med_del.add_argument("--ids", nargs="+", required=True)
|
|
641
|
+
med_del.set_defaults(func=cmd_media_delete)
|
|
642
|
+
|
|
643
|
+
# prompts
|
|
644
|
+
pr = sub.add_parser("prompts", help="Prompt enhancement")
|
|
645
|
+
pr_sub = pr.add_subparsers(dest="subcmd", required=True)
|
|
646
|
+
pr_enh = pr_sub.add_parser("enhance", help="Generate 4 enhanced prompt variations")
|
|
647
|
+
pr_enh.add_argument("--prompt", required=True)
|
|
648
|
+
pr_enh.add_argument("--batch-type", default="videos", choices=["videos","images"])
|
|
649
|
+
pr_enh.set_defaults(func=cmd_prompts_enhance)
|
|
650
|
+
|
|
651
|
+
# ingredients
|
|
652
|
+
ing = sub.add_parser("ingredients", help="Studio ingredients")
|
|
653
|
+
ing_sub = ing.add_subparsers(dest="subcmd", required=True)
|
|
654
|
+
ing_list = ing_sub.add_parser("list", help="List ingredients")
|
|
655
|
+
ing_list.add_argument("--owner-filter", default="LIBRARY", choices=["LIBRARY","VIEWER"])
|
|
656
|
+
ing_list.add_argument("--type", choices=["CHARACTER","STYLE","SETTING"],
|
|
657
|
+
help="Filter to one type")
|
|
658
|
+
ing_list.set_defaults(func=cmd_ingredients_list)
|
|
659
|
+
ing_cr = ing_sub.add_parser("create", help="Create an ingredient")
|
|
660
|
+
ing_cr.add_argument("--name", required=True)
|
|
661
|
+
ing_cr.add_argument("--type", required=True, choices=["CHARACTER","STYLE","SETTING"])
|
|
662
|
+
ing_cr.add_argument("--image-ent-id", help="Source image entity ID (from upload_image)")
|
|
663
|
+
ing_cr.add_argument("--image-url", help="Source image URL")
|
|
664
|
+
ing_cr.add_argument("--description")
|
|
665
|
+
ing_cr.set_defaults(func=cmd_ingredients_create)
|
|
666
|
+
ing_del = ing_sub.add_parser("delete", help="Delete an ingredient")
|
|
667
|
+
ing_del.add_argument("ingredient_id")
|
|
668
|
+
ing_del.set_defaults(func=cmd_ingredients_delete)
|
|
669
|
+
|
|
670
|
+
# share
|
|
671
|
+
sh = sub.add_parser("share", help="Share links")
|
|
672
|
+
sh_sub = sh.add_subparsers(dest="subcmd", required=True)
|
|
673
|
+
sh_cr = sh_sub.add_parser("create", help="Create a share link")
|
|
674
|
+
sh_cr.add_argument("--entity-type", required=True, choices=["project","content-item"])
|
|
675
|
+
sh_cr.add_argument("--entity-id", required=True)
|
|
676
|
+
sh_cr.set_defaults(func=cmd_share_create)
|
|
677
|
+
sh_ls = sh_sub.add_parser("list", help="List share links")
|
|
678
|
+
sh_ls.add_argument("--entity-type", required=True)
|
|
679
|
+
sh_ls.add_argument("--entity-id", required=True)
|
|
680
|
+
sh_ls.set_defaults(func=cmd_share_list)
|
|
681
|
+
sh_rv = sh_sub.add_parser("revoke", help="Revoke a share link")
|
|
682
|
+
sh_rv.add_argument("share_link_id")
|
|
683
|
+
sh_rv.set_defaults(func=cmd_share_revoke)
|
|
684
|
+
|
|
685
|
+
# batches
|
|
686
|
+
bt = sub.add_parser("batches", help="Generation batches")
|
|
687
|
+
bt_sub = bt.add_subparsers(dest="subcmd", required=True)
|
|
688
|
+
bt_ls = bt_sub.add_parser("list", help="List batches")
|
|
689
|
+
bt_ls.add_argument("--limit", type=int, default=12)
|
|
690
|
+
bt_ls.add_argument("--offset", type=int, default=0)
|
|
691
|
+
bt_ls.add_argument("--project-id")
|
|
692
|
+
bt_ls.set_defaults(func=cmd_batches_list)
|
|
693
|
+
bt_gt = bt_sub.add_parser("get", help="Get a batch")
|
|
694
|
+
bt_gt.add_argument("batch_id")
|
|
695
|
+
bt_gt.set_defaults(func=cmd_batches_get)
|
|
696
|
+
bt_pl = bt_sub.add_parser("poll", help="Poll until a batch completes")
|
|
697
|
+
bt_pl.add_argument("batch_id")
|
|
698
|
+
bt_pl.add_argument("--timeout", type=float, default=180.0)
|
|
699
|
+
bt_pl.set_defaults(func=cmd_batches_poll)
|
|
700
|
+
bt_rg = bt_sub.add_parser("regenerate", help="Regenerate a batch (re-roll)")
|
|
701
|
+
bt_rg.add_argument("batch_id")
|
|
702
|
+
bt_rg.add_argument("--project-id", required=True)
|
|
703
|
+
bt_rg.add_argument("--prompt", help="Override the original prompt")
|
|
704
|
+
bt_rg.add_argument("--no-poll", action="store_true")
|
|
705
|
+
bt_rg.set_defaults(func=cmd_batches_regenerate)
|
|
706
|
+
|
|
707
|
+
# music
|
|
708
|
+
mu = sub.add_parser("music", help="Music library")
|
|
709
|
+
mu_sub = mu.add_subparsers(dest="subcmd", required=True)
|
|
710
|
+
mu_se = mu_sub.add_parser("search", help="Search music")
|
|
711
|
+
mu_se.add_argument("--query", default="")
|
|
712
|
+
mu_se.add_argument("--limit", type=int, default=30)
|
|
713
|
+
mu_se.set_defaults(func=cmd_music_search)
|
|
714
|
+
|
|
715
|
+
# timeline chat
|
|
716
|
+
tc = sub.add_parser("chat", help="Stream timeline AI chat")
|
|
717
|
+
tc.add_argument("input", help="Your request, e.g. 'add a 5s sunset clip'")
|
|
718
|
+
tc.set_defaults(func=cmd_timeline_chat)
|
|
719
|
+
|
|
720
|
+
# one-shot
|
|
721
|
+
os_p = sub.add_parser("one-shot", help="End-to-end: create project + generate + download")
|
|
722
|
+
os_p.add_argument("--prompt", required=True)
|
|
723
|
+
os_p.add_argument("--name")
|
|
724
|
+
os_p.add_argument("--aspect-ratio", default="16:9", choices=["1:1","9:16","16:9","4:5","3:2","2:3"])
|
|
725
|
+
os_p.add_argument("--resolution", default="720p", choices=["480p","720p"])
|
|
726
|
+
os_p.add_argument("--variations", type=int, default=4)
|
|
727
|
+
os_p.add_argument("--download-dir")
|
|
728
|
+
os_p.set_defaults(func=cmd_one_shot)
|
|
729
|
+
|
|
730
|
+
# sync (real-time SSE)
|
|
731
|
+
syn = sub.add_parser("sync", help="Real-time sync (collaborative editing)")
|
|
732
|
+
syn_sub = syn.add_subparsers(dest="subcmd", required=True)
|
|
733
|
+
syn_st = syn_sub.add_parser("status", help="Get last-updated timestamp")
|
|
734
|
+
syn_st.add_argument("--entity-type", required=True, choices=["project","content-item"])
|
|
735
|
+
syn_st.add_argument("--entity-id", required=True)
|
|
736
|
+
syn_st.set_defaults(func=cmd_sync_status)
|
|
737
|
+
syn_sm = syn_sub.add_parser("stream", help="Stream SSE updates (Ctrl+C to stop)")
|
|
738
|
+
syn_sm.add_argument("--entity-type", required=True, choices=["project","content-item"])
|
|
739
|
+
syn_sm.add_argument("--entity-id", required=True)
|
|
740
|
+
syn_sm.set_defaults(func=cmd_sync_stream)
|
|
741
|
+
|
|
742
|
+
# quota
|
|
743
|
+
sub.add_parser("quota", help="Show quota / upsell info").set_defaults(func=cmd_quota)
|
|
744
|
+
|
|
745
|
+
# ----- v1.2.0 subcommands -----
|
|
746
|
+
|
|
747
|
+
# publish
|
|
748
|
+
pub = sub.add_parser("publish", help="Publish a content item to Vibes")
|
|
749
|
+
pub.add_argument("--content-id", required=True)
|
|
750
|
+
pub.add_argument("--batch-id")
|
|
751
|
+
pub.add_argument("--caption")
|
|
752
|
+
pub.add_argument("--prompt")
|
|
753
|
+
pub.add_argument("--image-prompt")
|
|
754
|
+
pub.add_argument("--video-prompt")
|
|
755
|
+
pub.set_defaults(func=cmd_publish)
|
|
756
|
+
|
|
757
|
+
# moodboard update
|
|
758
|
+
mb_up = sub.add_parser("moodboard-update", help="Update a moodboard")
|
|
759
|
+
mb_up.add_argument("moodboard_id")
|
|
760
|
+
mb_up.add_argument("--name", help="New name for the moodboard")
|
|
761
|
+
mb_up.set_defaults(func=cmd_moodboard_update)
|
|
762
|
+
|
|
763
|
+
# moodboard lookup
|
|
764
|
+
mb_lk = sub.add_parser("moodboard-lookup", help="Look up moodboard ID by code")
|
|
765
|
+
mb_lk.add_argument("code")
|
|
766
|
+
mb_lk.set_defaults(func=cmd_moodboard_lookup)
|
|
767
|
+
|
|
768
|
+
# share reset
|
|
769
|
+
sh_rs = sub.add_parser("share-reset", help="Reset share link (revoke + create new)")
|
|
770
|
+
sh_rs.add_argument("--entity-type", required=True, choices=["project","content-item"])
|
|
771
|
+
sh_rs.add_argument("--entity-id", required=True)
|
|
772
|
+
sh_rs.set_defaults(func=cmd_share_reset)
|
|
773
|
+
|
|
774
|
+
# playables
|
|
775
|
+
plb = sub.add_parser("playables", help="Playables (interactive posts)")
|
|
776
|
+
plb_sub = plb.add_subparsers(dest="subcmd", required=True)
|
|
777
|
+
plb_ls = plb_sub.add_parser("list", help="List playables")
|
|
778
|
+
plb_ls.add_argument("--limit", type=int, default=100)
|
|
779
|
+
plb_ls.add_argument("--offset", type=int, default=0)
|
|
780
|
+
plb_ls.add_argument("--status")
|
|
781
|
+
plb_ls.set_defaults(func=cmd_playables_list)
|
|
782
|
+
plb_gt = plb_sub.add_parser("get", help="Get a playable")
|
|
783
|
+
plb_gt.add_argument("playable_id")
|
|
784
|
+
plb_gt.set_defaults(func=cmd_playables_get)
|
|
785
|
+
plb_del = plb_sub.add_parser("delete", help="Delete a playable")
|
|
786
|
+
plb_del.add_argument("playable_id")
|
|
787
|
+
plb_del.set_defaults(func=cmd_playables_delete)
|
|
788
|
+
|
|
789
|
+
# ingredient update
|
|
790
|
+
ing_up = sub.add_parser("ingredients-update", help="Update an ingredient")
|
|
791
|
+
ing_up.add_argument("ingredient_id")
|
|
792
|
+
ing_up.add_argument("--name")
|
|
793
|
+
ing_up.add_argument("--description")
|
|
794
|
+
ing_up.add_argument("--personality")
|
|
795
|
+
ing_up.add_argument("--backstory")
|
|
796
|
+
ing_up.add_argument("--core-beliefs")
|
|
797
|
+
ing_up.set_defaults(func=cmd_ingredients_update)
|
|
798
|
+
|
|
799
|
+
# audio resolve
|
|
800
|
+
aud_rs = sub.add_parser("audio-resolve", help="Resolve audio URLs")
|
|
801
|
+
aud_rs.add_argument("--ids", nargs="+", required=True)
|
|
802
|
+
aud_rs.set_defaults(func=cmd_audio_resolve)
|
|
803
|
+
|
|
804
|
+
# audio proxy
|
|
805
|
+
aud_px = sub.add_parser("audio-proxy", help="Build proxy audio URL")
|
|
806
|
+
aud_px.add_argument("audio_id")
|
|
807
|
+
aud_px.add_argument("--title")
|
|
808
|
+
aud_px.set_defaults(func=cmd_audio_proxy)
|
|
809
|
+
|
|
810
|
+
# check-token
|
|
811
|
+
sub.add_parser("check-token", help="Check if session token is valid").set_defaults(func=cmd_check_token)
|
|
812
|
+
|
|
813
|
+
# rate-limit
|
|
814
|
+
sub.add_parser("rate-limit", help="Show current rate limit status").set_defaults(func=cmd_rate_limit)
|
|
815
|
+
|
|
816
|
+
# pending-export
|
|
817
|
+
pe = sub.add_parser("pending-export", help="Check for pending export")
|
|
818
|
+
pe.add_argument("project_id")
|
|
819
|
+
pe.set_defaults(func=cmd_pending_export)
|
|
820
|
+
|
|
821
|
+
# parse midjourney
|
|
822
|
+
pm = sub.add_parser("parse-midjourney", help="Parse Midjourney params from a prompt")
|
|
823
|
+
pm.add_argument("--prompt", required=True)
|
|
824
|
+
pm.set_defaults(func=cmd_parse_midjourney)
|
|
825
|
+
|
|
826
|
+
# validate prompt
|
|
827
|
+
vp = sub.add_parser("validate-prompt", help="Validate prompt length")
|
|
828
|
+
vp.add_argument("--prompt", required=True)
|
|
829
|
+
vp.set_defaults(func=cmd_validate_prompt)
|
|
830
|
+
|
|
831
|
+
return p
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def main() -> None:
|
|
835
|
+
p = build_parser()
|
|
836
|
+
args = p.parse_args()
|
|
837
|
+
# Some commands don't need a cookie (offline utilities)
|
|
838
|
+
offline_commands = {"parse-midjourney", "validate-prompt"}
|
|
839
|
+
if args.cmd in offline_commands:
|
|
840
|
+
client = None # type: ignore
|
|
841
|
+
else:
|
|
842
|
+
client = _client(args)
|
|
843
|
+
try:
|
|
844
|
+
args.func(client, args)
|
|
845
|
+
except VibesAPIError as e:
|
|
846
|
+
sys.exit(f"API error: {e}")
|
|
847
|
+
except KeyboardInterrupt:
|
|
848
|
+
sys.exit(130)
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
if __name__ == "__main__":
|
|
852
|
+
main()
|