@acedatacloud/skills 2026.628.6 → 2026.629.0
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acedatacloud/skills",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.629.0",
|
|
4
4
|
"description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -5,8 +5,11 @@ description: |
|
|
|
5
5
|
(platform.acedata.cloud). Use when the user wants to check their balance /
|
|
6
6
|
remaining credits, look up API call (usage) records and spend, list or create
|
|
7
7
|
or delete API keys (credentials), list subscribed services, list/create/pay
|
|
8
|
-
recharge orders, manage platform tokens,
|
|
9
|
-
publish an announcement.
|
|
8
|
+
recharge orders, manage platform tokens, view referral/affiliate earnings, or
|
|
9
|
+
(admins) publish an announcement. Also covers the PUBLIC catalog & docs (no
|
|
10
|
+
token needed): service detail & pricing, API list & OpenAPI specs, datasets,
|
|
11
|
+
integrations, full-text documentation search, and the model catalog with
|
|
12
|
+
per-model credit pricing. This is the self-service "console" API — distinct
|
|
10
13
|
from the data-generation APIs (image/video/music/search).
|
|
11
14
|
license: Apache-2.0
|
|
12
15
|
metadata:
|
|
@@ -19,7 +22,9 @@ compatibility: Requires ACEDATACLOUD_PLATFORM_TOKEN (a platform or user token).
|
|
|
19
22
|
# AceDataCloud Platform Management
|
|
20
23
|
|
|
21
24
|
Programmatically manage your AceDataCloud account: balances, usage records, API
|
|
22
|
-
keys, services, orders, platform tokens, models, and
|
|
25
|
+
keys, services, orders, platform tokens, models, announcements and referral
|
|
26
|
+
earnings — plus browse the public catalog & docs (service pricing, API specs,
|
|
27
|
+
datasets, integrations, documentation search, model catalog) without a token.
|
|
23
28
|
|
|
24
29
|
This is the **management / console** API at `https://platform.acedata.cloud/api/v1`
|
|
25
30
|
— the same surface the web console uses. It is **different** from the
|
|
@@ -68,6 +73,20 @@ python3 $ADC keys # list API keys (credentials)
|
|
|
68
73
|
python3 $ADC orders --state Finished # recharge orders
|
|
69
74
|
python3 $ADC tokens # platform tokens
|
|
70
75
|
python3 $ADC models # available chat models
|
|
76
|
+
python3 $ADC distributions # referral status + commission history
|
|
77
|
+
|
|
78
|
+
# Catalog & docs (PUBLIC — work without a token)
|
|
79
|
+
python3 $ADC get-service --service suno # one service's detail
|
|
80
|
+
python3 $ADC pricing --service suno # unit, free_amount and cost
|
|
81
|
+
python3 $ADC apis --service suno # API endpoints for a service
|
|
82
|
+
python3 $ADC spec --path /suno/audios # one API's OpenAPI definition + cost
|
|
83
|
+
python3 $ADC datasets # downloadable datasets
|
|
84
|
+
python3 $ADC integrations # third-party integrations
|
|
85
|
+
python3 $ADC docs-search --query "suno lyrics" --lang en # full-text doc search
|
|
86
|
+
python3 $ADC docs-list # browse documentation pages
|
|
87
|
+
python3 $ADC doc --id <document-uuid> # one doc's full content
|
|
88
|
+
python3 $ADC model-catalog --modality chat # rich model catalog + credit pricing
|
|
89
|
+
python3 $ADC model --model claude # look up a model by id/name
|
|
71
90
|
|
|
72
91
|
# Safe write (require --yes to actually execute)
|
|
73
92
|
python3 $ADC create-key --application <app-id> --name "ci" --yes
|
|
@@ -206,6 +225,22 @@ Filters: `api_id`, `application_id`, `status_code`, `created_at_from`,
|
|
|
206
225
|
OpenAI-style (no pagination): `{ "object": "list", "data": [ { "id": "gpt-4.1",
|
|
207
226
|
"label": "GPT-4.1", "owned_by": "openai", "type": "chat", "capabilities": ["vision"] } ] }`
|
|
208
227
|
|
|
228
|
+
### Catalog & docs (PUBLIC — no token required)
|
|
229
|
+
|
|
230
|
+
These work without auth (send the token if you have one; not required):
|
|
231
|
+
|
|
232
|
+
- **Service detail / pricing** — `GET /services/?id=<uuid>` → `items[0]` (full: `cost`, `unit`,
|
|
233
|
+
`free_amount`, `title`). The `services/?alias=` filter is **ignored** server-side, so resolve an
|
|
234
|
+
alias by paging `services/` and matching `alias` client-side. The `services/{id}/` detail route is broken (500).
|
|
235
|
+
- **APIs** — `GET /apis/?path=<path>` → exactly one item with its OpenAPI `definition` + `cost`.
|
|
236
|
+
`apis/?service_id=` is **ignored** server-side; filter by `service_id` client-side. `apis/{id}/` is broken (500).
|
|
237
|
+
- **Datasets / integrations** — `GET /datasets/`, `GET /integrations/`.
|
|
238
|
+
- **Doc search** — `GET /search/?query=<text>&lang=<code>` → `{ results: [ { id, alias, title, type, snippet, url } ] }`.
|
|
239
|
+
The param is **`query`** (not `keyword`).
|
|
240
|
+
- **Doc content** — `GET /documents/?id=<uuid>` → `items[0].content`. `documents/{id}/` (id or slug) is broken (404).
|
|
241
|
+
- **Model catalog** — `GET /models/catalog/` → `{ rates, modalities, count, items:[{ id, name, provider,
|
|
242
|
+
modality, unit, capabilities, pricing:{ input_credits, output_credits, official_* } }] }`. Filter client-side.
|
|
243
|
+
|
|
209
244
|
### Announcements — `GET /announcements/`
|
|
210
245
|
|
|
211
246
|
Public read: `{ "count": 20, "items": [ { "id", "title", "content",
|
|
@@ -241,4 +276,4 @@ publishing announcements are **irreversible or money-related**. Always:
|
|
|
241
276
|
- Announcement endpoints under `/admin/` require a **superuser** token; a normal
|
|
242
277
|
token gets `403`.
|
|
243
278
|
|
|
244
|
-
> **MCP:** `pip install mcp-acedatacloud` | See [all MCP servers](../_shared/mcp-servers.md). The MCP exposes these as tools (`
|
|
279
|
+
> **MCP:** `pip install mcp-acedatacloud` | Hosted: `https://mcp.acedata.cloud/mcp` | See [all MCP servers](../_shared/mcp-servers.md). The MCP exposes these as tools (`acedatacloud_get_balance`, `acedatacloud_list_usage`, `acedatacloud_get_pricing`, `acedatacloud_search_docs`, `acedatacloud_get_api_spec`, `acedatacloud_create_credential`, …) with the same write-confirmation guard.
|
|
@@ -18,6 +18,7 @@ import argparse
|
|
|
18
18
|
import datetime as dt
|
|
19
19
|
import json
|
|
20
20
|
import os
|
|
21
|
+
import re
|
|
21
22
|
import sys
|
|
22
23
|
import urllib.error
|
|
23
24
|
import urllib.parse
|
|
@@ -32,18 +33,9 @@ def _die(msg: str, code: int = 1) -> None:
|
|
|
32
33
|
sys.exit(code)
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
def _token(args: argparse.Namespace) -> str:
|
|
36
|
-
token = args.token or os.environ.get("ACEDATACLOUD_PLATFORM_TOKEN", "")
|
|
37
|
-
if not token:
|
|
38
|
-
_die(
|
|
39
|
-
"no platform token. Set ACEDATACLOUD_PLATFORM_TOKEN or pass --token.\n"
|
|
40
|
-
"Create one at https://platform.acedata.cloud/console/platform-tokens"
|
|
41
|
-
)
|
|
42
|
-
return token
|
|
43
|
-
|
|
44
|
-
|
|
45
36
|
def _request(args: argparse.Namespace, method: str, path: str,
|
|
46
|
-
params: dict | None = None, body: dict | None = None
|
|
37
|
+
params: dict | None = None, body: dict | None = None,
|
|
38
|
+
auth_required: bool = True) -> tuple[int, object]:
|
|
47
39
|
base = args.base_url.rstrip("/")
|
|
48
40
|
url = f"{base}/api/v1{path}"
|
|
49
41
|
if params:
|
|
@@ -51,11 +43,16 @@ def _request(args: argparse.Namespace, method: str, path: str,
|
|
|
51
43
|
if clean:
|
|
52
44
|
url += "?" + urllib.parse.urlencode(clean, doseq=True)
|
|
53
45
|
data = json.dumps(body).encode() if body is not None else None
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
|
|
46
|
+
headers = {"accept": "application/json", "content-type": "application/json"}
|
|
47
|
+
token = args.token or os.environ.get("ACEDATACLOUD_PLATFORM_TOKEN", "")
|
|
48
|
+
if token:
|
|
49
|
+
headers["authorization"] = f"Bearer {token}"
|
|
50
|
+
elif auth_required:
|
|
51
|
+
_die(
|
|
52
|
+
"no platform token. Set ACEDATACLOUD_PLATFORM_TOKEN or pass --token.\n"
|
|
53
|
+
"Create one at https://platform.acedata.cloud/console/platform-tokens"
|
|
54
|
+
)
|
|
55
|
+
req = urllib.request.Request(url, data=data, method=method, headers=headers)
|
|
59
56
|
try:
|
|
60
57
|
with urllib.request.urlopen(req, timeout=args.timeout) as resp:
|
|
61
58
|
raw = resp.read().decode("utf-8")
|
|
@@ -72,7 +69,7 @@ def _request(args: argparse.Namespace, method: str, path: str,
|
|
|
72
69
|
|
|
73
70
|
|
|
74
71
|
def _get_all(args: argparse.Namespace, path: str, params: dict | None = None,
|
|
75
|
-
page: int = 200, cap: int = 2000) -> tuple[int, list]:
|
|
72
|
+
page: int = 200, cap: int = 2000, auth_required: bool = True) -> tuple[int, list]:
|
|
76
73
|
"""Fetch every page of a {count, items} list endpoint (capped)."""
|
|
77
74
|
base = dict(params or {})
|
|
78
75
|
out: list = []
|
|
@@ -80,7 +77,7 @@ def _get_all(args: argparse.Namespace, path: str, params: dict | None = None,
|
|
|
80
77
|
total = 0
|
|
81
78
|
while len(out) < cap:
|
|
82
79
|
base.update({"limit": page, "offset": offset})
|
|
83
|
-
status, payload = _request(args, "GET", path, base)
|
|
80
|
+
status, payload = _request(args, "GET", path, base, auth_required=auth_required)
|
|
84
81
|
_check_ok(status, payload)
|
|
85
82
|
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
86
83
|
total = payload.get("count", 0) if isinstance(payload, dict) else 0
|
|
@@ -142,6 +139,29 @@ def _since(days: int | None) -> str | None:
|
|
|
142
139
|
return (dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=days)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
143
140
|
|
|
144
141
|
|
|
142
|
+
_UUID = re.compile(r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _resolve_service(args, ref: str) -> dict | None:
|
|
146
|
+
"""Resolve a service by UUID (services/?id=) or alias (paginated match).
|
|
147
|
+
|
|
148
|
+
The platform's services/?alias= filter is ignored server-side, so alias
|
|
149
|
+
lookups page through the catalog and match client-side.
|
|
150
|
+
"""
|
|
151
|
+
ref = ref.strip()
|
|
152
|
+
if _UUID.match(ref):
|
|
153
|
+
status, payload = _request(args, "GET", "/services/", {"id": ref}, auth_required=False)
|
|
154
|
+
_check_ok(status, payload)
|
|
155
|
+
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
156
|
+
return items[0] if items else None
|
|
157
|
+
target = ref.lower()
|
|
158
|
+
_, items = _get_all(args, "/services/", page=50, cap=600, auth_required=False)
|
|
159
|
+
for it in items:
|
|
160
|
+
if (it.get("alias") or "").lower() == target:
|
|
161
|
+
return it
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
|
|
145
165
|
# ---- read commands -------------------------------------------------------
|
|
146
166
|
|
|
147
167
|
def cmd_balance(args):
|
|
@@ -261,6 +281,179 @@ def cmd_announcements(args):
|
|
|
261
281
|
_emit(args, payload, rows, ("id", "title", "rank", "publish_at"))
|
|
262
282
|
|
|
263
283
|
|
|
284
|
+
# ---- catalog & docs commands (public, no token needed) ------------------
|
|
285
|
+
|
|
286
|
+
def cmd_get_service(args):
|
|
287
|
+
svc = _resolve_service(args, args.service)
|
|
288
|
+
if not svc:
|
|
289
|
+
_die(f"no service matched '{args.service}'", code=2)
|
|
290
|
+
_emit(args, svc)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def cmd_pricing(args):
|
|
294
|
+
svc = _resolve_service(args, args.service)
|
|
295
|
+
if not svc:
|
|
296
|
+
_die(f"no service matched '{args.service}'", code=2)
|
|
297
|
+
out = {
|
|
298
|
+
"service_id": svc.get("id"),
|
|
299
|
+
"alias": svc.get("alias"),
|
|
300
|
+
"title": svc.get("title"),
|
|
301
|
+
"type": svc.get("type"),
|
|
302
|
+
"unit": svc.get("unit"),
|
|
303
|
+
"free_amount": svc.get("free_amount"),
|
|
304
|
+
"cost": svc.get("cost"),
|
|
305
|
+
}
|
|
306
|
+
_emit(args, out)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def cmd_apis(args):
|
|
310
|
+
sid = None
|
|
311
|
+
if args.service:
|
|
312
|
+
svc = _resolve_service(args, args.service)
|
|
313
|
+
if not svc:
|
|
314
|
+
_die(f"no service matched '{args.service}'", code=2)
|
|
315
|
+
sid = svc.get("id")
|
|
316
|
+
# apis/?service_id= is ignored server-side, so filter client-side.
|
|
317
|
+
_, items = _get_all(args, "/apis/", page=50, cap=2000, auth_required=False)
|
|
318
|
+
if sid:
|
|
319
|
+
items = [it for it in items if it.get("service_id") == sid]
|
|
320
|
+
items = items[: args.limit]
|
|
321
|
+
slim = [{k: v for k, v in it.items() if k != "definition"} for it in items]
|
|
322
|
+
rows = [(
|
|
323
|
+
(it.get("path") or ""),
|
|
324
|
+
it.get("method"),
|
|
325
|
+
it.get("stage"),
|
|
326
|
+
(it.get("title") or "")[:30],
|
|
327
|
+
) for it in items]
|
|
328
|
+
_emit(args, {"count": len(slim), "items": slim}, rows, ("path", "method", "stage", "title"))
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def cmd_spec(args):
|
|
332
|
+
status, payload = _request(args, "GET", "/apis/", {"path": args.path}, auth_required=False)
|
|
333
|
+
_check_ok(status, payload)
|
|
334
|
+
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
335
|
+
if not items:
|
|
336
|
+
_die(f"no API matched path '{args.path}'", code=2)
|
|
337
|
+
api = items[0]
|
|
338
|
+
_emit(args, {
|
|
339
|
+
"id": api.get("id"),
|
|
340
|
+
"service_id": api.get("service_id"),
|
|
341
|
+
"title": api.get("title"),
|
|
342
|
+
"path": api.get("path"),
|
|
343
|
+
"method": api.get("method"),
|
|
344
|
+
"stage": api.get("stage"),
|
|
345
|
+
"cost": api.get("cost"),
|
|
346
|
+
"definition": api.get("definition"),
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def cmd_datasets(args):
|
|
351
|
+
status, payload = _request(args, "GET", "/datasets/", {"limit": args.limit}, auth_required=False)
|
|
352
|
+
_check_ok(status, payload)
|
|
353
|
+
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
354
|
+
rows = [(it.get("id", "")[:8], (it.get("title") or "")[:30], it.get("price"), (it.get("part") or "")) for it in items]
|
|
355
|
+
_emit(args, payload, rows, ("id", "title", "price", "part"))
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def cmd_integrations(args):
|
|
359
|
+
status, payload = _request(args, "GET", "/integrations/", {"limit": args.limit}, auth_required=False)
|
|
360
|
+
_check_ok(status, payload)
|
|
361
|
+
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
362
|
+
rows = [(it.get("id", "")[:8], (it.get("title") or "")[:34], it.get("stage")) for it in items]
|
|
363
|
+
_emit(args, payload, rows, ("id", "title", "stage"))
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def cmd_docs_search(args):
|
|
367
|
+
status, payload = _request(args, "GET", "/search/", {"query": args.query, "lang": args.lang}, auth_required=False)
|
|
368
|
+
_check_ok(status, payload)
|
|
369
|
+
results = payload.get("results", []) if isinstance(payload, dict) else []
|
|
370
|
+
rows = [((r.get("title") or "")[:44], r.get("type"), r.get("matched_lang"), (r.get("id") or "")[:8]) for r in results]
|
|
371
|
+
_emit(args, payload, rows, ("title", "type", "lang", "id"))
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def cmd_docs_list(args):
|
|
375
|
+
status, payload = _request(args, "GET", "/documents/", {"limit": args.limit, "type": args.type}, auth_required=False)
|
|
376
|
+
_check_ok(status, payload)
|
|
377
|
+
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
378
|
+
rows = [(it.get("id", "")[:8], (it.get("title") or "")[:40], it.get("type"), it.get("alias")) for it in items]
|
|
379
|
+
_emit(args, {"count": payload.get("count") if isinstance(payload, dict) else None, "items": items}, rows,
|
|
380
|
+
("id", "title", "type", "alias"))
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def cmd_doc(args):
|
|
384
|
+
if not _UUID.match(args.id.strip()):
|
|
385
|
+
_die("doc id must be a document UUID", code=2)
|
|
386
|
+
status, payload = _request(args, "GET", "/documents/", {"id": args.id.strip()}, auth_required=False)
|
|
387
|
+
_check_ok(status, payload)
|
|
388
|
+
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
389
|
+
if not items:
|
|
390
|
+
_die(f"no document with id '{args.id}'", code=2)
|
|
391
|
+
_emit(args, items[0])
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def cmd_model_catalog(args):
|
|
395
|
+
status, payload = _request(args, "GET", "/models/catalog/", auth_required=False)
|
|
396
|
+
_check_ok(status, payload)
|
|
397
|
+
items = payload.get("items", []) if isinstance(payload, dict) else []
|
|
398
|
+
if args.modality:
|
|
399
|
+
m = args.modality.lower()
|
|
400
|
+
items = [it for it in items if (it.get("modality") or "").lower() == m]
|
|
401
|
+
if args.provider:
|
|
402
|
+
pv = args.provider.lower()
|
|
403
|
+
items = [it for it in items if pv in (it.get("provider") or "").lower()]
|
|
404
|
+
rows = [(
|
|
405
|
+
it.get("id"),
|
|
406
|
+
it.get("provider"),
|
|
407
|
+
it.get("modality"),
|
|
408
|
+
(it.get("pricing") or {}).get("input_credits"),
|
|
409
|
+
(it.get("pricing") or {}).get("output_credits"),
|
|
410
|
+
) for it in items]
|
|
411
|
+
out = {"modalities": payload.get("modalities") if isinstance(payload, dict) else None,
|
|
412
|
+
"count": len(items), "items": items}
|
|
413
|
+
_emit(args, out, rows, ("id", "provider", "modality", "in_credits", "out_credits"))
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def cmd_model(args):
|
|
417
|
+
status, payload = _request(args, "GET", "/models/catalog/", auth_required=False)
|
|
418
|
+
_check_ok(status, payload)
|
|
419
|
+
q = args.model.strip().lower()
|
|
420
|
+
items = [it for it in (payload.get("items", []) if isinstance(payload, dict) else [])
|
|
421
|
+
if q in (it.get("id") or "").lower() or q in (it.get("name") or "").lower()]
|
|
422
|
+
if not items:
|
|
423
|
+
_die(f"no model matched '{args.model}'", code=2)
|
|
424
|
+
rows = [(
|
|
425
|
+
it.get("id"),
|
|
426
|
+
it.get("provider"),
|
|
427
|
+
it.get("modality"),
|
|
428
|
+
(it.get("pricing") or {}).get("input_credits"),
|
|
429
|
+
(it.get("pricing") or {}).get("output_credits"),
|
|
430
|
+
) for it in items]
|
|
431
|
+
_emit(args, {"count": len(items), "items": items}, rows,
|
|
432
|
+
("id", "provider", "modality", "in_credits", "out_credits"))
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def cmd_distributions(args):
|
|
436
|
+
status, status_payload = _request(args, "GET", "/distribution-statuses/", {"limit": 1})
|
|
437
|
+
_check_ok(status, status_payload)
|
|
438
|
+
st_items = status_payload.get("items", []) if isinstance(status_payload, dict) else []
|
|
439
|
+
hstatus, hist = _request(args, "GET", "/distribution-histories/", {"limit": args.limit})
|
|
440
|
+
_check_ok(hstatus, hist)
|
|
441
|
+
hitems = hist.get("items", []) if isinstance(hist, dict) else []
|
|
442
|
+
out = {
|
|
443
|
+
"status": st_items[0] if st_items else None,
|
|
444
|
+
"history_count": hist.get("count") if isinstance(hist, dict) else None,
|
|
445
|
+
"history": hitems,
|
|
446
|
+
}
|
|
447
|
+
rows = [(
|
|
448
|
+
(it.get("created_at") or "")[:10],
|
|
449
|
+
it.get("price"),
|
|
450
|
+
it.get("reward"),
|
|
451
|
+
it.get("percentage"),
|
|
452
|
+
"invalid" if it.get("invalid") else "ok",
|
|
453
|
+
) for it in hitems]
|
|
454
|
+
_emit(args, out, rows, ("date", "price", "reward", "pct", "state"))
|
|
455
|
+
|
|
456
|
+
|
|
264
457
|
# ---- write commands (gated by --yes) -------------------------------------
|
|
265
458
|
|
|
266
459
|
def _guard(args, action: str, detail: dict) -> bool:
|
|
@@ -405,6 +598,47 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
405
598
|
sp = add("announcements", cmd_announcements, "list announcements")
|
|
406
599
|
sp.add_argument("--limit", type=int, default=20)
|
|
407
600
|
|
|
601
|
+
sp = add("distributions", cmd_distributions, "referral status + commission history")
|
|
602
|
+
sp.add_argument("--limit", type=int, default=20)
|
|
603
|
+
|
|
604
|
+
# ---- catalog & docs (public, no token needed) ----
|
|
605
|
+
sp = add("get-service", cmd_get_service, "one service's detail by alias or id")
|
|
606
|
+
sp.add_argument("--service", required=True, help="service alias or UUID")
|
|
607
|
+
|
|
608
|
+
sp = add("pricing", cmd_pricing, "a service's unit, free_amount and cost")
|
|
609
|
+
sp.add_argument("--service", required=True, help="service alias or UUID")
|
|
610
|
+
|
|
611
|
+
sp = add("apis", cmd_apis, "list API endpoints (optionally per service)")
|
|
612
|
+
sp.add_argument("--service", help="scope to a service alias or UUID")
|
|
613
|
+
sp.add_argument("--limit", type=int, default=50)
|
|
614
|
+
|
|
615
|
+
sp = add("spec", cmd_spec, "one API's OpenAPI definition + cost, by path")
|
|
616
|
+
sp.add_argument("--path", required=True, help="API path, e.g. /suno/audios")
|
|
617
|
+
|
|
618
|
+
sp = add("datasets", cmd_datasets, "list downloadable datasets")
|
|
619
|
+
sp.add_argument("--limit", type=int, default=50)
|
|
620
|
+
|
|
621
|
+
sp = add("integrations", cmd_integrations, "list third-party integrations")
|
|
622
|
+
sp.add_argument("--limit", type=int, default=50)
|
|
623
|
+
|
|
624
|
+
sp = add("docs-search", cmd_docs_search, "full-text search the documentation")
|
|
625
|
+
sp.add_argument("--query", required=True)
|
|
626
|
+
sp.add_argument("--lang", help="language code, e.g. en, zh-cn")
|
|
627
|
+
|
|
628
|
+
sp = add("docs-list", cmd_docs_list, "browse documentation pages")
|
|
629
|
+
sp.add_argument("--limit", type=int, default=30)
|
|
630
|
+
sp.add_argument("--type", help="document type filter, e.g. Text")
|
|
631
|
+
|
|
632
|
+
sp = add("doc", cmd_doc, "fetch one doc's full content by UUID")
|
|
633
|
+
sp.add_argument("--id", required=True, help="document UUID")
|
|
634
|
+
|
|
635
|
+
sp = add("model-catalog", cmd_model_catalog, "rich model catalog with credit pricing")
|
|
636
|
+
sp.add_argument("--modality", help="chat/video/image/music/search/embedding")
|
|
637
|
+
sp.add_argument("--provider", help="filter by provider substring")
|
|
638
|
+
|
|
639
|
+
sp = add("model", cmd_model, "look up a model by id/name")
|
|
640
|
+
sp.add_argument("--model", required=True)
|
|
641
|
+
|
|
408
642
|
sp = add("create-key", cmd_create_key, "create an API key (needs --yes)")
|
|
409
643
|
sp.add_argument("--application", required=True)
|
|
410
644
|
sp.add_argument("--name")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: seedance-video
|
|
3
|
-
description: Generate AI
|
|
3
|
+
description: Generate AI videos with Seedance (ByteDance) via AceDataCloud API. Use when creating videos from text prompts, animating images into motion videos, or driving Seedance 2.0 multimodal generation with real-person / character image references, reference audio, and reference video. Supports multiple models with configurable resolution (up to 4k), aspect ratio, duration, and optional audio generation.
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: acedatacloud
|
|
@@ -20,7 +20,7 @@ Generate AI dance and motion videos through AceDataCloud's Seedance (ByteDance)
|
|
|
20
20
|
curl -X POST https://api.acedata.cloud/seedance/videos \
|
|
21
21
|
-H "Authorization: Bearer $ACEDATACLOUD_API_TOKEN" \
|
|
22
22
|
-H "Content-Type: application/json" \
|
|
23
|
-
-d '{"model": "doubao-seedance-
|
|
23
|
+
-d '{"model": "doubao-seedance-2-0-260128", "content": [{"type": "text", "text": "a dancer performing contemporary ballet in a misty forest"}], "callback_url": "https://api.acedata.cloud/health"}'
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
> **Async:** See [async task polling](../_shared/async-tasks.md). Poll via `POST /seedance/tasks` with `{"id": "..."}`.
|
|
@@ -35,11 +35,23 @@ curl -X POST https://api.acedata.cloud/seedance/tasks \
|
|
|
35
35
|
|
|
36
36
|
## Models
|
|
37
37
|
|
|
38
|
+
### Seedance 2.0 (current generation — multimodal reference)
|
|
39
|
+
|
|
40
|
+
The 2.0 series adds multimodal reference inputs: real-person / character **image** references, reference **audio**, and reference **video** (see the workflows below).
|
|
41
|
+
|
|
42
|
+
| Model | Best For | Max resolution |
|
|
43
|
+
|-------|----------|----------------|
|
|
44
|
+
| `doubao-seedance-2-0-260128` | Highest quality, real-person/character reference, 4k output | `4k` |
|
|
45
|
+
| `doubao-seedance-2-0-fast-260128` | Faster 2.0 generation | `720p` |
|
|
46
|
+
| `doubao-seedance-2-0-mini-260615` | Lightweight / most cost-effective 2.0 | `720p` |
|
|
47
|
+
|
|
48
|
+
### Seedance 1.x
|
|
49
|
+
|
|
38
50
|
| Model | Type | Best For |
|
|
39
51
|
|-------|------|----------|
|
|
52
|
+
| `doubao-seedance-1-5-pro-251215` | Text+Image-to-Video | 1.5 flagship, audio support |
|
|
40
53
|
| `doubao-seedance-1-0-pro-250528` | Text+Image-to-Video | General-purpose, reliable quality |
|
|
41
54
|
| `doubao-seedance-1-0-pro-fast-251015` | Text+Image-to-Video | Faster Pro generation |
|
|
42
|
-
| `doubao-seedance-1-5-pro-251215` | Text+Image-to-Video | Latest model, highest quality, audio support |
|
|
43
55
|
| `doubao-seedance-1-0-lite-t2v-250428` | Text-to-Video only | Lightweight text-to-video |
|
|
44
56
|
| `doubao-seedance-1-0-lite-i2v-250428` | Image-to-Video only | Lightweight image-to-video |
|
|
45
57
|
|
|
@@ -86,7 +98,11 @@ POST /seedance/videos
|
|
|
86
98
|
Image roles:
|
|
87
99
|
- `first_frame` — image is used as the opening frame
|
|
88
100
|
- `last_frame` — image is used as the closing frame
|
|
89
|
-
- `reference_image` — image is used as a style/
|
|
101
|
+
- `reference_image` — image is used as a style / subject / real-person reference (Seedance 2.0 keeps the referenced person or character consistent)
|
|
102
|
+
|
|
103
|
+
Reference media (Seedance 2.0 only):
|
|
104
|
+
- `audio_url` — reference audio for voice timbre / background music (no `role`)
|
|
105
|
+
- `video_url` — reference video for subject, camera movement, motion or overall style (no `role`)
|
|
90
106
|
|
|
91
107
|
### 3. First-frame + Last-frame
|
|
92
108
|
|
|
@@ -95,7 +111,7 @@ Provide both a start and end frame image:
|
|
|
95
111
|
```json
|
|
96
112
|
POST /seedance/videos
|
|
97
113
|
{
|
|
98
|
-
"model": "doubao-seedance-
|
|
114
|
+
"model": "doubao-seedance-2-0-260128",
|
|
99
115
|
"content": [
|
|
100
116
|
{"type": "text", "text": "smooth transition between two scenes"},
|
|
101
117
|
{"type": "image_url", "role": "first_frame", "image_url": {"url": "https://example.com/start.jpg"}},
|
|
@@ -104,18 +120,53 @@ POST /seedance/videos
|
|
|
104
120
|
}
|
|
105
121
|
```
|
|
106
122
|
|
|
123
|
+
### 4. Real-person / character reference (Seedance 2.0)
|
|
124
|
+
|
|
125
|
+
Seedance 2.0 models (`doubao-seedance-2-0-260128`, `doubao-seedance-2-0-fast-260128`, `doubao-seedance-2-0-mini-260615`) can keep a **specific person or character** consistent across a brand-new scene. Pass one or more photos as `image_url` items with `role: "reference_image"` — the model preserves that subject's appearance. Up to 9 reference images are accepted.
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
POST /seedance/videos
|
|
129
|
+
{
|
|
130
|
+
"model": "doubao-seedance-2-0-260128",
|
|
131
|
+
"content": [
|
|
132
|
+
{"type": "text", "text": "the same person walking through a neon-lit night market, cinematic"},
|
|
133
|
+
{"type": "image_url", "role": "reference_image", "image_url": {"url": "https://example.com/person.jpg"}}
|
|
134
|
+
],
|
|
135
|
+
"resolution": "1080p",
|
|
136
|
+
"duration": 8
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 5. Reference audio / video (Seedance 2.0)
|
|
141
|
+
|
|
142
|
+
2.0 models also accept reference **audio** (voice timbre, background music) and reference **video** (subject content, camera movement, motion, overall style). Add `audio_url` and/or `video_url` content items. Limits: up to 3 audio and 3 video references per request.
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
POST /seedance/videos
|
|
146
|
+
{
|
|
147
|
+
"model": "doubao-seedance-2-0-260128",
|
|
148
|
+
"content": [
|
|
149
|
+
{"type": "text", "text": "a singer performing on stage, matching the reference voice and motion"},
|
|
150
|
+
{"type": "image_url", "role": "reference_image", "image_url": {"url": "https://example.com/person.jpg"}},
|
|
151
|
+
{"type": "audio_url", "audio_url": {"url": "https://example.com/voice.mp3"}},
|
|
152
|
+
{"type": "video_url", "video_url": {"url": "https://example.com/motion.mp4"}}
|
|
153
|
+
],
|
|
154
|
+
"generate_audio": true
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
107
158
|
## Parameters
|
|
108
159
|
|
|
109
160
|
| Parameter | Values | Description |
|
|
110
161
|
|-----------|--------|-------------|
|
|
111
162
|
| `model` | see Models table | Model to use (required) |
|
|
112
|
-
| `content` | array | Input items: text
|
|
113
|
-
| `resolution` | `"480p"`, `"720p"`, `"1080p"` | Output resolution (default: 720p for pro, 480p for lite) |
|
|
163
|
+
| `content` | array | Input items: `text`, `image_url`, `audio_url` (2.0), `video_url` (2.0) (required) |
|
|
164
|
+
| `resolution` | `"480p"`, `"720p"`, `"1080p"`, `"4k"` | Output resolution. `4k` is `doubao-seedance-2-0-260128` (standard) only; `2-0-fast` / `2-0-mini` max out at `720p` (default: 720p for pro/2.0, 480p for lite) |
|
|
114
165
|
| `ratio` | `"16:9"`, `"4:3"`, `"1:1"`, `"3:4"`, `"9:16"`, `"21:9"`, `"adaptive"` | Aspect ratio (default: 16:9) |
|
|
115
|
-
| `duration` | `2` – `
|
|
116
|
-
| `frames` | 29–
|
|
166
|
+
| `duration` | `2` – `15` | Duration in seconds (Seedance 2.0 supports 4–15) |
|
|
167
|
+
| `frames` | 29–361 (must satisfy 25+4n) | Frame count — mutually exclusive with `duration` |
|
|
117
168
|
| `seed` | -1 to 4294967295 | Seed for reproducible results (-1 = random) |
|
|
118
|
-
| `generate_audio` | `true` / `false` | Generate audio (
|
|
169
|
+
| `generate_audio` | `true` / `false` | Generate audio (supported by `doubao-seedance-1-5-pro-251215` and the `doubao-seedance-2-0` series; other models ignore it) |
|
|
119
170
|
| `camerafixed` | `true` / `false` | Fix the camera position during generation |
|
|
120
171
|
| `watermark` | `true` / `false` | Add a watermark to the generated video |
|
|
121
172
|
| `return_last_frame` | `true` / `false` | Return the last frame of the generated video |
|
|
@@ -137,12 +188,13 @@ Supported inline params: `--rs` (resolution), `--rt` (ratio), `--dur` (duration)
|
|
|
137
188
|
- Model names use the `doubao-*` convention (e.g. `doubao-seedance-1-0-pro-250528`) — old short names like `seedance-1.0` are not valid
|
|
138
189
|
- The `content` array replaces the old `prompt` + `image_url` fields; always use `content`
|
|
139
190
|
- Image and text scenarios are mutually exclusive per content item — each item has either `text` or `image_url`, not both
|
|
140
|
-
- `first_frame
|
|
141
|
-
- `generate_audio: true` is
|
|
191
|
+
- `first_frame` and `last_frame` may be combined in one request, but `reference_image` is mutually exclusive with `first_frame` / `last_frame` — do not mix a reference image with first/last frames
|
|
192
|
+
- `generate_audio: true` is supported by `doubao-seedance-1-5-pro-251215` and the `doubao-seedance-2-0` series; other models ignore this field
|
|
142
193
|
- Lite models are split: `*-lite-t2v-*` only accepts text, `*-lite-i2v-*` only accepts image-to-video
|
|
143
|
-
-
|
|
194
|
+
- `audio_url` and `video_url` reference items are used by the **Seedance 2.0 series only**
|
|
195
|
+
- Resolution options are `480p`, `720p`, `1080p`, and `4k` (`4k` is `doubao-seedance-2-0-260128` only; `2-0-fast` / `2-0-mini` max out at `720p`) — there is no 360p or 540p
|
|
144
196
|
- `service_tier` values are `"default"` and `"flex"` (not "standard"/"premium")
|
|
145
|
-
- Duration range is **2–
|
|
197
|
+
- Duration range is **2–15 seconds** (Seedance 2.0 supports 4–15) — values outside this range will fail
|
|
146
198
|
- Task states use `"succeeded"` (not "completed") — check for this value when polling
|
|
147
199
|
|
|
148
200
|
> **MCP:** `pip install mcp-seedance` | Hosted: `https://seedance.mcp.acedata.cloud/mcp` | See [all MCP servers](../_shared/mcp-servers.md)
|