{"_id":"@alien-lobster-buffet/tts-conductor-fal","name":"@alien-lobster-buffet/tts-conductor-fal","dist-tags":{"alpha":"0.2.0-alpha.0","latest":"0.2.0-alpha.0"},"versions":{"0.2.0-alpha.0":{"name":"@alien-lobster-buffet/tts-conductor-fal","version":"0.2.0-alpha.0","description":"fal.ai provider bindings for the TTS Conductor ecosystem","keywords":["tts","fal","fal-ai","provider"],"license":"MIT","author":"Cole Reed <alienlobsterbuffet.dev@gmail.com>","homepage":"https://github.com/ichabodcole/tts-conductor#readme","bugs":{"url":"https://github.com/ichabodcole/tts-conductor/issues"},"repository":{"type":"git","url":"git+https://github.com/ichabodcole/tts-conductor.git","directory":"packages/tts-provider-fal"},"type":"module","exports":{".":{"import":"./dist/index.mjs","types":"./dist/index.d.mts"}},"main":"./dist/index.mjs","types":"./dist/index.d.mts","engines":{"node":">=18"},"publishConfig":{"access":"public"},"scripts":{"build":"tsdown","clean":"tsdown --clean","dev":"tsdown --watch","prepublishOnly":"tsdown","test":"vitest --run --config ../../vitest.config.ts","typecheck":"tsc --noEmit"},"peerDependencies":{"@alien-lobster-buffet/tts-conductor-core":"^0.2.0-alpha.1"},"dependencies":{"@fal-ai/client":"^1.10.1"},"devDependencies":{"@alien-lobster-buffet/tts-conductor-core":"^0.2.0-alpha.1"},"_id":"@alien-lobster-buffet/tts-conductor-fal@0.2.0-alpha.0","_integrity":"sha512-ZK6riKgquGZBqpfWvWH0eaSKSMOMZz1GgwGQ7dLHZxpDkYGGACC0CfH4GpPvtXKq8Gs3UFssnbd4tInK/cKwuQ==","_nodeVersion":"24.3.0","_npmVersion":"10.8.3","shasum":"4a0bb74c9fd8b0d03a0e3a411a7ad45078689f5f","dist":{"integrity":"sha512-ZK6riKgquGZBqpfWvWH0eaSKSMOMZz1GgwGQ7dLHZxpDkYGGACC0CfH4GpPvtXKq8Gs3UFssnbd4tInK/cKwuQ==","shasum":"4a0bb74c9fd8b0d03a0e3a411a7ad45078689f5f","tarball":"https://registry.npmjs.org/@alien-lobster-buffet/tts-conductor-fal/-/tts-conductor-fal-0.2.0-alpha.0.tgz","fileCount":6,"unpackedSize":50539,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDywfJKO8cBq1mIxTsd8Bc22IhAIh/wZxPiPDMzR23O8AiBHGxZ8XwgT013e+FROGjeXvAtVyoQrbaTh5J4NccJY1w=="}]},"_npmUser":{"name":"ichabodcole","email":"ichabodcole@gmail.com"},"directories":{},"maintainers":[{"name":"ichabodcole","email":"ichabodcole@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tts-conductor-fal_0.2.0-alpha.0_1780428264495_0.46908272531370776"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-02T19:24:24.323Z","0.2.0-alpha.0":"2026-06-02T19:24:24.797Z","modified":"2026-06-02T19:24:25.043Z"},"maintainers":[{"name":"ichabodcole","email":"ichabodcole@gmail.com"}],"description":"fal.ai provider bindings for the TTS Conductor ecosystem","homepage":"https://github.com/ichabodcole/tts-conductor#readme","keywords":["tts","fal","fal-ai","provider"],"repository":{"type":"git","url":"git+https://github.com/ichabodcole/tts-conductor.git","directory":"packages/tts-provider-fal"},"author":"Cole Reed <alienlobsterbuffet.dev@gmail.com>","bugs":{"url":"https://github.com/ichabodcole/tts-conductor/issues"},"license":"MIT","readme":"# @alien-lobster-buffet/tts-conductor-fal\n\n[fal.ai](https://fal.ai) provider bindings for the\n[TTS Conductor](https://github.com/ichabodcole/tts-conductor) ecosystem.\n\nfal.ai is a **gateway fronting many TTS engines**, each with its own input and\nvoice schema. This package models that as a single `fal` provider id that you\nparameterize with a `model` at construction — so the marketplace lives at\nconstruction time while each provider _instance_ is still one engine, fully\nhonoring the conductor's `TtsProvider` contract (one `caps`, one `generate`, one\noptional `voiceCatalog`).\n\n## Install\n\n```sh\nnpm install @alien-lobster-buffet/tts-conductor-core @alien-lobster-buffet/tts-conductor-fal\n```\n\nRequires a fal API key (`FAL_KEY`).\n\n## Quickstart\n\n```ts\nimport { createTtsConductor } from \"@alien-lobster-buffet/tts-conductor-core\";\nimport { falProviderFactory } from \"@alien-lobster-buffet/tts-conductor-fal\";\n\nconst conductor = createTtsConductor({ pauseTable: {}, maxPauseSeconds: 30 });\nconductor.registerProvider(falProviderFactory);\n\nconst provider = conductor.createProvider(\"fal\", {\n  apiKey: process.env.FAL_KEY!,\n  model: \"fal-ai/minimax/speech-02-hd\",\n  voice: { kind: \"preset\", id: \"Wise_Woman\" },\n});\n\nconst { audio, duration, providerMeta } = await conductor.generateFull(\n  \"Hello there. [PAUSE:2s] Welcome.\",\n  provider,\n);\n```\n\n## Starter models\n\n| `model`                            | text key | voice mechanism                                                                  | duration               |\n| ---------------------------------- | -------- | -------------------------------------------------------------------------------- | ---------------------- |\n| `fal-ai/minimax/speech-02-hd`      | `text`   | `{ kind: 'preset', id }` → `voice_setting` object                                | native (`duration_ms`) |\n| `fal-ai/gemini-3.1-flash-tts`      | `prompt` | `{ kind: 'preset', id }` (30-voice enum) or `{ kind: 'multiSpeaker', speakers }` | ffprobe                |\n| `fal-ai/chatterbox/text-to-speech` | `text`   | `{ kind: 'clone', audioUrl }` (no preset voices)                                 | ffprobe                |\n| `fal-ai/elevenlabs/tts/turbo-v2.5` | `text`   | `{ kind: 'preset', id }`                                                         | ffprobe                |\n\nSwitch model and voice at construction, or vary them per call:\n\n```ts\nawait provider.generate(chunk, {\n  overrides: {\n    voice: { kind: \"preset\", id: \"Aria\" },\n    params: { stability: 0.3 },\n  },\n});\n```\n\n`params` carries the model's scalar knobs (e.g. minimax `voiceSetting`, gemini\n`styleInstructions` / `temperature`, chatterbox `exaggeration` / `cfg`, 11labs\n`stability` / `similarity_boost` / `speed`). Each descriptor forwards only the\nkeys it recognizes.\n\n## Voice discovery\n\nOnly `fal-ai/gemini-3.1-flash-tts` exposes a `voiceCatalog` — its 30 preset\nvoices are the one schema-enumerable set. minimax and elevenlabs-on-fal take a\nvoice id as a free string (pass a known id), and chatterbox clones from\n`audio_url`; all three leave `voiceCatalog` undefined.\n\n```ts\nif (provider.voiceCatalog) {\n  const voices = await provider.voiceCatalog.listVoices({ search: \"kore\" });\n}\n```\n\n> Gemini voices carry no per-voice language metadata (the model is multilingual\n> via the `languageCode` param), so `listVoices({ language })` filters them all\n> out. Filter by `search` instead.\n\n## Cost reconciliation\n\nfal bills asynchronously. Each chunk's fal `request_id` is surfaced on the\ngeneration result via core's generic `providerMeta` channel — collect them from\nthe final result and reconcile against fal's billing-events API:\n\n```ts\nconst result = await conductor.generateFull(text, provider);\nconst requestIds =\n  result.providerMeta?.map((m) => m?.request_id).filter(Boolean) ?? [];\n```\n\n## Notes\n\n- **Multi-speaker (gemini) is single-chunk / short-form for now.** fal needs the\n  full `speakers[]` on every request and the prompt's `Alias:` line-prefixes to\n  survive chunking; long multi-speaker scripts aren't supported yet.\n- fal engines don't render SSML breaks — inter-chunk pauses become stitched\n  silence segments via the core orchestrator.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-eeb802817bf15f28f84063f5958f4577"}