honeydo 0.1.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/LICENSE +21 -0
- package/README.md +90 -0
- package/README.zh-CN.md +88 -0
- package/package.json +54 -0
- package/packages/cli/dist/index.d.ts +2 -0
- package/packages/cli/dist/index.js +171 -0
- package/packages/cli/dist/index.js.map +1 -0
- package/packages/doubao/dist/cli.d.ts +38 -0
- package/packages/doubao/dist/cli.d.ts.map +1 -0
- package/packages/doubao/dist/cli.js +206 -0
- package/packages/gcli/dist/cli.d.ts +465 -0
- package/packages/gcli/dist/cli.js +2017 -0
- package/packages/gcli/dist/cli.js.map +1 -0
- package/packages/lmedia/dist/index.d.ts +1 -0
- package/packages/lmedia/dist/index.js +1594 -0
- package/packages/lmedia/python/edit.py +107 -0
- package/packages/lmedia/python/esrgan_path.py +16 -0
- package/packages/lmedia/python/gen.py +131 -0
- package/packages/lmedia/python/serve.py +352 -0
- package/packages/lmedia/python/sfx.py +527 -0
- package/packages/lmedia/python/teacache.py +255 -0
- package/packages/lmedia/python/upscale.py +41 -0
- package/packages/minimax/dist/cli.d.ts +51 -0
- package/packages/minimax/dist/cli.js +307 -0
- package/packages/minimax/dist/cli.js.map +1 -0
- package/packages/minimax/dist/client.d.ts +20 -0
- package/packages/minimax/dist/client.js +55 -0
- package/packages/minimax/dist/client.js.map +1 -0
- package/packages/minimax/dist/tts.d.ts +33 -0
- package/packages/minimax/dist/tts.js +64 -0
- package/packages/minimax/dist/tts.js.map +1 -0
- package/packages/minimax/dist/validate.d.ts +29 -0
- package/packages/minimax/dist/validate.js +122 -0
- package/packages/minimax/dist/validate.js.map +1 -0
- package/packages/minimax/dist/voice-clone.d.ts +17 -0
- package/packages/minimax/dist/voice-clone.js +47 -0
- package/packages/minimax/dist/voice-clone.js.map +1 -0
- package/packages/minimax/dist/voices.d.ts +17 -0
- package/packages/minimax/dist/voices.js +20 -0
- package/packages/minimax/dist/voices.js.map +1 -0
- package/packages/qwen/dist/index.d.ts +1 -0
- package/packages/qwen/dist/index.js +311 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""teacache.py — TeaCache 步缓存(Qwen-Image 系专用,纯 PyTorch,MPS 兼容)。
|
|
2
|
+
* 算法:相邻去噪步 block0 调制输入(信号 A)的 rel-L1 → 标定多项式 → 累计值 < 阈值则
|
|
3
|
+
* 跳过 60 个 transformer block(body),用「当前 img_in 输出 + 上次 body 残差」过 tail
|
|
4
|
+
* (norm_out+proj_out 很便宜)。不动权重/步数/CFG/调度器。
|
|
5
|
+
* 系数:mlx-teacache 在 Apple Silicon 的实测标定值(Signal A 原点约束拟合,R²=0.85;
|
|
6
|
+
* 阈值 0.30 → 24/48 步跳过、SSIM 0.987 视觉无损;SSIM 随阈值无悬崖衰减)。
|
|
7
|
+
* ⚠️ 不要用 ComfyUI/vllm 的 [-450,280,-45,3.2,-0.02]:标定域不同且常数项为负,
|
|
8
|
+
* 我们的 rel 尺度下 acc 一路负漂 → 无限跳过 → 输出浆糊(2026-08-29 实录)。
|
|
9
|
+
* CFG:diffusers Qwen 管线每步正/负两次调用、hidden_states 完全相同 → 每步共享一次
|
|
10
|
+
* 门控决策(与 mlx-teacache「shared CFG gate」一致),残差缓存按流分开。
|
|
11
|
+
* 绕行:batch>1(--num>1 或未来 CFG 合批)直接 passthrough,不缓存。
|
|
12
|
+
* 重置:scheduler 时间步单调递减,t 回升 = 新生成 → 全部重置(daemon 跨任务安全)。
|
|
13
|
+
* 实现:forward 拆 prelude/body/tail 三段复刻(与 diffusers 0.36 transformer_qwenimage.py
|
|
14
|
+
* 逐行对齐);skip 也要跑 prelude/tail(<2% 前向耗时)。
|
|
15
|
+
* 参考:TeaCache(CVPR2025, arXiv 2411.19108);github.com/IonDen/mlx-teacache(Qwen 标定)。
|
|
16
|
+
"""
|
|
17
|
+
import math
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
import torch
|
|
22
|
+
from diffusers.models.modeling_outputs import Transformer2DModelOutput
|
|
23
|
+
from diffusers.models.transformers.transformer_qwenimage import compute_text_seq_len_from_mask
|
|
24
|
+
|
|
25
|
+
TRACE = os.environ.get("LMEDIA_TEACACHE_TRACE") == "1"
|
|
26
|
+
|
|
27
|
+
# mlx-teacache Signal A 原点约束拟合(scripts/_calibration_qwen.json,2026-06 标定;c4..c0,c0=0)
|
|
28
|
+
QWEN_COEFFS = (-12.954226906135869, 8.883805167578382, -0.9363839862290331, 1.4538816050570036, 0.0)
|
|
29
|
+
|
|
30
|
+
DEFAULT_THRESHOLD = 0.30 # mlx-teacache 阈值扫描:SSIM 0.995@0.20 / 0.987@0.30 / 0.981@0.40
|
|
31
|
+
DEFAULT_WARMUP_STEPS = 4 # 前 N 步(每流前 N 次调用)强制 compute——结构形成期禁缓存
|
|
32
|
+
#(cache-dit 对 Qwen 默认 warmup=8;2048 大图均值信号对构图大改不敏感,
|
|
33
|
+
# 无 warmup 时早期误跳 → 轨迹锁死在错误构图,2026-08-30 实录)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _rescale(x: float) -> float:
|
|
37
|
+
c = QWEN_COEFFS
|
|
38
|
+
return c[0] * x**4 + c[1] * x**3 + c[2] * x**2 + c[3] * x + c[4]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TeaCache:
|
|
42
|
+
"""transformer.forward 级钩子。attach 后按 enabled/thresh 动态开关,per-job 复用。"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, thresh: float = DEFAULT_THRESHOLD, warmup: int = DEFAULT_WARMUP_STEPS):
|
|
45
|
+
self.thresh = float(thresh)
|
|
46
|
+
self.warmup = int(warmup) # 每流前 warmup 次调用强制 compute
|
|
47
|
+
self.enabled = True
|
|
48
|
+
# 双流(0=正 1=负)各自的残差缓存;信号/决策按步共享
|
|
49
|
+
self._streams = [self._stream(), self._stream()]
|
|
50
|
+
self._prev_signal: torch.Tensor | None = None
|
|
51
|
+
self._acc = 0.0
|
|
52
|
+
self._step_t: float | None = None
|
|
53
|
+
self._step_count = 0
|
|
54
|
+
self._pending: tuple[bool, torch.Tensor] | None = None # (skip?, signal) 给本步第二次调用
|
|
55
|
+
self._last_t: float | None = None
|
|
56
|
+
self.calls = 0
|
|
57
|
+
self.skips = 0
|
|
58
|
+
|
|
59
|
+
@staticmethod
|
|
60
|
+
def _stream() -> dict:
|
|
61
|
+
return {"res_img": None, "res_enc": None}
|
|
62
|
+
|
|
63
|
+
def reset(self) -> None:
|
|
64
|
+
self._streams = [self._stream(), self._stream()]
|
|
65
|
+
self._prev_signal = None
|
|
66
|
+
self._acc = 0.0
|
|
67
|
+
self._step_t = None
|
|
68
|
+
self._step_count = 0
|
|
69
|
+
self._pending = None
|
|
70
|
+
self._last_t = None
|
|
71
|
+
|
|
72
|
+
def begin_job(self) -> None:
|
|
73
|
+
"""每个生成任务开始:清零统计(缓存状态靠时间步回升自动重置)。"""
|
|
74
|
+
self.calls = 0
|
|
75
|
+
self.skips = 0
|
|
76
|
+
|
|
77
|
+
def stats(self) -> dict:
|
|
78
|
+
return {"calls": self.calls, "skips": self.skips, "thresh": self.thresh}
|
|
79
|
+
|
|
80
|
+
# ---- forward 三段复刻(diffusers 0.36 QwenImageTransformer2DModel)----
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def _prelude(m, hidden_states, encoder_hidden_states, encoder_hidden_states_mask,
|
|
84
|
+
timestep, img_shapes, guidance, additional_t_cond):
|
|
85
|
+
hs = m.img_in(hidden_states)
|
|
86
|
+
t = timestep.to(hs.dtype)
|
|
87
|
+
modulate_index = None
|
|
88
|
+
if m.zero_cond_t:
|
|
89
|
+
t = torch.cat([t, t * 0], dim=0)
|
|
90
|
+
modulate_index = torch.tensor(
|
|
91
|
+
[[0] * math.prod(s[0]) + [1] * sum(math.prod(x) for x in s[1:]) for s in img_shapes],
|
|
92
|
+
device=t.device, dtype=torch.int,
|
|
93
|
+
)
|
|
94
|
+
enc = m.txt_in(m.txt_norm(encoder_hidden_states))
|
|
95
|
+
text_seq_len, _, enc_mask = compute_text_seq_len_from_mask(enc, encoder_hidden_states_mask)
|
|
96
|
+
if guidance is not None:
|
|
97
|
+
guidance = guidance.to(hs.dtype) * 1000
|
|
98
|
+
temb = (
|
|
99
|
+
m.time_text_embed(t, hs, additional_t_cond)
|
|
100
|
+
if guidance is None
|
|
101
|
+
else m.time_text_embed(t, guidance, hs, additional_t_cond)
|
|
102
|
+
)
|
|
103
|
+
rope = m.pos_embed(img_shapes, max_txt_seq_len=text_seq_len, device=hs.device)
|
|
104
|
+
return hs, enc, enc_mask, t, temb, rope, modulate_index
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def _signal(m, hs, temb, modulate_index, img_shapes):
|
|
108
|
+
"""信号 A:block0 img 流调制输入的「主图 token」部分(条件图 token 恒定,会稀释 rel-L1
|
|
109
|
+
导致过度跳过——2026-08-29 实录 4ref 全序列信号把 57% 调用错误跳过)。"""
|
|
110
|
+
with torch.no_grad():
|
|
111
|
+
block = m.transformer_blocks[0]
|
|
112
|
+
img_mod1, _ = block.img_mod(temb).chunk(2, dim=-1)
|
|
113
|
+
modulated, _ = block._modulate(block.img_norm1(hs), img_mod1, modulate_index)
|
|
114
|
+
main_lens = [math.prod(s[0]) for s in img_shapes]
|
|
115
|
+
return torch.cat([modulated[b, : main_lens[b]].reshape(-1) for b in range(len(main_lens))])
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def _run_body(m, hs, enc, enc_mask, temb, rope, modulate_index, attention_kwargs, controlnet_block_samples):
|
|
119
|
+
for index_block, block in enumerate(m.transformer_blocks):
|
|
120
|
+
enc, hs = block(
|
|
121
|
+
hidden_states=hs,
|
|
122
|
+
encoder_hidden_states=enc,
|
|
123
|
+
encoder_hidden_states_mask=enc_mask,
|
|
124
|
+
temb=temb,
|
|
125
|
+
image_rotary_emb=rope,
|
|
126
|
+
joint_attention_kwargs=attention_kwargs,
|
|
127
|
+
modulate_index=modulate_index,
|
|
128
|
+
)
|
|
129
|
+
if controlnet_block_samples is not None:
|
|
130
|
+
import numpy as np
|
|
131
|
+
|
|
132
|
+
interval = int(np.ceil(len(m.transformer_blocks) / len(controlnet_block_samples)))
|
|
133
|
+
hs = hs + controlnet_block_samples[index_block // interval]
|
|
134
|
+
return enc, hs
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def _tail(m, hs, temb):
|
|
138
|
+
t = temb.chunk(2, dim=0)[0] if m.zero_cond_t else temb
|
|
139
|
+
return m.proj_out(m.norm_out(hs, t))
|
|
140
|
+
|
|
141
|
+
def attach(self, transformer) -> None:
|
|
142
|
+
tc = self
|
|
143
|
+
m = transformer
|
|
144
|
+
|
|
145
|
+
def forward(
|
|
146
|
+
hidden_states,
|
|
147
|
+
encoder_hidden_states=None,
|
|
148
|
+
encoder_hidden_states_mask=None,
|
|
149
|
+
timestep=None,
|
|
150
|
+
img_shapes=None,
|
|
151
|
+
guidance=None,
|
|
152
|
+
attention_kwargs=None,
|
|
153
|
+
controlnet_block_samples=None,
|
|
154
|
+
additional_t_cond=None,
|
|
155
|
+
return_dict=True,
|
|
156
|
+
):
|
|
157
|
+
# batch>1(--num 或 CFG 合批)绕行:残差按整批缓存语义不安全
|
|
158
|
+
if not tc.enabled or hidden_states.size(0) != 1:
|
|
159
|
+
return _full()
|
|
160
|
+
|
|
161
|
+
t_val = float(timestep.reshape(-1)[0].item())
|
|
162
|
+
if tc._last_t is None or t_val > tc._last_t: # 时间步回升 = 新生成
|
|
163
|
+
tc.reset()
|
|
164
|
+
new_step = t_val != tc._step_t
|
|
165
|
+
tc._last_t = t_val
|
|
166
|
+
tc._step_t = t_val
|
|
167
|
+
tc.calls += 1
|
|
168
|
+
|
|
169
|
+
hs, enc, enc_mask, t, temb, rope, modulate_index = self._prelude(
|
|
170
|
+
m, hidden_states, encoder_hidden_states, encoder_hidden_states_mask,
|
|
171
|
+
timestep, img_shapes, guidance, additional_t_cond,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if new_step:
|
|
175
|
+
signal = self._signal(m, hs, temb, modulate_index, img_shapes)
|
|
176
|
+
tc._step_count += 1
|
|
177
|
+
skip = False
|
|
178
|
+
if tc._step_count <= tc.warmup:
|
|
179
|
+
pass # 结构形成期强制 compute(大图均值信号对构图大改不敏感,禁跳)
|
|
180
|
+
elif tc._prev_signal is not None:
|
|
181
|
+
rel = ((signal - tc._prev_signal).abs().mean()
|
|
182
|
+
/ (tc._prev_signal.abs().mean() + 1e-9)).item()
|
|
183
|
+
tc._acc += _rescale(rel)
|
|
184
|
+
skip = tc._acc < tc.thresh
|
|
185
|
+
if TRACE:
|
|
186
|
+
print(f"[teacache] t={t_val:.1f} rel={rel:.4f} acc={tc._acc:.3f} "
|
|
187
|
+
f"{'SKIP' if skip else 'compute'}", file=sys.stderr)
|
|
188
|
+
tc._pending = (skip, signal)
|
|
189
|
+
stream = 0
|
|
190
|
+
else:
|
|
191
|
+
skip, signal = tc._pending
|
|
192
|
+
stream = 1
|
|
193
|
+
if TRACE:
|
|
194
|
+
print(f"[teacache] t={t_val:.1f} 负流共享决策 {'SKIP' if skip else 'compute'}",
|
|
195
|
+
file=sys.stderr)
|
|
196
|
+
|
|
197
|
+
st = tc._streams[stream]
|
|
198
|
+
if skip and st["res_img"] is not None:
|
|
199
|
+
tc.skips += 1
|
|
200
|
+
out = self._tail(m, hs + st["res_img"], temb)
|
|
201
|
+
return Transformer2DModelOutput(sample=out) if return_dict else (out,)
|
|
202
|
+
|
|
203
|
+
enc_in, hs_in = enc, hs
|
|
204
|
+
enc, hs = self._run_body(m, hs, enc, enc_mask, temb, rope, modulate_index,
|
|
205
|
+
attention_kwargs, controlnet_block_samples)
|
|
206
|
+
st["res_img"] = hs - hs_in
|
|
207
|
+
st["res_enc"] = enc - enc_in
|
|
208
|
+
if new_step:
|
|
209
|
+
tc._prev_signal = signal
|
|
210
|
+
tc._acc = 0.0
|
|
211
|
+
out = self._tail(m, hs, temb)
|
|
212
|
+
return Transformer2DModelOutput(sample=out) if return_dict else (out,)
|
|
213
|
+
|
|
214
|
+
def _full():
|
|
215
|
+
return TeaCache._orig_forward(
|
|
216
|
+
m,
|
|
217
|
+
hidden_states, encoder_hidden_states, encoder_hidden_states_mask, timestep,
|
|
218
|
+
img_shapes, guidance, attention_kwargs, controlnet_block_samples,
|
|
219
|
+
additional_t_cond, return_dict,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
forward._orig = m.forward # 保留引用防 GC 歧义
|
|
223
|
+
m.forward = forward
|
|
224
|
+
|
|
225
|
+
# 由 attach 时填充
|
|
226
|
+
_orig_forward = None
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def attach_teacache(transformer, thresh: float = DEFAULT_THRESHOLD, warmup: int = DEFAULT_WARMUP_STEPS) -> TeaCache:
|
|
230
|
+
tc = TeaCache(thresh=thresh, warmup=warmup)
|
|
231
|
+
TeaCache._orig_forward = transformer.forward
|
|
232
|
+
tc.attach(transformer)
|
|
233
|
+
return tc
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def apply_teacache(pipe, cfg: dict) -> TeaCache | None:
|
|
237
|
+
"""per-job 开关:cfg['teaCache'] 为 {thresh?, warmup?} 或 true 时启用;否则挂起(零开销 passthrough)。
|
|
238
|
+
在 gen.py/edit.py 的 run() 开头调用——直跑与 daemon(serve.py run_job → run)两条路同时覆盖。"""
|
|
239
|
+
tc_cfg = cfg.get("teaCache")
|
|
240
|
+
tc: TeaCache | None = getattr(pipe, "_teacache", None)
|
|
241
|
+
if tc_cfg:
|
|
242
|
+
thresh = tc_cfg.get("thresh", DEFAULT_THRESHOLD) if isinstance(tc_cfg, dict) else DEFAULT_THRESHOLD
|
|
243
|
+
warmup = tc_cfg.get("warmup", DEFAULT_WARMUP_STEPS) if isinstance(tc_cfg, dict) else DEFAULT_WARMUP_STEPS
|
|
244
|
+
if tc is None:
|
|
245
|
+
tc = attach_teacache(pipe.transformer, thresh, warmup)
|
|
246
|
+
pipe._teacache = tc
|
|
247
|
+
else:
|
|
248
|
+
tc.thresh = float(thresh)
|
|
249
|
+
tc.warmup = int(warmup)
|
|
250
|
+
tc.enabled = True
|
|
251
|
+
tc.begin_job()
|
|
252
|
+
return tc
|
|
253
|
+
if tc is not None:
|
|
254
|
+
tc.enabled = False
|
|
255
|
+
return None
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""upscale.py - Real-ESRGAN x2 超分(spandrel + MPS)。
|
|
2
|
+
* 直跑:argv[1] = JSON {in, out, finalSize?: [w,h], model?}
|
|
3
|
+
* serve.py 复用:load_model / run(daemon 内懒加载常驻,二次超分秒级)
|
|
4
|
+
"""
|
|
5
|
+
import json
|
|
6
|
+
from esrgan_path import resolve_esrgan_path
|
|
7
|
+
import sys
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import torch
|
|
12
|
+
from PIL import Image
|
|
13
|
+
from spandrel import ModelLoader
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_model(path: str | None = None):
|
|
17
|
+
device = "mps" if torch.backends.mps.is_available() else "cpu"
|
|
18
|
+
return ModelLoader().load_from_file(path or resolve_esrgan_path()).to(device).eval()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def run(model, cfg: dict) -> dict:
|
|
22
|
+
t0 = time.time()
|
|
23
|
+
device = "mps" if torch.backends.mps.is_available() else "cpu"
|
|
24
|
+
img = np.array(Image.open(cfg["in"]).convert("RGB")).astype(np.float32) / 255.0
|
|
25
|
+
t = torch.from_numpy(img).permute(2, 0, 1).unsqueeze(0).to(device)
|
|
26
|
+
with torch.no_grad():
|
|
27
|
+
out = model(t)
|
|
28
|
+
up = Image.fromarray((out.squeeze(0).permute(1, 2, 0).clamp(0, 1).cpu().numpy() * 255).astype("uint8"))
|
|
29
|
+
if cfg.get("finalSize"):
|
|
30
|
+
up = up.resize(tuple(cfg["finalSize"]), Image.LANCZOS)
|
|
31
|
+
up.save(cfg["out"])
|
|
32
|
+
return {"out": cfg["out"], "size": up.size, "seconds": round(time.time() - t0, 1)}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def main() -> None:
|
|
36
|
+
cfg = json.loads(sys.argv[1])
|
|
37
|
+
print(json.dumps(run(load_model(cfg.get("model")), cfg), ensure_ascii=False))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* minimax — CLI for the MiniMax API.
|
|
4
|
+
*
|
|
5
|
+
* Subcommands (intentionally minimal — the official MCP exposes 10 tools but
|
|
6
|
+
* its schema costs agent context on every call; add more on demand):
|
|
7
|
+
* tts <text> text-to-audio (POST /v1/t2a_v2)
|
|
8
|
+
* voice-clone clone a voice from audio (POST /v1/files/upload + /v1/voice_clone)
|
|
9
|
+
* voices list voices as JSON (POST /v1/get_voice)
|
|
10
|
+
*/
|
|
11
|
+
import { type VoiceType } from "./voices.js";
|
|
12
|
+
export interface TtsCliArgs {
|
|
13
|
+
text?: string;
|
|
14
|
+
voiceId?: string;
|
|
15
|
+
model?: string;
|
|
16
|
+
output?: string;
|
|
17
|
+
speed?: number;
|
|
18
|
+
vol?: number;
|
|
19
|
+
pitch?: number;
|
|
20
|
+
emotion?: string;
|
|
21
|
+
format?: string;
|
|
22
|
+
sampleRate?: number;
|
|
23
|
+
bitrate?: number;
|
|
24
|
+
channel?: number;
|
|
25
|
+
languageBoost?: string;
|
|
26
|
+
/** R1 karaoke: 字幕开关 */
|
|
27
|
+
subtitleEnable?: boolean;
|
|
28
|
+
/** R1 karaoke: 字幕粒度(默认 'word') */
|
|
29
|
+
subtitleType?: "word" | "sentence";
|
|
30
|
+
}
|
|
31
|
+
export type TtsParse = TtsCliArgs | {
|
|
32
|
+
error: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function parseTtsArgs(argv: string[]): TtsParse;
|
|
35
|
+
export interface VoiceCloneCliArgs {
|
|
36
|
+
voiceId?: string;
|
|
37
|
+
audioFile?: string;
|
|
38
|
+
text?: string;
|
|
39
|
+
output?: string;
|
|
40
|
+
}
|
|
41
|
+
export type VoiceCloneParse = VoiceCloneCliArgs | {
|
|
42
|
+
error: string;
|
|
43
|
+
};
|
|
44
|
+
export declare function parseVoiceCloneArgs(argv: string[]): VoiceCloneParse;
|
|
45
|
+
export interface VoicesCliArgs {
|
|
46
|
+
type: VoiceType;
|
|
47
|
+
}
|
|
48
|
+
export type VoicesParse = VoicesCliArgs | {
|
|
49
|
+
error: string;
|
|
50
|
+
};
|
|
51
|
+
export declare function parseVoicesArgs(argv: string[]): VoicesParse;
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* minimax — CLI for the MiniMax API.
|
|
4
|
+
*
|
|
5
|
+
* Subcommands (intentionally minimal — the official MCP exposes 10 tools but
|
|
6
|
+
* its schema costs agent context on every call; add more on demand):
|
|
7
|
+
* tts <text> text-to-audio (POST /v1/t2a_v2)
|
|
8
|
+
* voice-clone clone a voice from audio (POST /v1/files/upload + /v1/voice_clone)
|
|
9
|
+
* voices list voices as JSON (POST /v1/get_voice)
|
|
10
|
+
*/
|
|
11
|
+
import { realpathSync } from "node:fs";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { parseArgs } from "node:util";
|
|
14
|
+
import { createClient } from "./client.js";
|
|
15
|
+
import { generateSpeech } from "./tts.js";
|
|
16
|
+
import { cloneVoice } from "./voice-clone.js";
|
|
17
|
+
import { listVoices } from "./voices.js";
|
|
18
|
+
const DEFAULT_HOST = "https://api.minimax.chat";
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// arg parsing (pure, unit-tested)
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
function num(v, name) {
|
|
23
|
+
if (v === undefined)
|
|
24
|
+
return undefined;
|
|
25
|
+
const n = Number(v);
|
|
26
|
+
if (!Number.isFinite(n)) {
|
|
27
|
+
throw new Error(`--${name} must be a number, got "${v}"`);
|
|
28
|
+
}
|
|
29
|
+
return n;
|
|
30
|
+
}
|
|
31
|
+
export function parseTtsArgs(argv) {
|
|
32
|
+
try {
|
|
33
|
+
const { values, positionals } = parseArgs({
|
|
34
|
+
args: argv,
|
|
35
|
+
options: {
|
|
36
|
+
voice: { type: "string" },
|
|
37
|
+
model: { type: "string" },
|
|
38
|
+
output: { type: "string" },
|
|
39
|
+
speed: { type: "string" },
|
|
40
|
+
vol: { type: "string" },
|
|
41
|
+
pitch: { type: "string" },
|
|
42
|
+
emotion: { type: "string" },
|
|
43
|
+
format: { type: "string" },
|
|
44
|
+
"sample-rate": { type: "string" },
|
|
45
|
+
bitrate: { type: "string" },
|
|
46
|
+
channel: { type: "string" },
|
|
47
|
+
"language-boost": { type: "string" },
|
|
48
|
+
subtitle: { type: "boolean", default: false },
|
|
49
|
+
"subtitle-type": { type: "string" },
|
|
50
|
+
},
|
|
51
|
+
allowPositionals: true,
|
|
52
|
+
allowNegative: true,
|
|
53
|
+
});
|
|
54
|
+
const subtitleTypeRaw = values["subtitle-type"];
|
|
55
|
+
const subtitleType = subtitleTypeRaw === "sentence" ? "sentence" : subtitleTypeRaw === "word" ? "word" : undefined;
|
|
56
|
+
return {
|
|
57
|
+
text: positionals[0],
|
|
58
|
+
voiceId: values.voice,
|
|
59
|
+
model: values.model,
|
|
60
|
+
output: values.output,
|
|
61
|
+
speed: num(values.speed, "speed"),
|
|
62
|
+
vol: num(values.vol, "vol"),
|
|
63
|
+
pitch: num(values.pitch, "pitch"),
|
|
64
|
+
emotion: values.emotion,
|
|
65
|
+
format: values.format,
|
|
66
|
+
sampleRate: num(values["sample-rate"], "sample-rate"),
|
|
67
|
+
bitrate: num(values.bitrate, "bitrate"),
|
|
68
|
+
channel: num(values.channel, "channel"),
|
|
69
|
+
languageBoost: values["language-boost"],
|
|
70
|
+
subtitleEnable: values.subtitle === true,
|
|
71
|
+
subtitleType,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export function parseVoiceCloneArgs(argv) {
|
|
79
|
+
try {
|
|
80
|
+
const { values } = parseArgs({
|
|
81
|
+
args: argv,
|
|
82
|
+
options: {
|
|
83
|
+
voice: { type: "string" },
|
|
84
|
+
audio: { type: "string" },
|
|
85
|
+
text: { type: "string" },
|
|
86
|
+
output: { type: "string" },
|
|
87
|
+
},
|
|
88
|
+
allowPositionals: false,
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
voiceId: values.voice,
|
|
92
|
+
audioFile: values.audio,
|
|
93
|
+
text: values.text,
|
|
94
|
+
output: values.output,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const VOICE_TYPES = ["all", "system", "voice_cloning"];
|
|
102
|
+
export function parseVoicesArgs(argv) {
|
|
103
|
+
try {
|
|
104
|
+
const { values } = parseArgs({
|
|
105
|
+
args: argv,
|
|
106
|
+
options: { type: { type: "string" } },
|
|
107
|
+
allowPositionals: false,
|
|
108
|
+
});
|
|
109
|
+
const t = (values.type ?? "all");
|
|
110
|
+
if (!VOICE_TYPES.includes(t)) {
|
|
111
|
+
return {
|
|
112
|
+
error: `--type must be one of ${VOICE_TYPES.join(", ")}, got "${t}"`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return { type: t };
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// help
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
const HELP = `Usage: minimax <command> [options]
|
|
125
|
+
|
|
126
|
+
Commands:
|
|
127
|
+
tts <text> Text-to-audio (POST /v1/t2a_v2)
|
|
128
|
+
voice-clone Clone a voice from audio (upload + /v1/voice_clone)
|
|
129
|
+
voices List voices as JSON (POST /v1/get_voice)
|
|
130
|
+
|
|
131
|
+
Options:
|
|
132
|
+
--help Show this help (per-command: minimax <command> --help)
|
|
133
|
+
|
|
134
|
+
Env:
|
|
135
|
+
MINIMAX_API_KEY (required) API key
|
|
136
|
+
MINIMAX_API_HOST default ${DEFAULT_HOST}
|
|
137
|
+
|
|
138
|
+
Exit codes: 0 success | 1 API error / missing key | 2 bad args
|
|
139
|
+
On file output, last stdout line is the saved path.`;
|
|
140
|
+
const TTS_HELP = `Usage: minimax tts "<text>" [options]
|
|
141
|
+
|
|
142
|
+
Options:
|
|
143
|
+
--voice <id> Voice ID (default male-qn-qingse)
|
|
144
|
+
--model <name> speech-02-hd (default) | speech-02-turbo | speech-01-*
|
|
145
|
+
--output <path> Output file (default: ./<voice>_<ts>.mp3)
|
|
146
|
+
--speed <n> 0.5-2.0 (default 1.0)
|
|
147
|
+
--vol <n> 0.1-10.0 (default 1.0)
|
|
148
|
+
--pitch <n> -12 to 12 (default 0; negatives need --pitch=-N)
|
|
149
|
+
--emotion <name> happy|sad|angry|fearful|disgusted|surprised|neutral
|
|
150
|
+
--format <f> mp3 (default) | pcm | flac | wav
|
|
151
|
+
--sample-rate <hz> 8000|16000|22050|24000|32000|44100
|
|
152
|
+
--bitrate <bps> 64000...320000
|
|
153
|
+
--channel <n> 1|2
|
|
154
|
+
--language-boost <l> auto (default) | Chinese | English | ...
|
|
155
|
+
--subtitle Enable subtitle (word-level timestamps; R1 karaoke)
|
|
156
|
+
--subtitle-type <t> word (default) | sentence`;
|
|
157
|
+
const VC_HELP = `Usage: minimax voice-clone --voice <id> --audio <file> [options]
|
|
158
|
+
|
|
159
|
+
Options:
|
|
160
|
+
--voice <id> (required) Voice ID to create
|
|
161
|
+
--audio <file> (required) Source audio file (mp3/m4a/wav)
|
|
162
|
+
--text <demo> Demo text (also synthesized to a demo wav)
|
|
163
|
+
--output <dir> Directory for the demo wav (default: current dir)`;
|
|
164
|
+
const VOICES_HELP = `Usage: minimax voices [--type <t>]
|
|
165
|
+
|
|
166
|
+
Options:
|
|
167
|
+
--type <t> all (default) | system | voice_cloning
|
|
168
|
+
Outputs JSON: { system: [{voice_id,voice_name}], cloned: [...] }`;
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// main
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
function fail(msg, code) {
|
|
173
|
+
process.stderr.write(`minimax: ${msg}\n`);
|
|
174
|
+
process.exit(code);
|
|
175
|
+
}
|
|
176
|
+
function envOrError() {
|
|
177
|
+
const apiKey = process.env.MINIMAX_API_KEY;
|
|
178
|
+
if (!apiKey) {
|
|
179
|
+
return { error: "MINIMAX_API_KEY environment variable is not set" };
|
|
180
|
+
}
|
|
181
|
+
return { apiKey, host: process.env.MINIMAX_API_HOST || DEFAULT_HOST };
|
|
182
|
+
}
|
|
183
|
+
function wantsHelp(rest) {
|
|
184
|
+
return rest.includes("--help") || rest.includes("-h");
|
|
185
|
+
}
|
|
186
|
+
async function runTts(rest) {
|
|
187
|
+
if (wantsHelp(rest)) {
|
|
188
|
+
process.stdout.write(`${TTS_HELP}\n`);
|
|
189
|
+
process.exit(0);
|
|
190
|
+
}
|
|
191
|
+
const parsed = parseTtsArgs(rest);
|
|
192
|
+
if ("error" in parsed)
|
|
193
|
+
fail(parsed.error, 2);
|
|
194
|
+
if (!parsed.text)
|
|
195
|
+
fail('tts requires <text> as the first argument', 2);
|
|
196
|
+
const env = envOrError();
|
|
197
|
+
if ("error" in env)
|
|
198
|
+
fail(env.error, 1);
|
|
199
|
+
const client = createClient(env);
|
|
200
|
+
const format = parsed.format || "mp3";
|
|
201
|
+
const output = parsed.output || `./${parsed.voiceId ?? "voice"}_${Date.now()}.${format}`;
|
|
202
|
+
try {
|
|
203
|
+
const r = await generateSpeech(client, {
|
|
204
|
+
text: parsed.text,
|
|
205
|
+
voiceId: parsed.voiceId,
|
|
206
|
+
model: parsed.model,
|
|
207
|
+
speed: parsed.speed,
|
|
208
|
+
vol: parsed.vol,
|
|
209
|
+
pitch: parsed.pitch,
|
|
210
|
+
emotion: parsed.emotion,
|
|
211
|
+
format: parsed.format,
|
|
212
|
+
sampleRate: parsed.sampleRate,
|
|
213
|
+
bitrate: parsed.bitrate,
|
|
214
|
+
channel: parsed.channel,
|
|
215
|
+
languageBoost: parsed.languageBoost,
|
|
216
|
+
subtitleEnable: parsed.subtitleEnable,
|
|
217
|
+
subtitleType: parsed.subtitleType,
|
|
218
|
+
}, output);
|
|
219
|
+
process.stdout.write(`Saved to: ${r.filePath}\n`);
|
|
220
|
+
if (r.timingsPath) {
|
|
221
|
+
process.stdout.write(`Timings: ${r.timingsPath}\n`);
|
|
222
|
+
}
|
|
223
|
+
process.exit(0);
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
fail(`tts failed: ${err instanceof Error ? err.message : String(err)}`, 1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function runVoiceClone(rest) {
|
|
230
|
+
if (wantsHelp(rest)) {
|
|
231
|
+
process.stdout.write(`${VC_HELP}\n`);
|
|
232
|
+
process.exit(0);
|
|
233
|
+
}
|
|
234
|
+
const parsed = parseVoiceCloneArgs(rest);
|
|
235
|
+
if ("error" in parsed)
|
|
236
|
+
fail(parsed.error, 2);
|
|
237
|
+
if (!parsed.voiceId)
|
|
238
|
+
fail("voice-clone requires --voice <id>", 2);
|
|
239
|
+
if (!parsed.audioFile)
|
|
240
|
+
fail("voice-clone requires --audio <file>", 2);
|
|
241
|
+
const env = envOrError();
|
|
242
|
+
if ("error" in env)
|
|
243
|
+
fail(env.error, 1);
|
|
244
|
+
const client = createClient(env);
|
|
245
|
+
try {
|
|
246
|
+
const r = await cloneVoice(client, {
|
|
247
|
+
voiceId: parsed.voiceId,
|
|
248
|
+
audioFile: parsed.audioFile,
|
|
249
|
+
text: parsed.text,
|
|
250
|
+
}, parsed.output || ".");
|
|
251
|
+
process.stdout.write(r.demoPath
|
|
252
|
+
? `Voice cloned: ${r.voiceId} (demo: ${r.demoPath})\n`
|
|
253
|
+
: `Voice cloned: ${r.voiceId}\n`);
|
|
254
|
+
process.exit(0);
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
fail(`voice-clone failed: ${err instanceof Error ? err.message : String(err)}`, 1);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async function runVoices(rest) {
|
|
261
|
+
if (wantsHelp(rest)) {
|
|
262
|
+
process.stdout.write(`${VOICES_HELP}\n`);
|
|
263
|
+
process.exit(0);
|
|
264
|
+
}
|
|
265
|
+
const parsed = parseVoicesArgs(rest);
|
|
266
|
+
if ("error" in parsed)
|
|
267
|
+
fail(parsed.error, 2);
|
|
268
|
+
const env = envOrError();
|
|
269
|
+
if ("error" in env)
|
|
270
|
+
fail(env.error, 1);
|
|
271
|
+
const client = createClient(env);
|
|
272
|
+
try {
|
|
273
|
+
const result = await listVoices(client, parsed.type);
|
|
274
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
275
|
+
process.exit(0);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
fail(`voices failed: ${err instanceof Error ? err.message : String(err)}`, 1);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async function main() {
|
|
282
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
283
|
+
switch (cmd) {
|
|
284
|
+
case "tts":
|
|
285
|
+
return runTts(rest);
|
|
286
|
+
case "voice-clone":
|
|
287
|
+
return runVoiceClone(rest);
|
|
288
|
+
case "voices":
|
|
289
|
+
return runVoices(rest);
|
|
290
|
+
case "--help":
|
|
291
|
+
case "-h":
|
|
292
|
+
case undefined:
|
|
293
|
+
process.stdout.write(`${HELP}\n`);
|
|
294
|
+
process.exit(0);
|
|
295
|
+
default:
|
|
296
|
+
fail(`unknown command "${cmd}". Run "minimax --help".`, 2);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const invokedDirectly = process.argv[1] !== undefined &&
|
|
300
|
+
realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
301
|
+
if (invokedDirectly) {
|
|
302
|
+
main().catch((err) => {
|
|
303
|
+
process.stderr.write(`minimax: fatal ${err instanceof Error ? err.message : String(err)}\n`);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|