Catalog npm
PACKAGE EXPLORERView in registry

60db-service

npm

Official 60db SDK for Node.js

60dbaisttttsvoice
Versions collected4
Direct dependencies3From release 1.1.1
Last observed20 Oct, 20:44 UTC

README

Current package documentation

60db

Official 60db SDK for JavaScript/TypeScript

Installation

npm install 60db-service

Quick Start

import { SixtyDBClient } from '60db-service';

const client = new SixtyDBClient('your-api-key');

Features

🎤 Text-to-Speech

Basic TTS (returns ArrayBuffer):

const audio = await client.textToSpeech({
  text: 'Hello, world!',
  voice_id: 'your-voice-id',
  speed: 1,          // 0.5 to 2.0 (default 1)
  stability: 50,     // 0 to 100 (default 50)
  similarity: 75,    // 0 to 100 (default 75)
  sample_rate: 24000
});

Streaming TTS (real-time chunks):

await client.textToSpeechStream(
  {
    text: 'This is a streaming example.',
    voice_id: 'your-voice-id',
    sample_rate: 24000
  },
  {
    onChunk: (chunkIndex, totalBytes) => {
      console.log(`Progress: ${chunkIndex} chunks, ${totalBytes} bytes`);
    },
    onRawChunk: (pcmBytes, sampleRate) => {
      console.log(`Received: ${pcmBytes.length} bytes at ${sampleRate}Hz`);
    },
    onComplete: (wavUrl, sampleRate, totalPcmBytes) => {
      console.log(`Complete! WAV: ${wavUrl}`);
      console.log(`Duration: ${totalPcmBytes / (sampleRate * 2)} seconds`);
    },
    onError: (error) => {
      console.error('Error:', error);
    }
  }
);

🤖 Chat Completions (LLM)

Non-streaming (simple):

const response = await client.chat.completions.create({
  model: 'qcall/slm-3b-int4',
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'What is 60db?' }
  ],
  stream: false
});

console.log(response.choices[0].message.content);

Streaming (real-time):

const stream = await client.chat.completions.create({
  model: 'qcall/slm-3b-int4',
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'Tell me a joke' }
  ],
  stream: true
});

for await (const chunk of stream) {
  if (chunk.choices?.[0]?.delta?.content) {
    process.stdout.write(chunk.choices[0].delta.content);
  }
}

Custom parameters:

const response = await client.chat.completions.create({
  model: 'qcall/slm-3b-int4',
  messages: [
    { role: 'user', content: 'Explain AI briefly' }
  ],
  top_k: 50,                           // Default: 100
  chat_template_kwargs: {
    enable_thinking: true              // Enable thinking mode
  },
  stream: false
});

🎧 Voices

// List all voices
const voices = await client.getVoices();
console.log('Total voices:', voices.data.cloned_voices.length);

// Get specific voice
const voice = await client.getVoice(voiceId);

🌍 Languages

const languages = await client.getLanguages();
// Returns: [{ language_id: 'en', name: 'English' }, ...]

🎤 Speech-to-Text

const result = await client.speechToText(audioFile, {
  language: 'en'
});

🎵 Music

Free during beta (no credit check, nothing charged). Each create() call makes 1 song, and only one generation runs at a time per workspace (a second create() while one is running returns 429). A song takes about 1.5-2.5 minutes.

// Create a song (async)
const { data } = await client.music.create({
  mode: 'simple',
  prompt: 'An upbeat pop song about summer road trips',
});
const songId = data.songs[0].id;

// Poll until it's done
const song = await client.music.waitForCompletion(songId);
console.log(song.status, song.audio_url);

// Download the MP3 permanently
const bytes = await client.music.download(songId);

// List / manage songs
await client.music.list({ limit: 10, status: 'ready' });
await client.music.get(songId);
await client.music.update(songId, { liked: true });
await client.music.delete(songId);

// Voices
const { data: voices } = await client.music.listVoices(); // { catalog, mine }
await client.music.createVoice({ name: 'My Voice', file: audioBlob });

await client.music.health();

⚖️ Judge

Scores content against a rubric you define, and parses conversational turns. It is a classifier, not a generator — every answer is a probability distribution over your own options, so results are comparable and sortable.

// Score a call. Three question types: choice, score, noul (true/false).
const run = await client.judge.evaluate({
  state: callTranscript,
  questions: {
    tone: { type: 'choice', instructions: 'How did the agent come across?',
            criteria: { professional: 'Calm and courteous',
                        dismissive: 'Brushes the caller off',
                        unknown: 'Not clear' } },          // always include an escape hatch
    satisfaction: { type: 'score', criteria: ['Angry', 'Neutral', 'Happy'] },
    resolved: { type: 'noul', instructions: 'Was it solved?' },
  },
});

run.answers.tone.choice          // 'dismissive'
run.answers.tone.probabilities   // { dismissive: 0.86, professional: 0.11, unknown: 0.03 }
run.answers.satisfaction.score   // 1.87 — weighted position on your ladder, not an index
run.answers.resolved.noul        // 0.28 — raw probability of true, NOT a confidence
run.min_confidence               // lowest across the answers; under 0.85 wants a human

