reelforge 0.4.2 → 0.5.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/README.md +10 -12
- package/dist/commands/config.js +5 -5
- package/dist/commands/create.js +13 -34
- package/dist/commands/images.js +8 -28
- package/dist/commands/llm.js +3 -3
- package/dist/commands/pipelines.js +3 -3
- package/dist/commands/tts.js +14 -15
- package/dist/index.js +1 -3
- package/package.json +2 -3
- package/dist/commands/workflows.js +0 -29
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ That's the whole story — no server to run.
|
|
|
44
44
|
|
|
45
45
|
### Self-hosting
|
|
46
46
|
|
|
47
|
-
If you want to run your own ReelForge Studio (own
|
|
47
|
+
If you want to run your own ReelForge Studio (own RelayX key, your own pricing) clone the upstream repo, `pnpm dev`, then point the CLI at it:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
50
|
rf --server http://localhost:8501 health
|
|
@@ -72,13 +72,12 @@ Run `rf <command> --help` for full details on any of these.
|
|
|
72
72
|
|
|
73
73
|
| command | what it does |
|
|
74
74
|
|---|---|
|
|
75
|
-
| `llm chat -p <text>` | Send one prompt to the configured LLM |
|
|
76
|
-
| `llm presets` | List built-in
|
|
77
|
-
| `tts edge -t <text> -o out.mp3` | Local Edge TTS synthesis |
|
|
78
|
-
| `tts
|
|
75
|
+
| `llm chat -p <text>` | Send one prompt to the configured LLM (RelayX gateway by default) |
|
|
76
|
+
| `llm presets` | List built-in RelayX model presets |
|
|
77
|
+
| `tts edge -t <text> -o out.mp3` | Local Edge TTS synthesis (free) |
|
|
78
|
+
| `tts relayx -t <text> -o out.mp3` | RelayX TTS (vox/index-tts-2, 149 built-in voices) |
|
|
79
79
|
| `tts voices [--locale zh]` | List supported Edge TTS voices |
|
|
80
|
-
| `images generate -p <prompt> -
|
|
81
|
-
| `images analyze -i <image>` | Reverse-describe an image |
|
|
80
|
+
| `images generate -p <prompt> -m rx-image-flux` | Image generation via RelayX (rx-image-z / rx-image-flux / rx-image-qwen) |
|
|
82
81
|
|
|
83
82
|
### Content generation
|
|
84
83
|
|
|
@@ -114,7 +113,6 @@ All `pipelines *` commands submit an **async task** and (by default) poll until
|
|
|
114
113
|
|
|
115
114
|
| command | what it does |
|
|
116
115
|
|---|---|
|
|
117
|
-
| `workflows list [--source runninghub] [--kind image]` | Browse ComfyUI workflows |
|
|
118
116
|
| `bgm list / upload <file> / delete <name>` | Manage background music |
|
|
119
117
|
| `files list / upload <file> / download <path> / delete <path>` | Manage user assets |
|
|
120
118
|
|
|
@@ -148,12 +146,12 @@ rf tasks list --limit 5
|
|
|
148
146
|
rf history get <task-id> --download recovered.mp4
|
|
149
147
|
|
|
150
148
|
# 4. JSON pipe for automation
|
|
151
|
-
rf
|
|
149
|
+
rf llm presets --json | jq '.[].defaultModel'
|
|
152
150
|
|
|
153
151
|
# 5. Configure & test LLM (self-hosted)
|
|
154
|
-
rf config set llm.api_key
|
|
155
|
-
rf config set llm.base_url https://
|
|
156
|
-
rf config set llm.model
|
|
152
|
+
rf config set llm.api_key rx-xxxxx # RelayX key (or your own provider key)
|
|
153
|
+
rf config set llm.base_url https://relayx.timor419.com/v1
|
|
154
|
+
rf config set llm.model anthropic/claude-4-7-sonnet
|
|
157
155
|
rf llm chat -p 'one-sentence summary of antifragile'
|
|
158
156
|
```
|
|
159
157
|
|
package/dist/commands/config.js
CHANGED
|
@@ -4,7 +4,7 @@ import { print } from "../utils/output.js";
|
|
|
4
4
|
export function registerConfig(program) {
|
|
5
5
|
const cfg = program
|
|
6
6
|
.command("config")
|
|
7
|
-
.description("Read or update the server config.yaml (LLM /
|
|
7
|
+
.description("Read or update the server config.yaml (LLM / RelayX keys)")
|
|
8
8
|
.helpOption("-h, --help", "show help");
|
|
9
9
|
cfg
|
|
10
10
|
.command("get")
|
|
@@ -22,10 +22,10 @@ export function registerConfig(program) {
|
|
|
22
22
|
"",
|
|
23
23
|
"Examples:",
|
|
24
24
|
" reelforge config set llm.api_key sk-xxxxxx",
|
|
25
|
-
" reelforge config set llm.base_url https://
|
|
26
|
-
" reelforge config set llm.model
|
|
27
|
-
" reelforge config set
|
|
28
|
-
" reelforge config set
|
|
25
|
+
" reelforge config set llm.base_url https://relayx.timor419.com/v1",
|
|
26
|
+
" reelforge config set llm.model openai/gpt-5-mini",
|
|
27
|
+
" reelforge config set relayx.api_key rx-xxxxxx",
|
|
28
|
+
" reelforge config set relayx.default_image_model rx-image-flux",
|
|
29
29
|
].join("\n"))
|
|
30
30
|
.action(async (key, value) => {
|
|
31
31
|
const parts = key.split(".");
|
package/dist/commands/create.js
CHANGED
|
@@ -7,18 +7,8 @@ import { downloadTo } from "../utils/download.js";
|
|
|
7
7
|
import { info, print, success, warn } from "../utils/output.js";
|
|
8
8
|
const LAST_CREATE_PATH = path.join(os.homedir(), ".reelforge", "last-create.json");
|
|
9
9
|
// ── Cost estimation (mirrors server src/lib/billing.ts) ──────────
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return 3;
|
|
13
|
-
const base = (wfKey.split("/").pop() || wfKey).toLowerCase();
|
|
14
|
-
if (base.startsWith("tts_"))
|
|
15
|
-
return 1;
|
|
16
|
-
if (base.startsWith("image_"))
|
|
17
|
-
return 3;
|
|
18
|
-
if (base.startsWith("analyse_") || base.startsWith("analyze_"))
|
|
19
|
-
return 2;
|
|
20
|
-
return 3;
|
|
21
|
-
}
|
|
10
|
+
const IMAGE_UNITS = 3; // matches ATOMIC_UNITS["images.generate"] in src/lib/billing.ts
|
|
11
|
+
const TTS_RELAYX_UNITS = 1; // matches ATOMIC_UNITS["tts.relayx"]
|
|
22
12
|
function estimateUnits(body) {
|
|
23
13
|
const mode = body.mode || "generate";
|
|
24
14
|
const titleExplicit = !!body.title;
|
|
@@ -31,12 +21,9 @@ function estimateUnits(body) {
|
|
|
31
21
|
: tplBase.startsWith("asset_")
|
|
32
22
|
? "asset"
|
|
33
23
|
: "image";
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
const ttsMode = body.tts_inference_mode || (body.tts_workflow ? "comfyui" : "local");
|
|
39
|
-
const ttsPerFrame = ttsMode === "comfyui" ? 1 : 0;
|
|
24
|
+
const mediaPerFrame = tplType === "image" ? IMAGE_UNITS : 0;
|
|
25
|
+
const ttsMode = body.tts_inference_mode || "edge";
|
|
26
|
+
const ttsPerFrame = ttsMode === "relayx" ? TTS_RELAYX_UNITS : 0;
|
|
40
27
|
const narrations = mode === "generate" ? 1 : 0;
|
|
41
28
|
const title = titleExplicit ? 0 : 1;
|
|
42
29
|
const imagePrompts = tplType === "static" ? 0 : 1;
|
|
@@ -147,14 +134,10 @@ function optsToBody(opts) {
|
|
|
147
134
|
out.tts_voice = opts.ttsVoice;
|
|
148
135
|
if (opts.voiceId !== undefined)
|
|
149
136
|
out.voice_id = opts.voiceId;
|
|
150
|
-
if (opts.ttsWorkflow !== undefined)
|
|
151
|
-
out.tts_workflow = opts.ttsWorkflow;
|
|
152
137
|
if (opts.ttsSpeed !== undefined)
|
|
153
138
|
out.tts_speed = opts.ttsSpeed;
|
|
154
|
-
if (opts.
|
|
155
|
-
out.
|
|
156
|
-
if (opts.mediaWorkflow !== undefined)
|
|
157
|
-
out.media_workflow = opts.mediaWorkflow;
|
|
139
|
+
if (opts.imageModel !== undefined)
|
|
140
|
+
out.image_model = opts.imageModel;
|
|
158
141
|
if (opts.frameTemplate !== undefined)
|
|
159
142
|
out.frame_template = opts.frameTemplate;
|
|
160
143
|
if (opts.promptPrefix !== undefined)
|
|
@@ -313,16 +296,14 @@ export function registerCreate(program) {
|
|
|
313
296
|
.option("--max-image-prompt-words <N>", "image prompt max words", (v) => parseInt(v, 10))
|
|
314
297
|
// --- Visual ---
|
|
315
298
|
.option("--frame-template <key>", "HTML frame template, e.g. 1080x1920/image_default.html")
|
|
316
|
-
.option("--
|
|
299
|
+
.option("--image-model <id>", "RelayX image model (rx-image-z | rx-image-flux | rx-image-qwen)")
|
|
317
300
|
.option("--prompt-prefix <text>", "raw style prefix prepended to every image prompt (overrides --style)")
|
|
318
301
|
.option("--style <preset>", "image style preset — shortcut for --prompt-prefix; see 'Style presets' below for the full list")
|
|
319
302
|
// --- Audio (TTS) ---
|
|
320
|
-
.option("--tts-voice <id>", "
|
|
303
|
+
.option("--tts-voice <id>", "TTS voice id; for edge use e.g. zh-CN-YunjianNeural / en-US-AriaNeural; for relayx use vox voice ids (default: 专业解说)")
|
|
321
304
|
.option("--tts-speed <n>", "speech speed 0.5..2", parseFloat)
|
|
322
|
-
.option("--tts-inference-mode <mode>", "local |
|
|
323
|
-
.option("--tts-workflow <key>", "ComfyUI TTS workflow (forces inference-mode=comfyui)")
|
|
305
|
+
.option("--tts-inference-mode <mode>", "edge (default, local Microsoft Edge TTS) | relayx (vox/index-tts-2 via RelayX)")
|
|
324
306
|
.option("--voice-id <id>", "alias of --tts-voice (legacy compat)")
|
|
325
|
-
.option("--ref-audio <path>", "reference audio for voice-cloning TTS workflows")
|
|
326
307
|
// --- Audio (BGM) ---
|
|
327
308
|
.option("--bgm <path>", "background music file path (server-side relative to bgm/)")
|
|
328
309
|
.option("--bgm-volume <n>", "BGM volume 0..1", parseFloat)
|
|
@@ -354,8 +335,8 @@ export function registerCreate(program) {
|
|
|
354
335
|
"",
|
|
355
336
|
"Param groups:",
|
|
356
337
|
" Content : --mode --title -n --split-mode --min/max-narration-words --min/max-image-prompt-words",
|
|
357
|
-
" Visual : --frame-template --
|
|
358
|
-
" TTS : --tts-voice --tts-speed --tts-inference-mode --
|
|
338
|
+
" Visual : --frame-template --image-model --style --prompt-prefix",
|
|
339
|
+
" TTS : --tts-voice --tts-speed --tts-inference-mode --voice-id",
|
|
359
340
|
" BGM : --bgm --bgm-volume --bgm-mode",
|
|
360
341
|
" Output : --video-fps --template-params -o --no-download --no-wait --poll-ms --timeout-ms",
|
|
361
342
|
" Workflow: --recipe --redo --dry-run",
|
|
@@ -373,8 +354,6 @@ export function registerCreate(program) {
|
|
|
373
354
|
"",
|
|
374
355
|
"Explore available resources (separate commands):",
|
|
375
356
|
" reelforge templates list # all HTML templates",
|
|
376
|
-
" reelforge workflows list --kind image # all AI image workflows",
|
|
377
|
-
" reelforge workflows list --kind video # all AI video workflows",
|
|
378
357
|
" reelforge tts voices --locale zh # Edge TTS voice ids",
|
|
379
358
|
" reelforge bgm list # built-in BGM files",
|
|
380
359
|
"",
|
|
@@ -427,7 +406,7 @@ export function registerCreate(program) {
|
|
|
427
406
|
' "text": "为什么我们还没找到外星文明?",',
|
|
428
407
|
' "n_scenes": 7,',
|
|
429
408
|
' "frame_template": "1080x1920/image_default.html",',
|
|
430
|
-
' "
|
|
409
|
+
' "image_model": "rx-image-flux",',
|
|
431
410
|
' "prompt_prefix": "Minimalist matchstick figure style",',
|
|
432
411
|
' "tts_voice": "zh-CN-YunjianNeural",',
|
|
433
412
|
' "tts_speed": 1.2,',
|
package/dist/commands/images.js
CHANGED
|
@@ -4,42 +4,32 @@ import { print, success } from "../utils/output.js";
|
|
|
4
4
|
export function registerImages(program) {
|
|
5
5
|
const images = program
|
|
6
6
|
.command("images")
|
|
7
|
-
.description("Image generation
|
|
7
|
+
.description("Image generation via RelayX (rx-image-z / rx-image-flux / rx-image-qwen)")
|
|
8
8
|
.helpOption("-h, --help", "show help");
|
|
9
9
|
images
|
|
10
10
|
.command("generate")
|
|
11
|
-
.description("Generate an image via
|
|
11
|
+
.description("Generate an image via RelayX")
|
|
12
12
|
.helpOption("-h, --help", "show help")
|
|
13
13
|
.requiredOption("-p, --prompt <text>", "text prompt")
|
|
14
|
-
.
|
|
14
|
+
.option("-m, --model <id>", "RelayX image model id (rx-image-z | rx-image-flux | rx-image-qwen)")
|
|
15
15
|
.option("--width <n>", "image width", parseInt)
|
|
16
16
|
.option("--height <n>", "image height", parseInt)
|
|
17
|
-
.option("--steps <n>", "sampling steps", parseInt)
|
|
18
|
-
.option("--seed <n>", "random seed", parseInt)
|
|
19
|
-
.option("--cfg <n>", "CFG scale", parseFloat)
|
|
20
|
-
.option("--negative <text>", "negative prompt")
|
|
21
17
|
.option("-o, --output <file>", "download first image to this local path")
|
|
22
18
|
.option("--all-output <dir>", "download ALL generated images into this directory")
|
|
23
19
|
.addHelpText("after", [
|
|
24
20
|
"",
|
|
25
21
|
"Examples:",
|
|
26
|
-
" reelforge images generate -p 'a cat' -
|
|
27
|
-
" reelforge images generate -p 'cyberpunk city'
|
|
22
|
+
" reelforge images generate -p 'a cat' -m rx-image-flux --width 1024 --height 1024 -o cat.png",
|
|
23
|
+
" reelforge images generate -p 'cyberpunk city, neon, 9:16' --width 1080 --height 1920 -o city.png",
|
|
28
24
|
].join("\n"))
|
|
29
25
|
.action(async (opts) => {
|
|
30
|
-
const body = { prompt: opts.prompt
|
|
26
|
+
const body = { prompt: opts.prompt };
|
|
27
|
+
if (opts.model)
|
|
28
|
+
body.model = opts.model;
|
|
31
29
|
if (opts.width !== undefined)
|
|
32
30
|
body.width = opts.width;
|
|
33
31
|
if (opts.height !== undefined)
|
|
34
32
|
body.height = opts.height;
|
|
35
|
-
if (opts.steps !== undefined)
|
|
36
|
-
body.steps = opts.steps;
|
|
37
|
-
if (opts.seed !== undefined)
|
|
38
|
-
body.seed = opts.seed;
|
|
39
|
-
if (opts.cfg !== undefined)
|
|
40
|
-
body.cfg = opts.cfg;
|
|
41
|
-
if (opts.negative)
|
|
42
|
-
body.negative_prompt = opts.negative;
|
|
43
33
|
const r = await post("/api/v1/images/generate", body);
|
|
44
34
|
if (opts.output && r.images?.[0]) {
|
|
45
35
|
await downloadTo(r.images[0], opts.output);
|
|
@@ -54,14 +44,4 @@ export function registerImages(program) {
|
|
|
54
44
|
}
|
|
55
45
|
print(r);
|
|
56
46
|
});
|
|
57
|
-
images
|
|
58
|
-
.command("analyze")
|
|
59
|
-
.description("Reverse-describe an image using an analyse_image workflow")
|
|
60
|
-
.helpOption("-h, --help", "show help")
|
|
61
|
-
.requiredOption("-i, --image <pathOrUrl>", "image to analyze (local path or URL)")
|
|
62
|
-
.option("-w, --workflow <key>", "workflow key", "selfhost/analyse_image.json")
|
|
63
|
-
.action(async (opts) => {
|
|
64
|
-
const r = await post("/api/v1/images/analyze", { image: opts.image, workflow: opts.workflow });
|
|
65
|
-
print(r);
|
|
66
|
-
});
|
|
67
47
|
}
|
package/dist/commands/llm.js
CHANGED
|
@@ -4,7 +4,7 @@ import { print, table } from "../utils/output.js";
|
|
|
4
4
|
export function registerLlm(program) {
|
|
5
5
|
const llm = program
|
|
6
6
|
.command("llm")
|
|
7
|
-
.description("Large-language-model utilities (chat, list
|
|
7
|
+
.description("Large-language-model utilities (chat, list RelayX model presets)")
|
|
8
8
|
.helpOption("-h, --help", "show help");
|
|
9
9
|
llm
|
|
10
10
|
.command("chat")
|
|
@@ -21,7 +21,7 @@ export function registerLlm(program) {
|
|
|
21
21
|
"",
|
|
22
22
|
"Examples:",
|
|
23
23
|
" reelforge llm chat -p 'Hello'",
|
|
24
|
-
" reelforge llm chat -p @prompt.txt -m
|
|
24
|
+
" reelforge llm chat -p @prompt.txt -m anthropic/claude-4-7-sonnet -t 0.4",
|
|
25
25
|
" reelforge llm chat -p 'movie review of Inception' --schema review.json --json",
|
|
26
26
|
].join("\n"))
|
|
27
27
|
.action(async (opts) => {
|
|
@@ -47,7 +47,7 @@ export function registerLlm(program) {
|
|
|
47
47
|
});
|
|
48
48
|
llm
|
|
49
49
|
.command("presets")
|
|
50
|
-
.description("List built-in
|
|
50
|
+
.description("List built-in RelayX model presets (GPT-5 / Claude 4.7 / Gemini 3 / DeepSeek / Qwen / Kimi)")
|
|
51
51
|
.helpOption("-h, --help", "show help")
|
|
52
52
|
.action(async () => {
|
|
53
53
|
const r = await get("/api/v1/llm/presets");
|
|
@@ -47,7 +47,7 @@ export function registerPipelines(program) {
|
|
|
47
47
|
.option("-n, --n-scenes <n>", "number of scenes (mode=generate)", parseInt, 5)
|
|
48
48
|
.option("--split-mode <mode>", "paragraph | line | sentence (mode=fixed)", "paragraph")
|
|
49
49
|
.option("--frame-template <key>", "template, e.g. 1080x1920/static_default.html", "1080x1920/static_default.html")
|
|
50
|
-
.option("--
|
|
50
|
+
.option("--image-model <id>", "RelayX image model (rx-image-z | rx-image-flux | rx-image-qwen) — only when template requires AI images")
|
|
51
51
|
.option("--prompt-prefix <text>", "style prefix prepended to image prompts")
|
|
52
52
|
.option("--tts-voice <id>", "Edge TTS voice", "zh-CN-YunjianNeural")
|
|
53
53
|
.option("--tts-speed <n>", "speech speed (0.5..2)", parseFloat, 1.2)
|
|
@@ -58,7 +58,7 @@ export function registerPipelines(program) {
|
|
|
58
58
|
"Examples:",
|
|
59
59
|
" reelforge pipelines standard -t 'why we explore space' -n 5 -o space.mp4",
|
|
60
60
|
" reelforge pipelines standard -t @script.txt --mode fixed --split-mode paragraph --title 'My Show' -o out.mp4",
|
|
61
|
-
" reelforge pipelines standard -t '宠物' --frame-template 1080x1920/image_default.html --
|
|
61
|
+
" reelforge pipelines standard -t '宠物' --frame-template 1080x1920/image_default.html --image-model rx-image-flux --prompt-prefix 'cinematic'",
|
|
62
62
|
].join("\n"))).action(async (opts) => {
|
|
63
63
|
let text = opts.text;
|
|
64
64
|
if (text.startsWith("@"))
|
|
@@ -70,7 +70,7 @@ export function registerPipelines(program) {
|
|
|
70
70
|
n_scenes: opts.nScenes,
|
|
71
71
|
split_mode: opts.splitMode,
|
|
72
72
|
frame_template: opts.frameTemplate,
|
|
73
|
-
|
|
73
|
+
image_model: opts.imageModel,
|
|
74
74
|
prompt_prefix: opts.promptPrefix,
|
|
75
75
|
tts_voice: opts.ttsVoice,
|
|
76
76
|
tts_speed: opts.ttsSpeed,
|
package/dist/commands/tts.js
CHANGED
|
@@ -4,7 +4,7 @@ import { print, table, success } from "../utils/output.js";
|
|
|
4
4
|
export function registerTts(program) {
|
|
5
5
|
const tts = program
|
|
6
6
|
.command("tts")
|
|
7
|
-
.description("Text-to-speech: local Edge TTS or
|
|
7
|
+
.description("Text-to-speech: local Edge TTS (free) or RelayX vox/index-tts-2")
|
|
8
8
|
.helpOption("-h, --help", "show help");
|
|
9
9
|
tts
|
|
10
10
|
.command("edge")
|
|
@@ -37,32 +37,31 @@ export function registerTts(program) {
|
|
|
37
37
|
print({ ok: r.ok, voice: r.voice, rate: r.rate, size_bytes: r.size_bytes, file_path: r.file_path, url: r.url, downloaded_to: opts.output || null });
|
|
38
38
|
});
|
|
39
39
|
tts
|
|
40
|
-
.command("
|
|
41
|
-
.description("Synthesize speech via
|
|
40
|
+
.command("relayx")
|
|
41
|
+
.description("Synthesize speech via RelayX (vox/index-tts-2 by default; 149 built-in voices)")
|
|
42
42
|
.helpOption("-h, --help", "show help")
|
|
43
43
|
.requiredOption("-t, --text <text>", "text to synthesize")
|
|
44
|
-
.
|
|
45
|
-
.option("--voice <id>", "voice
|
|
46
|
-
.option("--speed <n>", "speech speed multiplier", parseFloat)
|
|
47
|
-
.option("--ref-audio <path>", "reference audio (URL or local path) for clone-style workflows")
|
|
44
|
+
.option("-m, --model <id>", "RelayX TTS model id (default: vox/index-tts-2)")
|
|
45
|
+
.option("--voice <id>", "voice id within the model (vox default: 专业解说)")
|
|
46
|
+
.option("--speed <n>", "speech speed multiplier (0.5..2)", parseFloat)
|
|
48
47
|
.option("-o, --output <file>", "download audio to this local path")
|
|
49
48
|
.addHelpText("after", [
|
|
50
49
|
"",
|
|
51
50
|
"Example:",
|
|
52
|
-
" reelforge tts
|
|
51
|
+
" reelforge tts relayx -t '你好世界' --voice '专业解说' -o hello.mp3",
|
|
53
52
|
].join("\n"))
|
|
54
53
|
.action(async (opts) => {
|
|
55
|
-
const body = { text: opts.text
|
|
54
|
+
const body = { text: opts.text };
|
|
55
|
+
if (opts.model)
|
|
56
|
+
body.model = opts.model;
|
|
56
57
|
if (opts.voice)
|
|
57
58
|
body.voice = opts.voice;
|
|
58
59
|
if (opts.speed !== undefined)
|
|
59
60
|
body.speed = opts.speed;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
await downloadTo(r.audio_url, opts.output);
|
|
65
|
-
success(`Saved → ${opts.output}`);
|
|
61
|
+
const r = await post("/api/v1/tts/relayx", body);
|
|
62
|
+
if (opts.output) {
|
|
63
|
+
await downloadTo(r.url, opts.output);
|
|
64
|
+
success(`Saved → ${opts.output} (${r.size_bytes} bytes, model=${r.model}, voice=${r.voice})`);
|
|
66
65
|
}
|
|
67
66
|
print(r);
|
|
68
67
|
});
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,6 @@ import { registerTemplates } from "./commands/templates.js";
|
|
|
22
22
|
import { registerFrames } from "./commands/frames.js";
|
|
23
23
|
import { registerCompositions } from "./commands/compositions.js";
|
|
24
24
|
import { registerPipelines } from "./commands/pipelines.js";
|
|
25
|
-
import { registerWorkflows } from "./commands/workflows.js";
|
|
26
25
|
import { registerBgm } from "./commands/bgm.js";
|
|
27
26
|
import { registerFiles } from "./commands/files.js";
|
|
28
27
|
import { registerTasks } from "./commands/tasks.js";
|
|
@@ -69,7 +68,7 @@ program.addHelpText("afterAll", [
|
|
|
69
68
|
" rf create '...' -o ./videos/space.mp4 # pick the exact path",
|
|
70
69
|
" rf llm chat --prompt 'explain antifragile in 3 sentences'",
|
|
71
70
|
" rf tts edge --text 'hello world' --voice en-US-AriaNeural -o out.mp3",
|
|
72
|
-
" rf images generate --prompt 'a cat' --
|
|
71
|
+
" rf images generate --prompt 'a cat' --model rx-image-flux -o cat.png",
|
|
73
72
|
" rf pipelines standard --text 'why we explore space' --tts-voice zh-CN-YunjianNeural",
|
|
74
73
|
" rf tasks list --status running",
|
|
75
74
|
" rf config get",
|
|
@@ -84,7 +83,6 @@ registerTemplates(program);
|
|
|
84
83
|
registerFrames(program);
|
|
85
84
|
registerCompositions(program);
|
|
86
85
|
registerPipelines(program);
|
|
87
|
-
registerWorkflows(program);
|
|
88
86
|
registerBgm(program);
|
|
89
87
|
registerFiles(program);
|
|
90
88
|
registerTasks(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reelforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "CLI for ReelForge Studio — AI video engine. Installs as both `reelforge` and the short alias `rf`. Every REST API exposed as a command, with --help on every level.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,8 +35,7 @@
|
|
|
35
35
|
"keywords": [
|
|
36
36
|
"reelforge",
|
|
37
37
|
"ai-video",
|
|
38
|
-
"
|
|
39
|
-
"runninghub",
|
|
38
|
+
"relayx",
|
|
40
39
|
"tts",
|
|
41
40
|
"edge-tts",
|
|
42
41
|
"ffmpeg",
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { get } from "../client.js";
|
|
2
|
-
import { table } from "../utils/output.js";
|
|
3
|
-
export function registerWorkflows(program) {
|
|
4
|
-
const wf = program
|
|
5
|
-
.command("workflows")
|
|
6
|
-
.alias("workflow")
|
|
7
|
-
.description("Browse ComfyUI / RunningHub workflows under workflows/")
|
|
8
|
-
.helpOption("-h, --help", "show help");
|
|
9
|
-
wf
|
|
10
|
-
.command("list")
|
|
11
|
-
.description("List all available workflows")
|
|
12
|
-
.helpOption("-h, --help", "show help")
|
|
13
|
-
.option("--source <src>", "filter by source: selfhost | runninghub")
|
|
14
|
-
.option("--kind <kind>", "filter by kind: image | tts | analyse")
|
|
15
|
-
.action(async (opts) => {
|
|
16
|
-
const qs = new URLSearchParams();
|
|
17
|
-
if (opts.source)
|
|
18
|
-
qs.set("source", opts.source);
|
|
19
|
-
if (opts.kind)
|
|
20
|
-
qs.set("kind", opts.kind);
|
|
21
|
-
const r = await get(`/api/v1/workflows${qs.toString() ? `?${qs}` : ""}`);
|
|
22
|
-
table(r.workflows.map((w) => ({
|
|
23
|
-
key: w.key,
|
|
24
|
-
source: w.source,
|
|
25
|
-
kind: w.kind,
|
|
26
|
-
workflow_id: w.workflow_id || "-",
|
|
27
|
-
})));
|
|
28
|
-
});
|
|
29
|
-
}
|