sona-ai-voice 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +164 -0
  2. package/bin/blue +27 -0
  3. package/bin/sona +27 -0
  4. package/package.json +65 -0
  5. package/packages/audio/package.json +16 -0
  6. package/packages/cache/package.json +22 -0
  7. package/packages/cli/dist/audio-capture.d.ts +40 -0
  8. package/packages/cli/dist/audio-capture.d.ts.map +1 -0
  9. package/packages/cli/dist/audio-capture.js +122 -0
  10. package/packages/cli/dist/audio-capture.js.map +1 -0
  11. package/packages/cli/dist/audio-playback.d.ts +49 -0
  12. package/packages/cli/dist/audio-playback.d.ts.map +1 -0
  13. package/packages/cli/dist/audio-playback.js +153 -0
  14. package/packages/cli/dist/audio-playback.js.map +1 -0
  15. package/packages/cli/dist/echo-canceller.d.ts +53 -0
  16. package/packages/cli/dist/echo-canceller.d.ts.map +1 -0
  17. package/packages/cli/dist/echo-canceller.js +159 -0
  18. package/packages/cli/dist/echo-canceller.js.map +1 -0
  19. package/packages/cli/dist/gui/particles.html +383 -0
  20. package/packages/cli/dist/gui-server.d.ts +32 -0
  21. package/packages/cli/dist/gui-server.d.ts.map +1 -0
  22. package/packages/cli/dist/gui-server.js +140 -0
  23. package/packages/cli/dist/gui-server.js.map +1 -0
  24. package/packages/cli/dist/index.d.ts +7 -0
  25. package/packages/cli/dist/index.d.ts.map +1 -0
  26. package/packages/cli/dist/index.js +154 -0
  27. package/packages/cli/dist/index.js.map +1 -0
  28. package/packages/cli/dist/particle-ui.d.ts +105 -0
  29. package/packages/cli/dist/particle-ui.d.ts.map +1 -0
  30. package/packages/cli/dist/particle-ui.js +358 -0
  31. package/packages/cli/dist/particle-ui.js.map +1 -0
  32. package/packages/cli/dist/setup.d.ts +46 -0
  33. package/packages/cli/dist/setup.d.ts.map +1 -0
  34. package/packages/cli/dist/setup.js +206 -0
  35. package/packages/cli/dist/setup.js.map +1 -0
  36. package/packages/cli/dist/tools/codebase-context.d.ts +72 -0
  37. package/packages/cli/dist/tools/codebase-context.d.ts.map +1 -0
  38. package/packages/cli/dist/tools/codebase-context.js +339 -0
  39. package/packages/cli/dist/tools/codebase-context.js.map +1 -0
  40. package/packages/cli/dist/tools/tool-executor.d.ts +70 -0
  41. package/packages/cli/dist/tools/tool-executor.d.ts.map +1 -0
  42. package/packages/cli/dist/tools/tool-executor.js +302 -0
  43. package/packages/cli/dist/tools/tool-executor.js.map +1 -0
  44. package/packages/cli/dist/tools/web-search.d.ts +43 -0
  45. package/packages/cli/dist/tools/web-search.d.ts.map +1 -0
  46. package/packages/cli/dist/tools/web-search.js +169 -0
  47. package/packages/cli/dist/tools/web-search.js.map +1 -0
  48. package/packages/cli/dist/voice-conversation.d.ts +56 -0
  49. package/packages/cli/dist/voice-conversation.d.ts.map +1 -0
  50. package/packages/cli/dist/voice-conversation.js +352 -0
  51. package/packages/cli/dist/voice-conversation.js.map +1 -0
  52. package/packages/cli/package.json +31 -0
  53. package/packages/cli/src/gui/particles.html +383 -0
  54. package/packages/indexer/package.json +22 -0
  55. package/packages/realtime/dist/index.d.ts +5 -0
  56. package/packages/realtime/dist/index.d.ts.map +1 -0
  57. package/packages/realtime/dist/index.js +21 -0
  58. package/packages/realtime/dist/index.js.map +1 -0
  59. package/packages/realtime/dist/session.d.ts +91 -0
  60. package/packages/realtime/dist/session.d.ts.map +1 -0
  61. package/packages/realtime/dist/session.js +348 -0
  62. package/packages/realtime/dist/session.js.map +1 -0
  63. package/packages/realtime/package.json +22 -0
  64. package/packages/shared/dist/config.d.ts +14 -0
  65. package/packages/shared/dist/config.d.ts.map +1 -0
  66. package/packages/shared/dist/config.js +247 -0
  67. package/packages/shared/dist/config.js.map +1 -0
  68. package/packages/shared/dist/constants.d.ts +34 -0
  69. package/packages/shared/dist/constants.d.ts.map +1 -0
  70. package/packages/shared/dist/constants.js +61 -0
  71. package/packages/shared/dist/constants.js.map +1 -0
  72. package/packages/shared/dist/index.d.ts +7 -0
  73. package/packages/shared/dist/index.d.ts.map +1 -0
  74. package/packages/shared/dist/index.js +23 -0
  75. package/packages/shared/dist/index.js.map +1 -0
  76. package/packages/shared/dist/types.d.ts +101 -0
  77. package/packages/shared/dist/types.d.ts.map +1 -0
  78. package/packages/shared/dist/types.js +71 -0
  79. package/packages/shared/dist/types.js.map +1 -0
  80. package/packages/shared/package.json +22 -0
  81. package/packages/terminal/package.json +19 -0
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # Sona
2
+
3
+ A production-ready voice-to-voice CLI companion powered by OpenAI's Realtime API. Natural speech-to-speech interaction with codebase awareness and web search capabilities.
4
+
5
+ ## Features
6
+
7
+ - **Real-time voice conversation** - Natural speech-to-speech interaction
8
+ - **Codebase awareness** - Indexes your project and understands your code
9
+ - **Web search** - Search the web for current information (no API key needed)
10
+ - **Particle GUI** - Visual feedback (optional)
11
+ - **Secure** - API keys stored locally with restricted permissions
12
+ - **Barge-in support** - Interrupt Sona mid-sentence
13
+ - **Echo cancellation** - Prevents feedback loops
14
+
15
+ ## Prerequisites
16
+
17
+ - **Node.js** >= 18.0.0
18
+ - **sox** (for audio capture/playback)
19
+ ```bash
20
+ # macOS
21
+ brew install sox
22
+
23
+ # Ubuntu/Debian
24
+ sudo apt-get install sox
25
+
26
+ # Windows
27
+ choco install sox
28
+ ```
29
+ - **OpenAI API key** with Realtime API access
30
+
31
+ ## Installation
32
+
33
+ ### Quick Install
34
+
35
+ ```bash
36
+ npm install -g sona-ai-voice
37
+ ```
38
+
39
+ ### Fix Permission Errors (macOS/Linux)
40
+
41
+ If you see `EACCES: permission denied` errors, configure npm to use a user-owned directory:
42
+
43
+ ```bash
44
+ # 1. Create a directory for global packages
45
+ mkdir -p ~/.npm-global
46
+
47
+ # 2. Configure npm to use this directory
48
+ npm config set prefix '~/.npm-global'
49
+
50
+ # 3. Add to your PATH (choose your shell):
51
+ # For zsh (macOS default):
52
+ echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc
53
+ source ~/.zshrc
54
+
55
+ # For bash:
56
+ echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
57
+ source ~/.bashrc
58
+
59
+ # 4. Install Sona
60
+ npm install -g sona-ai-voice
61
+
62
+ # 5. Verify installation
63
+ sona --help
64
+ ```
65
+
66
+ **Alternative**: Use `sudo` (not recommended):
67
+ ```bash
68
+ sudo npm install -g sona-ai-voice
69
+ ```
70
+
71
+ ## Setup
72
+
73
+ First time setup - enter your OpenAI API key:
74
+
75
+ ```bash
76
+ sona setup
77
+ ```
78
+
79
+ Your API key will be stored securely in `~/.sona/config` with restricted file permissions.
80
+
81
+ ## Usage
82
+
83
+ ### Start a voice conversation
84
+
85
+ ```bash
86
+ # Navigate to any project directory
87
+ cd /path/to/your-project
88
+
89
+ # Start Sona (indexes current directory)
90
+ sona talk
91
+ ```
92
+
93
+ ### Options
94
+
95
+ ```bash
96
+ sona talk # Full experience with GUI
97
+ sona talk --no-gui # Terminal only (no particle window)
98
+ sona talk --no-index # Skip codebase indexing
99
+ ```
100
+
101
+ ### Other commands
102
+
103
+ ```bash
104
+ sona setup # Configure API key
105
+ sona test # Test API connection
106
+ sona logout # Remove stored API key
107
+ sona --help # Show all commands
108
+ ```
109
+
110
+ ## How It Works
111
+
112
+ 1. **Indexing**: When you run `sona talk`, it indexes the current directory's source files
113
+ 2. **Context**: Sona understands your codebase structure and can answer questions about it
114
+ 3. **Voice**: Uses OpenAI's Realtime API for natural voice conversation
115
+ 4. **Web Search**: Can search the web for information it doesn't know
116
+
117
+ ## Example Conversations
118
+
119
+ - "What files are in this project?"
120
+ - "Explain how the authentication works"
121
+ - "What dependencies does this project use?"
122
+ - "Search for the latest React 19 features"
123
+
124
+ ## Security
125
+
126
+ - API keys are stored in `~/.sona/config` with `600` permissions (owner-only)
127
+ - Keys are obfuscated (not plain text)
128
+ - Never committed to git (`.env.local` is gitignored)
129
+ - You can remove your key anytime with `sona logout`
130
+
131
+ ## Troubleshooting
132
+
133
+ ### "EACCES: permission denied" when installing
134
+ This happens because npm tries to install to `/usr/local` which requires admin access. **Solution**: Configure npm to use a user-owned directory (see Installation section above).
135
+
136
+ ### "sox not found"
137
+ Install sox: `brew install sox` (macOS) or `apt-get install sox` (Linux)
138
+
139
+ ### "API key required"
140
+ Run `sona setup` to configure your OpenAI API key
141
+
142
+ ### "sona: command not found"
143
+ Make sure `~/.npm-global/bin` (or your npm global bin path) is in your PATH. Check with:
144
+ ```bash
145
+ npm config get prefix
146
+ which sona
147
+ ```
148
+
149
+ ### Sona not responding
150
+ - Check your microphone is working
151
+ - Speak clearly and close to the mic
152
+ - Try `sona test` to verify API connection
153
+
154
+ ## Development
155
+
156
+ For development, see the [GitHub repository](https://github.com/zerish/Blue).
157
+
158
+ ## License
159
+
160
+ MIT
161
+
162
+ ## Author
163
+
164
+ zerish
package/bin/blue ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Sona CLI - Global Entry Point
5
+ * This file allows Sona to be run from anywhere
6
+ */
7
+
8
+ const path = require('path');
9
+ const { spawn } = require('child_process');
10
+
11
+ // Get the directory where Sona is installed
12
+ const sonaRoot = path.resolve(__dirname, '..');
13
+ const cliPath = path.join(sonaRoot, 'packages', 'cli', 'dist', 'index.js');
14
+
15
+ // Run the CLI with all arguments passed through
16
+ const child = spawn('node', [cliPath, ...process.argv.slice(2)], {
17
+ stdio: 'inherit',
18
+ cwd: process.cwd(), // Use current working directory for indexing
19
+ env: {
20
+ ...process.env,
21
+ SONA_ROOT: sonaRoot,
22
+ },
23
+ });
24
+
25
+ child.on('exit', (code) => {
26
+ process.exit(code || 0);
27
+ });
package/bin/sona ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Sona CLI - Global Entry Point
5
+ * This file allows Sona to be run from anywhere
6
+ */
7
+
8
+ const path = require('path');
9
+ const { spawn } = require('child_process');
10
+
11
+ // Get the directory where Sona is installed
12
+ const sonaRoot = path.resolve(__dirname, '..');
13
+ const cliPath = path.join(sonaRoot, 'packages', 'cli', 'dist', 'index.js');
14
+
15
+ // Run the CLI with all arguments passed through
16
+ const child = spawn('node', [cliPath, ...process.argv.slice(2)], {
17
+ stdio: 'inherit',
18
+ cwd: process.cwd(), // Use current working directory for indexing
19
+ env: {
20
+ ...process.env,
21
+ SONA_ROOT: sonaRoot,
22
+ },
23
+ });
24
+
25
+ child.on('exit', (code) => {
26
+ process.exit(code || 0);
27
+ });
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "sona-ai-voice",
3
+ "version": "0.1.5",
4
+ "description": "Voice-to-voice AI CLI companion powered by OpenAI Realtime API",
5
+ "author": "zerish",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/zerish/Blue.git"
10
+ },
11
+ "keywords": [
12
+ "ai",
13
+ "voice",
14
+ "openai",
15
+ "realtime",
16
+ "cli",
17
+ "speech-to-speech",
18
+ "conversational-ai"
19
+ ],
20
+ "bin": {
21
+ "sona": "packages/cli/dist/index.js"
22
+ },
23
+ "files": [
24
+ "packages/*/dist/**/*",
25
+ "packages/*/package.json",
26
+ "packages/cli/src/gui/**/*",
27
+ "bin/**/*"
28
+ ],
29
+ "workspaces": [
30
+ "packages/*"
31
+ ],
32
+ "scripts": {
33
+ "build": "bash scripts/build-for-publish.sh",
34
+ "build:all": "npm run build --workspaces --if-present",
35
+ "dev": "npm run dev --workspace=packages/cli",
36
+ "clean": "rm -rf packages/*/dist packages/*/*.tsbuildinfo node_modules/.cache",
37
+ "test": "npm run test --workspaces --if-present",
38
+ "lint": "eslint packages --ext .ts,.tsx",
39
+ "format": "prettier --write \"packages/**/*.{ts,tsx,json,md}\"",
40
+ "cache:clear": "rm -rf node_modules/.cache .sona-cache",
41
+ "prepublishOnly": "npm run build"
42
+ },
43
+ "dependencies": {
44
+ "chalk": "^4.1.2",
45
+ "commander": "^11.1.0",
46
+ "dotenv": "^16.0.0",
47
+ "ws": "^8.19.0",
48
+ "zod": "^3.22.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20.10.0",
52
+ "@typescript-eslint/eslint-plugin": "^6.13.0",
53
+ "@typescript-eslint/parser": "^6.13.0",
54
+ "eslint": "^8.54.0",
55
+ "eslint-config-airbnb-base": "^15.0.0",
56
+ "eslint-config-airbnb-typescript": "^17.1.0",
57
+ "eslint-plugin-import": "^2.29.0",
58
+ "prettier": "^3.1.0",
59
+ "typescript": "^5.3.0"
60
+ },
61
+ "engines": {
62
+ "node": ">=18.0.0",
63
+ "npm": ">=9.0.0"
64
+ }
65
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@blue/audio",
3
+ "version": "0.1.0",
4
+ "description": "Audio capture, playback, VAD, and endpointing for Blue",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "dev": "tsc --watch"
10
+ },
11
+ "dependencies": {},
12
+ "devDependencies": {
13
+ "typescript": "^5.3.2",
14
+ "@types/node": "^20.10.0"
15
+ }
16
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@blue/cache",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Multi-layer caching system for API optimization",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc -b",
10
+ "dev": "tsc -b --watch",
11
+ "clean": "rm -rf dist *.tsbuildinfo",
12
+ "test": "jest"
13
+ },
14
+ "dependencies": {
15
+ "lru-cache": "^10.1.0",
16
+ "xxhash-wasm": "^1.0.2"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^20.10.0",
20
+ "typescript": "^5.3.0"
21
+ }
22
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Audio Capture Module
3
+ * Mic capture with pause/resume for echo cancellation
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ export interface AudioCaptureConfig {
7
+ readonly sampleRate: number;
8
+ readonly channels: number;
9
+ readonly bitDepth: number;
10
+ }
11
+ export interface AudioCaptureEvents {
12
+ 'data': (audioBuffer: Buffer) => void;
13
+ 'error': (error: Error) => void;
14
+ 'started': () => void;
15
+ 'stopped': () => void;
16
+ }
17
+ export declare class AudioCapture extends EventEmitter {
18
+ private micProcess;
19
+ private isRecording;
20
+ private isPaused;
21
+ private config;
22
+ constructor(config: AudioCaptureConfig);
23
+ start(): void;
24
+ private spawnMic;
25
+ /**
26
+ * Pause audio capture (for echo cancellation during playback)
27
+ * Kills the mic process to ensure no audio leaks through
28
+ */
29
+ pause(): void;
30
+ /**
31
+ * Resume audio capture after playback ends
32
+ */
33
+ resume(): void;
34
+ stop(): void;
35
+ get recording(): boolean;
36
+ get paused(): boolean;
37
+ on<K extends keyof AudioCaptureEvents>(event: K, listener: AudioCaptureEvents[K]): this;
38
+ emit<K extends keyof AudioCaptureEvents>(event: K, ...args: Parameters<AudioCaptureEvents[K]>): boolean;
39
+ }
40
+ //# sourceMappingURL=audio-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-capture.d.ts","sourceRoot":"","sources":["../src/audio-capture.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,EAAE,kBAAkB;IAKtC,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,QAAQ;IAgDhB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAWb;;OAEG;IACH,MAAM,IAAI,IAAI;IAQd,IAAI,IAAI,IAAI;IAYZ,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAEQ,EAAE,CAAC,CAAC,SAAS,MAAM,kBAAkB,EAC5C,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,IAAI;IAIE,IAAI,CAAC,CAAC,SAAS,MAAM,kBAAkB,EAC9C,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,GACzC,OAAO;CAGX"}
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ /**
3
+ * Audio Capture Module
4
+ * Mic capture with pause/resume for echo cancellation
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.AudioCapture = void 0;
8
+ const child_process_1 = require("child_process");
9
+ const events_1 = require("events");
10
+ class AudioCapture extends events_1.EventEmitter {
11
+ micProcess = null;
12
+ isRecording = false;
13
+ isPaused = false;
14
+ config;
15
+ constructor(config) {
16
+ super();
17
+ this.config = config;
18
+ }
19
+ start() {
20
+ if (this.isRecording)
21
+ return;
22
+ this.spawnMic();
23
+ }
24
+ spawnMic() {
25
+ if (this.micProcess) {
26
+ try {
27
+ this.micProcess.kill('SIGKILL');
28
+ }
29
+ catch { }
30
+ this.micProcess = null;
31
+ }
32
+ this.micProcess = (0, child_process_1.spawn)('sox', [
33
+ '-d', // Default audio device
34
+ '-t', 'raw', // Raw PCM output
35
+ '-b', '16', // 16-bit
36
+ '-e', 'signed-integer', // Signed integer
37
+ '-r', '24000', // 24kHz (required by OpenAI)
38
+ '-c', '1', // Mono
39
+ '-q', // Quiet mode
40
+ '-', // Output to stdout
41
+ ]);
42
+ if (!this.micProcess.stdout) {
43
+ this.emit('error', new Error('Failed to start microphone'));
44
+ return;
45
+ }
46
+ this.micProcess.stdout.on('data', (chunk) => {
47
+ if (!this.isPaused) {
48
+ this.emit('data', chunk);
49
+ }
50
+ });
51
+ this.micProcess.stderr?.on('data', (data) => {
52
+ const msg = data.toString();
53
+ if (msg.includes('FAIL') || msg.includes('error')) {
54
+ this.emit('error', new Error(msg));
55
+ }
56
+ });
57
+ this.micProcess.on('error', (error) => {
58
+ this.emit('error', error);
59
+ });
60
+ this.micProcess.on('exit', () => {
61
+ this.isRecording = false;
62
+ });
63
+ this.isRecording = true;
64
+ this.isPaused = false;
65
+ this.emit('started');
66
+ }
67
+ /**
68
+ * Pause audio capture (for echo cancellation during playback)
69
+ * Kills the mic process to ensure no audio leaks through
70
+ */
71
+ pause() {
72
+ if (!this.isRecording || this.isPaused)
73
+ return;
74
+ this.isPaused = true;
75
+ // Kill the mic process to ensure complete silence
76
+ if (this.micProcess) {
77
+ try {
78
+ this.micProcess.kill('SIGKILL');
79
+ }
80
+ catch { }
81
+ this.micProcess = null;
82
+ }
83
+ }
84
+ /**
85
+ * Resume audio capture after playback ends
86
+ */
87
+ resume() {
88
+ if (!this.isPaused)
89
+ return;
90
+ this.isPaused = false;
91
+ // Restart the mic process
92
+ this.spawnMic();
93
+ }
94
+ stop() {
95
+ if (!this.isRecording)
96
+ return;
97
+ if (this.micProcess) {
98
+ try {
99
+ this.micProcess.kill('SIGTERM');
100
+ }
101
+ catch { }
102
+ this.micProcess = null;
103
+ }
104
+ this.isRecording = false;
105
+ this.isPaused = false;
106
+ this.emit('stopped');
107
+ }
108
+ get recording() {
109
+ return this.isRecording && !this.isPaused;
110
+ }
111
+ get paused() {
112
+ return this.isPaused;
113
+ }
114
+ on(event, listener) {
115
+ return super.on(event, listener);
116
+ }
117
+ emit(event, ...args) {
118
+ return super.emit(event, ...args);
119
+ }
120
+ }
121
+ exports.AudioCapture = AudioCapture;
122
+ //# sourceMappingURL=audio-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-capture.js","sourceRoot":"","sources":["../src/audio-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Audio Playback Module
3
+ * Smooth speaker output using sox with buffering to prevent audio cracks
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ export interface AudioPlaybackConfig {
7
+ readonly sampleRate: number;
8
+ readonly channels: number;
9
+ readonly bitDepth: number;
10
+ }
11
+ export interface AudioPlaybackEvents {
12
+ 'started': () => void;
13
+ 'stopped': () => void;
14
+ 'finished': () => void;
15
+ 'error': (error: Error) => void;
16
+ }
17
+ export declare class AudioPlayback extends EventEmitter {
18
+ private playProcess;
19
+ private isWritable;
20
+ private config;
21
+ private audioBuffer;
22
+ private isPlaying;
23
+ private totalBytesQueued;
24
+ private finishRequested;
25
+ private drainTimeout;
26
+ constructor(config: AudioPlaybackConfig);
27
+ start(): void;
28
+ private spawnProcess;
29
+ /**
30
+ * Queue audio for playback
31
+ */
32
+ play(audioBuffer: Buffer): void;
33
+ /**
34
+ * Signal that we're done sending audio for this response.
35
+ */
36
+ finishPlayback(): void;
37
+ /**
38
+ * Reset state for next response
39
+ */
40
+ private resetForNextResponse;
41
+ /**
42
+ * Immediately stop playback (for barge-in)
43
+ */
44
+ stop(): void;
45
+ get playing(): boolean;
46
+ on<K extends keyof AudioPlaybackEvents>(event: K, listener: AudioPlaybackEvents[K]): this;
47
+ emit<K extends keyof AudioPlaybackEvents>(event: K, ...args: Parameters<AudioPlaybackEvents[K]>): boolean;
48
+ }
49
+ //# sourceMappingURL=audio-playback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-playback.d.ts","sourceRoot":"","sources":["../src/audio-playback.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACjC;AAED,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAsB;IAGpC,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,YAAY,CAA+B;gBAEvC,MAAM,EAAE,mBAAmB;IAKvC,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,YAAY;IA+CpB;;OAEG;IACH,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAoB/B;;OAEG;IACH,cAAc,IAAI,IAAI;IAqBtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACH,IAAI,IAAI,IAAI;IA0BZ,IAAI,OAAO,IAAI,OAAO,CAErB;IAEQ,EAAE,CAAC,CAAC,SAAS,MAAM,mBAAmB,EAC7C,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC/B,IAAI;IAIE,IAAI,CAAC,CAAC,SAAS,MAAM,mBAAmB,EAC/C,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAC1C,OAAO;CAGX"}