diff --git a/bot_output_audio/.env.sample b/bot_output_audio/.env.sample new file mode 100644 index 0000000..60ec65a --- /dev/null +++ b/bot_output_audio/.env.sample @@ -0,0 +1,3 @@ +RECALL_API_KEY=RECALL_API_KEY +RECALL_REGION=RECALL_REGION # e.g. us-west-2, us-east-1, eu-central-1, ap-northeast-1 +MEETING_URL=MEETING_URL # e.g. any Zoom, Google Meet, Microsoft Teams, Webex, or GoToMeeting URL diff --git a/bot_output_audio/README.md b/bot_output_audio/README.md new file mode 100644 index 0000000..6a4888b --- /dev/null +++ b/bot_output_audio/README.md @@ -0,0 +1,75 @@ +# Output audio from a bot + +This example demonstrates how to create a bot that outputs audio when it starts recording. The bot uses the `automatic_audio_output` configuration to play a base64-encoded MP3 file when the bot begins recording in a meeting. + +## Pre-requisites + +- [Node.js](https://nodejs.org/en/download) +- [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) + +## Quickstart + +### 1. Set up environment variables + +Copy the `.env.sample` file and rename it to `.env`: + +```bash +cp .env.sample .env +``` + +Then fill out the variables in the `.env` file: + +- `RECALL_API_KEY` - Your Recall.ai API key +- `RECALL_REGION` - Your Recall.ai region (e.g., `us-west-2`) +- `MEETING_URL` - The meeting URL for the bot to join + +### 2. Add your audio + +Replace the base64-encoded MP3 audio in the `src/base64/` folder: + +- `in_call_recording.txt` - Base64-encoded MP3 played when the bot starts recording + +To convert an audio file to base64: + +```bash +base64 -i your_audio.mp3 > src/base64/in_call_recording.txt +``` + +**Audio requirements:** + +- Must be MP3 format + +### 3. Install dependencies + +Open this directory in a terminal and run: + +```bash +npm install +``` + +### 4. Start the server + +```bash +npm run dev +``` + +This will start a server on port 4000. + +### 5. Create a bot + +In a new terminal, trigger bot creation: + +```bash +curl http://localhost:4000 +``` + +Or use the provided script: + +```bash +chmod +x run.sh +./run.sh +``` + +### 6. View the output + +The bot will join the meeting and play your audio clip when it starts recording. diff --git a/bot_output_audio/package.json b/bot_output_audio/package.json new file mode 100644 index 0000000..f196918 --- /dev/null +++ b/bot_output_audio/package.json @@ -0,0 +1,24 @@ +{ + "name": "bot_output_audio", + "version": "1.0.0", + "description": "Create a bot that outputs audio using base64-encoded MP3 data", + "main": "index.ts", + "scripts": { + "dev": "ts-node src/index.ts" + }, + "author": "Gerry Saporito", + "license": "MIT", + "devDependencies": { + "@types/is-base64": "^1.1.3", + "@types/node": "^24.10.1", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" + }, + "dependencies": { + "dotenv": "^17.2.3", + "file-type": "^21.1.1", + "http": "^0.0.1-security", + "is-base64": "^1.1.0", + "zod": "^4.1.13" + } +} diff --git a/bot_output_audio/run.sh b/bot_output_audio/run.sh new file mode 100755 index 0000000..bf79509 --- /dev/null +++ b/bot_output_audio/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +curl http://localhost:4000 diff --git a/bot_output_audio/src/base64/in_call_recording.txt b/bot_output_audio/src/base64/in_call_recording.txt new file mode 100644 index 0000000..04aaa82 --- /dev/null +++ b/bot_output_audio/src/base64/in_call_recording.txt @@ -0,0 +1 @@ +SUQzAwAAAAAea1RSQ0sAAAAFAAAAMS8xAFRJVDIAAAAUAAAAMTAxc291bmRib2FyZHMuY29tAFRYWFgAAAAbAAAAYXV0aG9yADEwMXNvdW5kYm9hcmRzLmNvbQBUUEUyAAAAFAAAADEwMXNvdW5kYm9hcmRzLmNvbQBUQUxCAAAAFAAAADEwMXNvdW5kYm9hcmRzLmNvbQBUWFhYAAAAHQAAAGdyb3VwaW5nADEwMXNvdW5kYm9hcmRzLmNvbQBUQ09NAAAAFAAAADEwMXNvdW5kYm9hcmRzLmNvbQBUWFhYAAAAGQAAAHllYXIAMTAxc291bmRib2FyZHMuY29tAFRQRTEAAAAUAAAAMTAxc291bmRib2FyZHMuY29tAFRYWFgAAAAcAAAAY29tbWVudAAxMDFzb3VuZGJvYXJkcy5jb20AVENPTgAAABQAAAAxMDFzb3VuZGJvYXJkcy5jb20AVENPUAAAABQAAAAxMDFzb3VuZGJvYXJkcy5jb20AVFhYWAAAACAAAABkZXNjcmlwdGlvbgAxMDFzb3VuZGJvYXJkcy5jb20AVFhYWAAAAB0AAABzeW5vcHNpcwAxMDFzb3VuZGJvYXJkcy5jb20AVFhYWAAAABkAAABzaG93ADEwMXNvdW5kYm9hcmRzLmNvbQBUWFhYAAAAHwAAAGVwaXNvZGVfaWQAMTAxc291bmRib2FyZHMuY29tAFRYWFgAAAAcAAAAbmV0d29yawAxMDFzb3VuZGJvYXJkcy5jb20AVFhYWAAAABkAAABVU0xUADEwMXNvdW5kYm9hcmRzLmNvbQBUU1NFAAAADwAAAExhdmY1OC4xMi4xMDAAQVBJQwAADOIAAABpbWFnZS9wbmcAA0FsYnVtIGNvdmVyAIlQTkcNChoKAAAADUlIRFIAAAEsAAABLAgDAAAATqN+RwAAAIFQTFRF1uj10ePzKCwtKCsuxtjoSE5SlaGqMzc5scHOLkdpkp6pZ3F37monUlpfp7XCh5OdvMzalKm/CAsP45d0fYiQPUNGnau2TWSDcnyEXWVrssbZOFFybIOdU1xlfoiRq7rFxNbl1szN7HI03Lany9zptcXQLjQ6wNDeFRkd4Z+A1dTaGRXGBgAADARJREFUeNrs3cuunSAUBuCNGwqRcBmA0Xmbvv8bthxB5Oa2nbX+f5oe40k7+KLA8rJ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 \ No newline at end of file diff --git a/bot_output_audio/src/bot_output_audio.ts b/bot_output_audio/src/bot_output_audio.ts new file mode 100644 index 0000000..b9328f1 --- /dev/null +++ b/bot_output_audio/src/bot_output_audio.ts @@ -0,0 +1,89 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { fileTypeFromBuffer } from "file-type"; +import isBase64 from "is-base64"; +import { z } from "zod"; +import { env } from "./config/env"; + +/** + * Create a bot that outputs audio using base64-encoded MP3 data. + */ +export async function bot_output_audio() { + const base64_dir = resolve("src", "base64"); + const BASE64_IN_CALL_RECORDING = await import_base64({ path_to_file: resolve(base64_dir, "in_call_recording.txt") }); + + if (!BASE64_IN_CALL_RECORDING) { + throw new Error("No base64 data found."); + } + + const body: Record = { + meeting_url: env.MEETING_URL, + recording_config: { + start_recording_on: "participant_join", + }, + }; + if (BASE64_IN_CALL_RECORDING) { + if (!body.automatic_audio_output) { + body.automatic_audio_output = {}; + } + body.automatic_audio_output.in_call_recording = { + data: { + kind: "mp3", + b64_data: BASE64_IN_CALL_RECORDING, + }, + }; + } + + const response = await fetch(`https://${env.RECALL_REGION}.recall.ai/api/v1/bot`, { + method: "POST", + headers: { + "Authorization": `${env.RECALL_API_KEY}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error(`Failed to create bot output audio: ${await response.text()}`); + } + + const bot = await response.json(); + console.log(`Created bot: ${JSON.stringify(bot)}`); + return bot; +} + +/** + * Validate base64 data is a valid MP3. + * Throws if base64 data isn't valid. + */ +async function validate_base64_mp3(args: { base64: string }) { + const { base64 } = z.object({ base64: z.string() }).parse(args); + + const buffer = Buffer.from(base64, "base64"); + + if (!isBase64(base64, { allowMime: false })) { + throw new Error("Base64 data is not valid."); + } + if (buffer.length === 0) { + throw new Error("Base64 data is empty."); + } + const type = await fileTypeFromBuffer(buffer); + if (type?.mime !== "audio/mpeg") { + throw new Error(`Base64 data is not an MP3. Received '${type?.mime}'.`); + } +} + +/** + * Import the base64 MP3 audio. + * Throws if base64 data isn't valid. + */ +async function import_base64(args: { path_to_file: string }) { + const { path_to_file } = z.object({ path_to_file: z.string() }).parse(args); + const base64 = readFileSync(path_to_file, "utf8").trim(); + try { + await validate_base64_mp3({ base64 }); + return base64; + } catch (error) { + throw new Error(`Failed to import base64: ${error instanceof Error ? error.message : String(error)} Path: ${args.path_to_file}`); + } +} diff --git a/bot_output_audio/src/config/env.ts b/bot_output_audio/src/config/env.ts new file mode 100644 index 0000000..9611b67 --- /dev/null +++ b/bot_output_audio/src/config/env.ts @@ -0,0 +1,6 @@ +import dotenv from "dotenv"; +import { EnvSchema } from "../schemas/EnvSchema"; + +dotenv.config(); + +export const env = EnvSchema.parse(process.env); diff --git a/bot_output_audio/src/index.ts b/bot_output_audio/src/index.ts new file mode 100644 index 0000000..bdb5bb5 --- /dev/null +++ b/bot_output_audio/src/index.ts @@ -0,0 +1,29 @@ +import http from "http"; +import { bot_output_audio } from "./bot_output_audio"; +import { env } from "./config/env"; + +const server = http.createServer(); + +/** + * HTTP server for handling HTTP requests. + */ +server.on("request", async (req, res) => { + try { + const bot = await bot_output_audio(); + + console.log(`Created bot: ${req.method} ${req.url}`); + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify(bot)); + } catch (error) { + console.error(`Error creating bot: ${req.method} ${req.url}`, error); + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) })); + } +}); + +/** + * Start the server. + */ +server.listen(env.PORT, "0.0.0.0", () => { + console.log(`Server is running on port ${env.PORT}`); +}); diff --git a/bot_output_audio/src/schemas/EnvSchema.ts b/bot_output_audio/src/schemas/EnvSchema.ts new file mode 100644 index 0000000..440e3cb --- /dev/null +++ b/bot_output_audio/src/schemas/EnvSchema.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; + +export const EnvSchema = z.object({ + PORT: z.string().transform((val) => parseInt(val)).default(4000), + RECALL_REGION: z.string(), + RECALL_API_KEY: z.string(), + MEETING_URL: z.string(), +}); diff --git a/bot_output_audio/tsconfig.json b/bot_output_audio/tsconfig.json new file mode 100644 index 0000000..3332414 --- /dev/null +++ b/bot_output_audio/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "sourceMap": true + }, + "include": ["src"] +} diff --git a/bot_output_audio/types/is-base64.d.ts b/bot_output_audio/types/is-base64.d.ts new file mode 100644 index 0000000..067e602 --- /dev/null +++ b/bot_output_audio/types/is-base64.d.ts @@ -0,0 +1,10 @@ +declare module "is-base64" { + interface IsBase64Options { + allowMime?: boolean; + allowEmpty?: boolean; + } + + function isBase64(value: string, options?: IsBase64Options): boolean; + + export default isBase64; +} diff --git a/bot_output_image/src/bot_output_image.ts b/bot_output_image/src/bot_output_image.ts index 0aa0712..793b943 100644 --- a/bot_output_image/src/bot_output_image.ts +++ b/bot_output_image/src/bot_output_image.ts @@ -13,25 +13,41 @@ export async function bot_output_image() { const BASE64_IN_CALL_NOT_RECORDING = await import_base64({ path_to_file: resolve(base64_dir, "in_call_not_recording.txt") }); const BASE64_IN_CALL_RECORDING = await import_base64({ path_to_file: resolve(base64_dir, "in_call_recording.txt") }); + if (!BASE64_IN_CALL_NOT_RECORDING && !BASE64_IN_CALL_RECORDING) { + throw new Error("No base64 data found."); + } + + const body: Record = { + "meeting_url": env.MEETING_URL, + }; + if (BASE64_IN_CALL_NOT_RECORDING) { + if (!body.automatic_video_output) { + body.automatic_video_output = {}; + } + body.automatic_video_output.in_call_not_recording = { + "kind": "jpeg", + "b64_data": BASE64_IN_CALL_NOT_RECORDING, + }; + } + if (BASE64_IN_CALL_RECORDING) { + if (!body.automatic_video_output) { + body.automatic_video_output = {}; + } + body.automatic_video_output.in_call_recording = { + data: { + "kind": "jpeg", + "b64_data": BASE64_IN_CALL_RECORDING, + }, + }; + } + const response = await fetch(`https://${env.RECALL_REGION}.recall.ai/api/v1/bot`, { method: "POST", headers: { "Authorization": `${env.RECALL_API_KEY}`, "Content-Type": "application/json", }, - body: JSON.stringify({ - "meeting_url": env.MEETING_URL, - "automatic_video_output": { - "in_call_not_recording": { - "kind": "jpeg", - "b64_data": BASE64_IN_CALL_NOT_RECORDING, - }, - "in_call_recording": { - "kind": "jpeg", - "b64_data": BASE64_IN_CALL_RECORDING, - }, - }, - }), + body: JSON.stringify(body), }); if (!response.ok) { diff --git a/package-lock.json b/package-lock.json index ab01496..16e2ffa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2136,6 +2136,416 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "bot_output_audio": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "dotenv": "^17.2.3", + "file-type": "^21.1.1", + "http": "^0.0.1-security", + "is-base64": "^1.1.0", + "zod": "^4.1.13" + }, + "devDependencies": { + "@types/is-base64": "^1.1.3", + "@types/node": "^24.10.1", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" + } + }, + "bot_output_audio/node_modules/@types/is-base64": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/is-base64/-/is-base64-1.1.3.tgz", + "integrity": "sha512-8h40c+MFeMKhEw8Ebckd11MEt9sngs4AAkvcZVfDYOFDd7FeTD80pTfm3uvepbWcld1zVkHW+WA6b7UaHAOU/w==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "bot_output_audio/node_modules/@types/node/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "bot_output_audio/node_modules/file-type": { + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.1.tgz", + "integrity": "sha512-SrzXX46I/zsRDjTb82eucsGg0ODq2NpGDp4HcsFKApPy8P8vACjpJRDoGGMfEzhFC0ry61ajd7f72J3603anBA==", + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "bot_output_audio/node_modules/file-type/node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "bot_output_audio/node_modules/file-type/node_modules/@tokenizer/inflate/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "bot_output_audio/node_modules/file-type/node_modules/@tokenizer/inflate/node_modules/debug/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "bot_output_audio/node_modules/file-type/node_modules/strtok3": { + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz", + "integrity": "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "bot_output_audio/node_modules/file-type/node_modules/strtok3/node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "bot_output_audio/node_modules/file-type/node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "bot_output_audio/node_modules/file-type/node_modules/token-types/node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "bot_output_audio/node_modules/file-type/node_modules/token-types/node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "bot_output_audio/node_modules/file-type/node_modules/token-types/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "bot_output_audio/node_modules/file-type/node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "bot_output_audio/node_modules/http": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz", + "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g==" + }, + "bot_output_audio/node_modules/is-base64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-base64/-/is-base64-1.1.0.tgz", + "integrity": "sha512-Nlhg7Z2dVC4/PTvIFkgVVNvPHSO2eR/Yd0XzhGiXCXEvWnptXlXa/clQ8aePPiMuxEGcWfzWbGw2Fe3d+Y3v1g==", + "license": "MIT", + "bin": { + "is_base64": "bin/is-base64", + "is-base64": "bin/is-base64" + } + }, + "bot_output_audio/node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "bot_output_audio/node_modules/ts-node/node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "bot_output_audio/node_modules/ts-node/node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "bot_output_audio/node_modules/ts-node/node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "bot_output_audio/node_modules/ts-node/node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "bot_output_audio/node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "bot_output_audio/node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "bot_output_audio/node_modules/ts-node/node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "bot_output_audio/node_modules/ts-node/node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "bot_output_audio/node_modules/ts-node/node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "bot_output_audio/node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "bot_output_image": { "version": "1.0.0", "license": "MIT", @@ -15120,6 +15530,10 @@ "resolved": "bot_mixed_video_stream_realtime_rtmp_mux", "link": true }, + "node_modules/bot_output_audio": { + "resolved": "bot_output_audio", + "link": true + }, "node_modules/bot_output_image": { "resolved": "bot_output_image", "link": true