{"_id":"@confiture-ai/gradium-sdk-js","_rev":"2-e3f5f43e8e8757dd3a33b2ffd1e19b8e","name":"@confiture-ai/gradium-sdk-js","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@confiture-ai/gradium-sdk-js","version":"0.1.0","keywords":["gradium","tts","stt","text-to-speech","speech-to-text","ai","voice","audio","streaming"],"author":{"name":"Majdi Toumi","email":"majdi@confiture.ai"},"license":"MIT","_id":"@confiture-ai/gradium-sdk-js@0.1.0","maintainers":[{"name":"confiture","email":"majdi@confiture.ai"}],"homepage":"https://github.com/confiture-ai/gradium-sdk-js#readme","bugs":{"url":"https://github.com/confiture-ai/gradium-sdk-js/issues"},"dist":{"shasum":"a65d34660932ce8e5e680bcd81350255b8e714cb","tarball":"https://registry.npmjs.org/@confiture-ai/gradium-sdk-js/-/gradium-sdk-js-0.1.0.tgz","fileCount":38,"integrity":"sha512-/VK748rWpeH9ayRTjkfvPSkC7JLBKvzF9xXjFSSppszJqwRTYdOFGyD2oxqeRgRItScWflTEXUVObF0TETnDhw==","signatures":[{"sig":"MEYCIQDbh7gkMgGd9kKWxcTBhUg4X+VBKyze6aRdfCQoPPfh3gIhAJRUfxMn0/XSas1DUIWbrfu5Py4V14iVMEE+e87L2CI3","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":143283},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"b0c8b0b8936b3563c7f3b2ed579f2fa2fa15423b","scripts":{"dev":"bun --watch src/index.ts","lint":"biome check .","test":"bun test","build":"bun build ./src/index.ts --outdir ./dist --target node && tsc --emitDeclarationOnly","clean":"rm -rf dist","format":"biome format --write .","prepare":"lefthook install","lint:fix":"biome check --write .","typecheck":"tsc --noEmit","test:watch":"bun test --watch","test:coverage":"bun test --coverage","prepublishOnly":"bun run build"},"_npmUser":{"name":"confiture","email":"majdi@confiture.ai"},"repository":{"url":"git+https://github.com/confiture-ai/gradium-sdk-js.git","type":"git"},"_npmVersion":"10.8.2","description":"Unofficial TypeScript SDK for the Gradium API","directories":{},"_nodeVersion":"20.19.6","_hasShrinkwrap":false,"devDependencies":{"lefthook":"^1.11.13","ultracite":"^6.3.9","@types/bun":"latest","typescript":"^5.3.0","@biomejs/biome":"^2.3.8"},"_npmOperationalInternal":{"tmp":"tmp/gradium-sdk-js_0.1.0_1765235007929_0.8531990566050809","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@confiture-ai/gradium-sdk-js","version":"0.1.1","description":"Unofficial TypeScript SDK for the Gradium API","author":{"name":"Majdi Toumi","email":"majdi@confiture.ai"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","require":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"bun build ./src/index.ts --outdir ./dist --target node && tsc --emitDeclarationOnly","dev":"bun --watch src/index.ts","test":"bun test","test:watch":"bun test --watch","test:coverage":"bun test --coverage","typecheck":"tsc --noEmit","lint":"biome check .","lint:fix":"biome check --write .","format":"biome format --write .","clean":"rm -rf dist","prepare":"lefthook install","prepublishOnly":"bun run build"},"keywords":["gradium","tts","stt","text-to-speech","speech-to-text","ai","voice","audio","streaming"],"devDependencies":{"@biomejs/biome":"^2.3.8","@types/bun":"latest","lefthook":"^1.11.13","typescript":"^5.3.0","ultracite":"^6.3.9"},"engines":{"node":">=24"},"repository":{"type":"git","url":"git+https://github.com/confiture-ai/gradium-sdk-js.git"},"homepage":"https://github.com/confiture-ai/gradium-sdk-js#readme","bugs":{"url":"https://github.com/confiture-ai/gradium-sdk-js/issues"},"_id":"@confiture-ai/gradium-sdk-js@0.1.1","gitHead":"4cb2c935eb186527b3d4f716fa02db02e3269ac1","_nodeVersion":"20.19.6","_npmVersion":"10.8.2","dist":{"integrity":"sha512-AuSdl1jbkh0VXOJkdOCpl7LHNLHJ0EUdLsQMk3USAsEtZWh/135jT7eitw/ZIz0Xzfz2AMO3ETKZvaFYjRQO6g==","shasum":"33c75b947c45371d0bcc6299524e052db0ee5517","tarball":"https://registry.npmjs.org/@confiture-ai/gradium-sdk-js/-/gradium-sdk-js-0.1.1.tgz","fileCount":38,"unpackedSize":143376,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD2fHZFDfT02Av/ki7YhwwU2M4JWXVIFCwrfbr3P8qe1wIhAMubq2ZgJl+pe17+aSgY7cNqak9NigC3RkmWR9vBKS1h"}]},"_npmUser":{"name":"confiture","email":"majdi@confiture.ai"},"directories":{},"maintainers":[{"name":"confiture","email":"majdi@confiture.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gradium-sdk-js_0.1.1_1765370207509_0.4262573473263054"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-08T23:03:27.873Z","modified":"2025-12-10T12:36:47.847Z","0.1.0":"2025-12-08T23:03:28.059Z","0.1.1":"2025-12-10T12:36:47.659Z"},"bugs":{"url":"https://github.com/confiture-ai/gradium-sdk-js/issues"},"author":{"name":"Majdi Toumi","email":"majdi@confiture.ai"},"license":"MIT","homepage":"https://github.com/confiture-ai/gradium-sdk-js#readme","keywords":["gradium","tts","stt","text-to-speech","speech-to-text","ai","voice","audio","streaming"],"repository":{"type":"git","url":"git+https://github.com/confiture-ai/gradium-sdk-js.git"},"description":"Unofficial TypeScript SDK for the Gradium API","maintainers":[{"name":"confiture","email":"majdi@confiture.ai"}],"readme":"# Gradium AI SDK (JavaScript / TypeScript)\n\nUnofficial TypeScript SDK for the [Gradium API](https://gradium.ai) — low-latency, high-quality Text-to-Speech and Speech-to-Text services.\n\n## Features\n\n- 🎙️ **Text-to-Speech (TTS)** — Convert text to natural-sounding speech\n- 🎧 **Speech-to-Text (STT)** — Transcribe audio with real-time streaming\n- 🗣️ **Voice Cloning** — Create custom voices from audio samples\n- 🌍 **Multilingual** — Support for English, French, German, Spanish, and Portuguese\n- ⚡ **Low Latency** — Sub-300ms time-to-first-token\n- 🔄 **Streaming** — Real-time audio streaming via WebSockets\n\n## Installation\n\n```bash\nbun add @confiture-ai/gradium-sdk-js\n# or\nnpm install @confiture-ai/gradium-sdk-js\n# or\npnpm add @confiture-ai/gradium-sdk-js\n```\n\n## Quick Start\n\n```typescript\nimport Gradium from '@confiture-ai/gradium-sdk-js';\n\nconst client = new Gradium({\n  apiKey: process.env['GRADIUM_API_KEY'], // This is the default and can be omitted\n});\n\n// Text-to-Speech\nconst result = await client.tts.create({\n  voice_id: 'YTpq7expH9539ERJ', // Emma's voice\n  output_format: 'wav',\n  text: 'Hello, world! Welcome to Gradium.',\n});\n\nawait Bun.write('output.wav', result.raw_data);\n```\n\n## Configuration\n\n### Client Options\n\n```typescript\nconst client = new Gradium({\n  apiKey: 'gd_your_api_key',  // Required (or set GRADIUM_API_KEY env var)\n  region: 'eu',               // 'eu' or 'us' (default: 'eu')\n  baseURL: 'https://...',     // Custom API URL (optional)\n  timeout: 30000,             // Request timeout in ms (default: 30000)\n});\n```\n\n### Environment Variables\n\n```bash\n# bash/zsh\nexport GRADIUM_API_KEY=gd_your_api_key_here\n\n# fish\nset -x GRADIUM_API_KEY gd_your_api_key_here\n```\n\n## Text-to-Speech (TTS)\n\n### Basic Usage\n\n```typescript\nconst result = await client.tts.create({\n  voice_id: 'YTpq7expH9539ERJ',\n  output_format: 'wav',\n  text: 'I love confiture!',\n});\n\nconsole.log(`Sample rate: ${result.sample_rate}`);\nconsole.log(`Request ID: ${result.request_id}`);\nawait Bun.write('output.wav', result.raw_data);\n```\n\n### Streaming TTS\n\n```typescript\nconst stream = await client.tts.stream({\n  voice_id: 'YTpq7expH9539ERJ',\n  output_format: 'pcm',\n});\n\nawait stream.waitReady();\nstream.sendText('Hello, this is streamed audio.');\nstream.sendEndOfStream();\n\nfor await (const chunk of stream) {\n  console.log(`Received ${chunk.length} bytes`);\n  // Process audio chunk...\n}\n```\n\n### Streaming with Text Generator\n\n```typescript\nasync function* textGenerator() {\n  yield 'Hello, ';\n  yield 'this is ';\n  yield 'streamed ';\n  yield 'text.';\n}\n\nconst stream = await client.tts.streamText(\n  { voice_id: 'YTpq7expH9539ERJ', output_format: 'pcm' },\n  textGenerator()\n);\n\nfor await (const chunk of stream) {\n  // Process audio chunk...\n}\n```\n\n### Speed Control\n\n```typescript\n// Slower speech (positive padding_bonus: 0.1 to 4.0)\nconst slower = await client.tts.create({\n  voice_id: 'YTpq7expH9539ERJ',\n  output_format: 'wav',\n  text: 'This is slower speech.',\n  json_config: { padding_bonus: 2.0 },\n});\n\n// Faster speech (negative padding_bonus: -4.0 to -0.1)\nconst faster = await client.tts.create({\n  voice_id: 'YTpq7expH9539ERJ',\n  output_format: 'wav',\n  text: 'This is faster speech.',\n  json_config: { padding_bonus: -2.0 },\n});\n```\n\n### Adding Breaks/Pauses\n\n```typescript\nconst result = await client.tts.create({\n  voice_id: 'YTpq7expH9539ERJ',\n  output_format: 'wav',\n  text: 'First sentence. <break time=\"1.5s\" /> Second sentence after a pause.',\n});\n```\n\n### Output Formats\n\n| Format | Description |\n|--------|-------------|\n| `wav` | Standard WAV file |\n| `pcm` | Raw PCM (48kHz, 16-bit, mono) |\n| `opus` | Opus codec |\n| `ulaw_8000` | μ-law 8kHz |\n| `alaw_8000` | A-law 8kHz |\n| `pcm_16000` | PCM 16kHz |\n| `pcm_24000` | PCM 24kHz |\n\n## Speech-to-Text (STT)\n\n### Basic Streaming\n\n```typescript\nconst stream = await client.stt.stream({\n  input_format: 'pcm',\n  model_name: 'default',\n});\n\nconst readyInfo = await stream.waitReady();\nconsole.log(`Sample rate: ${readyInfo.sample_rate}`);\n\n// Send audio chunks\nstream.sendAudio(audioChunk1);\nstream.sendAudio(audioChunk2);\nstream.sendEndOfStream();\n\n// Process transcription results\nfor await (const result of stream) {\n  console.log(`${result.text} (at ${result.start_s}s)`);\n}\n```\n\n### Transcribe Complete Audio\n\n```typescript\nconst audioData = await Bun.file('audio.wav').arrayBuffer();\nconst text = await client.stt.transcribe(\n  { input_format: 'wav' },\n  new Uint8Array(audioData)\n);\n\nconsole.log(`Transcription: ${text}`);\n```\n\n### Voice Activity Detection (VAD)\n\n```typescript\nconst stream = await client.stt.stream({ input_format: 'pcm' });\nawait stream.waitReady();\n\n// Monitor VAD for turn-taking\nfor await (const vad of stream.iterVAD()) {\n  const inactivityProb = vad.vad[2]?.inactivity_prob ?? 0;\n  if (inactivityProb > 0.8) {\n    console.log('Speaker likely finished');\n  }\n}\n```\n\n### Audio Format Requirements (PCM)\n\n- **Sample Rate**: 24000 Hz (24kHz)\n- **Bit Depth**: 16-bit signed integer (little-endian)\n- **Channels**: Mono\n- **Chunk Size**: 1920 samples (80ms) recommended\n\n## Voices\n\n### List Voices\n\n```typescript\nconst voices = await client.voices.list();\nconsole.log(voices);\n\n// Include catalog voices\nconst allVoices = await client.voices.list({\n  include_catalog: true,\n  limit: 50,\n});\n```\n\n### Get Voice\n\n```typescript\nconst voice = await client.voices.get('voice_uid_here');\nconsole.log(voice.name);\n```\n\n### Create Voice\n\n```typescript\n// From file path\nconst voice = await client.voices.create({\n  audio_file: './my_voice_sample.wav',\n  name: 'My Custom Voice',\n  description: 'A voice created from my recording',\n  language: 'en',\n});\n\n// From Blob\nconst blob = new Blob([audioData], { type: 'audio/wav' });\nconst voice = await client.voices.create({\n  audio_file: blob,\n  name: 'My Custom Voice',\n});\n```\n\n### Update Voice\n\n```typescript\nawait client.voices.update('voice_uid_here', {\n  name: 'Updated Name',\n  description: 'Updated description',\n});\n```\n\n### Delete Voice\n\n```typescript\nawait client.voices.delete('voice_uid_here');\n```\n\n## Credit Management\n\n```typescript\nconst credits = await client.credits.get();\nconsole.log(`Remaining: ${credits.remaining_credits}/${credits.allocated_credits}`);\nconsole.log(`Plan: ${credits.plan_name}`);\nconsole.log(`Next rollover: ${credits.next_rollover_date}`);\n```\n\n## Available Voices\n\n### Flagship Voices\n\n| Name | Voice ID | Language | Gender | Description |\n|------|----------|----------|--------|-------------|\n| Emma | `YTpq7expH9539ERJ` | en-US | Feminine | Pleasant and smooth, ready to assist |\n| Kent | `LFZvm12tW_z0xfGo` | en-US | Masculine | Relaxed and authentic American |\n| Sydney | `jtEKaLYNn6iif5PR` | en-US | Feminine | Joyful and airy |\n| John | `KWJiFWu2O9nMPYcR` | en-US | Masculine | Warm, low-pitched broadcaster |\n| Eva | `ubuXFxVQwVYnZQhy` | en-GB | Feminine | Joyful and dynamic British |\n| Jack | `m86j6D7UZpGzHsNu` | en-GB | Masculine | Pleasant British |\n| Elise | `b35yykvVppLXyw_l` | fr-FR | Feminine | Warm French |\n| Leo | `axlOaUiFyOZhy4nv` | fr-FR | Masculine | Warm French |\n| Mia | `-uP9MuGtBqAvEyxI` | de-DE | Feminine | Joyful German |\n| Maximilian | `0y1VZjPabOBU3rWy` | de-DE | Masculine | Warm German |\n| Valentina | `B36pbz5_UoWn4BDl` | es-MX | Feminine | Warm Mexican |\n| Sergio | `xu7iJ_fn2ElcWp2s` | es-ES | Masculine | Warm Spanish |\n| Alice | `pYcGZz9VOo4n2ynh` | pt-BR | Feminine | Warm Brazilian |\n| Davi | `M-FvVo9c-jGR4PgP` | pt-BR | Masculine | Engaging Brazilian |\n\n> 💡 You can also create your own [custom voices](#voices).\n\n## Error Handling\n\n```typescript\nimport { \n  GradiumError,\n  AuthenticationError,\n  ValidationError,\n  RateLimitError,\n  WebSocketError \n} from '@confiture-ai/gradium-sdk-js';\n\ntry {\n  const result = await client.tts.create({ ... });\n} catch (error) {\n  if (error instanceof AuthenticationError) {\n    console.error('Invalid API key');\n  } else if (error instanceof ValidationError) {\n    console.error('Validation failed:', error.errors);\n  } else if (error instanceof RateLimitError) {\n    console.error(`Rate limited. Retry after ${error.retryAfter}s`);\n  } else if (error instanceof WebSocketError) {\n    console.error(`WebSocket error (${error.code}):`, error.message);\n  } else if (error instanceof GradiumError) {\n    console.error('Gradium error:', error.message);\n  }\n}\n```\n\n## TypeScript Support\n\nThe SDK is written in TypeScript and provides full type definitions:\n\n```typescript\nimport type {\n  Voice,\n  VoiceCreateParams,\n  TTSSetupParams,\n  TTSResult,\n  STTSetupParams,\n  CreditsSummary,\n} from '@confiture-ai/gradium-sdk-js';\n```\n\n## Testing\n\nRun the test suite with:\n\n```bash\nbun test\n```\n\n### Test Structure\n\nTests use mocked WebSocket and fetch — no real API calls are made:\n\n- **WebSocket mocking** — TTS/STT streams are fully simulated\n- **Fetch mocking** — REST API calls (voices, credits) use `spyOn(globalThis, \"fetch\")`\n\n### Creating Test Audio Files\n\nFor integration tests requiring real audio files:\n\n```bash\n# Using ffmpeg - creates a 0.1 second silent WAV\nffmpeg -f lavfi -i anullsrc=r=24000:cl=mono -t 0.1 -f wav test.wav\n```\n\n## License\n\nMIT\n\n---\n\nBuilt with love in Paris by [Majdi Toumi](https://majdi.im)\n","readmeFilename":"README.md"}