@micdrop/server 2.0.5 → 2.0.6
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/dist/index.d.mts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -67,7 +67,8 @@ declare enum MicdropServerCommands {
|
|
|
67
67
|
CancelLastAssistantMessage = "CancelLastAssistantMessage",
|
|
68
68
|
CancelLastUserMessage = "CancelLastUserMessage",
|
|
69
69
|
SkipAnswer = "SkipAnswer",
|
|
70
|
-
EndCall = "EndCall"
|
|
70
|
+
EndCall = "EndCall",
|
|
71
|
+
ToolCall = "ToolCall"
|
|
71
72
|
}
|
|
72
73
|
interface MicdropConfig {
|
|
73
74
|
firstMessage?: string;
|
|
@@ -90,6 +91,11 @@ interface MicdropConversationMessage<Data extends MicdropAnswerMetadata = Micdro
|
|
|
90
91
|
content: string;
|
|
91
92
|
metadata?: Data;
|
|
92
93
|
}
|
|
94
|
+
interface MicdropToolCall {
|
|
95
|
+
name: string;
|
|
96
|
+
parameters: any;
|
|
97
|
+
output: any;
|
|
98
|
+
}
|
|
93
99
|
type DeepPartial<T> = T extends object ? {
|
|
94
100
|
[P in keyof T]?: DeepPartial<T[P]>;
|
|
95
101
|
} : T;
|
|
@@ -103,6 +109,7 @@ interface AgentEvents {
|
|
|
103
109
|
CancelLastAssistantMessage: [];
|
|
104
110
|
SkipAnswer: [];
|
|
105
111
|
EndCall: [];
|
|
112
|
+
ToolCall: [MicdropToolCall];
|
|
106
113
|
}
|
|
107
114
|
declare abstract class Agent<Options extends AgentOptions = AgentOptions> extends EventEmitter<AgentEvents> {
|
|
108
115
|
protected options: Options;
|
|
@@ -167,4 +174,4 @@ declare class MicdropServer {
|
|
|
167
174
|
|
|
168
175
|
declare function waitForParams<CallParams>(socket: WebSocket$1, validate: (params: any) => CallParams): Promise<CallParams>;
|
|
169
176
|
|
|
170
|
-
export { Agent, type AgentEvents, type AgentOptions, type DeepPartial, FileSTT, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationMessage, MicdropError, MicdropErrorCode, MicdropServer, MicdropServerCommands, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, convertPCMToOpus, convertToOpus, convertToPCM, handleError, waitForParams };
|
|
177
|
+
export { Agent, type AgentEvents, type AgentOptions, type DeepPartial, FileSTT, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationMessage, MicdropError, MicdropErrorCode, MicdropServer, MicdropServerCommands, type MicdropToolCall, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, convertPCMToOpus, convertToOpus, convertToPCM, handleError, waitForParams };
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,8 @@ declare enum MicdropServerCommands {
|
|
|
67
67
|
CancelLastAssistantMessage = "CancelLastAssistantMessage",
|
|
68
68
|
CancelLastUserMessage = "CancelLastUserMessage",
|
|
69
69
|
SkipAnswer = "SkipAnswer",
|
|
70
|
-
EndCall = "EndCall"
|
|
70
|
+
EndCall = "EndCall",
|
|
71
|
+
ToolCall = "ToolCall"
|
|
71
72
|
}
|
|
72
73
|
interface MicdropConfig {
|
|
73
74
|
firstMessage?: string;
|
|
@@ -90,6 +91,11 @@ interface MicdropConversationMessage<Data extends MicdropAnswerMetadata = Micdro
|
|
|
90
91
|
content: string;
|
|
91
92
|
metadata?: Data;
|
|
92
93
|
}
|
|
94
|
+
interface MicdropToolCall {
|
|
95
|
+
name: string;
|
|
96
|
+
parameters: any;
|
|
97
|
+
output: any;
|
|
98
|
+
}
|
|
93
99
|
type DeepPartial<T> = T extends object ? {
|
|
94
100
|
[P in keyof T]?: DeepPartial<T[P]>;
|
|
95
101
|
} : T;
|
|
@@ -103,6 +109,7 @@ interface AgentEvents {
|
|
|
103
109
|
CancelLastAssistantMessage: [];
|
|
104
110
|
SkipAnswer: [];
|
|
105
111
|
EndCall: [];
|
|
112
|
+
ToolCall: [MicdropToolCall];
|
|
106
113
|
}
|
|
107
114
|
declare abstract class Agent<Options extends AgentOptions = AgentOptions> extends EventEmitter<AgentEvents> {
|
|
108
115
|
protected options: Options;
|
|
@@ -167,4 +174,4 @@ declare class MicdropServer {
|
|
|
167
174
|
|
|
168
175
|
declare function waitForParams<CallParams>(socket: WebSocket$1, validate: (params: any) => CallParams): Promise<CallParams>;
|
|
169
176
|
|
|
170
|
-
export { Agent, type AgentEvents, type AgentOptions, type DeepPartial, FileSTT, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationMessage, MicdropError, MicdropErrorCode, MicdropServer, MicdropServerCommands, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, convertPCMToOpus, convertToOpus, convertToPCM, handleError, waitForParams };
|
|
177
|
+
export { Agent, type AgentEvents, type AgentOptions, type DeepPartial, FileSTT, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationMessage, MicdropError, MicdropErrorCode, MicdropServer, MicdropServerCommands, type MicdropToolCall, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, convertPCMToOpus, convertToOpus, convertToPCM, handleError, waitForParams };
|
package/dist/index.js
CHANGED
|
@@ -211,6 +211,7 @@ var MicdropServerCommands = /* @__PURE__ */ ((MicdropServerCommands2) => {
|
|
|
211
211
|
MicdropServerCommands2["CancelLastUserMessage"] = "CancelLastUserMessage";
|
|
212
212
|
MicdropServerCommands2["SkipAnswer"] = "SkipAnswer";
|
|
213
213
|
MicdropServerCommands2["EndCall"] = "EndCall";
|
|
214
|
+
MicdropServerCommands2["ToolCall"] = "ToolCall";
|
|
214
215
|
return MicdropServerCommands2;
|
|
215
216
|
})(MicdropServerCommands || {});
|
|
216
217
|
|
|
@@ -291,6 +292,12 @@ var MicdropServer = class {
|
|
|
291
292
|
"EndCall",
|
|
292
293
|
() => this.socket?.send("EndCall" /* EndCall */)
|
|
293
294
|
);
|
|
295
|
+
this.config.agent.on(
|
|
296
|
+
"ToolCall",
|
|
297
|
+
(toolCall) => this.socket?.send(
|
|
298
|
+
`${"ToolCall" /* ToolCall */} ${JSON.stringify(toolCall)}`
|
|
299
|
+
)
|
|
300
|
+
);
|
|
294
301
|
this.sendFirstMessage();
|
|
295
302
|
socket.on("close", this.onClose);
|
|
296
303
|
socket.on("message", this.onMessage);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/agent/Agent.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["export * from './agent'\nexport * from './audio-convert'\nexport * from './errors'\nexport * from './Logger'\nexport * from './MicdropServer'\nexport * from './stt'\nexport * from './tts'\nexport * from './types'\nexport * from './waitForParams'\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationMessage,\n} from '../types'\n\nexport interface AgentOptions {\n systemPrompt: string\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationMessage]\n CancelLastUserMessage: []\n CancelLastAssistantMessage: []\n SkipAnswer: []\n EndCall: []\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n\n // Conversation history\n public conversation: MicdropConversation\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n }\n\n abstract answer(): Readable\n abstract cancel(): void\n\n public addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n public addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n protected addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'user') return\n this.conversation.pop()\n this.emit('CancelLastUserMessage')\n }\n\n protected cancelLastAssistantMessage() {\n this.log('Cancelling last assistant message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'assistant') return\n this.conversation.pop()\n this.emit('CancelLastAssistantMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n answer() {\n const stream = new PassThrough()\n\n // Answer message\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n stream.end()\n return stream\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport { Logger } from './Logger'\nimport {\n MicdropClientCommands,\n MicdropConfig,\n MicdropServerCommands,\n} from './types'\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('CancelLastAssistantMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastAssistantMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n await this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n await this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n await this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private async onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private async onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private async onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n if (conversation && conversation[conversation.length - 1].role === 'user') {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.answer()\n }\n }\n\n private async sendFirstMessage() {\n if (!this.config) return\n try {\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n await this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n await this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n private async answer() {\n if (!this.config) return\n this.cancel()\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this.speak(stream)\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n // Run text-to-speech and send to client\n private async speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this.sendAudio(audio)\n }\n\n private async sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Stream audio\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n })\n }\n}\n","import type { Agent } from './agent'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\n\nexport enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastAssistantMessage = 'CancelLastAssistantMessage',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversation = MicdropConversationMessage[]\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":"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","names":["import_stream","ffmpeg","ffmpegInstaller","MicdropErrorCode","import_stream","MicdropClientCommands","MicdropServerCommands","import_eventemitter3","import_stream"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/agent/Agent.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["export * from './agent'\nexport * from './audio-convert'\nexport * from './errors'\nexport * from './Logger'\nexport * from './MicdropServer'\nexport * from './stt'\nexport * from './tts'\nexport * from './types'\nexport * from './waitForParams'\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationMessage,\n MicdropToolCall,\n} from '../types'\n\nexport interface AgentOptions {\n systemPrompt: string\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationMessage]\n CancelLastUserMessage: []\n CancelLastAssistantMessage: []\n SkipAnswer: []\n EndCall: []\n ToolCall: [MicdropToolCall]\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n\n // Conversation history\n public conversation: MicdropConversation\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n }\n\n abstract answer(): Readable\n abstract cancel(): void\n\n public addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n public addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n protected addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'user') return\n this.conversation.pop()\n this.emit('CancelLastUserMessage')\n }\n\n protected cancelLastAssistantMessage() {\n this.log('Cancelling last assistant message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'assistant') return\n this.conversation.pop()\n this.emit('CancelLastAssistantMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n answer() {\n const stream = new PassThrough()\n\n // Answer message\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n stream.end()\n return stream\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport { Logger } from './Logger'\nimport {\n MicdropClientCommands,\n MicdropConfig,\n MicdropServerCommands,\n} from './types'\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('CancelLastAssistantMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastAssistantMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n this.config.agent.on('ToolCall', (toolCall) =>\n this.socket?.send(\n `${MicdropServerCommands.ToolCall} ${JSON.stringify(toolCall)}`\n )\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n await this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n await this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n await this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private async onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private async onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private async onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n if (conversation && conversation[conversation.length - 1].role === 'user') {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.answer()\n }\n }\n\n private async sendFirstMessage() {\n if (!this.config) return\n try {\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n await this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n await this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n private async answer() {\n if (!this.config) return\n this.cancel()\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this.speak(stream)\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n // Run text-to-speech and send to client\n private async speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this.sendAudio(audio)\n }\n\n private async sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Stream audio\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n })\n }\n}\n","import type { Agent } from './agent'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\n\nexport enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastAssistantMessage = 'CancelLastAssistantMessage',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n ToolCall = 'ToolCall',\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversation = MicdropConversationMessage[]\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport interface MicdropToolCall {\n name: string\n parameters: any\n output: any\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":"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","names":["import_stream","ffmpeg","ffmpegInstaller","MicdropErrorCode","import_stream","MicdropClientCommands","MicdropServerCommands","import_eventemitter3","import_stream"]}
|
package/dist/index.mjs
CHANGED
|
@@ -158,6 +158,7 @@ var MicdropServerCommands = /* @__PURE__ */ ((MicdropServerCommands2) => {
|
|
|
158
158
|
MicdropServerCommands2["CancelLastUserMessage"] = "CancelLastUserMessage";
|
|
159
159
|
MicdropServerCommands2["SkipAnswer"] = "SkipAnswer";
|
|
160
160
|
MicdropServerCommands2["EndCall"] = "EndCall";
|
|
161
|
+
MicdropServerCommands2["ToolCall"] = "ToolCall";
|
|
161
162
|
return MicdropServerCommands2;
|
|
162
163
|
})(MicdropServerCommands || {});
|
|
163
164
|
|
|
@@ -238,6 +239,12 @@ var MicdropServer = class {
|
|
|
238
239
|
"EndCall",
|
|
239
240
|
() => this.socket?.send("EndCall" /* EndCall */)
|
|
240
241
|
);
|
|
242
|
+
this.config.agent.on(
|
|
243
|
+
"ToolCall",
|
|
244
|
+
(toolCall) => this.socket?.send(
|
|
245
|
+
`${"ToolCall" /* ToolCall */} ${JSON.stringify(toolCall)}`
|
|
246
|
+
)
|
|
247
|
+
);
|
|
241
248
|
this.sendFirstMessage();
|
|
242
249
|
socket.on("close", this.onClose);
|
|
243
250
|
socket.on("message", this.onMessage);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent/Agent.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationMessage,\n} from '../types'\n\nexport interface AgentOptions {\n systemPrompt: string\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationMessage]\n CancelLastUserMessage: []\n CancelLastAssistantMessage: []\n SkipAnswer: []\n EndCall: []\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n\n // Conversation history\n public conversation: MicdropConversation\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n }\n\n abstract answer(): Readable\n abstract cancel(): void\n\n public addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n public addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n protected addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'user') return\n this.conversation.pop()\n this.emit('CancelLastUserMessage')\n }\n\n protected cancelLastAssistantMessage() {\n this.log('Cancelling last assistant message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'assistant') return\n this.conversation.pop()\n this.emit('CancelLastAssistantMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n answer() {\n const stream = new PassThrough()\n\n // Answer message\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n stream.end()\n return stream\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport { Logger } from './Logger'\nimport {\n MicdropClientCommands,\n MicdropConfig,\n MicdropServerCommands,\n} from './types'\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('CancelLastAssistantMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastAssistantMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n await this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n await this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n await this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private async onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private async onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private async onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n if (conversation && conversation[conversation.length - 1].role === 'user') {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.answer()\n }\n }\n\n private async sendFirstMessage() {\n if (!this.config) return\n try {\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n await this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n await this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n private async answer() {\n if (!this.config) return\n this.cancel()\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this.speak(stream)\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n // Run text-to-speech and send to client\n private async speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this.sendAudio(audio)\n }\n\n private async sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Stream audio\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n })\n }\n}\n","import type { Agent } from './agent'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\n\nexport enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastAssistantMessage = 'CancelLastAssistantMessage',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversation = MicdropConversationMessage[]\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":"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","names":["PassThrough","MicdropErrorCode","PassThrough","MicdropClientCommands","MicdropServerCommands","PassThrough","EventEmitter","PassThrough","PassThrough"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent/Agent.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationMessage,\n MicdropToolCall,\n} from '../types'\n\nexport interface AgentOptions {\n systemPrompt: string\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationMessage]\n CancelLastUserMessage: []\n CancelLastAssistantMessage: []\n SkipAnswer: []\n EndCall: []\n ToolCall: [MicdropToolCall]\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n\n // Conversation history\n public conversation: MicdropConversation\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n }\n\n abstract answer(): Readable\n abstract cancel(): void\n\n public addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n public addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n protected addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'user') return\n this.conversation.pop()\n this.emit('CancelLastUserMessage')\n }\n\n protected cancelLastAssistantMessage() {\n this.log('Cancelling last assistant message')\n const lastMessage = this.conversation[this.conversation.length - 1]\n if (lastMessage?.role !== 'assistant') return\n this.conversation.pop()\n this.emit('CancelLastAssistantMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n answer() {\n const stream = new PassThrough()\n\n // Answer message\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n stream.end()\n return stream\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport { Logger } from './Logger'\nimport {\n MicdropClientCommands,\n MicdropConfig,\n MicdropServerCommands,\n} from './types'\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('CancelLastAssistantMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastAssistantMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n this.config.agent.on('ToolCall', (toolCall) =>\n this.socket?.send(\n `${MicdropServerCommands.ToolCall} ${JSON.stringify(toolCall)}`\n )\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n await this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n await this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n await this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private async onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private async onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private async onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n if (conversation && conversation[conversation.length - 1].role === 'user') {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.answer()\n }\n }\n\n private async sendFirstMessage() {\n if (!this.config) return\n try {\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n await this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n await this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n private async answer() {\n if (!this.config) return\n this.cancel()\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this.speak(stream)\n } catch (error) {\n console.error('[MicdropServer]', error)\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n // Run text-to-speech and send to client\n private async speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this.sendAudio(audio)\n }\n\n private async sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Stream audio\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n })\n }\n}\n","import type { Agent } from './agent'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\n\nexport enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastAssistantMessage = 'CancelLastAssistantMessage',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n ToolCall = 'ToolCall',\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversation = MicdropConversationMessage[]\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport interface MicdropToolCall {\n name: string\n parameters: any\n output: any\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":"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","names":["PassThrough","MicdropErrorCode","PassThrough","MicdropClientCommands","MicdropServerCommands","PassThrough","EventEmitter","PassThrough","PassThrough"]}
|