{"_id":"@aid-on/unisttp","name":"@aid-on/unisttp","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.1":{"name":"@aid-on/unisttp","version":"0.1.1","description":"Unified STT (Speech-to-Text) provider for Cloudflare Workers AI / Groq","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsc","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest"},"keywords":["stt","speech-to-text","whisper","cloudflare","groq","workers-ai"],"author":{"name":"Aid-On"},"license":"MIT","devDependencies":{"@cloudflare/workers-types":"^4.20241218.0","typescript":"^5.7.2"},"_id":"@aid-on/unisttp@0.1.1","_nodeVersion":"20.19.6","_npmVersion":"10.8.2","dist":{"integrity":"sha512-NnclcPkMuKB4wjwyhtdQNiErIZjh/z24uqyr6yeWax8ME/5s+NV7naFLEqDJRpQdkWAdUfrKMYYTeoiZVdykmw==","shasum":"a862b8c0f16807774bd7406ce95cac5670ee3df9","tarball":"https://registry.npmjs.org/@aid-on/unisttp/-/unisttp-0.1.1.tgz","fileCount":40,"unpackedSize":102845,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDfMl0lvqqC8MC/ntS0nUsA6X/bHSQre/sqLkXw9o6RXAiEA4/2cXlxfFmukWFsKJunYOU10V58ZkK161sBvGlSF9xY="}]},"_npmUser":{"name":"aid-on","email":"hiromi.motodera@aid-on.org"},"directories":{},"maintainers":[{"name":"aid-on","email":"hiromi.motodera@aid-on.org"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/unisttp_0.1.1_1771435133158_0.15409419861823426"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-18T17:18:53.029Z","0.1.1":"2026-02-18T17:18:53.299Z","modified":"2026-02-18T17:18:53.585Z"},"maintainers":[{"name":"aid-on","email":"hiromi.motodera@aid-on.org"}],"description":"Unified STT (Speech-to-Text) provider for Cloudflare Workers AI / Groq","keywords":["stt","speech-to-text","whisper","cloudflare","groq","workers-ai"],"author":{"name":"Aid-On"},"license":"MIT","readme":"# @aid-on/unisttp\n\n<div align=\"center\">\n\n[![npm version](https://img.shields.io/npm/v/@aid-on/unisttp.svg?style=flat-square&color=00DC82)](https://www.npmjs.com/package/@aid-on/unisttp)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.7-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)\n\n<br />\n\n<h3>\n<b>unisttp</b> - Unified Speech-to-Text Provider for the Edge\n</h3>\n\n<p align=\"center\">\n<b>One interface. Multiple STT providers.</b><br/>\nA unified Speech-to-Text abstraction for Cloudflare Workers AI and Groq, powered by the \"provider:model\" spec format.\n</p>\n\n<br/>\n\n[**日本語**](./README.ja.md) | **English**\n\n<br/>\n\n</div>\n\n## Why unisttp?\n\nSpeech-to-text in edge applications means dealing with multiple providers, each with their own API quirks. unisttp gives you a single, type-safe interface to all of them:\n\n- **One spec format** - `\"cloudflare:whisper-large-v3-turbo\"` or `\"groq:whisper-large-v3\"` -- that's it\n- **Automatic fallback chains** - If Cloudflare fails, try Groq. No manual error handling\n- **VAD filtering** - Filter out silence and noise at the provider level\n- **Zero runtime dependencies** - Pure `fetch`-based, runs anywhere\n- **Edge-native** - Built for Cloudflare Workers from day one\n\n## Installation\n\n```bash\nnpm install @aid-on/unisttp\n```\n\n## Quick Start\n\n```typescript\nimport { getSTTProvider } from \"@aid-on/unisttp\";\n\n// Create a provider using the \"provider:model\" spec format\nconst provider = getSTTProvider(\"cloudflare:whisper-large-v3-turbo\", {\n  cloudflareBinding: env.AI,\n});\n\n// Transcribe audio\nconst result = await provider.transcribe(audioBuffer, {\n  language: \"ja\",\n  vadFilter: true,\n});\n\nconsole.log(result.text);       // \"Hello, world\"\nconsole.log(result.language);   // \"en\"\nconsole.log(result.duration);   // 2.5\n```\n\n## STTSpec Format\n\nThe core concept is the **STTSpec** -- a simple `\"provider:model\"` string that uniquely identifies a provider and model combination:\n\n```\ncloudflare:whisper-large-v3-turbo\n^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^\nprovider   model\n```\n\n### Available Specs\n\n| Spec | Description | VAD | Languages |\n|------|-------------|-----|-----------|\n| `cloudflare:whisper-large-v3-turbo` | Fast, accurate multilingual STT with VAD | Yes | All |\n| `cloudflare:whisper-large-v3` | High accuracy multilingual STT | Yes | All |\n| `cloudflare:whisper` | Base Whisper model | No | All |\n| `cloudflare:whisper-tiny-en` | Fast English-only STT | No | English |\n| `groq:whisper-large-v3` | High accuracy STT via Groq API | No | All |\n| `groq:whisper-large-v3-turbo` | Fast STT via Groq API | No | All |\n| `groq:distil-whisper-large-v3-en` | Distilled English STT via Groq | No | English |\n\n## API Reference\n\n### Core Functions\n\n#### `getSTTProvider(spec, credentials)`\n\nCreate an STT provider instance from a spec string.\n\n```typescript\nimport { getSTTProvider } from \"@aid-on/unisttp\";\n\n// Cloudflare Workers AI\nconst cfProvider = getSTTProvider(\"cloudflare:whisper-large-v3-turbo\", {\n  cloudflareBinding: env.AI,\n});\n\n// Groq\nconst groqProvider = getSTTProvider(\"groq:whisper-large-v3-turbo\", {\n  groqApiKey: env.GROQ_API_KEY,\n});\n```\n\n#### `parseSTTSpec(spec)`\n\nParse a spec string into its components.\n\n```typescript\nimport { parseSTTSpec } from \"@aid-on/unisttp\";\n\nconst parsed = parseSTTSpec(\"cloudflare:whisper-large-v3-turbo\");\n// => {\n//   provider: \"cloudflare\",\n//   model: \"whisper-large-v3-turbo\",\n//   spec: \"cloudflare:whisper-large-v3-turbo\"\n// }\n```\n\n#### `createSTTSpec(provider, model)`\n\nCreate a spec string from provider and model.\n\n```typescript\nimport { createSTTSpec } from \"@aid-on/unisttp\";\n\nconst spec = createSTTSpec(\"groq\", \"whisper-large-v3\");\n// => \"groq:whisper-large-v3\"\n```\n\n#### `getBestProvider(credentials)`\n\nAutomatically select the best available provider based on credentials. Priority: Cloudflare (VAD support) > Groq.\n\n```typescript\nimport { getBestProvider } from \"@aid-on/unisttp\";\n\nconst provider = getBestProvider({\n  cloudflareBinding: env.AI,\n  groqApiKey: env.GROQ_API_KEY,\n});\n// Returns Cloudflare provider (higher priority due to VAD support)\n```\n\n#### `getAvailableProviders(credentials)`\n\nList which providers are available based on the supplied credentials.\n\n```typescript\nimport { getAvailableProviders } from \"@aid-on/unisttp\";\n\nconst available = getAvailableProviders({\n  cloudflareBinding: env.AI,\n  groqApiKey: env.GROQ_API_KEY,\n});\n// => [\"cloudflare\", \"groq\"]\n```\n\n#### `hasCredentials(provider, credentials)`\n\nCheck if credentials are available for a specific provider.\n\n```typescript\nimport { hasCredentials } from \"@aid-on/unisttp\";\n\nhasCredentials(\"cloudflare\", { cloudflareBinding: env.AI }); // true\nhasCredentials(\"groq\", { cloudflareBinding: env.AI });       // false\n```\n\n### Fallback Chain\n\n#### `createFallbackChain(options)`\n\nCreate a resilient transcription pipeline that automatically falls back to the next provider on failure.\n\n```typescript\nimport { createFallbackChain } from \"@aid-on/unisttp\";\n\nconst chain = createFallbackChain({\n  specs: [\n    \"cloudflare:whisper-large-v3-turbo\",\n    \"groq:whisper-large-v3-turbo\",\n  ],\n  credentials: {\n    cloudflareBinding: env.AI,\n    groqApiKey: env.GROQ_API_KEY,\n  },\n  onFallback: (error, nextSpec) => {\n    console.warn(`Provider failed: ${error.message}, trying ${nextSpec}`);\n  },\n});\n\n// Transcribe with automatic fallback\nconst result = await chain.transcribe(audioBuffer, { language: \"ja\" });\n\n// Access chain metadata\nconst allProviders = chain.getProviders();\nconst primary = chain.getPrimary();\n```\n\n### Model Metadata\n\n#### `getModelInfo(spec)`\n\nGet detailed metadata about a model.\n\n```typescript\nimport { getModelInfo } from \"@aid-on/unisttp\";\n\nconst info = getModelInfo(\"cloudflare:whisper-large-v3-turbo\");\n// => {\n//   spec: \"cloudflare:whisper-large-v3-turbo\",\n//   provider: \"cloudflare\",\n//   model: \"whisper-large-v3-turbo\",\n//   name: \"Whisper Large V3 Turbo\",\n//   description: \"Fast, accurate multilingual STT with VAD support\",\n//   supportsVAD: true,\n//   supportsWordTimestamps: true,\n//   languages: []\n// }\n```\n\n#### `getModelsByProvider(provider)`\n\nGet all models for a specific provider.\n\n```typescript\nimport { getModelsByProvider } from \"@aid-on/unisttp\";\n\nconst cfModels = getModelsByProvider(\"cloudflare\");\n// => [whisper-large-v3-turbo, whisper-large-v3, whisper, whisper-tiny-en]\n```\n\n#### `getModelsWithVAD()`\n\nGet all models that support Voice Activity Detection filtering.\n\n```typescript\nimport { getModelsWithVAD } from \"@aid-on/unisttp\";\n\nconst vadModels = getModelsWithVAD();\n// => [cloudflare:whisper-large-v3-turbo, cloudflare:whisper-large-v3]\n```\n\n#### `isValidSpec(spec)` / `getAllSpecs()`\n\nValidate specs and list all available specs.\n\n```typescript\nimport { isValidSpec, getAllSpecs } from \"@aid-on/unisttp\";\n\nisValidSpec(\"cloudflare:whisper-large-v3-turbo\"); // true\nisValidSpec(\"invalid:model\");                      // false\n\nconst allSpecs = getAllSpecs();\n// => [\"cloudflare:whisper-large-v3-turbo\", \"cloudflare:whisper-large-v3\", ...]\n```\n\n### Types\n\n```typescript\nimport type {\n  ProviderType,        // \"cloudflare\" | \"groq\"\n  STTSpec,             // \"cloudflare:whisper-large-v3-turbo\" | ...\n  ParsedSTTSpec,       // { provider, model, spec }\n  Credentials,         // { cloudflareBinding?, groqApiKey?, ... }\n  STTOptions,          // { language?, prompt?, vadFilter?, temperature? }\n  STTResult,           // { text, language?, duration?, words? }\n  STTProvider,         // { name, model, spec, transcribe() }\n  ModelInfo,           // Full model metadata\n  FallbackChainOptions // { specs, credentials, onFallback? }\n} from \"@aid-on/unisttp\";\n```\n\n### Configuration\n\n#### STTOptions\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `language` | `string` | auto-detect | ISO 639-1 language code (e.g., `\"ja\"`, `\"en\"`) |\n| `prompt` | `string` | - | Initial prompt to guide transcription |\n| `vadFilter` | `boolean` | - | Enable VAD to filter non-speech segments |\n| `temperature` | `number` | - | Sampling temperature (0-1) |\n\n#### Credentials\n\n| Field | Type | Required For |\n|-------|------|-------------|\n| `cloudflareBinding` | `Ai` | Cloudflare Workers AI |\n| `groqApiKey` | `string` | Groq |\n| `cloudflareApiKey` | `string` | Cloudflare REST API |\n| `cloudflareAccountId` | `string` | Cloudflare REST API |\n\n## Real-World Example: Cloudflare Worker\n\n```typescript\nimport { createFallbackChain, getModelsWithVAD } from \"@aid-on/unisttp\";\n\nexport default {\n  async fetch(request: Request, env: Env) {\n    const audioBuffer = await request.arrayBuffer();\n\n    const chain = createFallbackChain({\n      specs: [\n        \"cloudflare:whisper-large-v3-turbo\",\n        \"groq:whisper-large-v3-turbo\",\n      ],\n      credentials: {\n        cloudflareBinding: env.AI,\n        groqApiKey: env.GROQ_API_KEY,\n      },\n      onFallback: (error, nextSpec) => {\n        console.warn(`Fallback: ${error.message} -> ${nextSpec}`);\n      },\n    });\n\n    const result = await chain.transcribe(audioBuffer, {\n      language: \"ja\",\n      vadFilter: true,\n    });\n\n    return Response.json({\n      text: result.text,\n      language: result.language,\n      duration: result.duration,\n      words: result.words,\n    });\n  },\n};\n```\n\n## License\n\nMIT (C) Aid-On\n\n---\n\n<div align=\"center\">\n\n**Unified STT for the edge. One spec, any provider.**\n\n<br/>\n\n[NPM](https://www.npmjs.com/package/@aid-on/unisttp) •\n[GitHub](https://github.com/Aid-On/aid-on-platform)\n\n</div>\n","readmeFilename":"README.md","_rev":"1-0fbd36ec3456c98de5e315b1df167c23"}