@remixmate/cli 0.9.56 → 0.9.57
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.
|
@@ -18,15 +18,20 @@ import { getCapabilities } from '../capabilities.js';
|
|
|
18
18
|
import { emitProgress } from '../progress.js';
|
|
19
19
|
import { isTrue, toNumber } from './shared.js';
|
|
20
20
|
const CLONE_TYPES = ['video', 'image'];
|
|
21
|
+
/**
|
|
22
|
+
* The only provider currently wired end to end (HiFly). HiFly's generate APIs
|
|
23
|
+
* take no aspect ratio or action prompt — the output keeps the cloned source's
|
|
24
|
+
* framing — so the handler sends neither.
|
|
25
|
+
*/
|
|
26
|
+
const ACTIVE_SOURCE = 'hifly';
|
|
21
27
|
function toId(value) {
|
|
22
28
|
if (value === undefined || value === null)
|
|
23
29
|
return '';
|
|
24
30
|
return String(value).trim();
|
|
25
31
|
}
|
|
26
32
|
async function listAvatars(ctx, input) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
payload.source = String(input.source);
|
|
33
|
+
// Only avatars of the active provider can be driven, so only those are listed.
|
|
34
|
+
const payload = { current: 1, pageSize: 100, source: ACTIVE_SOURCE };
|
|
30
35
|
if (input.gender)
|
|
31
36
|
payload.gender = String(input.gender);
|
|
32
37
|
if (isTrue(input.mine))
|
|
@@ -48,23 +53,26 @@ async function listAvatars(ctx, input) {
|
|
|
48
53
|
for (const a of avatars) {
|
|
49
54
|
process.stdout.write(`${toId(a.id).padEnd(24)} ${String(a.name ?? '').padEnd(16)} ${String(a.source ?? '').padEnd(14)} ${String(a.gender ?? '').padEnd(8)} ${String(a.aspectRatio ?? '').padEnd(6)} ${a.cloneStatus || '-'}\n`);
|
|
50
55
|
}
|
|
51
|
-
|
|
56
|
+
const total = data.pager?.total ?? avatars.length;
|
|
57
|
+
process.stdout.write(`\n${avatars.length} avatar(s) shown${total > avatars.length ? ` of ${total}; narrow with --name` : ''}\n`);
|
|
52
58
|
process.stdout.write('💡 Use --avatar-id <ID> to pick an avatar for generation\n');
|
|
53
59
|
}
|
|
54
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Look up one avatar's metadata. Only the caller's own avatars are searched: they
|
|
62
|
+
* are few, and they are the only ones that can be mid-clone or failed. The public
|
|
63
|
+
* HiFly catalog has ~1000 entries, far beyond one page, so a public id that is not
|
|
64
|
+
* among "mine" is passed through as-is and the backend validates it (unknown ids
|
|
65
|
+
* come back as a business error).
|
|
66
|
+
*/
|
|
55
67
|
async function fetchAvatarInfo(ctx, avatarId) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (found)
|
|
60
|
-
return found;
|
|
61
|
-
}
|
|
62
|
-
throw new SkillError(`❌ avatar_id=${avatarId} not found; use --list-avatars [--mine] to see what is available`);
|
|
68
|
+
const data = await mmPost(ctx, '/digital-human/avatar/page', { current: 1, pageSize: 100, mine: true, source: ACTIVE_SOURCE }, { timeoutMs: 30_000 });
|
|
69
|
+
const found = (data.list ?? []).find((a) => toId(a.id) === avatarId);
|
|
70
|
+
return found ?? { id: avatarId, source: ACTIVE_SOURCE };
|
|
63
71
|
}
|
|
64
|
-
function resolveSource(
|
|
65
|
-
const src = (
|
|
72
|
+
function resolveSource(avatar, validSources) {
|
|
73
|
+
const src = (avatar.source ?? '').trim() || ACTIVE_SOURCE;
|
|
66
74
|
if (!validSources.includes(src)) {
|
|
67
|
-
throw new SkillError(`❌
|
|
75
|
+
throw new SkillError(`❌ avatar uses provider "${src}", which is not available (supported: ${validSources.join('/')}). Pick another avatar from --list-avatars.`);
|
|
68
76
|
}
|
|
69
77
|
return src;
|
|
70
78
|
}
|
|
@@ -86,8 +94,6 @@ async function cloneAvatar(ctx, input) {
|
|
|
86
94
|
payload.thumbnailUrl = toId(input.thumbnail_url);
|
|
87
95
|
if (input.gender)
|
|
88
96
|
payload.gender = toId(input.gender);
|
|
89
|
-
if (input.aspect_ratio)
|
|
90
|
-
payload.aspectRatio = toId(input.aspect_ratio);
|
|
91
97
|
emitProgress({ phase: 'gen-digital-human:clone-request', sourceType });
|
|
92
98
|
const data = await mmPost(ctx, '/digital-human/avatar/clone', payload, { timeoutMs: 60_000 });
|
|
93
99
|
const avatarId = toId(data.id);
|
|
@@ -210,6 +216,9 @@ export async function genDigitalHuman(input, ctxIn) {
|
|
|
210
216
|
}
|
|
211
217
|
const audioUrl = (input.audio_url ?? '').trim();
|
|
212
218
|
const text = input.text ?? '';
|
|
219
|
+
if (audioUrl && !/^https?:\/\//i.test(audioUrl)) {
|
|
220
|
+
throw new SkillError(`❌ --audio-url needs a public http(s) URL (local files are not uploaded), received: ${audioUrl}`);
|
|
221
|
+
}
|
|
213
222
|
if (!audioUrl) {
|
|
214
223
|
if (!text.trim()) {
|
|
215
224
|
throw new SkillError('❌ in TTS mode provide --text, or use --audio-url for audio-driven mode');
|
|
@@ -224,12 +233,10 @@ export async function genDigitalHuman(input, ctxIn) {
|
|
|
224
233
|
if (avatar.cloneStatus === 'failed') {
|
|
225
234
|
throw new SkillError(`❌ avatar ${avatarId} failed to clone (${avatar.cloneError || 'unknown error'}); clone it again`);
|
|
226
235
|
}
|
|
227
|
-
const source = resolveSource(
|
|
236
|
+
const source = resolveSource(avatar, dh.sources);
|
|
228
237
|
const payload = { avatarId, source };
|
|
229
238
|
if (audioUrl) {
|
|
230
239
|
payload.audioUrl = audioUrl;
|
|
231
|
-
if (text.trim())
|
|
232
|
-
payload.text = text.trim();
|
|
233
240
|
}
|
|
234
241
|
else {
|
|
235
242
|
payload.text = text;
|
|
@@ -237,11 +244,6 @@ export async function genDigitalHuman(input, ctxIn) {
|
|
|
237
244
|
if (input.voice_name)
|
|
238
245
|
payload.voiceName = String(input.voice_name);
|
|
239
246
|
}
|
|
240
|
-
const aspectRatio = input.aspect_ratio ?? avatar.aspectRatio;
|
|
241
|
-
if (aspectRatio)
|
|
242
|
-
payload.aspectRatio = aspectRatio;
|
|
243
|
-
if (input.prompt)
|
|
244
|
-
payload.prompt = String(input.prompt);
|
|
245
247
|
emitProgress({ phase: 'gen-digital-human:request', avatarId, source, mode: audioUrl ? 'audio' : 'tts' });
|
|
246
248
|
const data = await mmPost(ctx, '/digital-human/video/generate', payload, { timeoutMs: 60_000 });
|
|
247
249
|
const generationId = data.generationId;
|
package/dist/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"version": "0.9.57",
|
|
4
|
+
"generatedAt": "2026-09-29T07:05:55.130Z",
|
|
5
5
|
"skills": [
|
|
6
6
|
{
|
|
7
7
|
"id": "doc-parse",
|
|
@@ -169,13 +169,12 @@
|
|
|
169
169
|
"tier": "atomic",
|
|
170
170
|
"category": "asset",
|
|
171
171
|
"title": "Digital-Human Talking-Head",
|
|
172
|
-
"summary": "Digital-human video: list
|
|
172
|
+
"summary": "Digital-human video (HiFly): list or clone avatars; produce a talking-head video from text via TTS, or drive an avatar from an existing audio URL. Aspect ratio follows the avatar's cloned source and cannot be chosen.",
|
|
173
173
|
"triggers": [
|
|
174
174
|
"Digital human, talking-head video, AI presenter, virtual host",
|
|
175
175
|
"Make a talking-head video out of this script / this audio file",
|
|
176
176
|
"List or browse digital-human avatars",
|
|
177
|
-
"
|
|
178
|
-
"Clone / create a custom avatar from a video or photo (HiFly)"
|
|
177
|
+
"Clone / create a custom avatar from a video or photo"
|
|
179
178
|
],
|
|
180
179
|
"entry": {
|
|
181
180
|
"type": "http",
|
|
@@ -202,14 +201,6 @@
|
|
|
202
201
|
"type": "string",
|
|
203
202
|
"description": "With list_avatars=true: fuzzy-filter avatars by name. With clone=true: the new avatar's name (required)."
|
|
204
203
|
},
|
|
205
|
-
"source": {
|
|
206
|
-
"type": "string",
|
|
207
|
-
"enum": [
|
|
208
|
-
"jimeng",
|
|
209
|
-
"hifly"
|
|
210
|
-
],
|
|
211
|
-
"description": "Provider filter / override. hifly avatars (including cloned custom avatars) are video-driven; jimeng is image-driven. Usually inferred from the avatar; pass it explicitly only when the avatar declares no source."
|
|
212
|
-
},
|
|
213
204
|
"gender": {
|
|
214
205
|
"type": "string",
|
|
215
206
|
"enum": [
|
|
@@ -240,7 +231,7 @@
|
|
|
240
231
|
},
|
|
241
232
|
"thumbnail_url": {
|
|
242
233
|
"type": "string",
|
|
243
|
-
"description": "With clone=true: optional cover image URL shown in avatar lists (image clones default to the image itself)."
|
|
234
|
+
"description": "With clone=true: optional cover image URL shown in avatar lists (image clones default to the image itself). The output aspect ratio always follows the cloned source; it cannot be chosen at generation time."
|
|
244
235
|
},
|
|
245
236
|
"wait": {
|
|
246
237
|
"type": "boolean",
|
|
@@ -252,28 +243,20 @@
|
|
|
252
243
|
},
|
|
253
244
|
"text": {
|
|
254
245
|
"type": "string",
|
|
255
|
-
"description": "Narration text (TTS mode)"
|
|
246
|
+
"description": "Narration text (TTS mode, ≤ 10000 chars). Synthesized with voice_id, then drives the avatar; the speech must last at least 5 s. Ignored when audio_url is given."
|
|
256
247
|
},
|
|
257
248
|
"audio_url": {
|
|
258
249
|
"type": "string",
|
|
259
|
-
"description": "Audio
|
|
250
|
+
"description": "Audio-driven mode: public http(s) URL of mp3 / m4a / wav, 5 s – 30 min, ≤ 100 MB. Takes precedence over text / voice_id."
|
|
260
251
|
},
|
|
261
252
|
"voice_id": {
|
|
262
253
|
"type": "string",
|
|
263
|
-
"description": "Voice id (TTS mode). Shares the
|
|
254
|
+
"description": "Voice id (TTS mode). Shares the catalog with gen-voice (including cloned voices) — call gen_voice with list_voices=true to see available ids rather than inventing one."
|
|
264
255
|
},
|
|
265
256
|
"voice_name": {
|
|
266
257
|
"type": "string",
|
|
267
258
|
"description": "Voice display name, recorded alongside voice_id for bookkeeping. Does not affect synthesis."
|
|
268
259
|
},
|
|
269
|
-
"aspect_ratio": {
|
|
270
|
-
"type": "string",
|
|
271
|
-
"description": "Aspect ratio: 9:16 / 16:9 / 3:4 / 1:1. Defaults to the avatar's own ratio."
|
|
272
|
-
},
|
|
273
|
-
"prompt": {
|
|
274
|
-
"type": "string",
|
|
275
|
-
"description": "Action prompt describing how the avatar should perform, e.g. 'more hand gestures'"
|
|
276
|
-
},
|
|
277
260
|
"check_status": {
|
|
278
261
|
"type": "boolean",
|
|
279
262
|
"description": "Status-check mode: poll an earlier job instead of starting a new one. Requires generation_id. Use this when a generate call timed out."
|
|
@@ -292,15 +275,11 @@
|
|
|
292
275
|
"ui": {
|
|
293
276
|
"primary": [
|
|
294
277
|
"avatar_id",
|
|
295
|
-
"text"
|
|
296
|
-
],
|
|
297
|
-
"advanced": [
|
|
298
|
-
"source",
|
|
278
|
+
"text",
|
|
299
279
|
"voice_id",
|
|
300
|
-
"aspect_ratio",
|
|
301
|
-
"prompt",
|
|
302
280
|
"audio_url"
|
|
303
281
|
],
|
|
282
|
+
"advanced": [],
|
|
304
283
|
"hidden": [
|
|
305
284
|
"json_output",
|
|
306
285
|
"list_avatars",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remixmate/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.57",
|
|
4
4
|
"description": "AI media generation skills for Claude Code / Codex — 12 skills covering image, video, voice, digital human, web screenshot, web recording, script, template registry, rendering, Jianying export, and video deconstruction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -1,117 +1,78 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gen-digital-human
|
|
3
3
|
description: |
|
|
4
|
-
Digital-human (talking-head) skill: list
|
|
4
|
+
Digital-human (talking-head) skill backed by HiFly: list avatars, clone a custom avatar from a video or photo, drive an avatar with text (TTS) or an existing audio URL, and check the status of pending jobs.
|
|
5
5
|
|
|
6
6
|
Use this skill immediately whenever the user asks for any of:
|
|
7
7
|
- Digital human, talking-head video, AI presenter, virtual host
|
|
8
8
|
- "Make a talking-head video out of this script / this audio file"
|
|
9
9
|
- List or browse digital-human avatars
|
|
10
|
-
-
|
|
11
|
-
- Clone / create a custom avatar from a video or photo (HiFly)
|
|
10
|
+
- Clone / create a custom avatar from a video or photo
|
|
12
11
|
|
|
13
12
|
Even without an explicit "use AI", any request that turns text or audio into a synthesized presenter video should route here.
|
|
14
13
|
triggers:
|
|
15
14
|
- Digital human, talking-head video, AI presenter, virtual host
|
|
16
15
|
- "Make a talking-head video out of this script / this audio file"
|
|
17
16
|
- List or browse digital-human avatars
|
|
18
|
-
-
|
|
19
|
-
- Clone / create a custom avatar from a video or photo (HiFly)
|
|
17
|
+
- Clone / create a custom avatar from a video or photo
|
|
20
18
|
---
|
|
21
19
|
|
|
22
20
|
# Digital-Human Skill
|
|
23
21
|
|
|
24
|
-
Wraps ab-api's digital-human endpoints (the same ones the web studio uses), authenticated with the **Tianyan privateToken**.
|
|
25
|
-
|
|
26
|
-
> This skill was migrated from a Python script to an remixmate CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_digital_human`, same params as in `skill.json`); local repro goes through `remixmate gen-digital-human ...`.
|
|
22
|
+
Wraps ab-api's digital-human endpoints (the same ones the web studio uses), authenticated with the **Tianyan privateToken**. The provider is **HiFly**: avatars are cloned from a video or photo, then driven by audio. Generation is async — the handler submits the task and polls `/digital-human/video/status` until completion.
|
|
27
23
|
|
|
28
24
|
## Capabilities
|
|
29
25
|
|
|
30
26
|
| Capability | Description | API |
|
|
31
27
|
|------------|-------------|-----|
|
|
32
|
-
| List avatars |
|
|
33
|
-
|
|
|
28
|
+
| List avatars | Public avatars, or your own with `--mine` | `POST /digital-human/avatar/page` |
|
|
29
|
+
| Text-driven | avatar + text + voice → speech is synthesized, then drives the avatar | `POST /digital-human/video/generate` |
|
|
34
30
|
| Audio-driven | avatar + existing audio URL → talking-head video | `POST /digital-human/video/generate` |
|
|
35
|
-
| Check status | Poll
|
|
36
|
-
| Clone avatar |
|
|
37
|
-
| Clone status |
|
|
38
|
-
|
|
39
|
-
Avatar ids are opaque strings (e.g. `dh_xxx`) — always copy them from `--list-avatars`, never invent or renumber them.
|
|
31
|
+
| Check status | Poll a generation job | `POST /digital-human/video/status` |
|
|
32
|
+
| Clone avatar | Custom avatar from a video (free) or portrait photo (costs HiFly credits) | `POST /digital-human/avatar/clone` |
|
|
33
|
+
| Clone status | `cloning` / `done` / `failed` for a cloned avatar | `POST /digital-human/avatar/clone-status` |
|
|
40
34
|
|
|
41
|
-
|
|
35
|
+
Avatar ids are opaque strings (e.g. `dh_xxx`) — always copy them from `--list-avatars`, never invent them.
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
**What you cannot choose**: aspect ratio and on-camera actions. The output keeps the framing of the source the avatar was cloned from (a 9:16 clone produces 9:16 videos). To get another ratio, clone the avatar from footage in that ratio.
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
**Cross-skill dependency**: voice ids are shared with `gen-voice` (including cloned voices). Use `gen-voice --list-voices` to see them.
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
- **Other environments**: configure the token. Without a token, non-interactive runs fail.
|
|
41
|
+
## Auth & environment
|
|
49
42
|
|
|
50
43
|
| Env var | Description | Default |
|
|
51
44
|
|---------|-------------|---------|
|
|
52
|
-
| `PRIV_TOKEN` | Tianyan token; `--priv-token` overrides | none |
|
|
45
|
+
| `PRIV_TOKEN` | Tianyan token; `--priv-token` overrides (not needed in Enterprise OpenClaw) | none |
|
|
53
46
|
| `MM_API_BASE_URL` | API root; `--api-base-url` overrides | `https://api.remixmate.ai/api` |
|
|
54
47
|
| `AGENT_NAME` | Optional `x-invoke-agent` header | none |
|
|
55
48
|
|
|
56
49
|
## Operations
|
|
57
50
|
|
|
58
|
-
|
|
51
|
+
Generation typically takes 1–5 minutes; the handler polls and emits `__progress__` lines. The resulting video URL is cloud-persisted — show it directly, no download needed.
|
|
59
52
|
|
|
60
53
|
### 1. List avatars
|
|
61
54
|
|
|
62
55
|
```bash
|
|
63
|
-
remixmate gen-digital-human --list-avatars
|
|
56
|
+
remixmate gen-digital-human --list-avatars --name "教师" # public avatars (~1000; always narrow with --name)
|
|
57
|
+
remixmate gen-digital-human --list-avatars --mine # your cloned avatars
|
|
58
|
+
remixmate gen-digital-human --list-avatars --gender female --name "alice"
|
|
64
59
|
```
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
# Filter by source (jimeng = image-driven, hifly = video-driven)
|
|
70
|
-
remixmate gen-digital-human --list-avatars --source jimeng
|
|
71
|
-
remixmate gen-digital-human --list-avatars --source hifly
|
|
72
|
-
|
|
73
|
-
# Filter by gender
|
|
74
|
-
remixmate gen-digital-human --list-avatars --gender female
|
|
75
|
-
|
|
76
|
-
# Show your custom avatars
|
|
77
|
-
remixmate gen-digital-human --list-avatars --mine
|
|
78
|
-
|
|
79
|
-
# Filter by name
|
|
80
|
-
remixmate gen-digital-human --list-avatars --name "alice"
|
|
81
|
-
```
|
|
61
|
+
### 2. Generate a video
|
|
82
62
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
### 2. Generate a digital-human video
|
|
86
|
-
|
|
87
|
-
#### TTS mode
|
|
63
|
+
Pick exactly one driver: **text** (+ voice) or **audio**. With `--audio-url`, text and voice are ignored.
|
|
88
64
|
|
|
89
65
|
```bash
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
--text "Hi everyone,
|
|
66
|
+
# Text-driven
|
|
67
|
+
remixmate gen-digital-human --avatar-id dh_xxx \
|
|
68
|
+
--text "Hi everyone, today I'll introduce a new product." \
|
|
93
69
|
--voice-id "male-qn-qingse"
|
|
94
|
-
```
|
|
95
70
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
remixmate gen-digital-human \
|
|
100
|
-
--avatar-id dh_xxx \
|
|
101
|
-
--text "Hi class, here's our brand-new course." \
|
|
102
|
-
--voice-id "female-shaonv" \
|
|
103
|
-
--aspect-ratio "9:16"
|
|
71
|
+
# Audio-driven
|
|
72
|
+
remixmate gen-digital-human --avatar-id dh_xxx --audio-url "https://example.com/voice.mp3"
|
|
104
73
|
```
|
|
105
74
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
remixmate gen-digital-human \
|
|
110
|
-
--avatar-id dh_yyy \
|
|
111
|
-
--source hifly \
|
|
112
|
-
--audio-url "https://example.com/voice.mp3" \
|
|
113
|
-
--aspect-ratio "16:9"
|
|
114
|
-
```
|
|
75
|
+
Limits: speech/audio must last **5 s – 30 min**; audio is mp3 / m4a / wav, ≤ 100 MB, public http(s) URL; text ≤ 10000 characters.
|
|
115
76
|
|
|
116
77
|
### 3. Check job status
|
|
117
78
|
|
|
@@ -119,7 +80,7 @@ remixmate gen-digital-human \
|
|
|
119
80
|
remixmate gen-digital-human --check-status --generation-id 123
|
|
120
81
|
```
|
|
121
82
|
|
|
122
|
-
### 4. Clone a custom avatar
|
|
83
|
+
### 4. Clone a custom avatar
|
|
123
84
|
|
|
124
85
|
The source must be a public http(s) URL (local files are not uploaded). Video: mp4/mov (h264), 5 s – 30 min, 360p – 4K, ≤ 500 MB, one person speaking to camera. Cloning takes minutes; the handler waits (up to ~20 min) and prints the new avatar id. The avatar also shows up under 素材库 → 数字人 in the web app.
|
|
125
86
|
|
|
@@ -127,7 +88,7 @@ The source must be a public http(s) URL (local files are not uploaded). Video: m
|
|
|
127
88
|
# Video clone (free)
|
|
128
89
|
remixmate gen-digital-human --clone --name "My presenter" --clone-url "https://example.com/me.mp4"
|
|
129
90
|
|
|
130
|
-
# Portrait
|
|
91
|
+
# Portrait photo clone (costs HiFly credits)
|
|
131
92
|
remixmate gen-digital-human --clone --clone-type image --name "My presenter" --clone-url "https://example.com/me.jpg"
|
|
132
93
|
|
|
133
94
|
# Submit without waiting, then poll
|
|
@@ -135,82 +96,26 @@ remixmate gen-digital-human --clone --wait false --name "My presenter" --clone-u
|
|
|
135
96
|
remixmate gen-digital-human --clone-status --avatar-id dh_xxx
|
|
136
97
|
```
|
|
137
98
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
|
145
|
-
|
|
146
|
-
| `--
|
|
147
|
-
| `--
|
|
148
|
-
| `--
|
|
149
|
-
| `--
|
|
150
|
-
| `--
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
|
155
|
-
|
|
156
|
-
| `--
|
|
157
|
-
|
|
|
158
|
-
| `--audio-url` | Audio URL (audio-driven mode) | none |
|
|
159
|
-
| `--voice-id` | Voice id (TTS mode) | `male-qn-qingse` |
|
|
160
|
-
| `--voice-name` | Voice display name (recordkeeping) | none |
|
|
161
|
-
| `--source` | `jimeng` / `hifly` (inferable from avatar) | auto |
|
|
162
|
-
| `--aspect-ratio` | `9:16` / `16:9` / `3:4` / `1:1` | avatar's default |
|
|
163
|
-
| `--prompt` | Action prompt (e.g. "more hand gestures") | none |
|
|
164
|
-
| `--api-base-url` | Override API root | see env vars |
|
|
165
|
-
| `--priv-token` | Override token | see env vars |
|
|
166
|
-
|
|
167
|
-
### Check status
|
|
168
|
-
|
|
169
|
-
| Flag | Description | Default |
|
|
170
|
-
|------|-------------|---------|
|
|
171
|
-
| `--check-status` | Enter status-check mode | — |
|
|
172
|
-
| `--generation-id` | Job id (required) | — |
|
|
173
|
-
|
|
174
|
-
### Clone avatar
|
|
175
|
-
|
|
176
|
-
| Flag | Description | Default |
|
|
177
|
-
|------|-------------|---------|
|
|
178
|
-
| `--clone` | Enter clone mode | — |
|
|
179
|
-
| `--name` | New avatar name (required) | — |
|
|
180
|
-
| `--clone-url` | Public URL of the source video / image (required) | — |
|
|
181
|
-
| `--clone-type` | `video` / `image` | `video` |
|
|
182
|
-
| `--thumbnail-url` | Cover image shown in lists | image itself / none |
|
|
183
|
-
| `--gender` | `male` / `female` | none |
|
|
184
|
-
| `--wait` | `false` to return right after submission | wait |
|
|
185
|
-
| `--clone-status` | Report clone status of `--avatar-id` | — |
|
|
186
|
-
|
|
187
|
-
## Typical flows
|
|
188
|
-
|
|
189
|
-
### Flow A — TTS
|
|
190
|
-
|
|
191
|
-
```
|
|
192
|
-
1. List avatars → --list-avatars [--gender female]
|
|
193
|
-
2. Pick avatar-id
|
|
194
|
-
3. Confirm or polish the speech text
|
|
195
|
-
4. (Optional) pick a voice → use gen-voice --list-voices
|
|
196
|
-
5. Generate → --avatar-id <id> --text "..." --voice-id "female-shaonv"
|
|
197
|
-
6. Show URL
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Flow B — Audio-driven
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
1. List avatars → --list-avatars [--mine]
|
|
204
|
-
2. Prepare an audio URL (gen-voice can produce one)
|
|
205
|
-
3. Generate → --avatar-id <id> --audio-url "https://..." [--source hifly]
|
|
206
|
-
4. Show URL
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
## Text guidance (TTS)
|
|
210
|
-
|
|
211
|
-
- Punctuation drives pacing — commas short, periods long.
|
|
212
|
-
- Keep individual jobs under ~500 characters.
|
|
213
|
-
- Tone and style of the script affect the perceived voice.
|
|
99
|
+
## Flags
|
|
100
|
+
|
|
101
|
+
| Flag | Mode | Description | Default |
|
|
102
|
+
|------|------|-------------|---------|
|
|
103
|
+
| `--list-avatars` | list | List avatars and exit | — |
|
|
104
|
+
| `--mine` | list | Only your own avatars | off |
|
|
105
|
+
| `--gender` | list / clone | `male` / `female` | none |
|
|
106
|
+
| `--name` | list / clone | Fuzzy filter; with `--clone` the new avatar's name (required) | — |
|
|
107
|
+
| `--avatar-id` | generate / clone-status | Avatar id (required) | — |
|
|
108
|
+
| `-t` / `--text` | generate | Script (text-driven) | — |
|
|
109
|
+
| `--voice-id` | generate | Voice id (text-driven) | `male-qn-qingse` |
|
|
110
|
+
| `--voice-name` | generate | Voice display name (recordkeeping only) | none |
|
|
111
|
+
| `--audio-url` | generate | Audio URL (audio-driven) | none |
|
|
112
|
+
| `--check-status` / `--generation-id` | status | Poll a generation job | — |
|
|
113
|
+
| `--clone` / `--clone-url` | clone | Clone mode and source URL (required) | — |
|
|
114
|
+
| `--clone-type` | clone | `video` / `image` | `video` |
|
|
115
|
+
| `--thumbnail-url` | clone | Cover shown in lists | image itself / none |
|
|
116
|
+
| `--wait` | clone | `false` to return right after submission | wait |
|
|
117
|
+
| `--clone-status` | clone-status | Report clone status of `--avatar-id` | — |
|
|
118
|
+
| `--api-base-url` / `--priv-token` | all | Overrides | see env vars |
|
|
214
119
|
|
|
215
120
|
## Credits
|
|
216
121
|
|
|
@@ -229,11 +134,10 @@ generation cost, and the balance is the only warning before a run fails with
|
|
|
229
134
|
- **401** / **token missing** (non-OpenClaw): set `PRIV_TOKEN`.
|
|
230
135
|
- **Business `code != 0`**: read `msg` on stderr.
|
|
231
136
|
- **429**: rate-limited; retry later.
|
|
232
|
-
- **Generation timeout**:
|
|
233
|
-
- **
|
|
137
|
+
- **Generation timeout**: polling caps at ~10 minutes; use `--check-status --generation-id <id>` later.
|
|
138
|
+
- **Speech/audio under 5 s**: lengthen the text or audio.
|
|
234
139
|
- **Invalid voice id**: re-check via `gen-voice --list-voices`.
|
|
235
140
|
- **Avatar id not found**: re-check via `--list-avatars` (or `--list-avatars --mine`).
|
|
236
141
|
- **Avatar still cloning / clone failed**: poll `--clone-status --avatar-id <id>`; on failure, re-clone with a clearer source (single speaker facing the camera, h264 mp4).
|
|
237
|
-
- **
|
|
238
|
-
- **Cannot infer source**: when the avatar lacks a `source` and `--source` is not set, pass `--source jimeng` or `--source hifly` explicitly.
|
|
142
|
+
- **User asks for a different aspect ratio or gestures**: not supported at generation time — explain that the ratio follows the cloned source, and offer to clone from footage in the wanted ratio.
|
|
239
143
|
- **Network**: verify connectivity and `MM_API_BASE_URL`.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"tier": "atomic",
|
|
5
5
|
"category": "asset",
|
|
6
6
|
"title": "Digital-Human Talking-Head",
|
|
7
|
-
"description": "Digital-human video: list
|
|
7
|
+
"description": "Digital-human video (HiFly): list or clone avatars; produce a talking-head video from text via TTS, or drive an avatar from an existing audio URL. Aspect ratio follows the avatar's cloned source and cannot be chosen.",
|
|
8
8
|
"auth": "required",
|
|
9
9
|
"joinsTake": true,
|
|
10
10
|
"envVars": [
|
|
@@ -31,14 +31,6 @@
|
|
|
31
31
|
"type": "string",
|
|
32
32
|
"description": "With list_avatars=true: fuzzy-filter avatars by name. With clone=true: the new avatar's name (required)."
|
|
33
33
|
},
|
|
34
|
-
"source": {
|
|
35
|
-
"type": "string",
|
|
36
|
-
"enum": [
|
|
37
|
-
"jimeng",
|
|
38
|
-
"hifly"
|
|
39
|
-
],
|
|
40
|
-
"description": "Provider filter / override. hifly avatars (including cloned custom avatars) are video-driven; jimeng is image-driven. Usually inferred from the avatar; pass it explicitly only when the avatar declares no source."
|
|
41
|
-
},
|
|
42
34
|
"gender": {
|
|
43
35
|
"type": "string",
|
|
44
36
|
"enum": [
|
|
@@ -69,7 +61,7 @@
|
|
|
69
61
|
},
|
|
70
62
|
"thumbnail_url": {
|
|
71
63
|
"type": "string",
|
|
72
|
-
"description": "With clone=true: optional cover image URL shown in avatar lists (image clones default to the image itself)."
|
|
64
|
+
"description": "With clone=true: optional cover image URL shown in avatar lists (image clones default to the image itself). The output aspect ratio always follows the cloned source; it cannot be chosen at generation time."
|
|
73
65
|
},
|
|
74
66
|
"wait": {
|
|
75
67
|
"type": "boolean",
|
|
@@ -81,28 +73,20 @@
|
|
|
81
73
|
},
|
|
82
74
|
"text": {
|
|
83
75
|
"type": "string",
|
|
84
|
-
"description": "Narration text (TTS mode)"
|
|
76
|
+
"description": "Narration text (TTS mode, ≤ 10000 chars). Synthesized with voice_id, then drives the avatar; the speech must last at least 5 s. Ignored when audio_url is given."
|
|
85
77
|
},
|
|
86
78
|
"audio_url": {
|
|
87
79
|
"type": "string",
|
|
88
|
-
"description": "Audio
|
|
80
|
+
"description": "Audio-driven mode: public http(s) URL of mp3 / m4a / wav, 5 s – 30 min, ≤ 100 MB. Takes precedence over text / voice_id."
|
|
89
81
|
},
|
|
90
82
|
"voice_id": {
|
|
91
83
|
"type": "string",
|
|
92
|
-
"description": "Voice id (TTS mode). Shares the
|
|
84
|
+
"description": "Voice id (TTS mode). Shares the catalog with gen-voice (including cloned voices) — call gen_voice with list_voices=true to see available ids rather than inventing one."
|
|
93
85
|
},
|
|
94
86
|
"voice_name": {
|
|
95
87
|
"type": "string",
|
|
96
88
|
"description": "Voice display name, recorded alongside voice_id for bookkeeping. Does not affect synthesis."
|
|
97
89
|
},
|
|
98
|
-
"aspect_ratio": {
|
|
99
|
-
"type": "string",
|
|
100
|
-
"description": "Aspect ratio: 9:16 / 16:9 / 3:4 / 1:1. Defaults to the avatar's own ratio."
|
|
101
|
-
},
|
|
102
|
-
"prompt": {
|
|
103
|
-
"type": "string",
|
|
104
|
-
"description": "Action prompt describing how the avatar should perform, e.g. 'more hand gestures'"
|
|
105
|
-
},
|
|
106
90
|
"check_status": {
|
|
107
91
|
"type": "boolean",
|
|
108
92
|
"description": "Status-check mode: poll an earlier job instead of starting a new one. Requires generation_id. Use this when a generate call timed out."
|
|
@@ -121,15 +105,11 @@
|
|
|
121
105
|
"ui": {
|
|
122
106
|
"primary": [
|
|
123
107
|
"avatar_id",
|
|
124
|
-
"text"
|
|
125
|
-
],
|
|
126
|
-
"advanced": [
|
|
127
|
-
"source",
|
|
108
|
+
"text",
|
|
128
109
|
"voice_id",
|
|
129
|
-
"aspect_ratio",
|
|
130
|
-
"prompt",
|
|
131
110
|
"audio_url"
|
|
132
111
|
],
|
|
112
|
+
"advanced": [],
|
|
133
113
|
"hidden": [
|
|
134
114
|
"json_output",
|
|
135
115
|
"list_avatars",
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "336",
|
|
5
5
|
"version": "V9",
|
|
6
|
-
"skillDescription": "Digital-human (talking-head) skill: list
|
|
6
|
+
"skillDescription": "Digital-human (talking-head) skill backed by HiFly: list avatars, clone a custom avatar from a video or photo, drive an avatar with text (TTS) or an existing audio URL, and check the status of pending jobs.\n\nUse this skill immediately whenever the user asks for any of:\n- Digital human, talking-head video, AI presenter, virtual host\n- \"Make a talking-head video out of this script / this audio file\"\n- List or browse digital-human avatars\n- Clone / create a custom avatar from a video or photo\n\nEven without an explicit \"use AI\", any request that turns text or audio into a synthesized presenter video should route here."
|
|
7
7
|
}
|