open-agents-ai 0.103.80 → 0.103.82
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/dist/index.js +199 -77
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38747,9 +38747,19 @@ var init_voice = __esm({
|
|
|
38747
38747
|
* Returns status message.
|
|
38748
38748
|
*/
|
|
38749
38749
|
async setCloneVoice(audioPath) {
|
|
38750
|
-
|
|
38751
|
-
|
|
38750
|
+
let p = audioPath.trim();
|
|
38751
|
+
if (p.startsWith("'") && p.endsWith("'") || p.startsWith('"') && p.endsWith('"')) {
|
|
38752
|
+
p = p.slice(1, -1);
|
|
38752
38753
|
}
|
|
38754
|
+
p = p.replace(/\\ /g, " ");
|
|
38755
|
+
if (p.startsWith("~/") || p === "~") {
|
|
38756
|
+
p = join43(homedir12(), p.slice(1));
|
|
38757
|
+
}
|
|
38758
|
+
if (!existsSync34(p)) {
|
|
38759
|
+
return `File not found: ${p}
|
|
38760
|
+
(original input: ${audioPath})`;
|
|
38761
|
+
}
|
|
38762
|
+
audioPath = p;
|
|
38753
38763
|
const refsDir = luxttsCloneRefsDir();
|
|
38754
38764
|
if (!existsSync34(refsDir))
|
|
38755
38765
|
mkdirSync14(refsDir, { recursive: true });
|
|
@@ -38957,6 +38967,19 @@ var init_voice = __esm({
|
|
|
38957
38967
|
this.config = null;
|
|
38958
38968
|
this.mlxActive = false;
|
|
38959
38969
|
this.luxttsActive = false;
|
|
38970
|
+
if (this._luxttsDaemon && !this._luxttsDaemon.killed) {
|
|
38971
|
+
try {
|
|
38972
|
+
this._luxttsDaemon.stdin.write('{"action":"quit"}\n');
|
|
38973
|
+
} catch {
|
|
38974
|
+
}
|
|
38975
|
+
setTimeout(() => {
|
|
38976
|
+
try {
|
|
38977
|
+
this._luxttsDaemon?.kill();
|
|
38978
|
+
} catch {
|
|
38979
|
+
}
|
|
38980
|
+
}, 2e3);
|
|
38981
|
+
}
|
|
38982
|
+
this._luxttsDaemon = null;
|
|
38960
38983
|
}
|
|
38961
38984
|
// -------------------------------------------------------------------------
|
|
38962
38985
|
// Text chunking for long TTS input
|
|
@@ -39610,70 +39633,95 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
39610
39633
|
}
|
|
39611
39634
|
}
|
|
39612
39635
|
}
|
|
39613
|
-
/**
|
|
39636
|
+
/** Persistent LuxTTS daemon process — keeps model warm in GPU memory */
|
|
39637
|
+
_luxttsDaemon = null;
|
|
39638
|
+
_luxttsPending = /* @__PURE__ */ new Map();
|
|
39639
|
+
_luxttsBuffer = "";
|
|
39640
|
+
/** Write the LuxTTS persistent daemon Python script */
|
|
39614
39641
|
writeLuxttsInferScript() {
|
|
39615
39642
|
const script = `#!/usr/bin/env python3
|
|
39616
|
-
"""LuxTTS
|
|
39617
|
-
|
|
39643
|
+
"""LuxTTS persistent daemon for open-agents voice engine.
|
|
39644
|
+
Keeps model warm in GPU memory. Reads JSON requests from stdin, writes JSON responses to stdout.
|
|
39618
39645
|
"""
|
|
39619
|
-
import sys, json, os, wave,
|
|
39646
|
+
import sys, json, os, wave, signal
|
|
39620
39647
|
import numpy as np
|
|
39621
39648
|
|
|
39622
39649
|
def main():
|
|
39623
|
-
|
|
39624
|
-
action = args.get('action', 'synthesize')
|
|
39625
|
-
|
|
39626
|
-
repo_path = args.get('repo_path', '')
|
|
39650
|
+
repo_path = os.environ.get('LUXTTS_REPO_PATH', '')
|
|
39627
39651
|
if repo_path:
|
|
39628
39652
|
sys.path.insert(0, repo_path)
|
|
39629
39653
|
|
|
39630
|
-
|
|
39654
|
+
import torch
|
|
39655
|
+
from zipvoice.luxvoice import LuxTTS
|
|
39656
|
+
|
|
39657
|
+
# Auto-detect best device
|
|
39658
|
+
if torch.cuda.is_available():
|
|
39659
|
+
device = 'cuda'
|
|
39660
|
+
elif hasattr(torch.backends, 'mps') and torch.backends.mps.is_available():
|
|
39661
|
+
device = 'mps'
|
|
39662
|
+
else:
|
|
39663
|
+
device = 'cpu'
|
|
39664
|
+
|
|
39665
|
+
# Load model ONCE \u2014 stays warm in GPU/CPU memory
|
|
39666
|
+
tts = LuxTTS(model_path='YatharthS/LuxTTS', device=device, threads=4)
|
|
39667
|
+
sys.stdout.write(json.dumps({'type': 'ready', 'device': device}) + '\\n')
|
|
39668
|
+
sys.stdout.flush()
|
|
39669
|
+
|
|
39670
|
+
# Cache encoded prompts by clone_ref path (avoid re-encoding same voice)
|
|
39671
|
+
prompt_cache = {}
|
|
39672
|
+
|
|
39673
|
+
for line in sys.stdin:
|
|
39674
|
+
line = line.strip()
|
|
39675
|
+
if not line:
|
|
39676
|
+
continue
|
|
39631
39677
|
try:
|
|
39632
|
-
|
|
39633
|
-
print(json.dumps({'ok': True}))
|
|
39678
|
+
req = json.loads(line)
|
|
39634
39679
|
except Exception as e:
|
|
39635
|
-
|
|
39636
|
-
|
|
39637
|
-
|
|
39638
|
-
|
|
39639
|
-
|
|
39640
|
-
|
|
39641
|
-
|
|
39642
|
-
|
|
39643
|
-
|
|
39644
|
-
|
|
39645
|
-
|
|
39646
|
-
|
|
39647
|
-
|
|
39648
|
-
|
|
39649
|
-
|
|
39650
|
-
|
|
39651
|
-
|
|
39652
|
-
|
|
39653
|
-
|
|
39654
|
-
|
|
39655
|
-
|
|
39656
|
-
|
|
39657
|
-
|
|
39658
|
-
|
|
39659
|
-
|
|
39660
|
-
|
|
39661
|
-
|
|
39662
|
-
|
|
39663
|
-
|
|
39664
|
-
|
|
39665
|
-
|
|
39666
|
-
|
|
39667
|
-
|
|
39668
|
-
|
|
39669
|
-
|
|
39670
|
-
|
|
39671
|
-
|
|
39672
|
-
|
|
39673
|
-
|
|
39674
|
-
|
|
39675
|
-
|
|
39676
|
-
|
|
39680
|
+
sys.stdout.write(json.dumps({'type': 'error', 'id': '', 'error': str(e)}) + '\\n')
|
|
39681
|
+
sys.stdout.flush()
|
|
39682
|
+
continue
|
|
39683
|
+
|
|
39684
|
+
req_id = req.get('id', '')
|
|
39685
|
+
|
|
39686
|
+
if req.get('action') == 'check':
|
|
39687
|
+
sys.stdout.write(json.dumps({'type': 'result', 'id': req_id, 'ok': True}) + '\\n')
|
|
39688
|
+
sys.stdout.flush()
|
|
39689
|
+
continue
|
|
39690
|
+
|
|
39691
|
+
if req.get('action') == 'quit':
|
|
39692
|
+
break
|
|
39693
|
+
|
|
39694
|
+
if req.get('action') == 'synthesize':
|
|
39695
|
+
try:
|
|
39696
|
+
text = req['text']
|
|
39697
|
+
clone_ref = req['clone_ref']
|
|
39698
|
+
output_path = req['output_path']
|
|
39699
|
+
speed = req.get('speed', 1.0)
|
|
39700
|
+
|
|
39701
|
+
# Use cached prompt encoding if available
|
|
39702
|
+
if clone_ref not in prompt_cache:
|
|
39703
|
+
prompt_cache[clone_ref] = tts.encode_prompt(clone_ref, duration=5, rms=0.001)
|
|
39704
|
+
encoded = prompt_cache[clone_ref]
|
|
39705
|
+
|
|
39706
|
+
wav_tensor = tts.generate_speech(text, encoded, num_steps=4, guidance_scale=3.0, t_shift=0.5, speed=speed)
|
|
39707
|
+
wav_np = wav_tensor.cpu().numpy().squeeze()
|
|
39708
|
+
|
|
39709
|
+
int16_data = (np.clip(wav_np, -1.0, 1.0) * 32767).astype(np.int16)
|
|
39710
|
+
with wave.open(output_path, 'wb') as wf:
|
|
39711
|
+
wf.setnchannels(1)
|
|
39712
|
+
wf.setsampwidth(2)
|
|
39713
|
+
wf.setframerate(48000)
|
|
39714
|
+
wf.writeframes(int16_data.tobytes())
|
|
39715
|
+
|
|
39716
|
+
sys.stdout.write(json.dumps({
|
|
39717
|
+
'type': 'result', 'id': req_id, 'ok': True,
|
|
39718
|
+
'path': output_path, 'sample_rate': 48000,
|
|
39719
|
+
'device': device, 'samples': len(int16_data),
|
|
39720
|
+
}) + '\\n')
|
|
39721
|
+
sys.stdout.flush()
|
|
39722
|
+
except Exception as e:
|
|
39723
|
+
sys.stdout.write(json.dumps({'type': 'error', 'id': req_id, 'error': str(e)}) + '\\n')
|
|
39724
|
+
sys.stdout.flush()
|
|
39677
39725
|
|
|
39678
39726
|
if __name__ == '__main__':
|
|
39679
39727
|
main()
|
|
@@ -39682,6 +39730,84 @@ if __name__ == '__main__':
|
|
|
39682
39730
|
mkdirSync14(voiceDir(), { recursive: true });
|
|
39683
39731
|
writeFileSync14(scriptPath2, script);
|
|
39684
39732
|
}
|
|
39733
|
+
/** Ensure the LuxTTS daemon is running, spawn if needed */
|
|
39734
|
+
async ensureLuxttsDaemon() {
|
|
39735
|
+
if (this._luxttsDaemon && !this._luxttsDaemon.killed)
|
|
39736
|
+
return true;
|
|
39737
|
+
const venvPy = luxttsVenvPy();
|
|
39738
|
+
if (!existsSync34(venvPy))
|
|
39739
|
+
return false;
|
|
39740
|
+
return new Promise((resolve31) => {
|
|
39741
|
+
const env = { ...process.env, LUXTTS_REPO_PATH: luxttsRepoDir() };
|
|
39742
|
+
const daemon = nodeSpawn(venvPy, [luxttsInferScript()], {
|
|
39743
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
39744
|
+
cwd: tmpdir6(),
|
|
39745
|
+
env
|
|
39746
|
+
});
|
|
39747
|
+
this._luxttsDaemon = daemon;
|
|
39748
|
+
this._luxttsBuffer = "";
|
|
39749
|
+
daemon.stdout.on("data", (chunk) => {
|
|
39750
|
+
this._luxttsBuffer += chunk.toString();
|
|
39751
|
+
const lines = this._luxttsBuffer.split("\n");
|
|
39752
|
+
this._luxttsBuffer = lines.pop();
|
|
39753
|
+
for (const line of lines) {
|
|
39754
|
+
if (!line.trim())
|
|
39755
|
+
continue;
|
|
39756
|
+
try {
|
|
39757
|
+
const msg = JSON.parse(line);
|
|
39758
|
+
if (msg.type === "ready") {
|
|
39759
|
+
resolve31(true);
|
|
39760
|
+
} else if (msg.type === "result" || msg.type === "error") {
|
|
39761
|
+
const pending = this._luxttsPending.get(msg.id);
|
|
39762
|
+
if (pending) {
|
|
39763
|
+
this._luxttsPending.delete(msg.id);
|
|
39764
|
+
if (msg.type === "error")
|
|
39765
|
+
pending.reject(new Error(msg.error));
|
|
39766
|
+
else
|
|
39767
|
+
pending.resolve(line);
|
|
39768
|
+
}
|
|
39769
|
+
}
|
|
39770
|
+
} catch {
|
|
39771
|
+
}
|
|
39772
|
+
}
|
|
39773
|
+
});
|
|
39774
|
+
daemon.on("exit", () => {
|
|
39775
|
+
this._luxttsDaemon = null;
|
|
39776
|
+
for (const [, p] of this._luxttsPending) {
|
|
39777
|
+
p.reject(new Error("LuxTTS daemon exited"));
|
|
39778
|
+
}
|
|
39779
|
+
this._luxttsPending.clear();
|
|
39780
|
+
});
|
|
39781
|
+
daemon.on("error", () => {
|
|
39782
|
+
this._luxttsDaemon = null;
|
|
39783
|
+
resolve31(false);
|
|
39784
|
+
});
|
|
39785
|
+
setTimeout(() => {
|
|
39786
|
+
if (this._luxttsDaemon === daemon && !this._luxttsPending.has("__ready__")) {
|
|
39787
|
+
resolve31(false);
|
|
39788
|
+
}
|
|
39789
|
+
}, 6e4);
|
|
39790
|
+
});
|
|
39791
|
+
}
|
|
39792
|
+
/** Send a request to the LuxTTS daemon and await the response */
|
|
39793
|
+
luxttsRequest(req) {
|
|
39794
|
+
return new Promise((resolve31, reject) => {
|
|
39795
|
+
if (!this._luxttsDaemon || this._luxttsDaemon.killed) {
|
|
39796
|
+
reject(new Error("LuxTTS daemon not running"));
|
|
39797
|
+
return;
|
|
39798
|
+
}
|
|
39799
|
+
const id = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
39800
|
+
req.id = id;
|
|
39801
|
+
this._luxttsPending.set(id, { resolve: resolve31, reject });
|
|
39802
|
+
this._luxttsDaemon.stdin.write(JSON.stringify(req) + "\n");
|
|
39803
|
+
setTimeout(() => {
|
|
39804
|
+
if (this._luxttsPending.has(id)) {
|
|
39805
|
+
this._luxttsPending.delete(id);
|
|
39806
|
+
reject(new Error("LuxTTS synthesis timeout"));
|
|
39807
|
+
}
|
|
39808
|
+
}, 12e4);
|
|
39809
|
+
});
|
|
39810
|
+
}
|
|
39685
39811
|
/**
|
|
39686
39812
|
* Synthesize and play audio using LuxTTS voice cloning.
|
|
39687
39813
|
* Speed is passed natively to LuxTTS. Pitch is post-processed via resampling.
|
|
@@ -39694,20 +39820,18 @@ if __name__ == '__main__':
|
|
|
39694
39820
|
const cleaned = text.replace(/\*/g, "").trim();
|
|
39695
39821
|
if (!cleaned)
|
|
39696
39822
|
return;
|
|
39697
|
-
const
|
|
39698
|
-
if (!
|
|
39823
|
+
const ready = await this.ensureLuxttsDaemon();
|
|
39824
|
+
if (!ready)
|
|
39699
39825
|
return;
|
|
39700
39826
|
const wavPath = join43(tmpdir6(), `oa-luxtts-${Date.now()}.wav`);
|
|
39701
|
-
const inferArgs = JSON.stringify({
|
|
39702
|
-
action: "synthesize",
|
|
39703
|
-
repo_path: luxttsRepoDir(),
|
|
39704
|
-
text: cleaned,
|
|
39705
|
-
clone_ref: this.luxttsCloneRef,
|
|
39706
|
-
output_path: wavPath,
|
|
39707
|
-
speed: speedFactor
|
|
39708
|
-
});
|
|
39709
39827
|
try {
|
|
39710
|
-
|
|
39828
|
+
await this.luxttsRequest({
|
|
39829
|
+
action: "synthesize",
|
|
39830
|
+
text: cleaned,
|
|
39831
|
+
clone_ref: this.luxttsCloneRef,
|
|
39832
|
+
output_path: wavPath,
|
|
39833
|
+
speed: speedFactor
|
|
39834
|
+
});
|
|
39711
39835
|
} catch {
|
|
39712
39836
|
return;
|
|
39713
39837
|
}
|
|
@@ -39770,20 +39894,18 @@ if __name__ == '__main__':
|
|
|
39770
39894
|
const cleaned = text.replace(/\*/g, "").trim();
|
|
39771
39895
|
if (!cleaned)
|
|
39772
39896
|
return null;
|
|
39773
|
-
const
|
|
39774
|
-
if (!
|
|
39897
|
+
const ready = await this.ensureLuxttsDaemon();
|
|
39898
|
+
if (!ready)
|
|
39775
39899
|
return null;
|
|
39776
39900
|
const wavPath = join43(tmpdir6(), `oa-luxtts-buf-${Date.now()}.wav`);
|
|
39777
|
-
const inferArgs = JSON.stringify({
|
|
39778
|
-
action: "synthesize",
|
|
39779
|
-
repo_path: luxttsRepoDir(),
|
|
39780
|
-
text: cleaned,
|
|
39781
|
-
clone_ref: this.luxttsCloneRef,
|
|
39782
|
-
output_path: wavPath,
|
|
39783
|
-
speed: 1
|
|
39784
|
-
});
|
|
39785
39901
|
try {
|
|
39786
|
-
|
|
39902
|
+
await this.luxttsRequest({
|
|
39903
|
+
action: "synthesize",
|
|
39904
|
+
text: cleaned,
|
|
39905
|
+
clone_ref: this.luxttsCloneRef,
|
|
39906
|
+
output_path: wavPath,
|
|
39907
|
+
speed: 1
|
|
39908
|
+
});
|
|
39787
39909
|
} catch {
|
|
39788
39910
|
return null;
|
|
39789
39911
|
}
|
package/package.json
CHANGED