@fraziym/axoniz 0.1.0
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/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/agents/definition.d.ts +15 -0
- package/dist/agents/definition.d.ts.map +1 -0
- package/dist/agents/definition.js +41 -0
- package/dist/agents/definition.js.map +1 -0
- package/dist/agents/index.d.ts +12 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +11 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/registry.d.ts +17 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +23 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/specialized.d.ts +31 -0
- package/dist/agents/specialized.d.ts.map +1 -0
- package/dist/agents/specialized.js +75 -0
- package/dist/agents/specialized.js.map +1 -0
- package/dist/awareness/index.d.ts +14 -0
- package/dist/awareness/index.d.ts.map +1 -0
- package/dist/awareness/index.js +22 -0
- package/dist/awareness/index.js.map +1 -0
- package/dist/awareness/service.d.ts +180 -0
- package/dist/awareness/service.d.ts.map +1 -0
- package/dist/awareness/service.js +789 -0
- package/dist/awareness/service.js.map +1 -0
- package/dist/cli/entry.d.ts +13 -0
- package/dist/cli/entry.d.ts.map +1 -0
- package/dist/cli/entry.js +35 -0
- package/dist/cli/entry.js.map +1 -0
- package/dist/comms/telegram.d.ts +41 -0
- package/dist/comms/telegram.d.ts.map +1 -0
- package/dist/comms/telegram.js +332 -0
- package/dist/comms/telegram.js.map +1 -0
- package/dist/core/agent.d.ts +252 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +1399 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/auth.d.ts +23 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +113 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/authority.d.ts +118 -0
- package/dist/core/authority.d.ts.map +1 -0
- package/dist/core/authority.js +402 -0
- package/dist/core/authority.js.map +1 -0
- package/dist/core/backend/async_queue.d.ts +17 -0
- package/dist/core/backend/async_queue.d.ts.map +1 -0
- package/dist/core/backend/async_queue.js +66 -0
- package/dist/core/backend/async_queue.js.map +1 -0
- package/dist/core/backend/index.d.ts +24 -0
- package/dist/core/backend/index.d.ts.map +1 -0
- package/dist/core/backend/index.js +128 -0
- package/dist/core/backend/index.js.map +1 -0
- package/dist/core/backend/llama_server.d.ts +39 -0
- package/dist/core/backend/llama_server.d.ts.map +1 -0
- package/dist/core/backend/llama_server.js +182 -0
- package/dist/core/backend/llama_server.js.map +1 -0
- package/dist/core/backend/llamacpp.d.ts +40 -0
- package/dist/core/backend/llamacpp.d.ts.map +1 -0
- package/dist/core/backend/llamacpp.js +200 -0
- package/dist/core/backend/llamacpp.js.map +1 -0
- package/dist/core/backend/lmstudio.d.ts +53 -0
- package/dist/core/backend/lmstudio.d.ts.map +1 -0
- package/dist/core/backend/lmstudio.js +274 -0
- package/dist/core/backend/lmstudio.js.map +1 -0
- package/dist/core/backend/ollama.d.ts +25 -0
- package/dist/core/backend/ollama.d.ts.map +1 -0
- package/dist/core/backend/ollama.js +86 -0
- package/dist/core/backend/ollama.js.map +1 -0
- package/dist/core/backend/openai.d.ts +27 -0
- package/dist/core/backend/openai.d.ts.map +1 -0
- package/dist/core/backend/openai.js +84 -0
- package/dist/core/backend/openai.js.map +1 -0
- package/dist/core/backend/types.d.ts +73 -0
- package/dist/core/backend/types.d.ts.map +1 -0
- package/dist/core/backend/types.js +137 -0
- package/dist/core/backend/types.js.map +1 -0
- package/dist/core/chat_store.d.ts +77 -0
- package/dist/core/chat_store.d.ts.map +1 -0
- package/dist/core/chat_store.js +332 -0
- package/dist/core/chat_store.js.map +1 -0
- package/dist/core/cli.d.ts +82 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +602 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +127 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +295 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/debug.d.ts +8 -0
- package/dist/core/debug.d.ts.map +1 -0
- package/dist/core/debug.js +8 -0
- package/dist/core/debug.js.map +1 -0
- package/dist/core/downloader.d.ts +31 -0
- package/dist/core/downloader.d.ts.map +1 -0
- package/dist/core/downloader.js +180 -0
- package/dist/core/downloader.js.map +1 -0
- package/dist/core/errors.d.ts +80 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +134 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/extras.d.ts +160 -0
- package/dist/core/extras.d.ts.map +1 -0
- package/dist/core/extras.js +553 -0
- package/dist/core/extras.js.map +1 -0
- package/dist/core/health.d.ts +27 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +96 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/history.d.ts +50 -0
- package/dist/core/history.d.ts.map +1 -0
- package/dist/core/history.js +276 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/intelligence/ast_index.d.ts +255 -0
- package/dist/core/intelligence/ast_index.d.ts.map +1 -0
- package/dist/core/intelligence/ast_index.js +1369 -0
- package/dist/core/intelligence/ast_index.js.map +1 -0
- package/dist/core/intelligence/confidence.d.ts +113 -0
- package/dist/core/intelligence/confidence.d.ts.map +1 -0
- package/dist/core/intelligence/confidence.js +298 -0
- package/dist/core/intelligence/confidence.js.map +1 -0
- package/dist/core/intelligence/context_compressor.d.ts +80 -0
- package/dist/core/intelligence/context_compressor.d.ts.map +1 -0
- package/dist/core/intelligence/context_compressor.js +245 -0
- package/dist/core/intelligence/context_compressor.js.map +1 -0
- package/dist/core/intelligence/daemon.d.ts +247 -0
- package/dist/core/intelligence/daemon.d.ts.map +1 -0
- package/dist/core/intelligence/daemon.js +842 -0
- package/dist/core/intelligence/daemon.js.map +1 -0
- package/dist/core/intelligence/index.d.ts +60 -0
- package/dist/core/intelligence/index.d.ts.map +1 -0
- package/dist/core/intelligence/index.js +101 -0
- package/dist/core/intelligence/index.js.map +1 -0
- package/dist/core/intelligence/predictor.d.ts +246 -0
- package/dist/core/intelligence/predictor.d.ts.map +1 -0
- package/dist/core/intelligence/predictor.js +590 -0
- package/dist/core/intelligence/predictor.js.map +1 -0
- package/dist/core/intelligence/reflex.d.ts +84 -0
- package/dist/core/intelligence/reflex.d.ts.map +1 -0
- package/dist/core/intelligence/reflex.js +344 -0
- package/dist/core/intelligence/reflex.js.map +1 -0
- package/dist/core/intelligence/self_correction.d.ts +121 -0
- package/dist/core/intelligence/self_correction.d.ts.map +1 -0
- package/dist/core/intelligence/self_correction.js +327 -0
- package/dist/core/intelligence/self_correction.js.map +1 -0
- package/dist/core/intelligence/skill_distiller.d.ts +100 -0
- package/dist/core/intelligence/skill_distiller.d.ts.map +1 -0
- package/dist/core/intelligence/skill_distiller.js +246 -0
- package/dist/core/intelligence/skill_distiller.js.map +1 -0
- package/dist/core/intelligence/swarm.d.ts +330 -0
- package/dist/core/intelligence/swarm.d.ts.map +1 -0
- package/dist/core/intelligence/swarm.js +1064 -0
- package/dist/core/intelligence/swarm.js.map +1 -0
- package/dist/core/intelligence/trajectory.d.ts +107 -0
- package/dist/core/intelligence/trajectory.d.ts.map +1 -0
- package/dist/core/intelligence/trajectory.js +330 -0
- package/dist/core/intelligence/trajectory.js.map +1 -0
- package/dist/core/logger.d.ts +111 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +640 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/loop.d.ts +123 -0
- package/dist/core/loop.d.ts.map +1 -0
- package/dist/core/loop.js +423 -0
- package/dist/core/loop.js.map +1 -0
- package/dist/core/memory.d.ts +81 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +328 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/metrics.d.ts +29 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/metrics.js +109 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/models.d.ts +51 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +146 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/optimizer.d.ts +34 -0
- package/dist/core/optimizer.d.ts.map +1 -0
- package/dist/core/optimizer.js +131 -0
- package/dist/core/optimizer.js.map +1 -0
- package/dist/core/persona.d.ts +35 -0
- package/dist/core/persona.d.ts.map +1 -0
- package/dist/core/persona.js +126 -0
- package/dist/core/persona.js.map +1 -0
- package/dist/core/rate_limit.d.ts +23 -0
- package/dist/core/rate_limit.d.ts.map +1 -0
- package/dist/core/rate_limit.js +62 -0
- package/dist/core/rate_limit.js.map +1 -0
- package/dist/core/runner.d.ts +63 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +671 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/core/stream_parser.d.ts +43 -0
- package/dist/core/stream_parser.d.ts.map +1 -0
- package/dist/core/stream_parser.js +140 -0
- package/dist/core/stream_parser.js.map +1 -0
- package/dist/core/tool_schemas.d.ts +26 -0
- package/dist/core/tool_schemas.d.ts.map +1 -0
- package/dist/core/tool_schemas.js +124 -0
- package/dist/core/tool_schemas.js.map +1 -0
- package/dist/core/which.d.ts +2 -0
- package/dist/core/which.d.ts.map +1 -0
- package/dist/core/which.js +35 -0
- package/dist/core/which.js.map +1 -0
- package/dist/goals/index.d.ts +9 -0
- package/dist/goals/index.d.ts.map +1 -0
- package/dist/goals/index.js +17 -0
- package/dist/goals/index.js.map +1 -0
- package/dist/goals/service.d.ts +115 -0
- package/dist/goals/service.d.ts.map +1 -0
- package/dist/goals/service.js +415 -0
- package/dist/goals/service.js.map +1 -0
- package/dist/goals/types.d.ts +47 -0
- package/dist/goals/types.d.ts.map +1 -0
- package/dist/goals/types.js +66 -0
- package/dist/goals/types.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/autonomous_startup.d.ts +51 -0
- package/dist/integrations/autonomous_startup.d.ts.map +1 -0
- package/dist/integrations/autonomous_startup.js +419 -0
- package/dist/integrations/autonomous_startup.js.map +1 -0
- package/dist/integrations/goose.d.ts +105 -0
- package/dist/integrations/goose.d.ts.map +1 -0
- package/dist/integrations/goose.js +408 -0
- package/dist/integrations/goose.js.map +1 -0
- package/dist/integrations/index.d.ts +21 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +17 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/mcp.d.ts +73 -0
- package/dist/integrations/mcp.d.ts.map +1 -0
- package/dist/integrations/mcp.js +307 -0
- package/dist/integrations/mcp.js.map +1 -0
- package/dist/integrations/mempalace.d.ts +18 -0
- package/dist/integrations/mempalace.d.ts.map +1 -0
- package/dist/integrations/mempalace.js +25 -0
- package/dist/integrations/mempalace.js.map +1 -0
- package/dist/integrations/multi_agent.d.ts +82 -0
- package/dist/integrations/multi_agent.d.ts.map +1 -0
- package/dist/integrations/multi_agent.js +280 -0
- package/dist/integrations/multi_agent.js.map +1 -0
- package/dist/integrations/unified_memory.d.ts +415 -0
- package/dist/integrations/unified_memory.d.ts.map +1 -0
- package/dist/integrations/unified_memory.js +1489 -0
- package/dist/integrations/unified_memory.js.map +1 -0
- package/dist/roles/beru.yaml +48 -0
- package/dist/sidecar/client.d.ts +63 -0
- package/dist/sidecar/client.d.ts.map +1 -0
- package/dist/sidecar/client.js +222 -0
- package/dist/sidecar/client.js.map +1 -0
- package/dist/sidecar/index.d.ts +7 -0
- package/dist/sidecar/index.d.ts.map +1 -0
- package/dist/sidecar/index.js +6 -0
- package/dist/sidecar/index.js.map +1 -0
- package/dist/startup.d.ts +22 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +194 -0
- package/dist/startup.js.map +1 -0
- package/dist/tools/_internal.d.ts +90 -0
- package/dist/tools/_internal.d.ts.map +1 -0
- package/dist/tools/_internal.js +375 -0
- package/dist/tools/_internal.js.map +1 -0
- package/dist/tools/_smoke.d.ts +2 -0
- package/dist/tools/_smoke.d.ts.map +1 -0
- package/dist/tools/_smoke.js +203 -0
- package/dist/tools/_smoke.js.map +1 -0
- package/dist/tools/axodex_tools.d.ts +51 -0
- package/dist/tools/axodex_tools.d.ts.map +1 -0
- package/dist/tools/axodex_tools.js +181 -0
- package/dist/tools/axodex_tools.js.map +1 -0
- package/dist/tools/code_tools.d.ts +33 -0
- package/dist/tools/code_tools.d.ts.map +1 -0
- package/dist/tools/code_tools.js +191 -0
- package/dist/tools/code_tools.js.map +1 -0
- package/dist/tools/computer_tools.d.ts +59 -0
- package/dist/tools/computer_tools.d.ts.map +1 -0
- package/dist/tools/computer_tools.js +348 -0
- package/dist/tools/computer_tools.js.map +1 -0
- package/dist/tools/file_tools.d.ts +51 -0
- package/dist/tools/file_tools.d.ts.map +1 -0
- package/dist/tools/file_tools.js +424 -0
- package/dist/tools/file_tools.js.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/shell_tools.d.ts +39 -0
- package/dist/tools/shell_tools.d.ts.map +1 -0
- package/dist/tools/shell_tools.js +163 -0
- package/dist/tools/shell_tools.js.map +1 -0
- package/dist/tools/web_tools.d.ts +31 -0
- package/dist/tools/web_tools.d.ts.map +1 -0
- package/dist/tools/web_tools.js +117 -0
- package/dist/tools/web_tools.js.map +1 -0
- package/dist/voice/index.d.ts +41 -0
- package/dist/voice/index.d.ts.map +1 -0
- package/dist/voice/index.js +58 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/light_daemon.d.ts +197 -0
- package/dist/voice/light_daemon.d.ts.map +1 -0
- package/dist/voice/light_daemon.js +746 -0
- package/dist/voice/light_daemon.js.map +1 -0
- package/dist/voice/setup.d.ts +63 -0
- package/dist/voice/setup.d.ts.map +1 -0
- package/dist/voice/setup.js +443 -0
- package/dist/voice/setup.js.map +1 -0
- package/dist/voice/stt.d.ts +148 -0
- package/dist/voice/stt.d.ts.map +1 -0
- package/dist/voice/stt.js +361 -0
- package/dist/voice/stt.js.map +1 -0
- package/dist/voice/tts.d.ts +168 -0
- package/dist/voice/tts.d.ts.map +1 -0
- package/dist/voice/tts.js +698 -0
- package/dist/voice/tts.js.map +1 -0
- package/dist/voice/voice_loop.d.ts +101 -0
- package/dist/voice/voice_loop.d.ts.map +1 -0
- package/dist/voice/voice_loop.js +463 -0
- package/dist/voice/voice_loop.js.map +1 -0
- package/dist/voice/wake_word.d.ts +153 -0
- package/dist/voice/wake_word.d.ts.map +1 -0
- package/dist/voice/wake_word.js +458 -0
- package/dist/voice/wake_word.js.map +1 -0
- package/dist/voice/wav.d.ts +99 -0
- package/dist/voice/wav.d.ts.map +1 -0
- package/dist/voice/wav.js +306 -0
- package/dist/voice/wav.js.map +1 -0
- package/dist/web/broker.d.ts +33 -0
- package/dist/web/broker.d.ts.map +1 -0
- package/dist/web/broker.js +58 -0
- package/dist/web/broker.js.map +1 -0
- package/dist/web/open_browser.d.ts +2 -0
- package/dist/web/open_browser.d.ts.map +1 -0
- package/dist/web/open_browser.js +42 -0
- package/dist/web/open_browser.js.map +1 -0
- package/dist/web/server.d.ts +54 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +831 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/static/app.js +4121 -0
- package/dist/web/static/index.html +2281 -0
- package/dist/web/static/js/MODULE_SUMMARY.md +124 -0
- package/dist/web/static/js/a11y.js +165 -0
- package/dist/web/static/js/admin.js +2145 -0
- package/dist/web/static/js/assistant.js +475 -0
- package/dist/web/static/js/calendar/reminders.js +114 -0
- package/dist/web/static/js/calendar/utils.js +166 -0
- package/dist/web/static/js/calendar.js +3348 -0
- package/dist/web/static/js/censor.js +356 -0
- package/dist/web/static/js/chat.js +4546 -0
- package/dist/web/static/js/chatRenderer.js +2294 -0
- package/dist/web/static/js/chatStream.js +276 -0
- package/dist/web/static/js/codeRunner.js +398 -0
- package/dist/web/static/js/color/hex.js +14 -0
- package/dist/web/static/js/colorPicker.js +453 -0
- package/dist/web/static/js/compare/icons.js +77 -0
- package/dist/web/static/js/compare/index.js +1482 -0
- package/dist/web/static/js/compare/models.js +104 -0
- package/dist/web/static/js/compare/panes.js +817 -0
- package/dist/web/static/js/compare/probe.js +78 -0
- package/dist/web/static/js/compare/scoreboard.js +223 -0
- package/dist/web/static/js/compare/selector.js +1335 -0
- package/dist/web/static/js/compare/state.js +58 -0
- package/dist/web/static/js/compare/stream.js +695 -0
- package/dist/web/static/js/compare/vote.js +254 -0
- package/dist/web/static/js/cookbook-diagnosis.js +694 -0
- package/dist/web/static/js/cookbook-hwfit.js +1888 -0
- package/dist/web/static/js/cookbook.js +2093 -0
- package/dist/web/static/js/cookbookDownload.js +633 -0
- package/dist/web/static/js/cookbookProgressSignal.js +29 -0
- package/dist/web/static/js/cookbookRunning.js +3506 -0
- package/dist/web/static/js/cookbookServe.js +2128 -0
- package/dist/web/static/js/document.js +9731 -0
- package/dist/web/static/js/documentLibrary.js +3376 -0
- package/dist/web/static/js/dragSort.js +265 -0
- package/dist/web/static/js/editor/ai-inpaint.js +374 -0
- package/dist/web/static/js/editor/ai-models.js +273 -0
- package/dist/web/static/js/editor/ai-rembg.js +230 -0
- package/dist/web/static/js/editor/ai-tool-runner.js +147 -0
- package/dist/web/static/js/editor/ai-tools-misc.js +216 -0
- package/dist/web/static/js/editor/build/controls.js +366 -0
- package/dist/web/static/js/editor/build/popups.js +112 -0
- package/dist/web/static/js/editor/build/right-panel.js +200 -0
- package/dist/web/static/js/editor/build/toolbar.js +73 -0
- package/dist/web/static/js/editor/build/topbar.js +131 -0
- package/dist/web/static/js/editor/build/transform-popup.js +109 -0
- package/dist/web/static/js/editor/canvas-coords.js +21 -0
- package/dist/web/static/js/editor/canvas-events.js +197 -0
- package/dist/web/static/js/editor/canvas-transforms.js +132 -0
- package/dist/web/static/js/editor/checkerboard.js +24 -0
- package/dist/web/static/js/editor/clipboard-and-drop.js +133 -0
- package/dist/web/static/js/editor/composite-helpers.js +83 -0
- package/dist/web/static/js/editor/filters/blur.js +118 -0
- package/dist/web/static/js/editor/filters/edge-feather.js +70 -0
- package/dist/web/static/js/editor/fx/adj-popup.js +677 -0
- package/dist/web/static/js/editor/fx/filter-string.js +38 -0
- package/dist/web/static/js/editor/fx/histogram.js +67 -0
- package/dist/web/static/js/editor/fx/pixel-pass.js +249 -0
- package/dist/web/static/js/editor/harmonize-masks.js +116 -0
- package/dist/web/static/js/editor/history-panel.js +176 -0
- package/dist/web/static/js/editor/keyboard-shortcuts.js +271 -0
- package/dist/web/static/js/editor/layer-helpers.js +131 -0
- package/dist/web/static/js/editor/layer-panel.js +600 -0
- package/dist/web/static/js/editor/mask-utils.js +91 -0
- package/dist/web/static/js/editor/shortcuts-popover.js +149 -0
- package/dist/web/static/js/editor/slider-ux.js +191 -0
- package/dist/web/static/js/editor/snap.js +107 -0
- package/dist/web/static/js/editor/state.js +257 -0
- package/dist/web/static/js/editor/stroke-pipeline.js +162 -0
- package/dist/web/static/js/editor/stroke-tool-sliders.js +64 -0
- package/dist/web/static/js/editor/tools/clone.js +81 -0
- package/dist/web/static/js/editor/tools/crop.js +137 -0
- package/dist/web/static/js/editor/tools/flood-fill.js +72 -0
- package/dist/web/static/js/editor/tools/lasso-mask.js +171 -0
- package/dist/web/static/js/editor/tools/lasso.js +65 -0
- package/dist/web/static/js/editor/tools/move.js +79 -0
- package/dist/web/static/js/editor/tools/stroke.js +123 -0
- package/dist/web/static/js/editor/tools/transform-drag.js +174 -0
- package/dist/web/static/js/editor/tools/transform-handles.js +271 -0
- package/dist/web/static/js/editor/tools/transform-session.js +381 -0
- package/dist/web/static/js/editor/tools/wand.js +46 -0
- package/dist/web/static/js/editor/wire-import.js +148 -0
- package/dist/web/static/js/editor/wire-inpaint-controls.js +164 -0
- package/dist/web/static/js/editor/wire-merge-buttons.js +103 -0
- package/dist/web/static/js/editor/wire-selection-controls.js +170 -0
- package/dist/web/static/js/editor/wire-topbar-menus.js +174 -0
- package/dist/web/static/js/editor/wire-topbar-overflow.js +49 -0
- package/dist/web/static/js/editor/wire-topbar.js +188 -0
- package/dist/web/static/js/emailInbox.js +1245 -0
- package/dist/web/static/js/emailLibrary/replyRecipients.js +27 -0
- package/dist/web/static/js/emailLibrary/signatureFold.js +339 -0
- package/dist/web/static/js/emailLibrary/state.js +34 -0
- package/dist/web/static/js/emailLibrary/utils.js +202 -0
- package/dist/web/static/js/emailLibrary.js +5217 -0
- package/dist/web/static/js/emojiPicker.js +311 -0
- package/dist/web/static/js/escMenuStack.js +102 -0
- package/dist/web/static/js/fileHandler.js +295 -0
- package/dist/web/static/js/gallery.js +2835 -0
- package/dist/web/static/js/galleryEditor.js +3798 -0
- package/dist/web/static/js/group.js +955 -0
- package/dist/web/static/js/init.js +405 -0
- package/dist/web/static/js/keyboard-shortcuts.js +292 -0
- package/dist/web/static/js/langIcons.js +187 -0
- package/dist/web/static/js/markdown/tableRow.js +19 -0
- package/dist/web/static/js/markdown.js +806 -0
- package/dist/web/static/js/memory.js +1418 -0
- package/dist/web/static/js/modalManager.js +1552 -0
- package/dist/web/static/js/modalSnap.js +782 -0
- package/dist/web/static/js/model/matchKey.js +19 -0
- package/dist/web/static/js/modelPicker.js +695 -0
- package/dist/web/static/js/modelSort.js +33 -0
- package/dist/web/static/js/models.js +642 -0
- package/dist/web/static/js/notes.js +5054 -0
- package/dist/web/static/js/package.json +1 -0
- package/dist/web/static/js/platform.js +47 -0
- package/dist/web/static/js/presets.js +1110 -0
- package/dist/web/static/js/providers.js +93 -0
- package/dist/web/static/js/rag.js +177 -0
- package/dist/web/static/js/research/jobs.js +335 -0
- package/dist/web/static/js/research/panel.js +1233 -0
- package/dist/web/static/js/researchSynapse.js +225 -0
- package/dist/web/static/js/search-chat.js +201 -0
- package/dist/web/static/js/search.js +52 -0
- package/dist/web/static/js/section-management.js +260 -0
- package/dist/web/static/js/sessions.js +3108 -0
- package/dist/web/static/js/settings.js +4991 -0
- package/dist/web/static/js/sidebar-layout.js +573 -0
- package/dist/web/static/js/signature.js +504 -0
- package/dist/web/static/js/skills.js +1908 -0
- package/dist/web/static/js/slashAutocomplete.js +267 -0
- package/dist/web/static/js/slashCommands.js +6099 -0
- package/dist/web/static/js/spinner.js +406 -0
- package/dist/web/static/js/storage.js +123 -0
- package/dist/web/static/js/tasks.js +2699 -0
- package/dist/web/static/js/theme.js +2086 -0
- package/dist/web/static/js/tileManager.js +386 -0
- package/dist/web/static/js/tourAutoplay.js +133 -0
- package/dist/web/static/js/tourHints.js +179 -0
- package/dist/web/static/js/tts-ai.js +521 -0
- package/dist/web/static/js/ui.js +1288 -0
- package/dist/web/static/js/util/ordinal.js +13 -0
- package/dist/web/static/js/voiceRecorder.js +283 -0
- package/dist/web/static/js/windowDrag.js +326 -0
- package/dist/web/static/js/windowResize.js +233 -0
- package/dist/web/static/landing.html +824 -0
- package/dist/web/static/lib/docx.umd.min.js +20116 -0
- package/dist/web/static/lib/highlight.min.js +1213 -0
- package/dist/web/static/lib/html2pdf.bundle.min.js +3 -0
- package/dist/web/static/lib/mammoth.browser.min.js +21 -0
- package/dist/web/static/lib/qrcode.min.js +8 -0
- package/dist/web/static/lib/xlsx.full.min.js +24 -0
- package/dist/web/static/login.html +582 -0
- package/dist/web/static/manifest.json +15 -0
- package/dist/web/static/style.css +35733 -0
- package/dist/web/static/sw.js +144 -0
- package/dist/workflows/engine.d.ts +162 -0
- package/dist/workflows/engine.d.ts.map +1 -0
- package/dist/workflows/engine.js +625 -0
- package/dist/workflows/engine.js.map +1 -0
- package/dist/workflows/index.d.ts +8 -0
- package/dist/workflows/index.d.ts.map +1 -0
- package/dist/workflows/index.js +14 -0
- package/dist/workflows/index.js.map +1 -0
- package/package.json +112 -0
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/voice/tts.ts
|
|
3
|
+
* =================
|
|
4
|
+
* BERU Text-to-Speech — offline-first, best quality available.
|
|
5
|
+
*
|
|
6
|
+
* Python provider priority (preserved by `_detectBackend()`):
|
|
7
|
+
* 1. kokoro-onnx — 82M params, Apache 2.0
|
|
8
|
+
* 2. mms — local VITS (transformers + torch)
|
|
9
|
+
* 2b. piper — fastest CPU TTS (`piper` module or `piper` binary)
|
|
10
|
+
* 3. edge-tts — free Microsoft cloud TTS (needs internet)
|
|
11
|
+
* 4. pyttsx3 — offline COM/espeak fallback
|
|
12
|
+
* 5. print — last resort
|
|
13
|
+
*
|
|
14
|
+
* ── Node reality ─────────────────────────────────────────────────────────────
|
|
15
|
+
* `kokoro-onnx`, `piper`, `pyttsx3`, `sounddevice`, `soundfile` and `transformers`
|
|
16
|
+
* are Python-only and not installable here. `edge-tts`'s Node equivalent
|
|
17
|
+
* **`msedge-tts` IS installed** (MIT, Microsoft Edge Read Aloud API) and is the
|
|
18
|
+
* primary working path. The offline `pyttsx3` slot is preserved but implemented
|
|
19
|
+
* as a clearly-marked unimplemented backend that returns a descriptive error.
|
|
20
|
+
*
|
|
21
|
+
* WAV output is written by hand (44-byte RIFF/PCM header, `node:fs`) — see
|
|
22
|
+
* `src/voice/wav.ts`. No `soundfile` package is used anywhere.
|
|
23
|
+
*
|
|
24
|
+
* Model files (kokoro, searched cwd → ~/.axoniz/voice_models → ~/Downloads):
|
|
25
|
+
* kokoro-v1.0.int8.onnx (88MB — recommended, CPU-optimized)
|
|
26
|
+
* kokoro-v1.0.onnx (310MB — full quality)
|
|
27
|
+
* voices-v1.0.bin (voice embeddings, always required)
|
|
28
|
+
*/
|
|
29
|
+
import fs from "node:fs";
|
|
30
|
+
import os from "node:os";
|
|
31
|
+
import path from "node:path";
|
|
32
|
+
import { fileURLToPath } from "node:url";
|
|
33
|
+
import { getLogger } from "../core/logger.js";
|
|
34
|
+
import { whichSync } from "../core/which.js";
|
|
35
|
+
import { loadConfig, AXONIZ_HOME } from "../core/config.js";
|
|
36
|
+
import { AUDIO_OUTPUT_MISSING_ERROR, getAudioOutputDriver, writeWav, } from "./wav.js";
|
|
37
|
+
const logger = getLogger();
|
|
38
|
+
/* ── Voice config ──────────────────────────────────────────────────────────── */
|
|
39
|
+
export const KOKORO_VOICE = process.env.BERU_KOKORO_VOICE ?? "am_liam"; // male, deep
|
|
40
|
+
export const KOKORO_SPEED = Number.parseFloat(process.env.BERU_KOKORO_SPEED ?? "0.95");
|
|
41
|
+
export const PIPER_VOICE = process.env.BERU_PIPER_VOICE ?? "en_US-lessac-medium";
|
|
42
|
+
export const EDGE_VOICE = process.env.BERU_EDGE_VOICE ?? "en-US-GuyNeural";
|
|
43
|
+
export const EDGE_RATE = process.env.BERU_EDGE_RATE ?? "-10%";
|
|
44
|
+
/** Kokoro native sample rate. */
|
|
45
|
+
export const SAMPLE_RATE = 24_000;
|
|
46
|
+
/** `os.path.dirname(os.path.dirname(abspath(__file__)))` → the `src/` directory. */
|
|
47
|
+
export const PROJECT_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
48
|
+
export const MMS_MODEL_PATH = path.join(PROJECT_ROOT, "mms-tts-oss");
|
|
49
|
+
/** ✅ FIX #1 (ported): MODULE-LEVEL GLOBALS FOR SINGLETON PATTERN. */
|
|
50
|
+
let _GLOBAL_KOKORO = null; // ← Kokoro model singleton
|
|
51
|
+
let _tts = null; // ← TTS engine singleton
|
|
52
|
+
/* ── Model file search ─────────────────────────────────────────────────────── */
|
|
53
|
+
export const VOICE_MODELS = path.join(AXONIZ_HOME, "voice_models");
|
|
54
|
+
const _ONNX_NAMES = [
|
|
55
|
+
"kokoro-v1.0.int8.onnx", // int8, 88MB — preferred
|
|
56
|
+
"kokoro-v1.0.onnx", // f32, 310MB
|
|
57
|
+
"kokoro-v1.0.fp16.onnx", // fp16, 169MB
|
|
58
|
+
];
|
|
59
|
+
const _VOICES_NAME = "voices-v1.0.bin";
|
|
60
|
+
const _SEARCH_DIRS = [
|
|
61
|
+
PROJECT_ROOT,
|
|
62
|
+
process.cwd(),
|
|
63
|
+
VOICE_MODELS,
|
|
64
|
+
path.join(os.homedir(), "Downloads"),
|
|
65
|
+
os.homedir(),
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* Search common locations for Kokoro model files.
|
|
69
|
+
* Returns `[onnxPath, voicesPath]`, each `null` when not found.
|
|
70
|
+
*/
|
|
71
|
+
export function _find_kokoro_models() {
|
|
72
|
+
let onnxPath = null;
|
|
73
|
+
let voicesPath = null;
|
|
74
|
+
const bigger = (p, min) => {
|
|
75
|
+
try {
|
|
76
|
+
return fs.existsSync(p) && fs.statSync(p).size > min;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
for (const d of _SEARCH_DIRS) {
|
|
83
|
+
if (onnxPath === null) {
|
|
84
|
+
for (const name of _ONNX_NAMES) {
|
|
85
|
+
const p = path.join(d, name);
|
|
86
|
+
if (bigger(p, 1024 * 1024)) {
|
|
87
|
+
onnxPath = p;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (voicesPath === null) {
|
|
93
|
+
const p = path.join(d, _VOICES_NAME);
|
|
94
|
+
if (bigger(p, 1024))
|
|
95
|
+
voicesPath = p;
|
|
96
|
+
}
|
|
97
|
+
if (onnxPath && voicesPath)
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
return [onnxPath, voicesPath];
|
|
101
|
+
}
|
|
102
|
+
/* ── Pluggable synthesis backends ──────────────────────────────────────────── */
|
|
103
|
+
/** Actionable error text for the unimplemented offline (pyttsx3) slot. */
|
|
104
|
+
export const OFFLINE_TTS_ERROR = "[ERROR] offline TTS unavailable — pyttsx3 is Python-only and has no Node.js " +
|
|
105
|
+
"equivalent installed. Install kokoro-onnx model files (run: tsx src/voice/setup.ts) " +
|
|
106
|
+
"or register a backend with registerTTSBackend('os-tts', …) that drives SAPI5 " +
|
|
107
|
+
"(PowerShell System.Speech) / espeak / say.";
|
|
108
|
+
export const TTS_UNAVAILABLE_ERROR = "[ERROR] text-to-speech unavailable — no TTS backend is available. " +
|
|
109
|
+
"Set BERU voice models via src/voice/setup.ts (kokoro) or ensure network access " +
|
|
110
|
+
"for msedge-tts, or register a backend with registerTTSBackend().";
|
|
111
|
+
const _backends = new Map();
|
|
112
|
+
/** Register (or replace) a TTS backend at runtime. */
|
|
113
|
+
export function registerTTSBackend(name, backend) {
|
|
114
|
+
_backends.set(name, backend);
|
|
115
|
+
}
|
|
116
|
+
export function unregisterTTSBackend(name) {
|
|
117
|
+
_backends.delete(name);
|
|
118
|
+
}
|
|
119
|
+
/* ── msedge-tts (PRIMARY, working path) ────────────────────────────────────── */
|
|
120
|
+
/**
|
|
121
|
+
* Import shape of `msedge-tts` v2.0.8 (verified against
|
|
122
|
+
* node_modules/msedge-tts/dist/index.d.ts):
|
|
123
|
+
*
|
|
124
|
+
* import { MsEdgeTTS, OUTPUT_FORMAT } from "msedge-tts";
|
|
125
|
+
*
|
|
126
|
+
* The package exposes named class exports only (no default export) and is
|
|
127
|
+
* CommonJS under `main` with `esModuleInterop` bridging it into ESM. Its output
|
|
128
|
+
* is MP3 (`audio-24khz-48kbitrate-mono-mp3`) or WebM/Opus — never WAV — so the
|
|
129
|
+
* edge path writes `.mp3`; use kokoro/piper when a real RIFF WAV is required.
|
|
130
|
+
*/
|
|
131
|
+
async function importMsEdgeTTS() {
|
|
132
|
+
return (await import("msedge-tts"));
|
|
133
|
+
}
|
|
134
|
+
/** "+0%" / "-0%" mean "leave it alone" — SSML rejects a zero relative change. */
|
|
135
|
+
function prosodyValue(raw, fallback = "default") {
|
|
136
|
+
if (!raw)
|
|
137
|
+
return fallback;
|
|
138
|
+
if (/^[+-]?0+(\.0+)?\s*%?$/.test(raw.trim()))
|
|
139
|
+
return fallback;
|
|
140
|
+
return raw;
|
|
141
|
+
}
|
|
142
|
+
const edgeBackend = {
|
|
143
|
+
name: "msedge-tts",
|
|
144
|
+
available() {
|
|
145
|
+
return true; // module is installed; network is required at call time
|
|
146
|
+
},
|
|
147
|
+
async synthesize(text, filePath, engine) {
|
|
148
|
+
const outDir = path.dirname(path.resolve(filePath));
|
|
149
|
+
try {
|
|
150
|
+
const { MsEdgeTTS, OUTPUT_FORMAT } = await importMsEdgeTTS();
|
|
151
|
+
const tts = new MsEdgeTTS();
|
|
152
|
+
const voice = engine.voice || EDGE_VOICE;
|
|
153
|
+
await tts.setMetadata(voice, OUTPUT_FORMAT["AUDIO_24KHZ_48KBITRATE_MONO_MP3"]);
|
|
154
|
+
const { audioFilePath } = await tts.toFile(outDir, text, {
|
|
155
|
+
rate: prosodyValue(engine.rate, EDGE_RATE),
|
|
156
|
+
volume: prosodyValue(engine.volume, "+0%"),
|
|
157
|
+
});
|
|
158
|
+
tts.close();
|
|
159
|
+
// `toFile` names the file after the voice; move it onto the requested path.
|
|
160
|
+
const target = path.resolve(filePath);
|
|
161
|
+
if (path.resolve(audioFilePath) !== target) {
|
|
162
|
+
fs.copyFileSync(audioFilePath, target);
|
|
163
|
+
try {
|
|
164
|
+
fs.unlinkSync(audioFilePath);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* best effort */
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const size = fileSize(target);
|
|
171
|
+
if (size <= 0) {
|
|
172
|
+
engine.storeLastError("[ERROR] msedge-tts produced an empty file");
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
catch (e) {
|
|
178
|
+
// Offline machines land here — this is the expected online-only failure.
|
|
179
|
+
engine.storeLastError(`[ERROR] msedge-tts synthesis failed (online Microsoft Edge Read Aloud API ` +
|
|
180
|
+
`unreachable?): ${errText(e)}`);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
/* ── Offline slot (pyttsx3 equivalent) — clearly unimplemented ─────────────── */
|
|
186
|
+
/**
|
|
187
|
+
* TODO(port): replaces `pyttsx3` (SAPI5/espeak). There is no Node package for
|
|
188
|
+
* offline OS speech synthesis installed on this machine. Recommended
|
|
189
|
+
* replacement: shell out to PowerShell `System.Speech.Synthesis.SpeechSynthesizer`
|
|
190
|
+
* on Windows, `say` on macOS, `espeak-ng` on Linux — or register a backend with
|
|
191
|
+
* `registerTTSBackend("os-tts", …)`. Until then `synthesize()` fails with a
|
|
192
|
+
* descriptive error and never throws.
|
|
193
|
+
*/
|
|
194
|
+
const osTtsBackend = {
|
|
195
|
+
name: "os-tts (unimplemented)",
|
|
196
|
+
available() {
|
|
197
|
+
return false;
|
|
198
|
+
},
|
|
199
|
+
async synthesize(_text, _filePath, engine) {
|
|
200
|
+
engine.storeLastError(OFFLINE_TTS_ERROR);
|
|
201
|
+
logger.debug(OFFLINE_TTS_ERROR);
|
|
202
|
+
return false;
|
|
203
|
+
},
|
|
204
|
+
async speak(_text, engine) {
|
|
205
|
+
engine.storeLastError(OFFLINE_TTS_ERROR);
|
|
206
|
+
return false;
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
export class TTSEngine {
|
|
210
|
+
/** BERU's voice output engine — offline-first, highest quality available. */
|
|
211
|
+
rate;
|
|
212
|
+
volume;
|
|
213
|
+
speed;
|
|
214
|
+
provider;
|
|
215
|
+
voice;
|
|
216
|
+
_backend;
|
|
217
|
+
_model = null;
|
|
218
|
+
_onnxPath = null;
|
|
219
|
+
_voicesPath = null;
|
|
220
|
+
_lastError = "";
|
|
221
|
+
constructor(voice = null, rate = EDGE_RATE, volume = "+0%", provider = "auto", speed = KOKORO_SPEED) {
|
|
222
|
+
this.rate = rate;
|
|
223
|
+
this.volume = volume;
|
|
224
|
+
this.speed = speed;
|
|
225
|
+
this.provider = provider;
|
|
226
|
+
this._backend = this._detect_backend();
|
|
227
|
+
this._model = null;
|
|
228
|
+
this._onnxPath = null;
|
|
229
|
+
this._voicesPath = null;
|
|
230
|
+
this.voice = voice || this._default_voice();
|
|
231
|
+
}
|
|
232
|
+
/* ── Backend detection ──────────────────────────────────────────────────── */
|
|
233
|
+
_detect_backend() {
|
|
234
|
+
if (this.provider !== "auto")
|
|
235
|
+
return this.provider;
|
|
236
|
+
// 1. Kokoro (best quality offline) — Python probed `kokoro_onnx` + sounddevice.
|
|
237
|
+
if (_backends.has("kokoro"))
|
|
238
|
+
return "kokoro";
|
|
239
|
+
const [onnx, voices] = _find_kokoro_models();
|
|
240
|
+
if (onnx && voices)
|
|
241
|
+
return "kokoro";
|
|
242
|
+
// 2. MMS-TTS (robust local VITS) — only check the path, do not load.
|
|
243
|
+
if (fs.existsSync(path.join(MMS_MODEL_PATH, "config.json")))
|
|
244
|
+
return "mms";
|
|
245
|
+
// 2b. Piper (module or binary)
|
|
246
|
+
if (_backends.has("piper"))
|
|
247
|
+
return "piper";
|
|
248
|
+
if (whichSync("piper") || whichSync("piper-tts"))
|
|
249
|
+
return "piper_bin";
|
|
250
|
+
// 3. edge-tts — the only engine with a working Node implementation here.
|
|
251
|
+
if (_backends.has("edge") || edgeBackend.available())
|
|
252
|
+
return "edge";
|
|
253
|
+
// 4. pyttsx3 — unimplemented offline slot.
|
|
254
|
+
if (_backends.has("os-tts"))
|
|
255
|
+
return "os-tts";
|
|
256
|
+
return "print";
|
|
257
|
+
}
|
|
258
|
+
_default_voice() {
|
|
259
|
+
const byBackend = {
|
|
260
|
+
kokoro: KOKORO_VOICE,
|
|
261
|
+
mms: "",
|
|
262
|
+
piper: PIPER_VOICE,
|
|
263
|
+
piper_bin: PIPER_VOICE,
|
|
264
|
+
edge: EDGE_VOICE,
|
|
265
|
+
"os-tts": "",
|
|
266
|
+
print: "",
|
|
267
|
+
};
|
|
268
|
+
return byBackend[this._backend] ?? "";
|
|
269
|
+
}
|
|
270
|
+
get backend() {
|
|
271
|
+
return this._backend;
|
|
272
|
+
}
|
|
273
|
+
/** Last `[ERROR] …` string produced by a degraded path. */
|
|
274
|
+
get lastError() {
|
|
275
|
+
return this._lastError;
|
|
276
|
+
}
|
|
277
|
+
get is_available() {
|
|
278
|
+
return this._backend !== "print" && this._backend !== "none";
|
|
279
|
+
}
|
|
280
|
+
get isAvailable() {
|
|
281
|
+
return this.is_available;
|
|
282
|
+
}
|
|
283
|
+
/* ── Public API ─────────────────────────────────────────────────────────── */
|
|
284
|
+
/** Speak `text` aloud. Returns true when something handled it. */
|
|
285
|
+
async speak(text) {
|
|
286
|
+
if (!text || !text.trim())
|
|
287
|
+
return false;
|
|
288
|
+
// Define priority order (Python: self._backend == "auto" → the whole chain).
|
|
289
|
+
const backends = this._backend === "auto"
|
|
290
|
+
? ["kokoro", "mms", "piper", "edge", "os-tts"]
|
|
291
|
+
: [this._backend];
|
|
292
|
+
for (const b of backends) {
|
|
293
|
+
try {
|
|
294
|
+
if (await this._speakBackend(b, text))
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
catch (e) {
|
|
298
|
+
logger.debug(`[TTS] Backend ${b} failed: ${errText(e)}, trying next...`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Last resort mirrors Python `print(f"[BERU] {text}")`.
|
|
302
|
+
process.stdout.write(`[BERU] ${text}\n`);
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
/** Fire-and-forget speak (replaces `threading.Thread(target=self.speak, daemon=True)`). */
|
|
306
|
+
speakAsync(text) {
|
|
307
|
+
void this.speak(text).catch((e) => {
|
|
308
|
+
logger.debug(`[TTS] speakAsync error: ${errText(e)}`);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Synthesize `text` to `filePath`.
|
|
313
|
+
*
|
|
314
|
+
* `filePath` should end in `.mp3` for edge (the only live engine) — the edge
|
|
315
|
+
* API cannot emit WAV. When the requested extension is `.wav` and a
|
|
316
|
+
* WAV-capable backend (kokoro/piper/mms) is unavailable, a clear
|
|
317
|
+
* `[ERROR] …` is stored in `lastError` and false is returned.
|
|
318
|
+
*/
|
|
319
|
+
async synthesize_to_file(text, filePath) {
|
|
320
|
+
try {
|
|
321
|
+
if (this._backend === "mms")
|
|
322
|
+
return await this._mms_to_file(text, filePath);
|
|
323
|
+
if (this._backend === "kokoro")
|
|
324
|
+
return await this._kokoro_to_file(text, filePath);
|
|
325
|
+
if (this._backend === "edge" || this._backend === "auto") {
|
|
326
|
+
return await this._edge_to_file(text, filePath);
|
|
327
|
+
}
|
|
328
|
+
if (this._backend === "os-tts" || this._backend === "pyttsx3") {
|
|
329
|
+
await osTtsBackend.synthesize(text, filePath, this);
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
this.storeLastError(`[ERROR] no synthesis backend for '${this._backend}' — file output unavailable.`);
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
catch (e) {
|
|
336
|
+
logger.debug(`[TTS] file synthesis failed: ${errText(e)}`);
|
|
337
|
+
this.storeLastError(`[ERROR] TTS file synthesis failed: ${errText(e)}`);
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
async synthesizeToFile(text, filePath) {
|
|
342
|
+
return this.synthesize_to_file(text, filePath);
|
|
343
|
+
}
|
|
344
|
+
async synthesize_to_bytes(text) {
|
|
345
|
+
const tmp = tempPath(".mp3");
|
|
346
|
+
try {
|
|
347
|
+
if (await this.synthesize_to_file(text, tmp)) {
|
|
348
|
+
return fs.readFileSync(tmp);
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
finally {
|
|
356
|
+
unlinkQuiet(tmp);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async synthesizeToBytes(text) {
|
|
360
|
+
return this.synthesize_to_bytes(text);
|
|
361
|
+
}
|
|
362
|
+
/* ── MMS-TTS ────────────────────────────────────────────────────────────── */
|
|
363
|
+
/**
|
|
364
|
+
* TODO(port): Python loaded a local VITS model via `transformers` + `torch`
|
|
365
|
+
* (`VitsModel.from_pretrained`). `@huggingface/transformers` is NOT installed
|
|
366
|
+
* on this machine and its install repeatedly failed. Recommended replacement:
|
|
367
|
+
* `@huggingface/transformers` (VITS/MMS ONNX) once reachable.
|
|
368
|
+
*/
|
|
369
|
+
async _get_mms_model() {
|
|
370
|
+
if (this._model === null) {
|
|
371
|
+
logger.info(`[TTS] Loading MMS-TTS from: ${MMS_MODEL_PATH}`);
|
|
372
|
+
throw new Error("[ERROR] MMS-TTS unavailable — the Python path used transformers+torch " +
|
|
373
|
+
"(VitsModel); '@huggingface/transformers' is not installed and its " +
|
|
374
|
+
"install failed on this machine. Install it or register a TTS backend.");
|
|
375
|
+
}
|
|
376
|
+
return this._model;
|
|
377
|
+
}
|
|
378
|
+
async _speak_mms(text) {
|
|
379
|
+
const tmp = tempPath(".wav");
|
|
380
|
+
try {
|
|
381
|
+
if (await this._mms_to_file(text, tmp))
|
|
382
|
+
return await _play_file(tmp);
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
finally {
|
|
386
|
+
unlinkQuiet(tmp);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async _mms_to_file(text, filePath) {
|
|
390
|
+
try {
|
|
391
|
+
const registered = _backends.get("mms");
|
|
392
|
+
if (registered) {
|
|
393
|
+
this._model = registered;
|
|
394
|
+
return await registered.synthesize(text, filePath, this);
|
|
395
|
+
}
|
|
396
|
+
await this._get_mms_model();
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
catch (e) {
|
|
400
|
+
logger.debug(`[TTS] MMS file error: ${errText(e)}`);
|
|
401
|
+
this.storeLastError(errText(e));
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
/* ── Kokoro ─────────────────────────────────────────────────────────────── */
|
|
406
|
+
/**
|
|
407
|
+
* TODO(port): Python used `kokoro_onnx.Kokoro`. `kokoro-js` is NOT installed
|
|
408
|
+
* and cannot be installed on this machine's npm connection. The model-file
|
|
409
|
+
* discovery logic is fully ported and `_GLOBAL_KOKORO` stays as the singleton
|
|
410
|
+
* slot; `registerTTSBackend("kokoro", …)` is the runtime hook.
|
|
411
|
+
*/
|
|
412
|
+
async _get_kokoro() {
|
|
413
|
+
if (_GLOBAL_KOKORO === null) {
|
|
414
|
+
const [onnx, voices] = _find_kokoro_models();
|
|
415
|
+
if (!onnx || !voices) {
|
|
416
|
+
throw new Error("[ERROR] Kokoro model files not found. " +
|
|
417
|
+
"Run: npx tsx src/voice/setup.ts (or register a TTS backend)");
|
|
418
|
+
}
|
|
419
|
+
this._onnxPath = onnx;
|
|
420
|
+
this._voicesPath = voices;
|
|
421
|
+
logger.info(`[TTS] Loading Kokoro globally: ${path.basename(onnx)}`);
|
|
422
|
+
const registered = _backends.get("kokoro");
|
|
423
|
+
if (!registered) {
|
|
424
|
+
throw new Error("[ERROR] kokoro engine unavailable — 'kokoro-js' is not installed " +
|
|
425
|
+
"(kokoro-onnx is Python-only). registerTTSBackend('kokoro', …) to supply one.");
|
|
426
|
+
}
|
|
427
|
+
_GLOBAL_KOKORO = registered;
|
|
428
|
+
}
|
|
429
|
+
this._model = _GLOBAL_KOKORO;
|
|
430
|
+
return this._model;
|
|
431
|
+
}
|
|
432
|
+
async _speak_kokoro(text) {
|
|
433
|
+
try {
|
|
434
|
+
const tmp = tempPath(".wav");
|
|
435
|
+
try {
|
|
436
|
+
if (!(await this._kokoro_to_file(text, tmp)))
|
|
437
|
+
return false;
|
|
438
|
+
return await _play_file(tmp);
|
|
439
|
+
}
|
|
440
|
+
finally {
|
|
441
|
+
unlinkQuiet(tmp);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
catch (e) {
|
|
445
|
+
logger.debug(`[TTS] Kokoro speak error: ${errText(e)}`);
|
|
446
|
+
this.storeLastError(errText(e));
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Write Kokoro output to a real RIFF WAV using the hand-rolled header in
|
|
452
|
+
* `src/voice/wav.ts` — the Python `soundfile.write` equivalent.
|
|
453
|
+
*/
|
|
454
|
+
async _kokoro_to_file(text, filePath) {
|
|
455
|
+
try {
|
|
456
|
+
const kokoro = (_backends.get("kokoro") ?? (await this._get_kokoro()));
|
|
457
|
+
if (!kokoro?.create) {
|
|
458
|
+
throw new Error("[ERROR] kokoro backend does not implement create(); cannot synthesize to file.");
|
|
459
|
+
}
|
|
460
|
+
const { samples, rate } = await kokoro.create(text, {
|
|
461
|
+
voice: this.voice,
|
|
462
|
+
speed: this.speed,
|
|
463
|
+
lang: "en-us",
|
|
464
|
+
});
|
|
465
|
+
writeWav(filePath, samples, rate, 1);
|
|
466
|
+
return fs.existsSync(filePath) && fileSize(filePath) > 0;
|
|
467
|
+
}
|
|
468
|
+
catch (e) {
|
|
469
|
+
logger.debug(`[TTS] Kokoro file error: ${errText(e)}`);
|
|
470
|
+
this.storeLastError(errText(e));
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
/* ── Piper ──────────────────────────────────────────────────────────────── */
|
|
475
|
+
/**
|
|
476
|
+
* TODO(port): Python used the `piper` module (or the `piper` binary).
|
|
477
|
+
* No Node binding is installed. The binary path is still honoured: if
|
|
478
|
+
* `piper`/`piper-tts` is on PATH we shell out exactly like `_speak_piper_bin`.
|
|
479
|
+
*/
|
|
480
|
+
async _speak_piper(text) {
|
|
481
|
+
if (whichSync("piper") || whichSync("piper-tts"))
|
|
482
|
+
return this._speak_piper_bin(text);
|
|
483
|
+
this.storeLastError("[ERROR] piper unavailable — no Node 'piper' binding and no piper binary on PATH.");
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
async _speak_piper_bin(text) {
|
|
487
|
+
const tmp = tempPath(".wav");
|
|
488
|
+
try {
|
|
489
|
+
const bin = whichSync("piper") ?? whichSync("piper-tts") ?? "piper";
|
|
490
|
+
const { spawn } = await import("node:child_process");
|
|
491
|
+
const ok = await new Promise((resolve) => {
|
|
492
|
+
const child = spawn(bin, ["--model", this.voice, "--output_file", tmp], {
|
|
493
|
+
windowsHide: true,
|
|
494
|
+
});
|
|
495
|
+
child.on("error", () => resolve(false));
|
|
496
|
+
child.on("close", (code) => resolve(code === 0));
|
|
497
|
+
try {
|
|
498
|
+
child.stdin?.end(text, "utf8");
|
|
499
|
+
}
|
|
500
|
+
catch {
|
|
501
|
+
/* best effort */
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
if (ok)
|
|
505
|
+
return await _play_file(tmp);
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
catch (e) {
|
|
509
|
+
logger.debug(`[TTS] piper bin error: ${errText(e)}`);
|
|
510
|
+
this.storeLastError(`[ERROR] piper binary failed: ${errText(e)}`);
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
finally {
|
|
514
|
+
unlinkQuiet(tmp);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
/* ── edge (msedge-tts) ──────────────────────────────────────────────────── */
|
|
518
|
+
async _speak_edge(text) {
|
|
519
|
+
const tmp = tempPath(".mp3");
|
|
520
|
+
try {
|
|
521
|
+
if (await this._edge_to_file(text, tmp))
|
|
522
|
+
return await _play_file(tmp);
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
catch (e) {
|
|
526
|
+
logger.debug(`[TTS] edge-tts error: ${errText(e)}`);
|
|
527
|
+
this.storeLastError(`[ERROR] msedge-tts error: ${errText(e)}`);
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
finally {
|
|
531
|
+
unlinkQuiet(tmp);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
async _edge_to_file(text, filePath) {
|
|
535
|
+
const backend = _backends.get("edge") ?? edgeBackend;
|
|
536
|
+
const ok = await backend.synthesize(text, filePath, this);
|
|
537
|
+
return ok && fs.existsSync(filePath) && fileSize(filePath) > 0;
|
|
538
|
+
}
|
|
539
|
+
/* ── pyttsx3 slot ───────────────────────────────────────────────────────── */
|
|
540
|
+
async _speak_pyttsx3(text) {
|
|
541
|
+
return osTtsBackend.speak ? osTtsBackend.speak(text, this) : false;
|
|
542
|
+
}
|
|
543
|
+
/* ── Info ───────────────────────────────────────────────────────────────── */
|
|
544
|
+
info() {
|
|
545
|
+
const [onnx] = _find_kokoro_models();
|
|
546
|
+
return {
|
|
547
|
+
backend: this._backend,
|
|
548
|
+
voice: this.voice,
|
|
549
|
+
rate: this.rate,
|
|
550
|
+
available: this.is_available,
|
|
551
|
+
kokoro_onnx: onnx ? path.basename(onnx) : null,
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
set_voice(voice) {
|
|
555
|
+
this.voice = voice;
|
|
556
|
+
this._model = null;
|
|
557
|
+
}
|
|
558
|
+
setVoice(voice) {
|
|
559
|
+
this.set_voice(voice);
|
|
560
|
+
}
|
|
561
|
+
set_speed(speed) {
|
|
562
|
+
this.speed = speed;
|
|
563
|
+
}
|
|
564
|
+
setSpeed(speed) {
|
|
565
|
+
this.set_speed(speed);
|
|
566
|
+
}
|
|
567
|
+
/** Record an `[ERROR] …` string and log it. Never throws. */
|
|
568
|
+
storeLastError(msg) {
|
|
569
|
+
this._lastError = msg;
|
|
570
|
+
logger.warning(msg);
|
|
571
|
+
}
|
|
572
|
+
/* ── dispatch ───────────────────────────────────────────────────────────── */
|
|
573
|
+
async _speakBackend(name, text) {
|
|
574
|
+
switch (name) {
|
|
575
|
+
case "mms":
|
|
576
|
+
return this._speak_mms(text);
|
|
577
|
+
case "kokoro":
|
|
578
|
+
return this._speak_kokoro(text);
|
|
579
|
+
case "piper":
|
|
580
|
+
case "piper_bin":
|
|
581
|
+
return this._speak_piper(text);
|
|
582
|
+
case "edge":
|
|
583
|
+
return this._speak_edge(text);
|
|
584
|
+
case "os-tts":
|
|
585
|
+
case "pyttsx3":
|
|
586
|
+
return this._speak_pyttsx3(text);
|
|
587
|
+
default: {
|
|
588
|
+
const custom = _backends.get(name);
|
|
589
|
+
if (custom?.speak)
|
|
590
|
+
return custom.speak(text, this);
|
|
591
|
+
if (custom) {
|
|
592
|
+
const tmp = tempPath(".mp3");
|
|
593
|
+
try {
|
|
594
|
+
return await custom.synthesize(text, tmp, this);
|
|
595
|
+
}
|
|
596
|
+
finally {
|
|
597
|
+
unlinkQuiet(tmp);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
/* ── Audio playback ────────────────────────────────────────────────────────── */
|
|
606
|
+
/**
|
|
607
|
+
* Play an audio file through the registered audio-output driver.
|
|
608
|
+
*
|
|
609
|
+
* TODO(port): Python tried `soundfile`+`sounddevice`, then `winsound`/`afplay`/
|
|
610
|
+
* `mpg123`/`ffplay`. There is no in-process Node audio dependency here, so this
|
|
611
|
+
* shells out to an OS player (see `getAudioOutputDriver()` in src/voice/wav.ts).
|
|
612
|
+
*/
|
|
613
|
+
export async function _play_file(filePath) {
|
|
614
|
+
const driver = getAudioOutputDriver();
|
|
615
|
+
if (!driver) {
|
|
616
|
+
logger.warning(AUDIO_OUTPUT_MISSING_ERROR);
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
try {
|
|
620
|
+
await driver.playFile(filePath);
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
catch (e) {
|
|
624
|
+
logger.debug(`[TTS] _play_file error via ${driver.name}: ${errText(e)}`);
|
|
625
|
+
return false;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
export function _which(name) {
|
|
629
|
+
return whichSync(name);
|
|
630
|
+
}
|
|
631
|
+
/* ── Module-level speak helper (used by light_daemon) ──────────────────────── */
|
|
632
|
+
/**
|
|
633
|
+
* Speak text with the module singleton. Ports the module-level `_speak()` in
|
|
634
|
+
* `light_daemon.py` so the daemon has a one-call path to the engine.
|
|
635
|
+
*/
|
|
636
|
+
export async function speakWithFallback(text) {
|
|
637
|
+
if (!text)
|
|
638
|
+
return false;
|
|
639
|
+
const engine = get_tts();
|
|
640
|
+
const ok = await engine.speak(text);
|
|
641
|
+
if (engine.lastError)
|
|
642
|
+
logger.debug(engine.lastError);
|
|
643
|
+
return ok;
|
|
644
|
+
}
|
|
645
|
+
/* ── Singleton ─────────────────────────────────────────────────────────────── */
|
|
646
|
+
function ttsConfigFromDisk() {
|
|
647
|
+
try {
|
|
648
|
+
const cfg = loadConfig();
|
|
649
|
+
const vcfg = (cfg["voice"] ?? cfg["tts"] ?? {});
|
|
650
|
+
return {
|
|
651
|
+
voice: typeof vcfg["voice"] === "string" ? vcfg["voice"] : undefined,
|
|
652
|
+
rate: typeof vcfg["rate"] === "string" ? vcfg["rate"] : undefined,
|
|
653
|
+
speed: typeof vcfg["speed"] === "number" ? vcfg["speed"] : undefined,
|
|
654
|
+
provider: typeof vcfg["provider"] === "string" ? vcfg["provider"] : undefined,
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
catch {
|
|
658
|
+
return {};
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
export function get_tts(provider = "auto", kwargs = {}) {
|
|
662
|
+
if (_tts === null) {
|
|
663
|
+
const vcfg = ttsConfigFromDisk();
|
|
664
|
+
_tts = new TTSEngine(vcfg.voice ?? kwargs.voice ?? null, vcfg.rate ?? kwargs.rate ?? EDGE_RATE, "+0%", vcfg.provider ?? provider, vcfg.speed ?? kwargs.speed ?? KOKORO_SPEED);
|
|
665
|
+
}
|
|
666
|
+
return _tts;
|
|
667
|
+
}
|
|
668
|
+
/** camelCase alias of `get_tts`. */
|
|
669
|
+
export const getTts = get_tts;
|
|
670
|
+
/** Test/DI hook — replace the singleton. */
|
|
671
|
+
export function setTts(engine) {
|
|
672
|
+
_tts = engine;
|
|
673
|
+
}
|
|
674
|
+
/* ── helpers ───────────────────────────────────────────────────────────────── */
|
|
675
|
+
function tempPath(ext) {
|
|
676
|
+
return path.join(os.tmpdir(), `beru-tts-${Date.now()}-${Math.floor(Math.random() * 1e6)}${ext}`);
|
|
677
|
+
}
|
|
678
|
+
function fileSize(p) {
|
|
679
|
+
try {
|
|
680
|
+
return fs.statSync(p).size;
|
|
681
|
+
}
|
|
682
|
+
catch {
|
|
683
|
+
return 0;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function unlinkQuiet(p) {
|
|
687
|
+
try {
|
|
688
|
+
if (p)
|
|
689
|
+
fs.unlinkSync(p);
|
|
690
|
+
}
|
|
691
|
+
catch {
|
|
692
|
+
/* best effort, mirrors Python `except: pass` */
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
function errText(e) {
|
|
696
|
+
return e instanceof Error ? e.message : String(e);
|
|
697
|
+
}
|
|
698
|
+
//# sourceMappingURL=tts.js.map
|