@absolutejs/voice 0.0.22-beta.82 → 0.0.22-beta.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export { applyVoiceTelephonyOutcome, createMemoryVoiceTelephonyWebhookIdempotenc
15
15
  export { createStoredVoiceCallReviewArtifact, createStoredVoiceExternalObjectMap, createStoredVoiceIntegrationEvent, createStoredVoiceOpsTask, createVoiceFileExternalObjectMapStore, createVoiceFileAssistantMemoryStore, createVoiceFileIntegrationEventStore, createVoiceFileReviewStore, createVoiceFileRuntimeStorage, createVoiceFileSessionStore, createVoiceFileTaskStore, createVoiceFileTraceSinkDeliveryStore, createVoiceFileTraceEventStore } from './fileStore';
16
16
  export { createVoiceAssistantMemoryHandle, createVoiceAssistantMemoryRecord, createVoiceMemoryAssistantMemoryStore, resolveVoiceAssistantMemoryNamespace } from './assistantMemory';
17
17
  export { createAnthropicVoiceAssistantModel, createGeminiVoiceAssistantModel, createJSONVoiceAssistantModel, createOpenAIVoiceAssistantModel, resolveVoiceProviderRoutingPolicyPreset, createVoiceProviderRouter } from './modelAdapters';
18
+ export { createOpenAIVoiceTTS } from './openaiTTS';
18
19
  export { createVoiceProviderHealthHTMLHandler, createVoiceProviderHealthJSONHandler, createVoiceProviderHealthRoutes, renderVoiceProviderHealthHTML, summarizeVoiceProviderHealth } from './providerHealth';
19
20
  export { createVoiceProviderCapabilityHTMLHandler, createVoiceProviderCapabilityJSONHandler, createVoiceProviderCapabilityRoutes, renderVoiceProviderCapabilityHTML, summarizeVoiceProviderCapabilities } from './providerCapabilities';
20
21
  export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
@@ -53,6 +54,7 @@ export type { VoiceEvalBaselineComparison, VoiceEvalBaselineComparisonOptions, V
53
54
  export type { VoiceWorkflowContract, VoiceWorkflowContractDefinition, VoiceWorkflowContractField, VoiceWorkflowContractFieldMatch, VoiceWorkflowContractPresetName, VoiceWorkflowContractPresetOptions, VoiceWorkflowContractTracePayload, VoiceWorkflowContractValidation, VoiceWorkflowContractValidationIssue, VoiceWorkflowOutcome } from './workflowContract';
54
55
  export type { VoiceSessionListHTMLHandlerOptions, VoiceSessionListItem, VoiceSessionListOptions, VoiceSessionListRoutesOptions, VoiceSessionListStatus, VoiceSessionReplay, VoiceSessionReplayHTMLHandlerOptions, VoiceSessionReplayOptions, VoiceSessionReplayRoutesOptions, VoiceSessionReplayTurn } from './sessionReplay';
55
56
  export type { AnthropicVoiceAssistantModelOptions, GeminiVoiceAssistantModelOptions, OpenAIVoiceAssistantModelOptions, VoiceProviderRouterEvent, VoiceProviderRouterFallbackMode, VoiceProviderRouterHealthOptions, VoiceProviderRouterOptions, VoiceProviderRouterPolicy, VoiceProviderRouterPolicyPreset, VoiceProviderRouterPolicyWeights, VoiceProviderRouterProviderHealth, VoiceProviderRouterProviderProfile, VoiceProviderRouterStrategy, VoiceJSONAssistantModelHandler, VoiceJSONAssistantModelOptions } from './modelAdapters';
57
+ export type { OpenAIVoiceTTSOptions, OpenAIVoiceTTSVoice } from './openaiTTS';
56
58
  export type { VoiceProviderHealthStatus, VoiceProviderHealthSummary, VoiceProviderHealthSummaryOptions } from './providerHealth';
57
59
  export type { VoiceProviderCapabilityDefinition, VoiceProviderCapabilityHandlerOptions, VoiceProviderCapabilityHTMLHandlerOptions, VoiceProviderCapabilityKind, VoiceProviderCapabilityOptions, VoiceProviderCapabilityReport, VoiceProviderCapabilityRoutesOptions, VoiceProviderCapabilitySummary } from './providerCapabilities';
58
60
  export type { VoiceTurnQualityHTMLHandlerOptions, VoiceTurnQualityItem, VoiceTurnQualityOptions, VoiceTurnQualityReport, VoiceTurnQualityRoutesOptions, VoiceTurnQualityStatus } from './turnQuality';
package/dist/index.js CHANGED
@@ -12424,6 +12424,138 @@ var createGeminiVoiceAssistantModel = (options) => {
12424
12424
  }
12425
12425
  };
12426
12426
  };
