voice-mode 2.33.4__py3-none-any.whl → 2.34.1__py3-none-any.whl
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.
- voice_mode/__version__.py +1 -1
- voice_mode/config.py +1 -1
- voice_mode/frontend/package-lock.json +1 -154
- voice_mode/templates/launchd/com.voicemode.whisper.plist +4 -4
- voice_mode/tools/service.py +11 -5
- voice_mode/tools/services/kokoro/install.py +207 -2
- voice_mode/tools/services/whisper/install.py +329 -189
- {voice_mode-2.33.4.dist-info → voice_mode-2.34.1.dist-info}/METADATA +1 -1
- voice_mode-2.34.1.dist-info/RECORD +116 -0
- voice_mode/frontend/.next/BUILD_ID +0 -1
- voice_mode/frontend/.next/app-build-manifest.json +0 -28
- voice_mode/frontend/.next/app-path-routes-manifest.json +0 -1
- voice_mode/frontend/.next/build-manifest.json +0 -32
- voice_mode/frontend/.next/export-marker.json +0 -1
- voice_mode/frontend/.next/images-manifest.json +0 -1
- voice_mode/frontend/.next/next-minimal-server.js.nft.json +0 -1
- voice_mode/frontend/.next/next-server.js.nft.json +0 -1
- voice_mode/frontend/.next/package.json +0 -1
- voice_mode/frontend/.next/prerender-manifest.json +0 -1
- voice_mode/frontend/.next/react-loadable-manifest.json +0 -1
- voice_mode/frontend/.next/required-server-files.json +0 -1
- voice_mode/frontend/.next/routes-manifest.json +0 -1
- voice_mode/frontend/.next/server/app/_not-found/page.js +0 -1
- voice_mode/frontend/.next/server/app/_not-found/page.js.nft.json +0 -1
- voice_mode/frontend/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
- voice_mode/frontend/.next/server/app/_not-found.html +0 -1
- voice_mode/frontend/.next/server/app/_not-found.meta +0 -6
- voice_mode/frontend/.next/server/app/_not-found.rsc +0 -9
- voice_mode/frontend/.next/server/app/api/connection-details/route.js +0 -12
- voice_mode/frontend/.next/server/app/api/connection-details/route.js.nft.json +0 -1
- voice_mode/frontend/.next/server/app/favicon.ico/route.js +0 -12
- voice_mode/frontend/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- voice_mode/frontend/.next/server/app/favicon.ico.body +0 -0
- voice_mode/frontend/.next/server/app/favicon.ico.meta +0 -1
- voice_mode/frontend/.next/server/app/index.html +0 -1
- voice_mode/frontend/.next/server/app/index.meta +0 -5
- voice_mode/frontend/.next/server/app/index.rsc +0 -7
- voice_mode/frontend/.next/server/app/page.js +0 -11
- voice_mode/frontend/.next/server/app/page.js.nft.json +0 -1
- voice_mode/frontend/.next/server/app/page_client-reference-manifest.js +0 -1
- voice_mode/frontend/.next/server/app-paths-manifest.json +0 -6
- voice_mode/frontend/.next/server/chunks/463.js +0 -1
- voice_mode/frontend/.next/server/chunks/682.js +0 -6
- voice_mode/frontend/.next/server/chunks/948.js +0 -2
- voice_mode/frontend/.next/server/chunks/994.js +0 -2
- voice_mode/frontend/.next/server/chunks/font-manifest.json +0 -1
- voice_mode/frontend/.next/server/font-manifest.json +0 -1
- voice_mode/frontend/.next/server/functions-config-manifest.json +0 -1
- voice_mode/frontend/.next/server/interception-route-rewrite-manifest.js +0 -1
- voice_mode/frontend/.next/server/middleware-build-manifest.js +0 -1
- voice_mode/frontend/.next/server/middleware-manifest.json +0 -6
- voice_mode/frontend/.next/server/middleware-react-loadable-manifest.js +0 -1
- voice_mode/frontend/.next/server/next-font-manifest.js +0 -1
- voice_mode/frontend/.next/server/next-font-manifest.json +0 -1
- voice_mode/frontend/.next/server/pages/404.html +0 -1
- voice_mode/frontend/.next/server/pages/500.html +0 -1
- voice_mode/frontend/.next/server/pages/_app.js +0 -1
- voice_mode/frontend/.next/server/pages/_app.js.nft.json +0 -1
- voice_mode/frontend/.next/server/pages/_document.js +0 -1
- voice_mode/frontend/.next/server/pages/_document.js.nft.json +0 -1
- voice_mode/frontend/.next/server/pages/_error.js +0 -1
- voice_mode/frontend/.next/server/pages/_error.js.nft.json +0 -1
- voice_mode/frontend/.next/server/pages-manifest.json +0 -1
- voice_mode/frontend/.next/server/server-reference-manifest.js +0 -1
- voice_mode/frontend/.next/server/server-reference-manifest.json +0 -1
- voice_mode/frontend/.next/server/webpack-runtime.js +0 -1
- voice_mode/frontend/.next/standalone/.next/BUILD_ID +0 -1
- voice_mode/frontend/.next/standalone/.next/app-build-manifest.json +0 -28
- voice_mode/frontend/.next/standalone/.next/app-path-routes-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/build-manifest.json +0 -32
- voice_mode/frontend/.next/standalone/.next/package.json +0 -1
- voice_mode/frontend/.next/standalone/.next/prerender-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/react-loadable-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/required-server-files.json +0 -1
- voice_mode/frontend/.next/standalone/.next/routes-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found/page.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found/page.js.nft.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found.html +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found.meta +0 -6
- voice_mode/frontend/.next/standalone/.next/server/app/_not-found.rsc +0 -9
- voice_mode/frontend/.next/standalone/.next/server/app/api/connection-details/route.js +0 -12
- voice_mode/frontend/.next/standalone/.next/server/app/api/connection-details/route.js.nft.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/favicon.ico/route.js +0 -12
- voice_mode/frontend/.next/standalone/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/favicon.ico.body +0 -0
- voice_mode/frontend/.next/standalone/.next/server/app/favicon.ico.meta +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/index.html +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/index.meta +0 -5
- voice_mode/frontend/.next/standalone/.next/server/app/index.rsc +0 -7
- voice_mode/frontend/.next/standalone/.next/server/app/page.js +0 -11
- voice_mode/frontend/.next/standalone/.next/server/app/page.js.nft.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app/page_client-reference-manifest.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/app-paths-manifest.json +0 -6
- voice_mode/frontend/.next/standalone/.next/server/chunks/463.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/chunks/682.js +0 -6
- voice_mode/frontend/.next/standalone/.next/server/chunks/948.js +0 -2
- voice_mode/frontend/.next/standalone/.next/server/chunks/994.js +0 -2
- voice_mode/frontend/.next/standalone/.next/server/font-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/middleware-build-manifest.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/middleware-manifest.json +0 -6
- voice_mode/frontend/.next/standalone/.next/server/middleware-react-loadable-manifest.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/next-font-manifest.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/next-font-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/404.html +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/500.html +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/_app.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/_app.js.nft.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/_document.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/_document.js.nft.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/_error.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages/_error.js.nft.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/pages-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/server-reference-manifest.js +0 -1
- voice_mode/frontend/.next/standalone/.next/server/server-reference-manifest.json +0 -1
- voice_mode/frontend/.next/standalone/.next/server/webpack-runtime.js +0 -1
- voice_mode/frontend/.next/standalone/package.json +0 -40
- voice_mode/frontend/.next/standalone/server.js +0 -38
- voice_mode/frontend/.next/static/chunks/117-40bc79a2b97edb21.js +0 -2
- voice_mode/frontend/.next/static/chunks/144d3bae-2d5f122b82426d88.js +0 -1
- voice_mode/frontend/.next/static/chunks/471-bd4b96a33883dfa2.js +0 -3
- voice_mode/frontend/.next/static/chunks/app/_not-found/page-5011050e402ab9c8.js +0 -1
- voice_mode/frontend/.next/static/chunks/app/layout-47219099102c5d79.js +0 -1
- voice_mode/frontend/.next/static/chunks/app/page-85f325377cba9fba.js +0 -1
- voice_mode/frontend/.next/static/chunks/fd9d1056-af324d327b243cf1.js +0 -1
- voice_mode/frontend/.next/static/chunks/framework-f66176bb897dc684.js +0 -1
- voice_mode/frontend/.next/static/chunks/main-3163eca598b76a9f.js +0 -1
- voice_mode/frontend/.next/static/chunks/main-app-a8b9b6fe38c11e50.js +0 -1
- voice_mode/frontend/.next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
- voice_mode/frontend/.next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
- voice_mode/frontend/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- voice_mode/frontend/.next/static/chunks/webpack-0ea9b80f19935b70.js +0 -1
- voice_mode/frontend/.next/static/css/a2f49a47752b5010.css +0 -3
- voice_mode/frontend/.next/static/media/01099be941da1820-s.woff2 +0 -0
- voice_mode/frontend/.next/static/media/39883d31a7792467-s.p.woff2 +0 -0
- voice_mode/frontend/.next/static/media/6368404d2e8d66fe-s.woff2 +0 -0
- voice_mode/frontend/.next/static/y_E42BoG1rMRxX7c_GYcB/_buildManifest.js +0 -1
- voice_mode/frontend/.next/static/y_E42BoG1rMRxX7c_GYcB/_ssgManifest.js +0 -1
- voice_mode/frontend/.next/trace +0 -43
- voice_mode/frontend/.next/types/app/api/connection-details/route.ts +0 -343
- voice_mode/frontend/.next/types/app/layout.ts +0 -79
- voice_mode/frontend/.next/types/app/page.ts +0 -79
- voice_mode/frontend/.next/types/package.json +0 -1
- voice_mode-2.33.4.dist-info/RECORD +0 -250
- {voice_mode-2.33.4.dist-info → voice_mode-2.34.1.dist-info}/WHEEL +0 -0
- {voice_mode-2.33.4.dist-info → voice_mode-2.34.1.dist-info}/entry_points.txt +0 -0
voice_mode/__version__.py
CHANGED
voice_mode/config.py
CHANGED
@@ -286,7 +286,7 @@ VAD_AGGRESSIVENESS = int(os.getenv("VOICEMODE_VAD_AGGRESSIVENESS", "2")) # 0-3,
|
|
286
286
|
SILENCE_THRESHOLD_MS = int(os.getenv("VOICEMODE_SILENCE_THRESHOLD_MS", "1000")) # Stop after 1000ms (1 second) of silence
|
287
287
|
MIN_RECORDING_DURATION = float(os.getenv("VOICEMODE_MIN_RECORDING_DURATION", "0.5")) # Minimum 0.5s recording
|
288
288
|
VAD_CHUNK_DURATION_MS = 30 # VAD frame size (must be 10, 20, or 30ms)
|
289
|
-
INITIAL_SILENCE_GRACE_PERIOD = float(os.getenv("VOICEMODE_INITIAL_SILENCE_GRACE_PERIOD", "
|
289
|
+
INITIAL_SILENCE_GRACE_PERIOD = float(os.getenv("VOICEMODE_INITIAL_SILENCE_GRACE_PERIOD", "1")) # No initial silence grace period by default
|
290
290
|
|
291
291
|
# Default listen duration for converse tool
|
292
292
|
DEFAULT_LISTEN_DURATION = float(os.getenv("VOICEMODE_DEFAULT_LISTEN_DURATION", "120.0")) # Default 120s listening time
|
@@ -21,7 +21,6 @@
|
|
21
21
|
"@types/node": "^20.17.13",
|
22
22
|
"@types/react": "^18.3.18",
|
23
23
|
"@types/react-dom": "^18.3.5",
|
24
|
-
"autoprefixer": "^10.4.21",
|
25
24
|
"eslint": "^8.57.1",
|
26
25
|
"eslint-config-next": "14.2.29",
|
27
26
|
"eslint-config-prettier": "9.1.0",
|
@@ -1255,44 +1254,6 @@
|
|
1255
1254
|
"node": ">= 0.4"
|
1256
1255
|
}
|
1257
1256
|
},
|
1258
|
-
"node_modules/autoprefixer": {
|
1259
|
-
"version": "10.4.21",
|
1260
|
-
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
|
1261
|
-
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
|
1262
|
-
"dev": true,
|
1263
|
-
"funding": [
|
1264
|
-
{
|
1265
|
-
"type": "opencollective",
|
1266
|
-
"url": "https://opencollective.com/postcss/"
|
1267
|
-
},
|
1268
|
-
{
|
1269
|
-
"type": "tidelift",
|
1270
|
-
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
|
1271
|
-
},
|
1272
|
-
{
|
1273
|
-
"type": "github",
|
1274
|
-
"url": "https://github.com/sponsors/ai"
|
1275
|
-
}
|
1276
|
-
],
|
1277
|
-
"license": "MIT",
|
1278
|
-
"dependencies": {
|
1279
|
-
"browserslist": "^4.24.4",
|
1280
|
-
"caniuse-lite": "^1.0.30001702",
|
1281
|
-
"fraction.js": "^4.3.7",
|
1282
|
-
"normalize-range": "^0.1.2",
|
1283
|
-
"picocolors": "^1.1.1",
|
1284
|
-
"postcss-value-parser": "^4.2.0"
|
1285
|
-
},
|
1286
|
-
"bin": {
|
1287
|
-
"autoprefixer": "bin/autoprefixer"
|
1288
|
-
},
|
1289
|
-
"engines": {
|
1290
|
-
"node": "^10 || ^12 || >=14"
|
1291
|
-
},
|
1292
|
-
"peerDependencies": {
|
1293
|
-
"postcss": "^8.1.0"
|
1294
|
-
}
|
1295
|
-
},
|
1296
1257
|
"node_modules/available-typed-arrays": {
|
1297
1258
|
"version": "1.0.7",
|
1298
1259
|
"dev": true,
|
@@ -1359,39 +1320,6 @@
|
|
1359
1320
|
"node": ">=8"
|
1360
1321
|
}
|
1361
1322
|
},
|
1362
|
-
"node_modules/browserslist": {
|
1363
|
-
"version": "4.25.3",
|
1364
|
-
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz",
|
1365
|
-
"integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==",
|
1366
|
-
"dev": true,
|
1367
|
-
"funding": [
|
1368
|
-
{
|
1369
|
-
"type": "opencollective",
|
1370
|
-
"url": "https://opencollective.com/browserslist"
|
1371
|
-
},
|
1372
|
-
{
|
1373
|
-
"type": "tidelift",
|
1374
|
-
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
1375
|
-
},
|
1376
|
-
{
|
1377
|
-
"type": "github",
|
1378
|
-
"url": "https://github.com/sponsors/ai"
|
1379
|
-
}
|
1380
|
-
],
|
1381
|
-
"license": "MIT",
|
1382
|
-
"dependencies": {
|
1383
|
-
"caniuse-lite": "^1.0.30001735",
|
1384
|
-
"electron-to-chromium": "^1.5.204",
|
1385
|
-
"node-releases": "^2.0.19",
|
1386
|
-
"update-browserslist-db": "^1.1.3"
|
1387
|
-
},
|
1388
|
-
"bin": {
|
1389
|
-
"browserslist": "cli.js"
|
1390
|
-
},
|
1391
|
-
"engines": {
|
1392
|
-
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
1393
|
-
}
|
1394
|
-
},
|
1395
1323
|
"node_modules/busboy": {
|
1396
1324
|
"version": "1.6.0",
|
1397
1325
|
"dev": true,
|
@@ -1489,9 +1417,7 @@
|
|
1489
1417
|
}
|
1490
1418
|
},
|
1491
1419
|
"node_modules/caniuse-lite": {
|
1492
|
-
"version": "1.0.
|
1493
|
-
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz",
|
1494
|
-
"integrity": "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==",
|
1420
|
+
"version": "1.0.30001726",
|
1495
1421
|
"dev": true,
|
1496
1422
|
"funding": [
|
1497
1423
|
{
|
@@ -1773,13 +1699,6 @@
|
|
1773
1699
|
"dev": true,
|
1774
1700
|
"license": "MIT"
|
1775
1701
|
},
|
1776
|
-
"node_modules/electron-to-chromium": {
|
1777
|
-
"version": "1.5.209",
|
1778
|
-
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.209.tgz",
|
1779
|
-
"integrity": "sha512-Xoz0uMrim9ZETCQt8UgM5FxQF9+imA7PBpokoGcZloA1uw2LeHzTlip5cb5KOAsXZLjh/moN2vReN3ZjJmjI9A==",
|
1780
|
-
"dev": true,
|
1781
|
-
"license": "ISC"
|
1782
|
-
},
|
1783
1702
|
"node_modules/emoji-regex": {
|
1784
1703
|
"version": "9.2.2",
|
1785
1704
|
"dev": true,
|
@@ -1946,16 +1865,6 @@
|
|
1946
1865
|
"url": "https://github.com/sponsors/ljharb"
|
1947
1866
|
}
|
1948
1867
|
},
|
1949
|
-
"node_modules/escalade": {
|
1950
|
-
"version": "3.2.0",
|
1951
|
-
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
1952
|
-
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
1953
|
-
"dev": true,
|
1954
|
-
"license": "MIT",
|
1955
|
-
"engines": {
|
1956
|
-
"node": ">=6"
|
1957
|
-
}
|
1958
|
-
},
|
1959
1868
|
"node_modules/escape-string-regexp": {
|
1960
1869
|
"version": "4.0.0",
|
1961
1870
|
"dev": true,
|
@@ -2553,20 +2462,6 @@
|
|
2553
2462
|
"url": "https://github.com/sponsors/isaacs"
|
2554
2463
|
}
|
2555
2464
|
},
|
2556
|
-
"node_modules/fraction.js": {
|
2557
|
-
"version": "4.3.7",
|
2558
|
-
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
|
2559
|
-
"integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
|
2560
|
-
"dev": true,
|
2561
|
-
"license": "MIT",
|
2562
|
-
"engines": {
|
2563
|
-
"node": "*"
|
2564
|
-
},
|
2565
|
-
"funding": {
|
2566
|
-
"type": "patreon",
|
2567
|
-
"url": "https://github.com/sponsors/rawify"
|
2568
|
-
}
|
2569
|
-
},
|
2570
2465
|
"node_modules/framer-motion": {
|
2571
2466
|
"version": "11.18.2",
|
2572
2467
|
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz",
|
@@ -3798,13 +3693,6 @@
|
|
3798
3693
|
"node": "^10 || ^12 || >=14"
|
3799
3694
|
}
|
3800
3695
|
},
|
3801
|
-
"node_modules/node-releases": {
|
3802
|
-
"version": "2.0.19",
|
3803
|
-
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
3804
|
-
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
3805
|
-
"dev": true,
|
3806
|
-
"license": "MIT"
|
3807
|
-
},
|
3808
3696
|
"node_modules/normalize-path": {
|
3809
3697
|
"version": "3.0.0",
|
3810
3698
|
"dev": true,
|
@@ -3813,16 +3701,6 @@
|
|
3813
3701
|
"node": ">=0.10.0"
|
3814
3702
|
}
|
3815
3703
|
},
|
3816
|
-
"node_modules/normalize-range": {
|
3817
|
-
"version": "0.1.2",
|
3818
|
-
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
3819
|
-
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
|
3820
|
-
"dev": true,
|
3821
|
-
"license": "MIT",
|
3822
|
-
"engines": {
|
3823
|
-
"node": ">=0.10.0"
|
3824
|
-
}
|
3825
|
-
},
|
3826
3704
|
"node_modules/object-assign": {
|
3827
3705
|
"version": "4.1.1",
|
3828
3706
|
"dev": true,
|
@@ -5340,37 +5218,6 @@
|
|
5340
5218
|
"@unrs/resolver-binding-win32-x64-msvc": "1.9.2"
|
5341
5219
|
}
|
5342
5220
|
},
|
5343
|
-
"node_modules/update-browserslist-db": {
|
5344
|
-
"version": "1.1.3",
|
5345
|
-
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
5346
|
-
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
|
5347
|
-
"dev": true,
|
5348
|
-
"funding": [
|
5349
|
-
{
|
5350
|
-
"type": "opencollective",
|
5351
|
-
"url": "https://opencollective.com/browserslist"
|
5352
|
-
},
|
5353
|
-
{
|
5354
|
-
"type": "tidelift",
|
5355
|
-
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
5356
|
-
},
|
5357
|
-
{
|
5358
|
-
"type": "github",
|
5359
|
-
"url": "https://github.com/sponsors/ai"
|
5360
|
-
}
|
5361
|
-
],
|
5362
|
-
"license": "MIT",
|
5363
|
-
"dependencies": {
|
5364
|
-
"escalade": "^3.2.0",
|
5365
|
-
"picocolors": "^1.1.1"
|
5366
|
-
},
|
5367
|
-
"bin": {
|
5368
|
-
"update-browserslist-db": "cli.js"
|
5369
|
-
},
|
5370
|
-
"peerDependencies": {
|
5371
|
-
"browserslist": ">= 4.21.0"
|
5372
|
-
}
|
5373
|
-
},
|
5374
5221
|
"node_modules/uri-js": {
|
5375
5222
|
"version": "4.4.1",
|
5376
5223
|
"dev": true,
|
@@ -9,18 +9,18 @@
|
|
9
9
|
<string>com.voicemode.whisper</string>
|
10
10
|
<key>ProgramArguments</key>
|
11
11
|
<array>
|
12
|
-
<string
|
12
|
+
<string>{START_SCRIPT_PATH}</string>
|
13
13
|
</array>
|
14
14
|
<key>RunAtLoad</key>
|
15
15
|
<true/>
|
16
16
|
<key>KeepAlive</key>
|
17
17
|
<true/>
|
18
18
|
<key>StandardOutPath</key>
|
19
|
-
<string
|
19
|
+
<string>{LOG_DIR}/whisper/whisper.out.log</string>
|
20
20
|
<key>StandardErrorPath</key>
|
21
|
-
<string
|
21
|
+
<string>{LOG_DIR}/whisper/whisper.err.log</string>
|
22
22
|
<key>WorkingDirectory</key>
|
23
|
-
<string
|
23
|
+
<string>{INSTALL_DIR}</string>
|
24
24
|
<key>EnvironmentVariables</key>
|
25
25
|
<dict>
|
26
26
|
<key>PATH</key>
|
voice_mode/tools/service.py
CHANGED
@@ -582,12 +582,18 @@ async def enable_service(service_name: str) -> str:
|
|
582
582
|
if not model_file:
|
583
583
|
return "❌ No Whisper model found. Please run download_model first."
|
584
584
|
|
585
|
+
# Find the start script
|
586
|
+
# whisper_bin is at ~/.voicemode/services/whisper/build/bin/whisper-server
|
587
|
+
# start script is at ~/.voicemode/services/whisper/bin/start-whisper-server.sh
|
588
|
+
install_dir = Path(whisper_bin).parent.parent.parent # Go up from build/bin/whisper-server to whisper dir
|
589
|
+
start_script_path = install_dir / "bin" / "start-whisper-server.sh"
|
590
|
+
if not start_script_path.exists():
|
591
|
+
return f"❌ Start script not found: {start_script_path}"
|
592
|
+
|
585
593
|
content = template.format(
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
LOG_DIR=logs_dir,
|
590
|
-
WORKING_DIR=Path(whisper_bin).parent
|
594
|
+
START_SCRIPT_PATH=str(start_script_path),
|
595
|
+
LOG_DIR=str(logs_dir),
|
596
|
+
INSTALL_DIR=str(install_dir)
|
591
597
|
)
|
592
598
|
elif service_name == "kokoro":
|
593
599
|
kokoro_dir = find_kokoro_fastapi()
|
@@ -22,6 +22,152 @@ from voice_mode.utils.migration_helpers import auto_migrate_if_needed
|
|
22
22
|
logger = logging.getLogger("voice-mode")
|
23
23
|
|
24
24
|
|
25
|
+
async def update_kokoro_service_files(
|
26
|
+
install_dir: str,
|
27
|
+
voicemode_dir: str,
|
28
|
+
port: int,
|
29
|
+
start_script_path: str,
|
30
|
+
auto_enable: Optional[bool] = None
|
31
|
+
) -> Dict[str, Any]:
|
32
|
+
"""Update service files (plist/systemd) for kokoro service.
|
33
|
+
|
34
|
+
This function updates the service files without reinstalling kokoro itself.
|
35
|
+
It ensures paths are properly expanded and templates are up to date.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
Dict with success status and details about what was updated
|
39
|
+
"""
|
40
|
+
system = platform.system()
|
41
|
+
result = {"success": False, "updated": False}
|
42
|
+
|
43
|
+
# Create log directory
|
44
|
+
log_dir = os.path.join(voicemode_dir, 'logs', 'kokoro')
|
45
|
+
os.makedirs(log_dir, exist_ok=True)
|
46
|
+
|
47
|
+
if system == "Darwin":
|
48
|
+
logger.info("Updating launchagent for kokoro...")
|
49
|
+
launchagents_dir = os.path.expanduser("~/Library/LaunchAgents")
|
50
|
+
os.makedirs(launchagents_dir, exist_ok=True)
|
51
|
+
|
52
|
+
plist_name = "com.voicemode.kokoro.plist"
|
53
|
+
plist_path = os.path.join(launchagents_dir, plist_name)
|
54
|
+
|
55
|
+
plist_content = f"""<?xml version="1.0" encoding="UTF-8"?>
|
56
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
57
|
+
<plist version="1.0">
|
58
|
+
<dict>
|
59
|
+
<key>Label</key>
|
60
|
+
<string>com.voicemode.kokoro</string>
|
61
|
+
<key>ProgramArguments</key>
|
62
|
+
<array>
|
63
|
+
<string>{start_script_path}</string>
|
64
|
+
</array>
|
65
|
+
<key>WorkingDirectory</key>
|
66
|
+
<string>{install_dir}</string>
|
67
|
+
<key>RunAtLoad</key>
|
68
|
+
<true/>
|
69
|
+
<key>KeepAlive</key>
|
70
|
+
<true/>
|
71
|
+
<key>StandardOutPath</key>
|
72
|
+
<string>{os.path.join(voicemode_dir, 'logs', 'kokoro', 'kokoro.log')}</string>
|
73
|
+
<key>StandardErrorPath</key>
|
74
|
+
<string>{os.path.join(voicemode_dir, 'logs', 'kokoro', 'kokoro.error.log')}</string>
|
75
|
+
<key>EnvironmentVariables</key>
|
76
|
+
<dict>
|
77
|
+
<key>PATH</key>
|
78
|
+
<string>{os.path.expanduser("~/.local/bin")}:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin</string>
|
79
|
+
</dict>
|
80
|
+
</dict>
|
81
|
+
</plist>"""
|
82
|
+
|
83
|
+
# Unload if already loaded (ignore errors)
|
84
|
+
try:
|
85
|
+
subprocess.run(["launchctl", "unload", plist_path], capture_output=True)
|
86
|
+
except:
|
87
|
+
pass
|
88
|
+
|
89
|
+
# Write updated plist
|
90
|
+
with open(plist_path, 'w') as f:
|
91
|
+
f.write(plist_content)
|
92
|
+
|
93
|
+
result["success"] = True
|
94
|
+
result["updated"] = True
|
95
|
+
result["plist_path"] = plist_path
|
96
|
+
|
97
|
+
# Handle auto_enable if specified
|
98
|
+
if auto_enable is None:
|
99
|
+
auto_enable = SERVICE_AUTO_ENABLE
|
100
|
+
|
101
|
+
if auto_enable:
|
102
|
+
logger.info("Auto-enabling kokoro service...")
|
103
|
+
from voice_mode.tools.service import enable_service
|
104
|
+
enable_result = await enable_service("kokoro")
|
105
|
+
if "✅" in enable_result:
|
106
|
+
result["enabled"] = True
|
107
|
+
else:
|
108
|
+
logger.warning(f"Auto-enable failed: {enable_result}")
|
109
|
+
result["enabled"] = False
|
110
|
+
|
111
|
+
elif system == "Linux":
|
112
|
+
logger.info("Updating systemd user service for kokoro...")
|
113
|
+
systemd_user_dir = os.path.expanduser("~/.config/systemd/user")
|
114
|
+
os.makedirs(systemd_user_dir, exist_ok=True)
|
115
|
+
|
116
|
+
service_name = "voicemode-kokoro.service"
|
117
|
+
service_path = os.path.join(systemd_user_dir, service_name)
|
118
|
+
|
119
|
+
service_content = f"""[Unit]
|
120
|
+
Description=VoiceMode Kokoro TTS Service
|
121
|
+
After=network.target
|
122
|
+
[Service]
|
123
|
+
Type=simple
|
124
|
+
ExecStart={start_script_path}
|
125
|
+
Restart=on-failure
|
126
|
+
RestartSec=10
|
127
|
+
WorkingDirectory={install_dir}
|
128
|
+
StandardOutput=append:{os.path.join(voicemode_dir, 'logs', 'kokoro', 'kokoro.log')}
|
129
|
+
StandardError=append:{os.path.join(voicemode_dir, 'logs', 'kokoro', 'kokoro.error.log')}
|
130
|
+
Environment="PATH=/usr/local/bin:/usr/bin:/bin:/home/m/.local/bin"
|
131
|
+
[Install]
|
132
|
+
WantedBy=default.target
|
133
|
+
"""
|
134
|
+
|
135
|
+
with open(service_path, 'w') as f:
|
136
|
+
f.write(service_content)
|
137
|
+
|
138
|
+
# Reload systemd
|
139
|
+
try:
|
140
|
+
subprocess.run(["systemctl", "--user", "daemon-reload"], check=True)
|
141
|
+
result["success"] = True
|
142
|
+
result["updated"] = True
|
143
|
+
result["service_path"] = service_path
|
144
|
+
except subprocess.CalledProcessError as e:
|
145
|
+
logger.warning(f"Failed to reload systemd: {e}")
|
146
|
+
result["success"] = True # Still consider it success if file was written
|
147
|
+
result["updated"] = True
|
148
|
+
result["service_path"] = service_path
|
149
|
+
|
150
|
+
# Handle auto_enable if specified
|
151
|
+
if auto_enable is None:
|
152
|
+
auto_enable = SERVICE_AUTO_ENABLE
|
153
|
+
|
154
|
+
if auto_enable:
|
155
|
+
logger.info("Auto-enabling kokoro service...")
|
156
|
+
from voice_mode.tools.service import enable_service
|
157
|
+
enable_result = await enable_service("kokoro")
|
158
|
+
if "✅" in enable_result:
|
159
|
+
result["enabled"] = True
|
160
|
+
else:
|
161
|
+
logger.warning(f"Auto-enable failed: {enable_result}")
|
162
|
+
result["enabled"] = False
|
163
|
+
|
164
|
+
else:
|
165
|
+
result["success"] = False
|
166
|
+
result["error"] = f"Unsupported platform: {system}"
|
167
|
+
|
168
|
+
return result
|
169
|
+
|
170
|
+
|
25
171
|
@mcp.tool()
|
26
172
|
async def kokoro_install(
|
27
173
|
install_dir: Optional[str] = None,
|
@@ -101,13 +247,58 @@ async def kokoro_install(
|
|
101
247
|
# Check if the requested version is already installed
|
102
248
|
if is_version_installed(Path(install_dir), version):
|
103
249
|
current_version = get_current_version(Path(install_dir))
|
250
|
+
|
251
|
+
# Determine which start script to use
|
252
|
+
system = platform.system()
|
253
|
+
if system == "Darwin":
|
254
|
+
start_script_name = "start-gpu_mac.sh"
|
255
|
+
else:
|
256
|
+
start_script_name = "start-gpu.sh" # Default to GPU version
|
257
|
+
|
258
|
+
start_script_path = os.path.join(install_dir, start_script_name)
|
259
|
+
|
260
|
+
# If a custom port is requested, create custom start script
|
261
|
+
if port != 8880 and os.path.exists(start_script_path):
|
262
|
+
logger.info(f"Creating custom start script for port {port}")
|
263
|
+
with open(start_script_path, 'r') as f:
|
264
|
+
script_content = f.read()
|
265
|
+
modified_script = script_content.replace("--port 8880", f"--port {port}")
|
266
|
+
custom_script_name = f"start-custom-{port}.sh"
|
267
|
+
custom_script_path = os.path.join(install_dir, custom_script_name)
|
268
|
+
with open(custom_script_path, 'w') as f:
|
269
|
+
f.write(modified_script)
|
270
|
+
os.chmod(custom_script_path, 0o755)
|
271
|
+
start_script_path = custom_script_path
|
272
|
+
|
273
|
+
# Always update service files even if kokoro is already installed
|
274
|
+
logger.info("Kokoro is already installed, updating service files...")
|
275
|
+
service_update_result = await update_kokoro_service_files(
|
276
|
+
install_dir=install_dir,
|
277
|
+
voicemode_dir=voicemode_dir,
|
278
|
+
port=port,
|
279
|
+
start_script_path=start_script_path,
|
280
|
+
auto_enable=auto_enable
|
281
|
+
)
|
282
|
+
|
283
|
+
# Build response message
|
284
|
+
message = f"kokoro-fastapi version {current_version} already installed."
|
285
|
+
if service_update_result.get("updated"):
|
286
|
+
message += " Service files updated."
|
287
|
+
if service_update_result.get("enabled"):
|
288
|
+
message += " Service auto-enabled."
|
289
|
+
|
104
290
|
return {
|
105
291
|
"success": True,
|
106
292
|
"install_path": install_dir,
|
107
293
|
"models_path": models_dir,
|
108
294
|
"already_installed": True,
|
295
|
+
"service_files_updated": service_update_result.get("updated", False),
|
109
296
|
"version": current_version,
|
110
|
-
"
|
297
|
+
"plist_path": service_update_result.get("plist_path"),
|
298
|
+
"service_path": service_update_result.get("service_path"),
|
299
|
+
"start_script": start_script_path,
|
300
|
+
"service_url": f"http://127.0.0.1:{port}",
|
301
|
+
"message": message
|
111
302
|
}
|
112
303
|
|
113
304
|
# Check Python version
|
@@ -215,7 +406,21 @@ async def kokoro_install(
|
|
215
406
|
"message": f"Kokoro-fastapi {current_version} installed. Run: cd {install_dir} && ./{os.path.basename(start_script_path)}{' (' + migration_msg + ')' if migration_msg else ''}"
|
216
407
|
}
|
217
408
|
|
218
|
-
# Install
|
409
|
+
# Install/update service files
|
410
|
+
service_update_result = await update_kokoro_service_files(
|
411
|
+
install_dir=install_dir,
|
412
|
+
voicemode_dir=voicemode_dir,
|
413
|
+
port=port,
|
414
|
+
start_script_path=start_script_path,
|
415
|
+
auto_enable=auto_enable
|
416
|
+
)
|
417
|
+
|
418
|
+
if not service_update_result.get("success"):
|
419
|
+
logger.error(f"Failed to update service files: {service_update_result.get('error', 'Unknown error')}")
|
420
|
+
result["error"] = f"Service file update failed: {service_update_result.get('error', 'Unknown error')}"
|
421
|
+
return result
|
422
|
+
|
423
|
+
# Update result with service file information based on platform
|
219
424
|
if system == "Darwin":
|
220
425
|
logger.info("Installing launchagent for automatic startup...")
|
221
426
|
launchagents_dir = os.path.expanduser("~/Library/LaunchAgents")
|