npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@oruk-ai/sdk

v0.2.10

Published

Official TypeScript client for the oruk Speech API: English transcription, multilabel emotion and speaking-style scores, and unified audio analysis.

Readme

oruk TypeScript SDK

Official TypeScript client for the oruk Speech API.

oruk analyses prerecorded speech and returns three things from the audio itself: an English transcript, emotion scores across 15 labels, and speaking-style scores across 16 labels. The emotion and style scores are acoustic — they are derived from how something was said, not inferred from the transcript text.

npm install @oruk-ai/[email protected]

Versioned package mirror.

Requires Node 18 or newer (the client uses the platform fetch, FormData, and Blob). Works in any runtime that provides those, including Deno, Bun, and Cloudflare Workers.

Quickstart

import { readFile } from 'node:fs/promises'
import { Oruk } from '@oruk-ai/sdk'

const apiKey = process.env.ORUK_API_KEY
if (!apiKey) throw new Error('Set ORUK_API_KEY in your environment.')
const oruk = new Oruk({ apiKey })

const bytes = await readFile('sample.wav')
const result = await oruk.analyze({
  file: new Blob([new Uint8Array(bytes)], { type: 'audio/wav' }),
  filename: 'sample.wav',
  model: 'oruk-resonance',
})

console.log(result.text)      // actual transcript from this recording
console.log(result.emotions)  // selected labels and scores
console.log(result.styles)    // selected styles; can be empty

Create an account at oruk.ai/auth/signup, choose a subscription plan, and create your API key. Standard self-serve plans begin with a 7-day trial: a card is required, $0 is charged today, and you can cancel before it ends.

Methods

The first five methods take AudioRequest and return SpeechResult. proficiency takes ProficiencyRequest (including an optional transcript) and returns ProficiencyResult, which also contains proficiency and check. One audio minute uses one plan minute per request; separate calls process and meter the file separately. See the endpoint reference for each model and endpoint's output scope.

| Method | Returns | | --- | --- | | oruk.transcribe(req) | Transcript only | | oruk.emotions(req) | Emotion scores only | | oruk.styles(req) | Speaking-style scores only | | oruk.affect(req) | Emotion and style scores | | oruk.analyze(req) | Transcript, emotion, and style in one call | | oruk.proficiency(req) | English speaking proficiency: CEFR band, 0–5 score, fluency; optional transcript; preview |

type AudioRequest = {
  file: Blob           // the audio
  filename?: string    // defaults to 'audio.wav'
  model?: OrukModel    // defaults to oruk-resonance on the first five endpoints
  requestId?: string   // defaults to a generated UUID
  diarize?: boolean    // oruk-resonance only: label speakers, one segment per speaker turn
  numSpeakers?: number // known speaker count (1-32); omit to detect automatically
}

On the first five endpoints, model: 'oruk-resonance', diarize: true makes segments correspond to speaker turns. Fields still follow the endpoint: emotion-only output does not gain a transcript. Segments carry speaker (speaker_0, speaker_1, ...) and the result carries diarized and speakers. Labels are local to the recording, not identities or roles. Diarization is included in plan minutes. Proficiency uses the separate oruk-proficiency-1 model, not Resonance or Fourier; it does not take diarization parameters. A supplied proficiency transcript skips built-in transcription.

analyze returns transcript and affect in one request, avoiding separate transcription and affect calls over the same audio. When you only want emotion, emotions on Resonance runs the encoder and affect head and never invokes the transcription decoder, so no transcript is produced (text is null). Either endpoint uses one plan minute per minute of audio.

const tone = await oruk.emotions({ file, filename: 'call.wav', model: 'oruk-resonance' })
console.log(tone.emotions)    // actual selected labels and scores
console.log(tone.text)         // null

Results

type SpeechResult = {
  id: string
  task: string
  model: string
  text?: string | null
  tagged_text?: string | null
  language?: string | null
  duration: number
  emotions: Score[]    // { label: string; score: number }
  styles: Score[]
  segments: SpeechSegment[]   // per-segment timings, text, and scores
  usage: SpeechUsage          // audio duration and reference pricing fields
}

The 15 emotion labels and 16 speaking-style labels are model vocabularies, not a guarantee that every response contains every label. Outputs are selected by model thresholds. If no emotion clears its threshold, the highest-scoring emotion is returned; styles can be empty. Several labels may be high and scores need not sum to one. These thresholds do not establish calibrated probabilities of a person's private feelings. Evaluate representative audio before choosing application thresholds. See label interpretation and the scope of the evaluations.

usage includes measured and billable audio duration and may carry reference fields such as rate_per_minute_usd, estimated_cost_usd, or pricing_version. Those reference estimates are not your subscription invoice. Actual charges follow the plan allowance, overage terms, and billing records.

Errors and retries

Failures throw OrukApiError, which carries the HTTP status, the API error code, and the request ID to quote in a support thread.

import { Oruk, OrukApiError } from '@oruk-ai/sdk'

try {
  await oruk.analyze({ file, filename: 'sample.wav' })
} catch (error) {
  if (error instanceof OrukApiError) {
    console.error(error.status, error.code, error.requestId)
  }
}

The client retries HTTP 429, 500, 502, 503, and 504, as well as network and timeout failures, with jittered backoff (two retries by default). Every attempt reuses one X-Request-ID, so a retried call stays a single traceable request on both ends. Client errors such as 400 and 401 throw immediately rather than burning attempts.

Configuration

const oruk = new Oruk({
  apiKey: process.env.ORUK_API_KEY!,
  baseUrl: 'https://speech-api.oruk.ai',  // override for a private deployment
  timeoutMs: 120_000,                     // per attempt
  maxRetries: 2,
  fetch: customFetch,                     // inject your own, e.g. for tracing
})

Runnable file workflows

Set ORUK_API_KEY in your environment and download the complete TypeScript example. These commands use Node.js 22+ and the tsx TypeScript runner:

npm install --save-dev tsx
curl --fail -O https://oruk.ai/examples/analyze-file.mts
npx tsx analyze-file.mts sample.wav --task analysis > result.json
npx tsx analyze-file.mts support-call.wav --task analysis --diarize > speakers.json
npx tsx analyze-file.mts speaking-sample.wav --task proficiency > proficiency.json

Each command makes one logical request, with bounded retries if needed. Running multiple commands processes the audio separately. --help describes model selection, known speaker count, and an optional proficiency transcript file. The program writes the complete API response to stdout and errors to stderr. It does not fabricate missing labels or assume every proficiency request was scored. For proficiency, use 30–60 seconds of spontaneous English and inspect check.status; insufficient_audio does not establish a CEFR level. A model estimate is not a language certificate. Keep API keys in server-side code. These file methods do not implement the separate realtime WebSocket workflow.

Scope

Worth knowing before you build on it:

  • English file API. Resonance is the flagship speech recognition model for recorded English audio.
  • Separate realtime preview. Multilingual transcription in 32 locales and phrase-level emotion scores are available over WebSocket; see the realtime reference.
  • Up to 30 MB and 60 minutes per request.
  • Speech in, labels out. No speaker identification, no diarisation by identity, no video or face analysis, no lie detection.

See oruk.ai/capabilities for the full statement of what the API does and does not do.

Links

License

MIT

Orukeet

Use model oruk-orukeet for English transcription up to 60 seconds / 4 MiB. Every subscription includes an Orukeet allowance; see current plans and task rates. Optional emotion detection and speaker diarization draw from that same allowance. Extra usage shares the plan spending cap. See the Orukeet contract for availability, outputs, streaming, and limits.