agentgui 1.0.217 → 1.0.219
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 +1 -11
- package/package.json +5 -1
- package/server.js +14 -49
- package/lib/webtalk-patch.js +0 -33
- package/lib/windows-pocket-tts-setup.js +0 -209
package/lib/speech.js
CHANGED
|
@@ -4,7 +4,6 @@ import path from 'path';
|
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import http from 'http';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
|
-
import { patchWebtalkForWindows } from './webtalk-patch.js';
|
|
8
7
|
|
|
9
8
|
const require = createRequire(import.meta.url);
|
|
10
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -13,8 +12,6 @@ const ROOT = path.dirname(__dirname);
|
|
|
13
12
|
const serverSTT = require('webtalk/server-stt');
|
|
14
13
|
const serverTTS = require('webtalk/server-tts');
|
|
15
14
|
|
|
16
|
-
patchWebtalkForWindows(serverTTS);
|
|
17
|
-
|
|
18
15
|
const EXTRA_VOICE_DIRS = [path.join(ROOT, 'voices')];
|
|
19
16
|
|
|
20
17
|
const POCKET_TTS_VOICES = [
|
|
@@ -124,14 +121,7 @@ function getStatus() {
|
|
|
124
121
|
function preloadTTS() {
|
|
125
122
|
const defaultVoice = serverTTS.findVoiceFile('custom_cleetus', EXTRA_VOICE_DIRS) || '/config/voices/cleetus.wav';
|
|
126
123
|
const voicePath = fs.existsSync(defaultVoice) ? defaultVoice : null;
|
|
127
|
-
|
|
128
|
-
binaryPaths: [
|
|
129
|
-
path.join(os.homedir(), '.gmgui', 'pocket-venv', 'Scripts', 'pocket-tts.exe'),
|
|
130
|
-
path.join(os.homedir(), '.gmgui', 'pocket-venv', 'bin', 'pocket-tts.exe'),
|
|
131
|
-
path.join(os.homedir(), '.gmgui', 'pocket-venv', 'bin', 'pocket-tts'),
|
|
132
|
-
]
|
|
133
|
-
};
|
|
134
|
-
serverTTS.start(voicePath, options).then(ok => {
|
|
124
|
+
serverTTS.start(voicePath, {}).then(ok => {
|
|
135
125
|
if (ok) console.log('[TTS] pocket-tts sidecar started');
|
|
136
126
|
else console.log('[TTS] pocket-tts failed to start');
|
|
137
127
|
}).catch(err => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentgui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.219",
|
|
4
4
|
"description": "Multi-agent ACP client with real-time communication",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server.js",
|
|
@@ -32,5 +32,9 @@
|
|
|
32
32
|
"onnxruntime-node": "^1.24.1",
|
|
33
33
|
"webtalk": "github:AnEntrypoint/webtalk",
|
|
34
34
|
"ws": "^8.14.2"
|
|
35
|
+
},
|
|
36
|
+
"overrides": {
|
|
37
|
+
"onnxruntime-web": "npm:empty-npm-package@1.0.0",
|
|
38
|
+
"sharp": "npm:empty-npm-package@1.0.0"
|
|
35
39
|
}
|
|
36
40
|
}
|
package/server.js
CHANGED
|
@@ -11,44 +11,17 @@ import { createRequire } from 'module';
|
|
|
11
11
|
import { OAuth2Client } from 'google-auth-library';
|
|
12
12
|
import { queries } from './database.js';
|
|
13
13
|
import { runClaudeWithStreaming } from './lib/claude-runner.js';
|
|
14
|
-
import { isSetup, install, detectPython } from './lib/windows-pocket-tts-setup.js';
|
|
15
14
|
let speechModule = null;
|
|
16
15
|
async function getSpeech() {
|
|
17
16
|
if (!speechModule) speechModule = await import('./lib/speech.js');
|
|
18
17
|
return speechModule;
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
const pocketTtsSetupState = { attempted: false, ready: false, error: null, inProgress: false };
|
|
22
|
-
|
|
23
20
|
async function ensurePocketTtsSetup(onProgress) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (pocketTtsSetupState.inProgress) {
|
|
29
|
-
let waited = 0;
|
|
30
|
-
const MAX_WAIT = 600000;
|
|
31
|
-
while (pocketTtsSetupState.inProgress && waited < MAX_WAIT) {
|
|
32
|
-
await new Promise(r => setTimeout(r, 100));
|
|
33
|
-
waited += 100;
|
|
34
|
-
}
|
|
35
|
-
return pocketTtsSetupState.ready;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
pocketTtsSetupState.inProgress = true;
|
|
39
|
-
|
|
40
|
-
if (onProgress) onProgress({ step: 'detecting-python', status: 'in-progress', message: 'Detecting Python installation' });
|
|
41
|
-
|
|
42
|
-
const result = await install((msg) => {
|
|
43
|
-
if (onProgress) onProgress(msg);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
pocketTtsSetupState.attempted = true;
|
|
47
|
-
pocketTtsSetupState.ready = result.success;
|
|
48
|
-
pocketTtsSetupState.error = result.error || null;
|
|
49
|
-
pocketTtsSetupState.inProgress = false;
|
|
50
|
-
|
|
51
|
-
return pocketTtsSetupState.ready;
|
|
21
|
+
const { createRequire: cr } = await import('module');
|
|
22
|
+
const r = cr(import.meta.url);
|
|
23
|
+
const serverTTS = r('webtalk/server-tts');
|
|
24
|
+
return serverTTS.ensureInstalled(onProgress);
|
|
52
25
|
}
|
|
53
26
|
|
|
54
27
|
function eagerTTS(text, conversationId, sessionId) {
|
|
@@ -1446,12 +1419,12 @@ const server = http.createServer(async (req, res) => {
|
|
|
1446
1419
|
return;
|
|
1447
1420
|
}
|
|
1448
1421
|
|
|
1449
|
-
if (
|
|
1422
|
+
if (process.platform === 'win32') {
|
|
1450
1423
|
const setupOk = await ensurePocketTtsSetup((msg) => {
|
|
1451
1424
|
broadcastSync({ type: 'tts_setup_progress', ...msg });
|
|
1452
1425
|
});
|
|
1453
1426
|
if (!setupOk) {
|
|
1454
|
-
sendJSON(req, res, 503, { error:
|
|
1427
|
+
sendJSON(req, res, 503, { error: 'pocket-tts setup failed', retryable: false });
|
|
1455
1428
|
return;
|
|
1456
1429
|
}
|
|
1457
1430
|
|
|
@@ -1524,26 +1497,18 @@ const server = http.createServer(async (req, res) => {
|
|
|
1524
1497
|
try {
|
|
1525
1498
|
const { getStatus } = await getSpeech();
|
|
1526
1499
|
const baseStatus = getStatus();
|
|
1527
|
-
const
|
|
1528
|
-
const
|
|
1500
|
+
const r = createRequire(import.meta.url);
|
|
1501
|
+
const serverTTS = r('webtalk/server-tts');
|
|
1502
|
+
const pyInfo = serverTTS.detectPython();
|
|
1503
|
+
sendJSON(req, res, 200, {
|
|
1529
1504
|
...baseStatus,
|
|
1530
|
-
pythonDetected:
|
|
1531
|
-
pythonVersion:
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
attempted: pocketTtsSetupState.attempted,
|
|
1535
|
-
error: pocketTtsSetupState.error,
|
|
1536
|
-
},
|
|
1537
|
-
setupMessage: pocketTtsSetupState.error || (pocketTtsSetupState.ready ? 'pocket-tts ready' : 'Will setup on first TTS request'),
|
|
1538
|
-
};
|
|
1539
|
-
sendJSON(req, res, 200, statusWithSetup);
|
|
1505
|
+
pythonDetected: pyInfo.found,
|
|
1506
|
+
pythonVersion: pyInfo.version || null,
|
|
1507
|
+
setupMessage: baseStatus.ttsReady ? 'pocket-tts ready' : 'Will setup on first TTS request',
|
|
1508
|
+
});
|
|
1540
1509
|
} catch (err) {
|
|
1541
|
-
const pythonDetect = detectPython();
|
|
1542
1510
|
sendJSON(req, res, 200, {
|
|
1543
1511
|
sttReady: false, ttsReady: false, sttLoading: false, ttsLoading: false,
|
|
1544
|
-
pythonDetected: pythonDetect.found,
|
|
1545
|
-
pythonVersion: pythonDetect.version,
|
|
1546
|
-
pocketTtsSetup: { ready: false, attempted: false, error: null },
|
|
1547
1512
|
setupMessage: 'Will setup on first TTS request',
|
|
1548
1513
|
});
|
|
1549
1514
|
}
|
package/lib/webtalk-patch.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
|
|
5
|
-
export function patchWebtalkForWindows(serverTTS) {
|
|
6
|
-
if (process.platform !== 'win32') return;
|
|
7
|
-
|
|
8
|
-
const venvDir = path.join(os.homedir(), '.gmgui', 'pocket-venv');
|
|
9
|
-
|
|
10
|
-
// Check if pocket-tts exists at Windows paths
|
|
11
|
-
const windowsBinaries = [
|
|
12
|
-
path.join(venvDir, 'Scripts', 'pocket-tts.exe'),
|
|
13
|
-
path.join(venvDir, 'bin', 'pocket-tts.exe'),
|
|
14
|
-
path.join(venvDir, 'bin', 'pocket-tts'),
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
const found = windowsBinaries.find(p => fs.existsSync(p));
|
|
18
|
-
|
|
19
|
-
if (found) {
|
|
20
|
-
// Patch the start function to use the correct binary
|
|
21
|
-
const originalStart = serverTTS.start;
|
|
22
|
-
|
|
23
|
-
serverTTS.start = function(voicePath, options) {
|
|
24
|
-
if (!options) options = {};
|
|
25
|
-
if (!options.binaryPaths) options.binaryPaths = [];
|
|
26
|
-
|
|
27
|
-
// Ensure Windows paths are first
|
|
28
|
-
options.binaryPaths = [...windowsBinaries, ...options.binaryPaths];
|
|
29
|
-
|
|
30
|
-
return originalStart.call(this, voicePath, options);
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { execSync, spawnSync } from 'child_process';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import os from 'os';
|
|
5
|
-
|
|
6
|
-
const PYTHON_VERSION_MIN = [3, 9];
|
|
7
|
-
const VENV_DIR = path.join(os.homedir(), '.gmgui', 'pocket-venv');
|
|
8
|
-
const isWin = process.platform === 'win32';
|
|
9
|
-
const EXECUTABLE_NAME = isWin ? 'pocket-tts.exe' : 'pocket-tts';
|
|
10
|
-
|
|
11
|
-
const CONFIG = {
|
|
12
|
-
PIP_TIMEOUT: 120000,
|
|
13
|
-
VENV_CREATION_TIMEOUT: 30000,
|
|
14
|
-
MAX_RETRIES: 3,
|
|
15
|
-
RETRY_DELAY_MS: 1000,
|
|
16
|
-
RETRY_BACKOFF_MULTIPLIER: 2,
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
function getPocketTtsPath() {
|
|
20
|
-
if (isWin) {
|
|
21
|
-
return path.join(VENV_DIR, 'Scripts', EXECUTABLE_NAME);
|
|
22
|
-
}
|
|
23
|
-
return path.join(VENV_DIR, 'bin', EXECUTABLE_NAME);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function detectPython() {
|
|
27
|
-
try {
|
|
28
|
-
const versionOutput = execSync('python --version', { encoding: 'utf-8', timeout: 10000 }).trim();
|
|
29
|
-
const match = versionOutput.match(/(\d+)\.(\d+)/);
|
|
30
|
-
if (!match) return { found: false, version: null, error: 'Could not parse version' };
|
|
31
|
-
|
|
32
|
-
const major = parseInt(match[1], 10);
|
|
33
|
-
const minor = parseInt(match[2], 10);
|
|
34
|
-
const versionOk = major > PYTHON_VERSION_MIN[0] || (major === PYTHON_VERSION_MIN[0] && minor >= PYTHON_VERSION_MIN[1]);
|
|
35
|
-
|
|
36
|
-
if (!versionOk) {
|
|
37
|
-
return { found: true, version: `${major}.${minor}`, error: `Python ${major}.${minor} found but ${PYTHON_VERSION_MIN[0]}.${PYTHON_VERSION_MIN[1]}+ required` };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return { found: true, version: `${major}.${minor}`, error: null };
|
|
41
|
-
} catch (e) {
|
|
42
|
-
return { found: false, version: null, error: 'Python not found in PATH' };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function isSetup() {
|
|
47
|
-
const exePath = getPocketTtsPath();
|
|
48
|
-
return fs.existsSync(exePath);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function cleanupPartialInstall() {
|
|
52
|
-
try {
|
|
53
|
-
if (fs.existsSync(VENV_DIR)) {
|
|
54
|
-
fs.rmSync(VENV_DIR, { recursive: true, force: true });
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
} catch (e) {
|
|
58
|
-
console.error(`Failed to cleanup partial install: ${e.message}`);
|
|
59
|
-
}
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function verifyInstallation() {
|
|
64
|
-
const exePath = getPocketTtsPath();
|
|
65
|
-
if (!fs.existsSync(exePath)) {
|
|
66
|
-
return { valid: false, error: `Binary not found at ${exePath}` };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
const versionOutput = execSync(`"${exePath}" --version`, { encoding: 'utf-8', timeout: 10000, stdio: 'pipe' });
|
|
71
|
-
return { valid: true, version: versionOutput.trim() };
|
|
72
|
-
} catch (e) {
|
|
73
|
-
return { valid: false, error: `Binary exists but failed verification: ${e.message}` };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async function executeWithRetry(fn, stepName, maxRetries = CONFIG.MAX_RETRIES) {
|
|
78
|
-
let lastError = null;
|
|
79
|
-
let delayMs = CONFIG.RETRY_DELAY_MS;
|
|
80
|
-
|
|
81
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
82
|
-
try {
|
|
83
|
-
return await fn(attempt);
|
|
84
|
-
} catch (e) {
|
|
85
|
-
lastError = e;
|
|
86
|
-
if (attempt < maxRetries) {
|
|
87
|
-
console.log(`Attempt ${attempt}/${maxRetries} failed for ${stepName}, retrying in ${delayMs}ms`);
|
|
88
|
-
await new Promise(r => setTimeout(r, delayMs));
|
|
89
|
-
delayMs *= CONFIG.RETRY_BACKOFF_MULTIPLIER;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const msg = `${stepName} failed after ${maxRetries} attempts: ${lastError.message || lastError}`;
|
|
95
|
-
throw new Error(msg);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async function install(onProgress) {
|
|
99
|
-
const pythonDetect = detectPython();
|
|
100
|
-
|
|
101
|
-
if (!pythonDetect.found) {
|
|
102
|
-
const msg = pythonDetect.error || 'Python not found';
|
|
103
|
-
if (onProgress) onProgress({ step: 'detecting-python', status: 'error', message: msg });
|
|
104
|
-
return { success: false, error: msg };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (pythonDetect.error) {
|
|
108
|
-
if (onProgress) onProgress({ step: 'detecting-python', status: 'error', message: pythonDetect.error });
|
|
109
|
-
return { success: false, error: pythonDetect.error };
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (onProgress) onProgress({ step: 'detecting-python', status: 'success', message: `Found Python ${pythonDetect.version}` });
|
|
113
|
-
|
|
114
|
-
if (isSetup()) {
|
|
115
|
-
const verify = verifyInstallation();
|
|
116
|
-
if (verify.valid) {
|
|
117
|
-
if (onProgress) onProgress({ step: 'verifying', status: 'success', message: 'pocket-tts already installed' });
|
|
118
|
-
return { success: true };
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (onProgress) onProgress({ step: 'creating-venv', status: 'in-progress', message: `Creating virtual environment at ${VENV_DIR}` });
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
await executeWithRetry(async (attempt) => {
|
|
126
|
-
return execSync(`python -m venv "${VENV_DIR}"`, {
|
|
127
|
-
encoding: 'utf-8',
|
|
128
|
-
stdio: 'pipe',
|
|
129
|
-
timeout: CONFIG.VENV_CREATION_TIMEOUT,
|
|
130
|
-
});
|
|
131
|
-
}, 'venv creation', 2);
|
|
132
|
-
|
|
133
|
-
if (onProgress) onProgress({ step: 'creating-venv', status: 'success', message: 'Virtual environment created' });
|
|
134
|
-
} catch (e) {
|
|
135
|
-
const msg = `Failed to create venv: ${e.message || e}`;
|
|
136
|
-
if (onProgress) onProgress({ step: 'creating-venv', status: 'error', message: msg });
|
|
137
|
-
cleanupPartialInstall();
|
|
138
|
-
return { success: false, error: msg };
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (onProgress) onProgress({ step: 'installing', status: 'in-progress', message: 'Installing pocket-tts via pip (this may take 2-5 minutes on slow connections)' });
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
await executeWithRetry(async (attempt) => {
|
|
145
|
-
if (attempt > 1 && onProgress) {
|
|
146
|
-
onProgress({ step: 'installing', status: 'in-progress', message: `Installing pocket-tts (attempt ${attempt}/${CONFIG.MAX_RETRIES})` });
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const pipCmd = isWin
|
|
150
|
-
? `"${path.join(VENV_DIR, 'Scripts', 'pip')}" install --no-cache-dir pocket-tts`
|
|
151
|
-
: `"${path.join(VENV_DIR, 'bin', 'pip')}" install --no-cache-dir pocket-tts`;
|
|
152
|
-
|
|
153
|
-
return execSync(pipCmd, {
|
|
154
|
-
encoding: 'utf-8',
|
|
155
|
-
stdio: 'pipe',
|
|
156
|
-
timeout: CONFIG.PIP_TIMEOUT,
|
|
157
|
-
env: { ...process.env, PIP_DEFAULT_TIMEOUT: '120' },
|
|
158
|
-
});
|
|
159
|
-
}, 'pip install', CONFIG.MAX_RETRIES);
|
|
160
|
-
|
|
161
|
-
if (onProgress) onProgress({ step: 'installing', status: 'success', message: 'pocket-tts installed successfully' });
|
|
162
|
-
} catch (e) {
|
|
163
|
-
const msg = `Failed to install pocket-tts: ${e.message || e}`;
|
|
164
|
-
if (onProgress) onProgress({ step: 'installing', status: 'error', message: msg });
|
|
165
|
-
cleanupPartialInstall();
|
|
166
|
-
return { success: false, error: msg };
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (onProgress) onProgress({ step: 'verifying', status: 'in-progress', message: 'Verifying installation' });
|
|
170
|
-
|
|
171
|
-
const verify = verifyInstallation();
|
|
172
|
-
if (!verify.valid) {
|
|
173
|
-
const msg = verify.error || 'Installation verification failed';
|
|
174
|
-
if (onProgress) onProgress({ step: 'verifying', status: 'error', message: msg });
|
|
175
|
-
cleanupPartialInstall();
|
|
176
|
-
return { success: false, error: msg };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const exePath = getPocketTtsPath();
|
|
180
|
-
const binDir = path.join(VENV_DIR, 'bin');
|
|
181
|
-
const binExePath = path.join(binDir, 'pocket-tts');
|
|
182
|
-
|
|
183
|
-
if (isWin) {
|
|
184
|
-
try {
|
|
185
|
-
fs.mkdirSync(binDir, { recursive: true });
|
|
186
|
-
} catch (e) {}
|
|
187
|
-
|
|
188
|
-
const exeWithExt = path.join(binDir, 'pocket-tts.exe');
|
|
189
|
-
if (fs.existsSync(exePath) && !fs.existsSync(exeWithExt)) {
|
|
190
|
-
try {
|
|
191
|
-
fs.copyFileSync(exePath, exeWithExt);
|
|
192
|
-
} catch (e) {}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const batchFile = path.join(binDir, 'pocket-tts.bat');
|
|
196
|
-
if (!fs.existsSync(batchFile) && fs.existsSync(exeWithExt)) {
|
|
197
|
-
try {
|
|
198
|
-
const batchContent = `@echo off\nsetlocal enabledelayedexpansion\nset PYTHONUNBUFFERED=1\nset HF_HUB_DISABLE_SYMLINKS_WARNING=1\n"${exeWithExt}" %*\n`;
|
|
199
|
-
fs.writeFileSync(batchFile, batchContent, 'utf-8');
|
|
200
|
-
} catch (e) {}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (onProgress) onProgress({ step: 'verifying', status: 'success', message: `pocket-tts ready (${verify.version})` });
|
|
205
|
-
|
|
206
|
-
return { success: true };
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export { detectPython, isSetup, install, getPocketTtsPath, VENV_DIR, CONFIG, cleanupPartialInstall, verifyInstallation };
|