12427
+ // src/openaiTTS.ts
12428
+ var OPENAI_PCM24_FORMAT = {
12429
+ channels: 1,
12430
+ container: "raw",
12431
+ encoding: "pcm_s16le",
12432
+ sampleRateHz: 24000
12433
+ };
12434
+ var resolveInstructions = async (instructions, input) => {
12435
+ if (typeof instructions === "function") {
12436
+ return instructions(input);
12437
+ }
12438
+ return instructions;
12439
+ };
12440
+ var createTTSHTTPError = (response) => new Error(`OpenAI voice TTS failed: HTTP ${response.status}`);
12441
+ var emit = async (listeners, event, payload) => {
12442
+ for (const handler of listeners[event]) {
12443
+ await Promise.resolve(handler(payload));
12444
+ }
12445
+ };
12446
+ var createOpenAIVoiceTTS = (options) => {
12447
+ const fetchImpl = options.fetch ?? globalThis.fetch;
12448
+ const baseUrl = options.baseUrl ?? "https://api.openai.com/v1";
12449
+ const model = options.model ?? "gpt-4o-mini-tts";
12450
+ const voice2 = options.voice ?? "coral";
12451
+ return {
12452
+ kind: "tts",
12453
+ open: (openOptions) => {
12454
+ const listeners = {
12455
+ audio: new Set,
12456
+ close: new Set,
12457
+ error: new Set
12458
+ };
12459
+ const abortController = new AbortController;
12460
+ const signalAbort = () => abortController.abort();
12461
+ openOptions.signal?.addEventListener("abort", signalAbort, { once: true });
12462
+ let closed = false;
12463
+ return {
12464
+ close: async (reason) => {
12465
+ if (closed) {
12466
+ return;
12467
+ }
12468
+ closed = true;
12469
+ abortController.abort();
12470
+ openOptions.signal?.removeEventListener("abort", signalAbort);
12471
+ await emit(listeners, "close", {
12472
+ reason,
12473
+ type: "close"
12474
+ });
12475
+ },
12476
+ on: (event, handler) => {
12477
+ listeners[event].add(handler);
12478
+ return () => {
12479
+ listeners[event].delete(handler);
12480
+ };
12481
+ },
12482
+ send: async (text) => {
12483
+ if (closed || !text.trim()) {
12484
+ return;
12485
+ }
12486
+ try {
12487
+ const instructions = await resolveInstructions(options.instructions, {
12488
+ lexicon: openOptions.lexicon,
12489
+ sessionId: openOptions.sessionId,
12490
+ text
12491
+ });
12492
+ const response = await fetchImpl(`${baseUrl.replace(/\/$/, "")}/audio/speech`, {
12493
+ body: JSON.stringify({
12494
+ input: text,
12495
+ instructions,
12496
+ model,
12497
+ response_format: "pcm",
12498
+ speed: options.speed,
12499
+ voice: voice2
12500
+ }),
12501
+ headers: {
12502
+ authorization: `Bearer ${options.apiKey}`,
12503
+ "content-type": "application/json"
12504
+ },
12505
+ method: "POST",
12506
+ signal: abortController.signal
12507
+ });
12508
+ if (!response.ok) {
12509
+ throw createTTSHTTPError(response);
12510
+ }
12511
+ if (!response.body) {
12512
+ const chunk = new Uint8Array(await response.arrayBuffer());
12513
+ if (!closed && chunk.byteLength > 0) {
12514
+ await emit(listeners, "audio", {
12515
+ chunk,
12516
+ format: OPENAI_PCM24_FORMAT,
12517
+ receivedAt: Date.now(),
12518
+ type: "audio"
12519
+ });
12520
+ }
12521
+ return;
12522
+ }
12523
+ const reader = response.body.getReader();
12524
+ try {
12525
+ while (!closed) {
12526
+ const { done, value } = await reader.read();
12527
+ if (done) {
12528
+ break;
12529
+ }
12530
+ if (value.byteLength > 0) {
12531
+ await emit(listeners, "audio", {
12532
+ chunk: new Uint8Array(value),
12533
+ format: OPENAI_PCM24_FORMAT,
12534
+ receivedAt: Date.now(),
12535
+ type: "audio"
12536
+ });
12537
+ }
12538
+ }
12539
+ } finally {
12540
+ reader.releaseLock();
12541
+ }
12542
+ } catch (error) {
12543
+ if (closed || abortController.signal.aborted) {
12544
+ return;
12545
+ }
12546
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
12547
+ await emit(listeners, "error", {
12548
+ error: normalizedError,
12549
+ recoverable: true,
12550
+ type: "error"
12551
+ });
12552
+ throw normalizedError;
12553
+ }
12554
+ }
12555
+ };
12556
+ }
12557
+ };
12558
+ };
12427
12559
  // src/providerAdapters.ts
12428
12560
  class VoiceIOProviderTimeoutError extends Error {
12429
12561
  provider;
@@ -12611,11 +12743,11 @@ var createResolver = (options) => {
12611
12743
  selectedProvider: preferred
12612
12744
  };
12613
12745
  };
12614
- const emit = async (event, input) => {
12746
+ const emit2 = async (event, input) => {
12615
12747
  await options.onProviderEvent?.(event, input);
12616
12748
  };
12617
12749
  return {
12618
- emit,
12750
+ emit: emit2,
12619
12751
  getSuppressionRemainingMs,
12620
12752
  providerIds,
12621
12753
  recordError,
@@ -17300,6 +17432,7 @@ export {
17300
17432
  createPlivoVoiceResponse,
17301
17433
  createPlivoMediaStreamBridge,
17302
17434
  createPhraseHintCorrectionHandler,
17435
+ createOpenAIVoiceTTS,
17303
17436
  createOpenAIVoiceAssistantModel,
17304
17437
  createMemoryVoiceTelephonyWebhookIdempotencyStore,
17305
17438
  createJSONVoiceAssistantModel,
@@ -0,0 +1,18 @@
1
+ import type { TTSAdapter, TTSAdapterOpenOptions, VoiceLexiconEntry } from './types';
2
+ export type OpenAIVoiceTTSVoice = 'alloy' | 'ash' | 'ballad' | 'cedar' | 'coral' | 'echo' | 'fable' | 'marin' | 'nova' | 'onyx' | 'sage' | 'shimmer' | 'verse' | (string & {});
3
+ export type OpenAIVoiceTTSOptions = {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ fetch?: typeof fetch;
7
+ instructions?: string | ((input: {
8
+ lexicon?: VoiceLexiconEntry[];
9
+ sessionId: string;
10
+ text: string;
11
+ }) => Promise<string | undefined> | string | undefined);
12
+ model?: 'gpt-4o-mini-tts' | 'tts-1' | 'tts-1-hd' | (string & {});
13
+ speed?: number;
14
+ voice?: OpenAIVoiceTTSVoice | {
15
+ id: string;
16
+ };
17
+ };
18
+ export declare const createOpenAIVoiceTTS: (options: OpenAIVoiceTTSOptions) => TTSAdapter<TTSAdapterOpenOptions>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.82",
3
+ "version": "0.0.22-beta.84",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",