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.
Files changed (3) hide show
  1. package/lib/speech.js +22 -2
  2. package/package.json +2 -2
  3. 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 = voiceId ? await getVoiceEmbedding(voiceId) : null;
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 = voiceId ? await getVoiceEmbedding(voiceId) : null;
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.296",
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.14",
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 = (bundledModels && fs.existsSync(path.join(bundledModels, 'onnx-community'))) ? bundledModels : gmguiModels;
81
- const sttDir = path.join(modelsBase, 'onnx-community', 'whisper-base');
82
- const ttsDir = path.join(modelsBase, 'tts');
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 sttOk = fs.existsSync(sttDir) && fs.readdirSync(sttDir).length > 0;
85
- const ttsOk = fs.existsSync(ttsDir) && fs.readdirSync(ttsDir).length > 0;
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
- const totalFiles = 16;
97
- let completedFiles = 0;
98
-
99
- if (!sttOk) {
100
- console.log('[MODELS] Downloading STT model via IPFS...');
101
- broadcastModelProgress({ started: true, done: false, downloading: true, type: 'stt', source: 'ipfs', completedFiles, totalFiles });
102
-
103
- try {
104
- const ipfsCid = queries.getIpfsCidByModel('whisper-base', 'stt');
105
- if (!ipfsCid) {
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, completedFiles: totalFiles, totalFiles });
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);