#!/usr/bin/env bun import { $ } from "bun"; // Parse ~/.env for ElevenLabs credentials const envText = await Bun.file(`${process.env.HOME}/.env`).text(); const env: Record = {}; for (const line of envText.split("\n")) { const match = line.match(/^([^#=]+)=(.*)$/); if (match) env[match[1].trim()] = match[2].trim(); } const apiKey = env.ELEVENLABS_API_KEY; const voiceId = env.ELEVENLABS_VOICE_ID; if (!apiKey || !voiceId) { console.error("Missing ELEVENLABS_API_KEY or ELEVENLABS_VOICE_ID in ~/.env"); process.exit(1); } // Grab text from argv (everything after the script name) const text = Bun.argv.slice(2).join(" "); if (!text) { console.error("Usage: speak "); process.exit(1); } // Call ElevenLabs TTS API const response = await fetch( `https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, { method: "POST", headers: { "xi-api-key": apiKey, "Content-Type": "application/json", }, body: JSON.stringify({ text }), } ); if (!response.ok) { console.error(`ElevenLabs API error: ${response.status} ${response.statusText}`); process.exit(1); } // Write MP3 to temp file, play it, clean up const tmpFile = `${Bun.env.TMPDIR || "/tmp"}/speak-${Date.now()}.mp3`; await Bun.write(tmpFile, response); try { await $`afplay ${tmpFile}`.quiet(); } finally { await $`rm ${tmpFile}`.quiet(); }