agentgui 1.0.296 → 1.0.298
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/lib/speech.js +22 -2
- package/package.json +2 -2
- package/server.js +27 -126
package/lib/speech.js
CHANGED
|
@@ -150,11 +150,30 @@ function getSttOptions() {
|
|
|
150
150
|
return {};
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
async function getEmbeddingForVoice(voiceId) {
|
|
154
|
+
if (voiceId && voiceId !== 'default') {
|
|
155
|
+
const emb = await getVoiceEmbedding(voiceId);
|
|
156
|
+
if (emb) return emb;
|
|
157
|
+
}
|
|
158
|
+
// Fall back to first available voice file
|
|
159
|
+
for (const dir of VOICE_DIRS) {
|
|
160
|
+
for (const ext of AUDIO_EXTENSIONS) {
|
|
161
|
+
const entries = fs.existsSync(dir) ? fs.readdirSync(dir).filter(f => f.endsWith(ext)) : [];
|
|
162
|
+
if (entries.length) {
|
|
163
|
+
const emb = await getVoiceEmbedding('custom_' + entries[0].replace(new RegExp(`\\${ext}$`), ''));
|
|
164
|
+
if (emb) return emb;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
153
171
|
async function synthesize(text, voiceId) {
|
|
154
172
|
if (isOnnxApi) {
|
|
155
173
|
// Node.js ONNX TTS - no Python required
|
|
156
174
|
const modelDir = getModelDir();
|
|
157
|
-
const embedding =
|
|
175
|
+
const embedding = await getEmbeddingForVoice(voiceId);
|
|
176
|
+
if (!embedding) throw new Error('No voice file available for TTS - add a WAV file to ~/voices/');
|
|
158
177
|
const pcm = await serverTTS.synthesize(text, embedding, modelDir);
|
|
159
178
|
return pcmToWav(pcm);
|
|
160
179
|
}
|
|
@@ -170,7 +189,8 @@ async function synthesize(text, voiceId) {
|
|
|
170
189
|
async function* synthesizeStream(text, voiceId) {
|
|
171
190
|
if (isOnnxApi) {
|
|
172
191
|
const modelDir = getModelDir();
|
|
173
|
-
const embedding =
|
|
192
|
+
const embedding = await getEmbeddingForVoice(voiceId);
|
|
193
|
+
if (!embedding) throw new Error('No voice file available for TTS - add a WAV file to ~/voices/');
|
|
174
194
|
const pcm = await serverTTS.synthesize(text, embedding, modelDir);
|
|
175
195
|
yield pcmToWav(pcm);
|
|
176
196
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentgui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.298",
|
|
4
4
|
"description": "Multi-agent ACP client with real-time communication",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"fsbrowse": "^0.2.18",
|
|
31
31
|
"google-auth-library": "^10.5.0",
|
|
32
32
|
"onnxruntime-node": "^1.24.1",
|
|
33
|
-
"webtalk": "^1.0.
|
|
33
|
+
"webtalk": "^1.0.17",
|
|
34
34
|
"ws": "^8.14.2"
|
|
35
35
|
},
|
|
36
36
|
"overrides": {
|
package/server.js
CHANGED
|
@@ -72,17 +72,24 @@ async function ensureModelsDownloaded() {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
try {
|
|
75
|
-
const { createRequire: cr } = await import('module');
|
|
76
|
-
const r = cr(import.meta.url);
|
|
77
|
-
|
|
78
|
-
const bundledModels = process.env.PORTABLE_EXE_DIR ? path.join(process.env.PORTABLE_EXE_DIR, 'models') : null;
|
|
79
75
|
const gmguiModels = path.join(os.homedir(), '.gmgui', 'models');
|
|
80
|
-
const modelsBase =
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
const modelsBase = process.env.PORTABLE_EXE_DIR
|
|
77
|
+
? (fs.existsSync(path.join(process.env.PORTABLE_EXE_DIR, 'models', 'onnx-community')) ? path.join(process.env.PORTABLE_EXE_DIR, 'models') : gmguiModels)
|
|
78
|
+
: gmguiModels;
|
|
79
|
+
|
|
80
|
+
const { ensureModels } = createRequire(import.meta.url)('webtalk/ipfs-downloader');
|
|
81
|
+
const { createConfig } = createRequire(import.meta.url)('webtalk/config');
|
|
82
|
+
const config = createConfig({
|
|
83
|
+
modelsDir: modelsBase,
|
|
84
|
+
ttsModelsDir: path.join(modelsBase, 'tts'),
|
|
85
|
+
sttModelsDir: path.join(modelsBase, 'stt'),
|
|
86
|
+
});
|
|
83
87
|
|
|
84
|
-
const
|
|
85
|
-
const
|
|
88
|
+
const { checkTTSModelExists } = createRequire(import.meta.url)('webtalk/tts-models');
|
|
89
|
+
const { checkWhisperModelExists } = createRequire(import.meta.url)('webtalk/whisper-models');
|
|
90
|
+
|
|
91
|
+
const sttOk = await checkWhisperModelExists(config.defaultWhisperModel, config).catch(() => false);
|
|
92
|
+
const ttsOk = await checkTTSModelExists(config).catch(() => false);
|
|
86
93
|
|
|
87
94
|
if (sttOk && ttsOk) {
|
|
88
95
|
console.log('[MODELS] All model files present');
|
|
@@ -93,125 +100,19 @@ async function ensureModelsDownloaded() {
|
|
|
93
100
|
modelDownloadState.downloading = true;
|
|
94
101
|
modelDownloadState.error = null;
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
console.warn('[MODELS] STT IPFS CID not registered in database');
|
|
107
|
-
console.warn('[MODELS] To enable STT: Pin whisper-base model to IPFS and register CID via: queries.recordIpfsCid(cid, "whisper-base", "stt", hash, gateway)');
|
|
108
|
-
broadcastModelProgress({
|
|
109
|
-
done: true,
|
|
110
|
-
error: 'STT model CID not registered - speech will be unavailable. Register via IPFS.',
|
|
111
|
-
type: 'stt',
|
|
112
|
-
completedFiles,
|
|
113
|
-
totalFiles
|
|
114
|
-
});
|
|
115
|
-
} else {
|
|
116
|
-
console.log('[MODELS] Downloading STT from Lighthouse IPFS:', ipfsCid.cid);
|
|
117
|
-
fs.mkdirSync(sttDir, { recursive: true });
|
|
118
|
-
|
|
119
|
-
// Download from Lighthouse gateway: https://gateway.lighthouse.storage/ipfs/CID/stt/onnx-community/whisper-base/
|
|
120
|
-
const lighthouseGateway = 'https://gateway.lighthouse.storage/ipfs';
|
|
121
|
-
const sttUrl = `${lighthouseGateway}/${ipfsCid.cid}/stt/onnx-community/whisper-base/onnx/`;
|
|
122
|
-
const sttFile = path.join(sttDir, 'whisper-onnx.tar');
|
|
123
|
-
|
|
124
|
-
await downloadWithProgress(
|
|
125
|
-
sttUrl,
|
|
126
|
-
sttFile,
|
|
127
|
-
(progress) => {
|
|
128
|
-
broadcastModelProgress({
|
|
129
|
-
started: true,
|
|
130
|
-
done: false,
|
|
131
|
-
downloading: true,
|
|
132
|
-
type: 'stt',
|
|
133
|
-
source: 'lighthouse-ipfs',
|
|
134
|
-
gateway: 'gateway.lighthouse.storage',
|
|
135
|
-
...progress,
|
|
136
|
-
completedFiles,
|
|
137
|
-
totalFiles
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
);
|
|
141
|
-
console.log('[MODELS] STT model downloaded successfully from Lighthouse IPFS');
|
|
142
|
-
}
|
|
143
|
-
} catch (err) {
|
|
144
|
-
console.error('[MODELS] IPFS STT download failed:', err.message);
|
|
145
|
-
broadcastModelProgress({
|
|
146
|
-
done: true,
|
|
147
|
-
error: `IPFS STT download failed: ${err.message}`,
|
|
148
|
-
type: 'stt',
|
|
149
|
-
completedFiles,
|
|
150
|
-
totalFiles
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
completedFiles += 10;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (!ttsOk) {
|
|
157
|
-
console.log('[MODELS] Downloading TTS models via IPFS...');
|
|
158
|
-
broadcastModelProgress({ started: true, done: false, downloading: true, type: 'tts', source: 'ipfs', completedFiles, totalFiles });
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const ipfsCid = queries.getIpfsCidByModel('tts', 'voice');
|
|
162
|
-
if (!ipfsCid) {
|
|
163
|
-
console.warn('[MODELS] TTS IPFS CID not registered in database');
|
|
164
|
-
console.warn('[MODELS] To enable TTS: Pin TTS models to IPFS and register CID via: queries.recordIpfsCid(cid, "tts", "voice", hash, gateway)');
|
|
165
|
-
broadcastModelProgress({
|
|
166
|
-
done: true,
|
|
167
|
-
error: 'TTS model CID not registered - speech synthesis will be unavailable. Register via IPFS.',
|
|
168
|
-
type: 'tts',
|
|
169
|
-
completedFiles,
|
|
170
|
-
totalFiles
|
|
171
|
-
});
|
|
172
|
-
} else {
|
|
173
|
-
console.log('[MODELS] Downloading TTS from Lighthouse IPFS:', ipfsCid.cid);
|
|
174
|
-
fs.mkdirSync(ttsDir, { recursive: true });
|
|
175
|
-
|
|
176
|
-
// Download from Lighthouse gateway: https://gateway.lighthouse.storage/ipfs/CID/tts/
|
|
177
|
-
const lighthouseGateway = 'https://gateway.lighthouse.storage/ipfs';
|
|
178
|
-
const ttsUrl = `${lighthouseGateway}/${ipfsCid.cid}/tts/`;
|
|
179
|
-
const ttsFile = path.join(ttsDir, 'tts-models.tar');
|
|
180
|
-
|
|
181
|
-
await downloadWithProgress(
|
|
182
|
-
ttsUrl,
|
|
183
|
-
ttsFile,
|
|
184
|
-
(progress) => {
|
|
185
|
-
broadcastModelProgress({
|
|
186
|
-
started: true,
|
|
187
|
-
done: false,
|
|
188
|
-
downloading: true,
|
|
189
|
-
type: 'tts',
|
|
190
|
-
source: 'lighthouse-ipfs',
|
|
191
|
-
gateway: 'gateway.lighthouse.storage',
|
|
192
|
-
...progress,
|
|
193
|
-
completedFiles,
|
|
194
|
-
totalFiles
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
console.log('[MODELS] TTS models downloaded successfully from Lighthouse IPFS');
|
|
199
|
-
}
|
|
200
|
-
} catch (err) {
|
|
201
|
-
console.error('[MODELS] IPFS TTS download failed:', err.message);
|
|
202
|
-
broadcastModelProgress({
|
|
203
|
-
done: true,
|
|
204
|
-
error: `IPFS TTS download failed: ${err.message}`,
|
|
205
|
-
type: 'tts',
|
|
206
|
-
completedFiles,
|
|
207
|
-
totalFiles
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
completedFiles += 6;
|
|
211
|
-
}
|
|
103
|
+
await ensureModels(config, (progress) => {
|
|
104
|
+
broadcastModelProgress({
|
|
105
|
+
started: true,
|
|
106
|
+
done: progress.done || false,
|
|
107
|
+
downloading: progress.status === 'downloading',
|
|
108
|
+
type: progress.type,
|
|
109
|
+
source: 'ipfs',
|
|
110
|
+
...progress,
|
|
111
|
+
});
|
|
112
|
+
});
|
|
212
113
|
|
|
213
114
|
modelDownloadState.complete = true;
|
|
214
|
-
broadcastModelProgress({ started: true, done: true, downloading: false
|
|
115
|
+
broadcastModelProgress({ started: true, done: true, downloading: false });
|
|
215
116
|
return true;
|
|
216
117
|
} catch (err) {
|
|
217
118
|
console.error('[MODELS] Download error:', err.message);
|