// Save a rubric once, then run it by id.
const rubric = await client.judge.rubrics.create({ name: 'Call QA', questions });
await client.judge.evaluate({ state: transcript, rubric_id: rubric.id });

// Parse one live turn: intent, operation and entity spans.
const turn = await client.judge.extract({
  text: 'move my 10am appointment to friday',
  schema: {
    intents:    { booking: 'Wants to change a booking' },
    operations: { reschedule: 'Move it to a new time' },
    entities:   { date: 'A calendar date', time: 'A clock time' },
  },
});
turn.intent.label     // 'booking'
turn.entities         // [{ label: 'date', text: 'friday', start: 28, end: 34, confidence: 0.8 }]

// The review queue — runs the judge was under 85% sure about.
const { runs } = await client.judge.runs.list({ needs_review: true });

await client.judge.models();                 // authoritative model list — don't hardcode
await client.judge.usage('current_month');   // spend and run counts

Entity offsets are Unicode code points, not UTF-16 indices — slice with Array.from(text).slice(start, end) or an emoji earlier in the turn shifts every span after it.

Pricing: per input token. The upstream re-encodes the shared state once per question, so a 10-question rubric costs ten times the transcript. Context is 8K tokens per question. A failed run is refunded automatically.

📞 Dialer

Not free: a number costs $6.00/month, calls cost $0.003/min. Most calls need a finished trunk setup (dashboard) and approved dialer KYC (also done in the dashboard, not exposed by this SDK). calls.reserve() does not dial — it only pre-authorizes a call id for a SIP client (softphone/PBX) to use.

await client.dialer.status();

// Numbers
await client.dialer.numbers.search();
// Buying requires approved KYC (done in the 60db app) — otherwise 403
// DIALER_KYC_REQUIRED / DIALER_KYC_PENDING / DIALER_KYC_REJECTED.
// Charges $6.00 now, then $6.00/month.
await client.dialer.numbers.buy({ assign_for: 'sip' });
await client.dialer.numbers.list();
await client.dialer.numbers.setCallerId('+919876543210');
await client.dialer.numbers.release('+919876543210');

// Calls
await client.dialer.calls.list({ limit: 20 });
// Reserves a call id — does NOT dial; a SIP client places the actual call.
await client.dialer.calls.reserve({ to: '+919876543210', from: '+911234567890', sipCallId: 'uuid' });
await client.dialer.calls.live();

// Recordings
await client.dialer.recordings.list();
await client.dialer.recordings.setEnabled(true);

// Billing
await client.dialer.billing.usage({ limit: 20 });
await client.dialer.billing.subscriptions();

// Webhooks
await client.dialer.webhooks.create({ name: 'My hook', url: 'https://example.com/hook', event_types: ['call.completed'] });
await client.dialer.webhooks.list();

Configuration

const client = new SixtyDBClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.60db.ai'  // Optional, default shown
});

API Reference

MethodDescription
textToSpeech(params)Convert text to speech (returns ArrayBuffer)
textToSpeechStream(params, callbacks)Stream text to speech with callbacks
chat.completions.create(params)Chat completions (LLM) with streaming support
getVoices()List all available voices
getVoice(id)Get specific voice details
getLanguages()Get supported languages
speechToText(audio, options)Transcribe audio to text
music.create(params)Create a song (async, free during beta)
music.list(params)List songs
music.get(id)Get a song (includes lyrics)
music.update(id, params)Update liked/played flags
music.delete(id)Move a song to trash
music.download(id)Download the MP3 (ArrayBuffer)
music.waitForCompletion(id, opts)Poll until the song succeeds/fails
music.listVoices()List catalog + saved voices
music.createVoice(params)Save a voice from an audio clip
music.health()Song service status
judge.evaluate(params)Score content against inline questions or a saved rubric
judge.extract(params)Classify one turn: intent, operation, entity spans
judge.models()Model names evaluate accepts (authoritative)
judge.usage(period)Judge spend and saved-run counts
judge.health()Judge upstream readiness and model revisions
judge.rubrics.*List, create, get, update, delete saved rubrics
judge.runs.*List (incl. needs_review queue), get, delete runs
dialer.status()Dialer provisioning status
dialer.numbers.*Search/buy/list/release numbers, set caller id
dialer.calls.*Call history, get, live, line status, reserve
dialer.recordings.*List, playback URL, transcript, delete, enable
dialer.billing.*Subscriptions, usage
dialer.webhooks.*List, create, update, delete, rotate secret, test, deliveries

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 4

Collected releases
VersionPublishedDirect dependenciesOpen version
1.1.1Registry latest28 Sept 20263
1.1.028 Sept 20263
1.0.128 Sept 20263
1.0.028 Sept 20263

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
kapilkarda/qlabs-ui

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 20:44 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:b8adc34fa939a4d3a0a85751cae15aa063315b8576d128c1da77dab15d613c5e