@ai-ecoverse/pi-audio 1.14.0 → 1.16.0

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/README.md CHANGED
@@ -23,8 +23,12 @@ pi-audio does not apply that patch. Hosts such as slicc-agent record monkeypatch
23
23
 
24
24
  `@ai-ecoverse/pi-audio/durable` appends a `voice.truncate` entry for a `VoiceCut`. The entry has no model messages. Its `edits` replace the target assistant message with the text heard so far and keep tool calls. The stored entry stays intact, and pi-durable derives the shorter message for the next model request. `@earendil-works/pi-durable` is an optional peer (`^1.1.0`); the root package does not import it. `VoiceCut.entryId` is the decimal string of pi-durable's numeric entry id.
25
25
 
26
+ `@ai-ecoverse/pi-audio/mistral` registers Mistral speech adapters when `registerMistral()` is called. `voxtral-mini-latest` posts multipart audio to `/audio/transcriptions` ($0.003 per minute, diarization on). `voxtral-mini-transcribe-realtime-2602` streams base64 PCM on `wss://…/audio/transcriptions/realtime` after `session.created` ($0.006 per minute). Realtime has no server endpointing, so `turnDetection` is `none` and the registry VAD wrapper applies. `voxtral-mini-tts-2603` posts JSON to `/audio/speech` and reads SSE `speech.audio.delta` float32 PCM at 24 kHz ($0.016 per thousand characters). Hosted voice ids such as `en_paul_neutral` differ from the open-weight presets. `textStreaming` is false.
27
+
26
28
  `@ai-ecoverse/pi-audio/elevenlabs` registers ElevenLabs speech adapters when `registerElevenLabs()` is called. `scribe_v2` posts multipart audio to `/speech-to-text`. `scribe_v2_realtime` streams base64 audio on `wss://…/speech-to-text/realtime` and commits turns with `turn_prediction` (`turnDetection: 'semantic'`). `eleven_flash_v2_5` and `eleven_multilingual_v2` post JSON to `/text-to-speech/{voice}/with-timestamps` for a string and stream text on `stream-input` for an async iterable, with character alignment. `eleven_v3` and `eleven_v4` stay on the HTTP path (`textStreaming: false`). Scribe prices are $0.22 per hour for batch and $0.39 per hour for realtime.
27
29
 
30
+ `followBed(bed, soundscape)` cues a `BedChannel` from `VoicePhase`. A loop waits `graceMs` before it starts, so a short gap stays silent. `keep` leaves the current loop running across chained tools. Speech ducks the bed to `duckUnderSpeech`; listening ducks it to `duckUnderUser`. `voiceTurns` does this when `options.soundscape` is set and `out` is an `AudioOut` (`speech`, `bed`, `reference`, `playback`). A plain `AudioSink` still receives only the spoken audio.
31
+
28
32
  `voiceTurns` captions include `agent_spoken`. `upTo` follows `AudioSink` playback: per character when the chunk has alignment, and evenly across the sentence when it does not. `captionsFromHistory(entries)` rebuilds user captions from entries whose `data.source` is `voice`, and agent captions from the assistant text. A `voice.truncate` entry adds `agent_spoken` and `agent_cut` at `heardUpTo`, so the rest of the original text stays available as unheard.
29
33
  `@ai-ecoverse/pi-audio/xai` registers xAI speech adapters when `registerXAI()` is called. `grok-voice-transcribe-2.0` posts multipart audio to `/stt` (fields before `file`) and streams raw binary frames on `wss://…/stt` after `transcript.created`, with Smart Turn (`turnDetection: 'semantic'`). The catalog id is shared, so `audioCost` uses the streaming rate of $0.20 per hour. `grok-voice-tts-1.0` posts JSON to `/tts` for a string and streams `text.delta` / `audio.delta` on `wss://…/tts` for an async iterable (`textStreaming: true`). Voices are eve, ara, rex, sal, and leo. Codecs are mp3, pcm, wav, mulaw, and alaw.
30
34
 
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ import {
23
23
  speak,
24
24
  transcribe
25
25
  } from "./registry.js";
26
+ import { followBed } from "./soundscape.js";
26
27
  import { SpeechEventStream } from "./speech.js";
27
28
  import { askAgent, bindThinker, talkerTools } from "./talker.js";
28
29
  import { mintRealtimeToken } from "./tokens.js";
@@ -46,6 +47,7 @@ export {
46
47
  decodeAudioBase64,
47
48
  encodeAudioBase64,
48
49
  energyVad,
50
+ followBed,
49
51
  getVoiceModel,
50
52
  listVoiceModels,
51
53
  listen,
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["export type {\n AudioChunk,\n AudioEncoding,\n AudioFormat,\n AudioSink,\n AudioSource,\n AudioTag,\n CharAlignment,\n TextSpan,\n} from './audio.ts';\nexport { resolveVoiceAuth } from './auth.ts';\nexport { blankUsage } from './blank-usage.ts';\nexport type { CaptionHistoryEntry } from './captions.ts';\nexport { captionsFromHistory } from './captions.ts';\nexport {\n convertAudio,\n convertAudioSource,\n decodeAudioBase64,\n encodeAudioBase64,\n} from './convert.ts';\nexport { VoiceRequestError } from './errors.ts';\nexport type {\n Delivery,\n DeliverySupport,\n KnownRealtimeApi,\n KnownSpeechApi,\n KnownTranscriptionApi,\n RealtimeApi,\n RealtimeModel,\n SpeechApi,\n SpeechModel,\n TranscriptionApi,\n TranscriptionModel,\n VoiceInfo,\n VoiceModel,\n VoiceModelType,\n} from './models.ts';\nexport {\n getVoiceModel,\n listVoiceModels,\n registerVoiceModel,\n} from './models.ts';\nexport type {\n DeliveryPlan,\n RealtimeApiProvider,\n RealtimeContext,\n RealtimeEvent,\n RealtimeOptions,\n RealtimeSession,\n RealtimeSocket,\n RealtimeToken,\n TruncationPlan,\n} from './realtime.ts';\nexport { planDelivery, planTruncation, RealtimeLedger, realtimeSocket } from './realtime.ts';\nexport {\n connectRealtime,\n listen,\n registerRealtimeApiProvider,\n registerSpeechApiProvider,\n registerTranscriptionApiProvider,\n speak,\n transcribe,\n} from './registry.ts';\nexport type { SpeechApiProvider, SpeechEvent, SpeechInput } from './speech.ts';\nexport { SpeechEventStream } from './speech.ts';\nexport type { VoiceAgentEvent, VoiceMessageChange } from './spoken.ts';\nexport type {\n BindThinkerOptions,\n BoundThinker,\n Thinker,\n ThinkerCaption,\n ThinkerPhase,\n ThinkerUpdate,\n} from './talker.ts';\nexport { askAgent, bindThinker, talkerTools } from './talker.ts';\nexport type { RealtimeConstraints } from './tokens.ts';\nexport { mintRealtimeToken } from './tokens.ts';\nexport type {\n AudioInput,\n ListenOptions,\n Transcript,\n TranscriptionApiProvider,\n TranscriptionEvent,\n TranscriptSegment,\n} from './transcription.ts';\nexport { TranscriptionEventStream } from './transcription.ts';\nexport type {\n BargeIn,\n CaptionEvent,\n EchoRecommendation,\n VoiceConversation,\n VoiceCut,\n VoiceModels,\n VoicePhase,\n VoiceSession,\n VoiceTurnMeta,\n VoiceTurnOptions,\n} from './turns.ts';\nexport { voiceTurns } from './turns.ts';\nexport type {\n AudioCost,\n AudioCounters,\n AudioUsage,\n RealtimeAudioCost,\n SpeechAudioCost,\n TranscriptionAudioCost,\n} from './usage.ts';\nexport { addAudioCounters, priceAudio } from './usage.ts';\nexport type { VadHook, VadUpdate } from './vad.ts';\nexport { energyVad } from './vad.ts';\n"],
5
- "mappings": "AAUA,SAAS,wBAAwB;AACjC,SAAS,kBAAkB;AAE3B,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAiBlC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAYP,SAAS,cAAc,gBAAgB,gBAAgB,sBAAsB;AAC7E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,yBAAyB;AAUlC,SAAS,UAAU,aAAa,mBAAmB;AAEnD,SAAS,yBAAyB;AASlC,SAAS,gCAAgC;AAazC,SAAS,kBAAkB;AAS3B,SAAS,kBAAkB,kBAAkB;AAE7C,SAAS,iBAAiB;",
4
+ "sourcesContent": ["export type {\n AudioChunk,\n AudioEncoding,\n AudioFormat,\n AudioSink,\n AudioSource,\n AudioTag,\n CharAlignment,\n TextSpan,\n} from './audio.ts';\nexport { resolveVoiceAuth } from './auth.ts';\nexport { blankUsage } from './blank-usage.ts';\nexport type { CaptionHistoryEntry } from './captions.ts';\nexport { captionsFromHistory } from './captions.ts';\nexport {\n convertAudio,\n convertAudioSource,\n decodeAudioBase64,\n encodeAudioBase64,\n} from './convert.ts';\nexport { VoiceRequestError } from './errors.ts';\nexport type {\n Delivery,\n DeliverySupport,\n KnownRealtimeApi,\n KnownSpeechApi,\n KnownTranscriptionApi,\n RealtimeApi,\n RealtimeModel,\n SpeechApi,\n SpeechModel,\n TranscriptionApi,\n TranscriptionModel,\n VoiceInfo,\n VoiceModel,\n VoiceModelType,\n} from './models.ts';\nexport {\n getVoiceModel,\n listVoiceModels,\n registerVoiceModel,\n} from './models.ts';\nexport type {\n DeliveryPlan,\n RealtimeApiProvider,\n RealtimeContext,\n RealtimeEvent,\n RealtimeOptions,\n RealtimeSession,\n RealtimeSocket,\n RealtimeToken,\n TruncationPlan,\n} from './realtime.ts';\nexport { planDelivery, planTruncation, RealtimeLedger, realtimeSocket } from './realtime.ts';\nexport {\n connectRealtime,\n listen,\n registerRealtimeApiProvider,\n registerSpeechApiProvider,\n registerTranscriptionApiProvider,\n speak,\n transcribe,\n} from './registry.ts';\nexport type { AudioOut, BedChannel, Cue, CueSource, Soundscape } from './soundscape.ts';\nexport { followBed } from './soundscape.ts';\nexport type { SpeechApiProvider, SpeechEvent, SpeechInput } from './speech.ts';\nexport { SpeechEventStream } from './speech.ts';\nexport type { VoiceAgentEvent, VoiceMessageChange } from './spoken.ts';\nexport type {\n BindThinkerOptions,\n BoundThinker,\n Thinker,\n ThinkerCaption,\n ThinkerPhase,\n ThinkerUpdate,\n} from './talker.ts';\nexport { askAgent, bindThinker, talkerTools } from './talker.ts';\nexport type { RealtimeConstraints } from './tokens.ts';\nexport { mintRealtimeToken } from './tokens.ts';\nexport type {\n AudioInput,\n ListenOptions,\n Transcript,\n TranscriptionApiProvider,\n TranscriptionEvent,\n TranscriptSegment,\n} from './transcription.ts';\nexport { TranscriptionEventStream } from './transcription.ts';\nexport type {\n BargeIn,\n CaptionEvent,\n EchoRecommendation,\n VoiceConversation,\n VoiceCut,\n VoiceModels,\n VoicePhase,\n VoiceSession,\n VoiceTurnMeta,\n VoiceTurnOptions,\n} from './turns.ts';\nexport { voiceTurns } from './turns.ts';\nexport type {\n AudioCost,\n AudioCounters,\n AudioUsage,\n RealtimeAudioCost,\n SpeechAudioCost,\n TranscriptionAudioCost,\n} from './usage.ts';\nexport { addAudioCounters, priceAudio } from './usage.ts';\nexport type { VadHook, VadUpdate } from './vad.ts';\nexport { energyVad } from './vad.ts';\n"],
5
+ "mappings": "AAUA,SAAS,wBAAwB;AACjC,SAAS,kBAAkB;AAE3B,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAiBlC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAYP,SAAS,cAAc,gBAAgB,gBAAgB,sBAAsB;AAC7E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,iBAAiB;AAE1B,SAAS,yBAAyB;AAUlC,SAAS,UAAU,aAAa,mBAAmB;AAEnD,SAAS,yBAAyB;AASlC,SAAS,gCAAgC;AAazC,SAAS,kBAAkB;AAS3B,SAAS,kBAAkB,kBAAkB;AAE7C,SAAS,iBAAiB;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,109 @@
1
+ import {
2
+ registerVoiceModel
3
+ } from "../models.js";
4
+ import { registerSpeechApiProvider, registerTranscriptionApiProvider } from "../registry.js";
5
+ import { listenMistral } from "./listen.js";
6
+ import { speakMistral } from "./speak.js";
7
+ import { transcribeMistral } from "./transcribe.js";
8
+ const tokenCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
9
+ const mistral = "https://api.mistral.ai/v1";
10
+ const languages = ["en", "zh", "hi", "es", "ar", "fr", "pt", "ru", "de", "ja", "ko", "it", "nl"];
11
+ const pcm16 = (sampleRate) => ({
12
+ encoding: "pcm16",
13
+ sampleRate,
14
+ channels: 1
15
+ });
16
+ const container = (encoding, sampleRate) => ({
17
+ encoding,
18
+ sampleRate,
19
+ channels: 1
20
+ });
21
+ const voices = [
22
+ { id: "en_paul_neutral", name: "Paul", languages: ["en"] },
23
+ { id: "gb_jane_neutral", name: "Jane", languages: ["en"] },
24
+ { id: "gb_oliver_neutral", name: "Oliver", languages: ["en"] },
25
+ { id: "fr_marie_neutral", name: "Marie", languages: ["fr"] }
26
+ ];
27
+ function mistralCatalog() {
28
+ const batch = {
29
+ id: "voxtral-mini-latest",
30
+ name: "voxtral-mini-latest",
31
+ api: "mistral-transcriptions",
32
+ provider: "mistral",
33
+ baseUrl: mistral,
34
+ type: "transcription",
35
+ streaming: false,
36
+ turnDetection: "none",
37
+ inputFormats: [
38
+ container("wav", 16e3),
39
+ container("mp3", 16e3),
40
+ container("flac", 16e3),
41
+ pcm16(16e3)
42
+ ],
43
+ languages,
44
+ diarization: true,
45
+ cost: tokenCost,
46
+ audioCost: { perInputMinute: 3e-3 }
47
+ };
48
+ const realtime = {
49
+ id: "voxtral-mini-transcribe-realtime-2602",
50
+ name: "voxtral-mini-transcribe-realtime-2602",
51
+ api: "mistral-transcriptions",
52
+ provider: "mistral",
53
+ baseUrl: mistral,
54
+ type: "transcription",
55
+ streaming: true,
56
+ turnDetection: "none",
57
+ inputFormats: [pcm16(16e3)],
58
+ languages,
59
+ diarization: false,
60
+ cost: tokenCost,
61
+ audioCost: { perInputMinute: 6e-3 }
62
+ };
63
+ const speech = {
64
+ id: "voxtral-mini-tts-2603",
65
+ name: "voxtral-mini-tts-2603",
66
+ api: "mistral-speech",
67
+ provider: "mistral",
68
+ baseUrl: mistral,
69
+ type: "speech",
70
+ textStreaming: false,
71
+ outputFormats: [
72
+ container("pcmf32", 24e3),
73
+ container("mp3", 24e3),
74
+ container("wav", 24e3),
75
+ container("flac", 24e3),
76
+ container("opus", 24e3)
77
+ ],
78
+ voices,
79
+ cloning: true,
80
+ cost: tokenCost,
81
+ audioCost: { perThousandChars: 0.016 }
82
+ };
83
+ return [batch, realtime, speech];
84
+ }
85
+ function registerMistral() {
86
+ const models = mistralCatalog();
87
+ const unregisterModels = models.map((model) => registerVoiceModel(model));
88
+ const unregisterTranscription = registerTranscriptionApiProvider({
89
+ api: "mistral-transcriptions",
90
+ transcribe: transcribeMistral,
91
+ listen: listenMistral
92
+ });
93
+ const unregisterSpeech = registerSpeechApiProvider({
94
+ api: "mistral-speech",
95
+ speak: speakMistral
96
+ });
97
+ let released = false;
98
+ return () => {
99
+ if (released) return;
100
+ released = true;
101
+ for (const unregister of unregisterModels) unregister();
102
+ unregisterTranscription();
103
+ unregisterSpeech();
104
+ };
105
+ }
106
+ export {
107
+ registerMistral
108
+ };
109
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mistral/catalog.ts"],
4
+ "sourcesContent": ["import type { AudioFormat } from '../audio.ts';\nimport {\n registerVoiceModel,\n type SpeechModel,\n type TranscriptionModel,\n type VoiceInfo,\n} from '../models.ts';\nimport { registerSpeechApiProvider, registerTranscriptionApiProvider } from '../registry.ts';\nimport { listenMistral } from './listen.ts';\nimport { speakMistral } from './speak.ts';\nimport { transcribeMistral } from './transcribe.ts';\n\nconst tokenCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst mistral = 'https://api.mistral.ai/v1';\nconst languages = ['en', 'zh', 'hi', 'es', 'ar', 'fr', 'pt', 'ru', 'de', 'ja', 'ko', 'it', 'nl'];\n\nconst pcm16 = (sampleRate: number): AudioFormat => ({\n encoding: 'pcm16',\n sampleRate,\n channels: 1,\n});\n\nconst container = (\n encoding: 'wav' | 'mp3' | 'flac' | 'opus' | 'pcmf32',\n sampleRate: number\n): AudioFormat => ({\n encoding,\n sampleRate,\n channels: 1,\n});\n\nconst voices: VoiceInfo[] = [\n { id: 'en_paul_neutral', name: 'Paul', languages: ['en'] },\n { id: 'gb_jane_neutral', name: 'Jane', languages: ['en'] },\n { id: 'gb_oliver_neutral', name: 'Oliver', languages: ['en'] },\n { id: 'fr_marie_neutral', name: 'Marie', languages: ['fr'] },\n];\n\nfunction mistralCatalog(): Array<TranscriptionModel<string> | SpeechModel<string>> {\n const batch: TranscriptionModel<string> = {\n id: 'voxtral-mini-latest',\n name: 'voxtral-mini-latest',\n api: 'mistral-transcriptions',\n provider: 'mistral',\n baseUrl: mistral,\n type: 'transcription',\n streaming: false,\n turnDetection: 'none',\n inputFormats: [\n container('wav', 16000),\n container('mp3', 16000),\n container('flac', 16000),\n pcm16(16000),\n ],\n languages,\n diarization: true,\n cost: tokenCost,\n audioCost: { perInputMinute: 0.003 },\n };\n const realtime: TranscriptionModel<string> = {\n id: 'voxtral-mini-transcribe-realtime-2602',\n name: 'voxtral-mini-transcribe-realtime-2602',\n api: 'mistral-transcriptions',\n provider: 'mistral',\n baseUrl: mistral,\n type: 'transcription',\n streaming: true,\n turnDetection: 'none',\n inputFormats: [pcm16(16000)],\n languages,\n diarization: false,\n cost: tokenCost,\n audioCost: { perInputMinute: 0.006 },\n };\n const speech: SpeechModel<string> = {\n id: 'voxtral-mini-tts-2603',\n name: 'voxtral-mini-tts-2603',\n api: 'mistral-speech',\n provider: 'mistral',\n baseUrl: mistral,\n type: 'speech',\n textStreaming: false,\n outputFormats: [\n container('pcmf32', 24000),\n container('mp3', 24000),\n container('wav', 24000),\n container('flac', 24000),\n container('opus', 24000),\n ],\n voices,\n cloning: true,\n cost: tokenCost,\n audioCost: { perThousandChars: 0.016 },\n };\n return [batch, realtime, speech];\n}\n\nexport function registerMistral(): () => void {\n const models = mistralCatalog();\n const unregisterModels = models.map((model) => registerVoiceModel(model));\n const unregisterTranscription = registerTranscriptionApiProvider({\n api: 'mistral-transcriptions',\n transcribe: transcribeMistral,\n listen: listenMistral,\n });\n const unregisterSpeech = registerSpeechApiProvider({\n api: 'mistral-speech',\n speak: speakMistral,\n });\n let released = false;\n return () => {\n if (released) return;\n released = true;\n for (const unregister of unregisterModels) unregister();\n unregisterTranscription();\n unregisterSpeech();\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,5 @@
1
+ import { registerMistral } from "./catalog.js";
2
+ export {
3
+ registerMistral
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mistral/index.ts"],
4
+ "sourcesContent": ["export { registerMistral } from './catalog.ts';\n"],
5
+ "mappings": "AAAA,SAAS,uBAAuB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,260 @@
1
+ import { chunkSeconds } from "../audio.js";
2
+ import { encodeAudioBase64 } from "../convert.js";
3
+ import { asVoiceError, isRecord, numberField, stringField } from "../openai/wire.js";
4
+ import {
5
+ TranscriptionEventStream
6
+ } from "../transcription.js";
7
+ import { priceAudio } from "../usage.js";
8
+ import {
9
+ awaitOpen,
10
+ bearerHeaders,
11
+ connectSocket,
12
+ messageText,
13
+ realtimeEncoding,
14
+ sameFormat,
15
+ socketUrl
16
+ } from "./wire.js";
17
+ function textOr(event) {
18
+ const text = stringField(event, "text");
19
+ if (text === void 0) return "";
20
+ return text;
21
+ }
22
+ function secondsOf(word, key) {
23
+ const value = numberField(word, key);
24
+ if (value === void 0) return 0;
25
+ return value;
26
+ }
27
+ function segmentFrom(word) {
28
+ const text = textOr(word);
29
+ if (text === "") return void 0;
30
+ const speaker = stringField(word, "speaker_id");
31
+ const segment = {
32
+ text,
33
+ start: secondsOf(word, "start"),
34
+ end: secondsOf(word, "end")
35
+ };
36
+ if (speaker !== void 0) segment.speaker = speaker;
37
+ return segment;
38
+ }
39
+ function listenError(event) {
40
+ const direct = stringField(event, "error");
41
+ if (direct !== void 0) return direct;
42
+ const error = event.error;
43
+ if (!isRecord(error)) return "Mistral transcription failed";
44
+ const message = error.message;
45
+ if (typeof message === "string") return message;
46
+ if (isRecord(message)) {
47
+ const detail = stringField(message, "detail");
48
+ if (detail !== void 0) return detail;
49
+ }
50
+ return "Mistral transcription failed";
51
+ }
52
+ function spokenText(partial, doneText) {
53
+ if (partial !== "") return partial;
54
+ return doneText;
55
+ }
56
+ function sttUrl(model, options) {
57
+ const url = socketUrl(model.baseUrl, "audio/transcriptions/realtime");
58
+ const params = new URLSearchParams();
59
+ params.set("model", model.id);
60
+ if (options?.language) params.set("language", options.language);
61
+ url.search = params.toString();
62
+ return url.toString();
63
+ }
64
+ function chosenFormat(model, chunk) {
65
+ const format = chunk === void 0 ? model.inputFormats[0] : chunk.format;
66
+ if (!format) throw new Error("No input format");
67
+ realtimeEncoding(format);
68
+ const known = model.inputFormats.some((item) => sameFormat(item, format));
69
+ if (!known) throw new Error(`Unsupported audio format ${format.encoding}`);
70
+ return format;
71
+ }
72
+ function addSegment(word, state) {
73
+ const segment = segmentFrom(word);
74
+ if (segment) state.segments.push(segment);
75
+ }
76
+ function addSegments(value, state) {
77
+ if (!Array.isArray(value)) return;
78
+ for (const word of value) {
79
+ if (!isRecord(word)) continue;
80
+ addSegment(word, state);
81
+ }
82
+ }
83
+ function emitFinal(spoken, state, push) {
84
+ if (spoken === "") return;
85
+ if (!state.started) {
86
+ state.started = true;
87
+ push({ type: "speech_start", at: 0 });
88
+ }
89
+ const segmentId = String(state.segment);
90
+ state.segment += 1;
91
+ state.turns.push(spoken);
92
+ push({ type: "final", segmentId, text: spoken });
93
+ state.started = false;
94
+ push({ type: "turn_end", text: spoken, at: 0 });
95
+ }
96
+ function applyListen(event, state, push) {
97
+ const type = stringField(event, "type");
98
+ if (type === "session.created" || type === "session.updated") {
99
+ state.ready = true;
100
+ return;
101
+ }
102
+ if (type === "transcription.text.delta") {
103
+ state.partial += textOr(event);
104
+ if (!state.started) {
105
+ state.started = true;
106
+ push({ type: "speech_start", at: 0 });
107
+ }
108
+ push({ type: "partial", segmentId: String(state.segment), text: state.partial });
109
+ return;
110
+ }
111
+ if (type === "transcription.segment") {
112
+ addSegment(event, state);
113
+ return;
114
+ }
115
+ if (type === "transcription.done") {
116
+ const language = stringField(event, "language");
117
+ if (language !== void 0) state.language = language;
118
+ addSegments(event.segments, state);
119
+ const spoken = spokenText(state.partial, textOr(event));
120
+ state.partial = "";
121
+ state.sawDone = true;
122
+ emitFinal(spoken, state, push);
123
+ return;
124
+ }
125
+ if (type === "error") {
126
+ state.failed = true;
127
+ push({ type: "error", reason: "error", error: listenError(event) });
128
+ }
129
+ }
130
+ function finish(model, format, state, push) {
131
+ if (state.failed || state.completed) return;
132
+ state.completed = true;
133
+ const heard = chunkSeconds({ data: new Uint8Array(state.bytes), format, timestamp: 0 });
134
+ push({
135
+ type: "done",
136
+ transcript: {
137
+ text: state.turns.join(" "),
138
+ ...state.language !== void 0 ? { language: state.language } : {},
139
+ ...state.segments.length > 0 ? { segments: state.segments } : {},
140
+ usage: priceAudio(model.audioCost, { inputSeconds: heard })
141
+ }
142
+ });
143
+ }
144
+ function listenMistral(model, audio, options) {
145
+ const stream = new TranscriptionEventStream();
146
+ void pumpListen(model, audio, options, stream);
147
+ return stream;
148
+ }
149
+ async function pumpListen(model, audio, options, stream) {
150
+ const state = {
151
+ turns: [],
152
+ segments: [],
153
+ segment: 0,
154
+ started: false,
155
+ bytes: 0,
156
+ opened: false,
157
+ ready: false,
158
+ clientDone: false,
159
+ sawDone: false,
160
+ failed: false,
161
+ completed: false,
162
+ partial: "",
163
+ language: void 0
164
+ };
165
+ let settled = false;
166
+ const push = (event) => {
167
+ if (settled) return;
168
+ if (event.type === "done" || event.type === "error") settled = true;
169
+ stream.push(event);
170
+ };
171
+ let socket;
172
+ const readyWait = Promise.withResolvers();
173
+ const doneWait = Promise.withResolvers();
174
+ const wake = (kind) => {
175
+ if (state.ready || state.failed) readyWait.resolve();
176
+ if (state.failed) doneWait.resolve();
177
+ if (!state.clientDone) return;
178
+ if (kind === "transcription.done") doneWait.resolve();
179
+ if (kind === "close") doneWait.resolve();
180
+ };
181
+ try {
182
+ if (options?.signal?.aborted) throw new DOMException("aborted", "AbortError");
183
+ const iterator = audio[Symbol.asyncIterator]();
184
+ const first = await iterator.next();
185
+ const format = chosenFormat(model, first.done ? void 0 : first.value);
186
+ socket = connectSocket(sttUrl(model, options), bearerHeaders(model, options));
187
+ let incoming = Promise.resolve();
188
+ socket.addEventListener("message", (event) => {
189
+ incoming = incoming.then(() => onMessage(event.data, state, push, wake));
190
+ });
191
+ socket.addEventListener("close", () => {
192
+ if (state.opened && !state.failed && !state.completed && !state.clientDone) {
193
+ state.failed = true;
194
+ push({ type: "error", reason: "error", error: "Mistral transcription socket closed" });
195
+ }
196
+ wake("close");
197
+ });
198
+ await awaitOpen(socket, "Mistral transcription", (message) => {
199
+ state.failed = true;
200
+ push({ type: "error", reason: "error", error: message });
201
+ wake("fail");
202
+ });
203
+ if (state.failed) return;
204
+ state.opened = true;
205
+ if (!state.ready) await readyWait.promise;
206
+ if (state.failed) return;
207
+ socket.send(
208
+ JSON.stringify({
209
+ type: "session.update",
210
+ session: {
211
+ audio_format: { encoding: realtimeEncoding(format), sample_rate: format.sampleRate }
212
+ }
213
+ })
214
+ );
215
+ if (!first.done) sendChunk(socket, first.value, format, state);
216
+ while (!state.failed) {
217
+ if (options?.signal?.aborted) throw new DOMException("aborted", "AbortError");
218
+ const next = await iterator.next();
219
+ if (next.done) break;
220
+ sendChunk(socket, next.value, format, state);
221
+ }
222
+ if (state.failed) return;
223
+ socket.send(JSON.stringify({ type: "input_audio.flush" }));
224
+ socket.send(JSON.stringify({ type: "input_audio.end" }));
225
+ state.clientDone = true;
226
+ if (state.sawDone) doneWait.resolve();
227
+ await doneWait.promise;
228
+ finish(model, format, state, push);
229
+ } catch (error) {
230
+ const voice = asVoiceError(error);
231
+ state.failed = true;
232
+ push({ type: "error", reason: voice.reason, error: voice.error });
233
+ } finally {
234
+ socket?.close();
235
+ }
236
+ }
237
+ function sendChunk(socket, chunk, format, state) {
238
+ if (!sameFormat(chunk.format, format)) {
239
+ throw new Error(`Unsupported audio format ${chunk.format.encoding}`);
240
+ }
241
+ state.bytes += chunk.data.byteLength;
242
+ socket.send(JSON.stringify({ type: "input_audio.append", audio: encodeAudioBase64(chunk.data) }));
243
+ }
244
+ async function onMessage(data, state, push, wake) {
245
+ try {
246
+ const parsed = JSON.parse(await messageText(data));
247
+ if (!isRecord(parsed)) throw new Error("Mistral transcription event was not JSON");
248
+ applyListen(parsed, state, push);
249
+ wake(stringField(parsed, "type"));
250
+ } catch (error) {
251
+ const voice = asVoiceError(error);
252
+ state.failed = true;
253
+ push({ type: "error", reason: voice.reason, error: voice.error });
254
+ wake("fail");
255
+ }
256
+ }
257
+ export {
258
+ listenMistral
259
+ };
260
+ //# sourceMappingURL=listen.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mistral/listen.ts"],
4
+ "sourcesContent": ["import type { AudioChunk, AudioFormat } from '../audio.ts';\nimport { chunkSeconds } from '../audio.ts';\nimport { encodeAudioBase64 } from '../convert.ts';\nimport type { TranscriptionModel } from '../models.ts';\nimport { asVoiceError, isRecord, numberField, stringField } from '../openai/wire.ts';\nimport {\n type ListenOptions,\n type TranscriptionEvent,\n TranscriptionEventStream,\n type TranscriptSegment,\n} from '../transcription.ts';\nimport { priceAudio } from '../usage.ts';\nimport {\n awaitOpen,\n bearerHeaders,\n connectSocket,\n messageText,\n realtimeEncoding,\n sameFormat,\n socketUrl,\n} from './wire.ts';\n\ninterface ListenState {\n turns: string[];\n segments: TranscriptSegment[];\n segment: number;\n started: boolean;\n bytes: number;\n opened: boolean;\n ready: boolean;\n clientDone: boolean;\n sawDone: boolean;\n failed: boolean;\n completed: boolean;\n partial: string;\n language: string | undefined;\n}\n\nfunction textOr(event: Record<string, unknown>): string {\n const text = stringField(event, 'text');\n if (text === undefined) return '';\n return text;\n}\n\nfunction secondsOf(word: Record<string, unknown>, key: string): number {\n const value = numberField(word, key);\n if (value === undefined) return 0;\n return value;\n}\n\nfunction segmentFrom(word: Record<string, unknown>): TranscriptSegment | undefined {\n const text = textOr(word);\n if (text === '') return undefined;\n const speaker = stringField(word, 'speaker_id');\n const segment: TranscriptSegment = {\n text,\n start: secondsOf(word, 'start'),\n end: secondsOf(word, 'end'),\n };\n if (speaker !== undefined) segment.speaker = speaker;\n return segment;\n}\n\nfunction listenError(event: Record<string, unknown>): string {\n const direct = stringField(event, 'error');\n if (direct !== undefined) return direct;\n const error = event.error;\n if (!isRecord(error)) return 'Mistral transcription failed';\n const message = error.message;\n if (typeof message === 'string') return message;\n if (isRecord(message)) {\n const detail = stringField(message, 'detail');\n if (detail !== undefined) return detail;\n }\n return 'Mistral transcription failed';\n}\n\nfunction spokenText(partial: string, doneText: string): string {\n if (partial !== '') return partial;\n return doneText;\n}\n\nfunction sttUrl(model: TranscriptionModel<string>, options: ListenOptions | undefined): string {\n const url = socketUrl(model.baseUrl, 'audio/transcriptions/realtime');\n const params = new URLSearchParams();\n params.set('model', model.id);\n if (options?.language) params.set('language', options.language);\n url.search = params.toString();\n return url.toString();\n}\n\nfunction chosenFormat(\n model: TranscriptionModel<string>,\n chunk: AudioChunk | undefined\n): AudioFormat {\n const format = chunk === undefined ? model.inputFormats[0] : chunk.format;\n if (!format) throw new Error('No input format');\n realtimeEncoding(format);\n const known = model.inputFormats.some((item) => sameFormat(item, format));\n if (!known) throw new Error(`Unsupported audio format ${format.encoding}`);\n return format;\n}\n\nfunction addSegment(word: Record<string, unknown>, state: ListenState) {\n const segment = segmentFrom(word);\n if (segment) state.segments.push(segment);\n}\n\nfunction addSegments(value: unknown, state: ListenState) {\n if (!Array.isArray(value)) return;\n for (const word of value) {\n if (!isRecord(word)) continue;\n addSegment(word, state);\n }\n}\n\nfunction emitFinal(spoken: string, state: ListenState, push: (event: TranscriptionEvent) => void) {\n if (spoken === '') return;\n if (!state.started) {\n state.started = true;\n push({ type: 'speech_start', at: 0 });\n }\n const segmentId = String(state.segment);\n state.segment += 1;\n state.turns.push(spoken);\n push({ type: 'final', segmentId, text: spoken });\n state.started = false;\n push({ type: 'turn_end', text: spoken, at: 0 });\n}\n\nfunction applyListen(\n event: Record<string, unknown>,\n state: ListenState,\n push: (event: TranscriptionEvent) => void\n) {\n const type = stringField(event, 'type');\n if (type === 'session.created' || type === 'session.updated') {\n state.ready = true;\n return;\n }\n if (type === 'transcription.text.delta') {\n state.partial += textOr(event);\n if (!state.started) {\n state.started = true;\n push({ type: 'speech_start', at: 0 });\n }\n push({ type: 'partial', segmentId: String(state.segment), text: state.partial });\n return;\n }\n if (type === 'transcription.segment') {\n addSegment(event, state);\n return;\n }\n if (type === 'transcription.done') {\n const language = stringField(event, 'language');\n if (language !== undefined) state.language = language;\n addSegments(event.segments, state);\n const spoken = spokenText(state.partial, textOr(event));\n state.partial = '';\n state.sawDone = true;\n emitFinal(spoken, state, push);\n return;\n }\n if (type === 'error') {\n state.failed = true;\n push({ type: 'error', reason: 'error', error: listenError(event) });\n }\n}\n\nfunction finish(\n model: TranscriptionModel<string>,\n format: AudioFormat,\n state: ListenState,\n push: (event: TranscriptionEvent) => void\n) {\n if (state.failed || state.completed) return;\n state.completed = true;\n const heard = chunkSeconds({ data: new Uint8Array(state.bytes), format, timestamp: 0 });\n push({\n type: 'done',\n transcript: {\n text: state.turns.join(' '),\n ...(state.language !== undefined ? { language: state.language } : {}),\n ...(state.segments.length > 0 ? { segments: state.segments } : {}),\n usage: priceAudio(model.audioCost, { inputSeconds: heard }),\n },\n });\n}\n\nexport function listenMistral(\n model: TranscriptionModel<string>,\n audio: AsyncIterable<AudioChunk>,\n options?: ListenOptions\n): TranscriptionEventStream {\n const stream = new TranscriptionEventStream();\n void pumpListen(model, audio, options, stream);\n return stream;\n}\n\nasync function pumpListen(\n model: TranscriptionModel<string>,\n audio: AsyncIterable<AudioChunk>,\n options: ListenOptions | undefined,\n stream: TranscriptionEventStream\n) {\n const state: ListenState = {\n turns: [],\n segments: [],\n segment: 0,\n started: false,\n bytes: 0,\n opened: false,\n ready: false,\n clientDone: false,\n sawDone: false,\n failed: false,\n completed: false,\n partial: '',\n language: undefined,\n };\n let settled = false;\n const push = (event: TranscriptionEvent) => {\n if (settled) return;\n if (event.type === 'done' || event.type === 'error') settled = true;\n stream.push(event);\n };\n let socket: WebSocket | undefined;\n const readyWait = Promise.withResolvers<void>();\n const doneWait = Promise.withResolvers<void>();\n const wake = (kind: string | undefined) => {\n if (state.ready || state.failed) readyWait.resolve();\n if (state.failed) doneWait.resolve();\n if (!state.clientDone) return;\n if (kind === 'transcription.done') doneWait.resolve();\n if (kind === 'close') doneWait.resolve();\n };\n try {\n if (options?.signal?.aborted) throw new DOMException('aborted', 'AbortError');\n const iterator = audio[Symbol.asyncIterator]();\n const first = await iterator.next();\n const format = chosenFormat(model, first.done ? undefined : first.value);\n socket = connectSocket(sttUrl(model, options), bearerHeaders(model, options));\n let incoming = Promise.resolve();\n socket.addEventListener('message', (event) => {\n incoming = incoming.then(() => onMessage(event.data, state, push, wake));\n });\n socket.addEventListener('close', () => {\n if (state.opened && !state.failed && !state.completed && !state.clientDone) {\n state.failed = true;\n push({ type: 'error', reason: 'error', error: 'Mistral transcription socket closed' });\n }\n wake('close');\n });\n await awaitOpen(socket, 'Mistral transcription', (message) => {\n state.failed = true;\n push({ type: 'error', reason: 'error', error: message });\n wake('fail');\n });\n if (state.failed) return;\n state.opened = true;\n if (!state.ready) await readyWait.promise;\n if (state.failed) return;\n socket.send(\n JSON.stringify({\n type: 'session.update',\n session: {\n audio_format: { encoding: realtimeEncoding(format), sample_rate: format.sampleRate },\n },\n })\n );\n if (!first.done) sendChunk(socket, first.value, format, state);\n while (!state.failed) {\n if (options?.signal?.aborted) throw new DOMException('aborted', 'AbortError');\n const next = await iterator.next();\n if (next.done) break;\n sendChunk(socket, next.value, format, state);\n }\n if (state.failed) return;\n socket.send(JSON.stringify({ type: 'input_audio.flush' }));\n socket.send(JSON.stringify({ type: 'input_audio.end' }));\n state.clientDone = true;\n if (state.sawDone) doneWait.resolve();\n await doneWait.promise;\n finish(model, format, state, push);\n } catch (error) {\n const voice = asVoiceError(error);\n state.failed = true;\n push({ type: 'error', reason: voice.reason, error: voice.error });\n } finally {\n socket?.close();\n }\n}\n\nfunction sendChunk(socket: WebSocket, chunk: AudioChunk, format: AudioFormat, state: ListenState) {\n if (!sameFormat(chunk.format, format)) {\n throw new Error(`Unsupported audio format ${chunk.format.encoding}`);\n }\n state.bytes += chunk.data.byteLength;\n socket.send(JSON.stringify({ type: 'input_audio.append', audio: encodeAudioBase64(chunk.data) }));\n}\n\nasync function onMessage(\n data: unknown,\n state: ListenState,\n push: (event: TranscriptionEvent) => void,\n wake: (kind: string | undefined) => void\n) {\n try {\n const parsed = JSON.parse(await messageText(data)) as unknown;\n if (!isRecord(parsed)) throw new Error('Mistral transcription event was not JSON');\n applyListen(parsed, state, push);\n wake(stringField(parsed, 'type'));\n } catch (error) {\n const voice = asVoiceError(error);\n state.failed = true;\n push({ type: 'error', reason: voice.reason, error: voice.error });\n wake('fail');\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }