@ai-ecoverse/pi-audio 1.9.0 → 1.11.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.
@@ -0,0 +1,8 @@
1
+ import type { AssistantMessage } from '@earendil-works/pi-ai';
2
+ import type { ConversationId, EntryRecord, Tx } from '@earendil-works/pi-durable';
3
+ import type { VoiceCut } from '../turns.ts';
4
+ interface TruncateSession<C> {
5
+ commit<T>(change: (tx: Tx) => T | Promise<T>, context: C): Promise<T>;
6
+ }
7
+ export declare function appendVoiceTruncate<C>(session: TruncateSession<C>, conversationId: ConversationId, cut: VoiceCut, message: AssistantMessage, context: C): Promise<EntryRecord>;
8
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { RealtimeModel } from '../models.ts';
2
+ import { type GeminiOptions } from './session.ts';
3
+ export declare const gemini38Live: RealtimeModel<"gemini-live">;
4
+ export declare const gemini25NativeAudio: RealtimeModel<"gemini-live">;
5
+ export declare const gemini31FlashLive: RealtimeModel<"gemini-live">;
6
+ export declare function registerGeminiLive(options?: GeminiOptions): () => void;
7
+ export type { GeminiOptions, VoiceWireFactory } from './session.ts';
@@ -0,0 +1,12 @@
1
+ import type { AudioFormat } from '../audio.ts';
2
+ import type { RealtimeModel } from '../models.ts';
3
+ import { type VoiceSocketConstructor, type VoiceWire, type VoiceWireTarget } from '../openai-realtime/socket.ts';
4
+ import type { RealtimeContext, RealtimeOptions, RealtimeSession } from '../realtime.ts';
5
+ export type VoiceWireFactory = (target: VoiceWireTarget) => VoiceWire;
6
+ export interface GeminiOptions {
7
+ wire?: VoiceWireFactory;
8
+ socket?: VoiceSocketConstructor;
9
+ vocabulary?: string[];
10
+ }
11
+ export declare function connectGeminiSession(model: RealtimeModel<string>, context: RealtimeContext, options: RealtimeOptions | undefined, gemini: GeminiOptions): Promise<RealtimeSession>;
12
+ export declare function pcmFormat(sampleRate: number): AudioFormat;
@@ -0,0 +1 @@
1
+ export declare function registerXAI(): () => void;
@@ -2,3 +2,4 @@ import type { RealtimeModel } from '../models.ts';
2
2
  import { type AdapterOptions } from '../openai-realtime/session.ts';
3
3
  export declare const grokVoiceLatest: RealtimeModel<'xai-realtime'>;
4
4
  export declare function registerXaiRealtime(options?: AdapterOptions): () => void;
5
+ export { registerXAI } from './catalog.ts';
@@ -0,0 +1,4 @@
1
+ import type { AudioChunk } from '../audio.ts';
2
+ import type { TranscriptionModel } from '../models.ts';
3
+ import { type ListenOptions, TranscriptionEventStream } from '../transcription.ts';
4
+ export declare function listenXAI(model: TranscriptionModel<string>, audio: AsyncIterable<AudioChunk>, options?: ListenOptions): TranscriptionEventStream;
@@ -0,0 +1,4 @@
1
+ import type { ProviderRequestOptions } from '@earendil-works/pi-ai';
2
+ import type { SpeechModel } from '../models.ts';
3
+ import { SpeechEventStream, type SpeechInput } from '../speech.ts';
4
+ export declare function speakXAI(model: SpeechModel<string>, input: SpeechInput, options?: ProviderRequestOptions): SpeechEventStream;
@@ -0,0 +1,4 @@
1
+ import type { ProviderRequestOptions } from '@earendil-works/pi-ai';
2
+ import type { TranscriptionModel } from '../models.ts';
3
+ import type { AudioInput, Transcript } from '../transcription.ts';
4
+ export declare function transcribeXAI(model: TranscriptionModel<string>, input: AudioInput, options?: ProviderRequestOptions): Promise<Transcript>;
@@ -0,0 +1,20 @@
1
+ import type { AudioFormat } from '../audio.ts';
2
+ import type { TranscriptionModel } from '../models.ts';
3
+ export interface XaiFile {
4
+ data: Uint8Array;
5
+ mimeType: string;
6
+ filename: string;
7
+ }
8
+ export declare function mediaType(mimeType: string): string;
9
+ export declare function audioFilename(mimeType: string): string;
10
+ export declare function rawFields(mimeType: string, model: TranscriptionModel<string>): Record<string, string> | undefined;
11
+ export declare function encodeForm(file: XaiFile, fields: Record<string, string>): ArrayBuffer;
12
+ export declare function formType(): string;
13
+ export declare function socketUrl(baseUrl: string, path: string): URL;
14
+ export declare function codecName(encoding: AudioFormat['encoding']): string;
15
+ export declare function encodingName(encoding: AudioFormat['encoding']): string;
16
+ export declare function connectSocket(url: string, headers: Record<string, string>): WebSocket;
17
+ export declare function awaitOpen(socket: WebSocket, label: string, fail: (message: string) => void): Promise<void>;
18
+ export declare function messageText(data: unknown): Promise<string>;
19
+ export declare function sameFormat(left: AudioFormat, right: AudioFormat): boolean;
20
+ export declare function copiedBytes(data: Uint8Array): ArrayBuffer;
@@ -0,0 +1,133 @@
1
+ import {
2
+ registerVoiceModel
3
+ } from "../models.js";
4
+ import { registerSpeechApiProvider, registerTranscriptionApiProvider } from "../registry.js";
5
+ import { listenXAI } from "./listen.js";
6
+ import { speakXAI } from "./speak.js";
7
+ import { transcribeXAI } from "./transcribe.js";
8
+ const tokenCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
9
+ const xai = "https://api.x.ai/v1";
10
+ const languages = [
11
+ "ar",
12
+ "bs",
13
+ "bg",
14
+ "yue",
15
+ "ca",
16
+ "zh",
17
+ "hr",
18
+ "cs",
19
+ "da",
20
+ "nl",
21
+ "en",
22
+ "fil",
23
+ "fi",
24
+ "fr",
25
+ "de",
26
+ "el",
27
+ "hi",
28
+ "hu",
29
+ "id",
30
+ "it",
31
+ "ja",
32
+ "ko",
33
+ "mk",
34
+ "ms",
35
+ "nb",
36
+ "fa",
37
+ "pl",
38
+ "pt",
39
+ "ro",
40
+ "ru",
41
+ "sk",
42
+ "es",
43
+ "sv",
44
+ "th",
45
+ "tr",
46
+ "uk",
47
+ "ur",
48
+ "vi"
49
+ ];
50
+ const pcm16 = (sampleRate) => ({
51
+ encoding: "pcm16",
52
+ sampleRate,
53
+ channels: 1
54
+ });
55
+ const law = (encoding, sampleRate = 8e3) => ({
56
+ encoding,
57
+ sampleRate,
58
+ channels: 1
59
+ });
60
+ const container = (encoding, sampleRate) => ({
61
+ encoding,
62
+ sampleRate,
63
+ channels: 1
64
+ });
65
+ const voices = ["eve", "ara", "rex", "sal", "leo"].map((id) => ({ id, name: id }));
66
+ function xaiCatalog() {
67
+ const transcription = {
68
+ id: "grok-voice-transcribe-2.0",
69
+ name: "grok-voice-transcribe-2.0",
70
+ api: "xai-stt",
71
+ provider: "xai",
72
+ baseUrl: xai,
73
+ type: "transcription",
74
+ streaming: true,
75
+ turnDetection: "semantic",
76
+ inputFormats: [
77
+ pcm16(16e3),
78
+ pcm16(24e3),
79
+ law("mulaw"),
80
+ law("alaw"),
81
+ container("wav", 16e3),
82
+ container("mp3", 16e3),
83
+ container("flac", 16e3)
84
+ ],
85
+ languages,
86
+ diarization: true,
87
+ cost: tokenCost,
88
+ audioCost: { perInputMinute: 0.2 / 60 }
89
+ };
90
+ const speech = {
91
+ id: "grok-voice-tts-1.0",
92
+ name: "grok-voice-tts-1.0",
93
+ api: "xai-tts",
94
+ provider: "xai",
95
+ baseUrl: xai,
96
+ type: "speech",
97
+ textStreaming: true,
98
+ outputFormats: [
99
+ container("mp3", 24e3),
100
+ pcm16(24e3),
101
+ container("wav", 24e3),
102
+ law("mulaw"),
103
+ law("alaw")
104
+ ],
105
+ voices,
106
+ cloning: false,
107
+ cost: tokenCost,
108
+ audioCost: { perThousandChars: 0.015 }
109
+ };
110
+ return [transcription, speech];
111
+ }
112
+ function registerXAI() {
113
+ const models = xaiCatalog();
114
+ const unregisterModels = models.map((model) => registerVoiceModel(model));
115
+ const unregisterStt = registerTranscriptionApiProvider({
116
+ api: "xai-stt",
117
+ transcribe: transcribeXAI,
118
+ listen: listenXAI
119
+ });
120
+ const unregisterTts = registerSpeechApiProvider({ api: "xai-tts", speak: speakXAI });
121
+ let released = false;
122
+ return () => {
123
+ if (released) return;
124
+ released = true;
125
+ for (const unregister of unregisterModels) unregister();
126
+ unregisterStt();
127
+ unregisterTts();
128
+ };
129
+ }
130
+ export {
131
+ registerXAI
132
+ };
133
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/xai/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 { listenXAI } from './listen.ts';\nimport { speakXAI } from './speak.ts';\nimport { transcribeXAI } from './transcribe.ts';\n\nconst tokenCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst xai = 'https://api.x.ai/v1';\n\nconst languages = [\n 'ar',\n 'bs',\n 'bg',\n 'yue',\n 'ca',\n 'zh',\n 'hr',\n 'cs',\n 'da',\n 'nl',\n 'en',\n 'fil',\n 'fi',\n 'fr',\n 'de',\n 'el',\n 'hi',\n 'hu',\n 'id',\n 'it',\n 'ja',\n 'ko',\n 'mk',\n 'ms',\n 'nb',\n 'fa',\n 'pl',\n 'pt',\n 'ro',\n 'ru',\n 'sk',\n 'es',\n 'sv',\n 'th',\n 'tr',\n 'uk',\n 'ur',\n 'vi',\n];\n\nconst pcm16 = (sampleRate: number): AudioFormat => ({\n encoding: 'pcm16',\n sampleRate,\n channels: 1,\n});\n\nconst law = (encoding: 'mulaw' | 'alaw', sampleRate = 8000): AudioFormat => ({\n encoding,\n sampleRate,\n channels: 1,\n});\n\nconst container = (encoding: 'wav' | 'mp3' | 'flac', sampleRate: number): AudioFormat => ({\n encoding,\n sampleRate,\n channels: 1,\n});\n\nconst voices: VoiceInfo[] = ['eve', 'ara', 'rex', 'sal', 'leo'].map((id) => ({ id, name: id }));\n\nfunction xaiCatalog(): Array<TranscriptionModel<string> | SpeechModel<string>> {\n const transcription: TranscriptionModel<string> = {\n id: 'grok-voice-transcribe-2.0',\n name: 'grok-voice-transcribe-2.0',\n api: 'xai-stt',\n provider: 'xai',\n baseUrl: xai,\n type: 'transcription',\n streaming: true,\n turnDetection: 'semantic',\n inputFormats: [\n pcm16(16000),\n pcm16(24000),\n law('mulaw'),\n law('alaw'),\n container('wav', 16000),\n container('mp3', 16000),\n container('flac', 16000),\n ],\n languages,\n diarization: true,\n cost: tokenCost,\n audioCost: { perInputMinute: 0.2 / 60 },\n };\n const speech: SpeechModel<string> = {\n id: 'grok-voice-tts-1.0',\n name: 'grok-voice-tts-1.0',\n api: 'xai-tts',\n provider: 'xai',\n baseUrl: xai,\n type: 'speech',\n textStreaming: true,\n outputFormats: [\n container('mp3', 24000),\n pcm16(24000),\n container('wav', 24000),\n law('mulaw'),\n law('alaw'),\n ],\n voices,\n cloning: false,\n cost: tokenCost,\n audioCost: { perThousandChars: 0.015 },\n };\n return [transcription, speech];\n}\n\nexport function registerXAI(): () => void {\n const models = xaiCatalog();\n const unregisterModels = models.map((model) => registerVoiceModel(model));\n const unregisterStt = registerTranscriptionApiProvider({\n api: 'xai-stt',\n transcribe: transcribeXAI,\n listen: listenXAI,\n });\n const unregisterTts = registerSpeechApiProvider({ api: 'xai-tts', speak: speakXAI });\n let released = false;\n return () => {\n if (released) return;\n released = true;\n for (const unregister of unregisterModels) unregister();\n unregisterStt();\n unregisterTts();\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/xai/index.js CHANGED
@@ -44,8 +44,10 @@ function registerXaiRealtime(options = {}) {
44
44
  unregisterApi();
45
45
  };
46
46
  }
47
+ import { registerXAI } from "./catalog.js";
47
48
  export {
48
49
  grokVoiceLatest,
50
+ registerXAI,
49
51
  registerXaiRealtime
50
52
  };
51
53
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/xai/index.ts"],
4
- "sourcesContent": ["import type { RealtimeModel } from '../models.ts';\nimport { registerVoiceModel } from '../models.ts';\nimport {\n type AdapterOptions,\n connectVendorSession,\n pcmFormat,\n} from '../openai-realtime/session.ts';\nimport { registerRealtimeApiProvider } from '../registry.ts';\n\nconst voices = [\n { id: 'eve', name: 'Eve' },\n { id: 'ara', name: 'Ara' },\n { id: 'rex', name: 'Rex' },\n { id: 'sal', name: 'Sal' },\n { id: 'leo', name: 'Leo' },\n];\n\nexport const grokVoiceLatest: RealtimeModel<'xai-realtime'> = {\n id: 'grok-voice-latest',\n name: 'Grok Voice',\n api: 'xai-realtime',\n provider: 'xai',\n baseUrl: 'wss://api.x.ai/v1/realtime',\n type: 'realtime',\n transports: ['websocket', 'webrtc'],\n toolCalls: 'blocking',\n inputFormat: pcmFormat(24000),\n outputFormat: pcmFormat(24000),\n maxSessionMs: 7_200_000,\n resumable: true,\n ephemeralAuth: true,\n voices,\n provisioning: 'none',\n delivery: { interrupt: 'native', when_idle: 'approximate', silent: 'native' },\n truncation: 'client',\n liveToolUpdate: true,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n audioCost: { perInputMinute: 0.08, perOutputMinute: 0.08, perTextMessage: 0.004 },\n};\n\nexport function registerXaiRealtime(options: AdapterOptions = {}): () => void {\n const unregisterModel = registerVoiceModel(grokVoiceLatest);\n const unregisterApi = registerRealtimeApiProvider({\n api: 'xai-realtime',\n connect: (model, context, connectOptions) =>\n connectVendorSession(model, context, connectOptions, { ...options, dialect: 'xai' }),\n });\n return () => {\n unregisterModel();\n unregisterApi();\n };\n}\n"],
5
- "mappings": "AACA,SAAS,0BAA0B;AACnC;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAS,mCAAmC;AAE5C,MAAM,SAAS;AAAA,EACb,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAC3B;AAEO,MAAM,kBAAiD;AAAA,EAC5D,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,KAAK;AAAA,EACL,UAAU;AAAA,EACV,SAAS;AAAA,EACT,MAAM;AAAA,EACN,YAAY,CAAC,aAAa,QAAQ;AAAA,EAClC,WAAW;AAAA,EACX,aAAa,UAAU,IAAK;AAAA,EAC5B,cAAc,UAAU,IAAK;AAAA,EAC7B,cAAc;AAAA,EACd,WAAW;AAAA,EACX,eAAe;AAAA,EACf;AAAA,EACA,cAAc;AAAA,EACd,UAAU,EAAE,WAAW,UAAU,WAAW,eAAe,QAAQ,SAAS;AAAA,EAC5E,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,EAAE;AAAA,EACzD,WAAW,EAAE,gBAAgB,MAAM,iBAAiB,MAAM,gBAAgB,KAAM;AAClF;AAEO,SAAS,oBAAoB,UAA0B,CAAC,GAAe;AAC5E,QAAM,kBAAkB,mBAAmB,eAAe;AAC1D,QAAM,gBAAgB,4BAA4B;AAAA,IAChD,KAAK;AAAA,IACL,SAAS,CAAC,OAAO,SAAS,mBACxB,qBAAqB,OAAO,SAAS,gBAAgB,EAAE,GAAG,SAAS,SAAS,MAAM,CAAC;AAAA,EACvF,CAAC;AACD,SAAO,MAAM;AACX,oBAAgB;AAChB,kBAAc;AAAA,EAChB;AACF;",
4
+ "sourcesContent": ["import type { RealtimeModel } from '../models.ts';\nimport { registerVoiceModel } from '../models.ts';\nimport {\n type AdapterOptions,\n connectVendorSession,\n pcmFormat,\n} from '../openai-realtime/session.ts';\nimport { registerRealtimeApiProvider } from '../registry.ts';\n\nconst voices = [\n { id: 'eve', name: 'Eve' },\n { id: 'ara', name: 'Ara' },\n { id: 'rex', name: 'Rex' },\n { id: 'sal', name: 'Sal' },\n { id: 'leo', name: 'Leo' },\n];\n\nexport const grokVoiceLatest: RealtimeModel<'xai-realtime'> = {\n id: 'grok-voice-latest',\n name: 'Grok Voice',\n api: 'xai-realtime',\n provider: 'xai',\n baseUrl: 'wss://api.x.ai/v1/realtime',\n type: 'realtime',\n transports: ['websocket', 'webrtc'],\n toolCalls: 'blocking',\n inputFormat: pcmFormat(24000),\n outputFormat: pcmFormat(24000),\n maxSessionMs: 7_200_000,\n resumable: true,\n ephemeralAuth: true,\n voices,\n provisioning: 'none',\n delivery: { interrupt: 'native', when_idle: 'approximate', silent: 'native' },\n truncation: 'client',\n liveToolUpdate: true,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n audioCost: { perInputMinute: 0.08, perOutputMinute: 0.08, perTextMessage: 0.004 },\n};\n\nexport function registerXaiRealtime(options: AdapterOptions = {}): () => void {\n const unregisterModel = registerVoiceModel(grokVoiceLatest);\n const unregisterApi = registerRealtimeApiProvider({\n api: 'xai-realtime',\n connect: (model, context, connectOptions) =>\n connectVendorSession(model, context, connectOptions, { ...options, dialect: 'xai' }),\n });\n return () => {\n unregisterModel();\n unregisterApi();\n };\n}\n\nexport { registerXAI } from './catalog.ts';\n"],
5
+ "mappings": "AACA,SAAS,0BAA0B;AACnC;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAS,mCAAmC;AAE5C,MAAM,SAAS;AAAA,EACb,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAAA,EACzB,EAAE,IAAI,OAAO,MAAM,MAAM;AAC3B;AAEO,MAAM,kBAAiD;AAAA,EAC5D,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,KAAK;AAAA,EACL,UAAU;AAAA,EACV,SAAS;AAAA,EACT,MAAM;AAAA,EACN,YAAY,CAAC,aAAa,QAAQ;AAAA,EAClC,WAAW;AAAA,EACX,aAAa,UAAU,IAAK;AAAA,EAC5B,cAAc,UAAU,IAAK;AAAA,EAC7B,cAAc;AAAA,EACd,WAAW;AAAA,EACX,eAAe;AAAA,EACf;AAAA,EACA,cAAc;AAAA,EACd,UAAU,EAAE,WAAW,UAAU,WAAW,eAAe,QAAQ,SAAS;AAAA,EAC5E,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,EAAE;AAAA,EACzD,WAAW,EAAE,gBAAgB,MAAM,iBAAiB,MAAM,gBAAgB,KAAM;AAClF;AAEO,SAAS,oBAAoB,UAA0B,CAAC,GAAe;AAC5E,QAAM,kBAAkB,mBAAmB,eAAe;AAC1D,QAAM,gBAAgB,4BAA4B;AAAA,IAChD,KAAK;AAAA,IACL,SAAS,CAAC,OAAO,SAAS,mBACxB,qBAAqB,OAAO,SAAS,gBAAgB,EAAE,GAAG,SAAS,SAAS,MAAM,CAAC;AAAA,EACvF,CAAC;AACD,SAAO,MAAM;AACX,oBAAgB;AAChB,kBAAc;AAAA,EAChB;AACF;AAEA,SAAS,mBAAmB;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,211 @@
1
+ import { chunkSeconds } from "../audio.js";
2
+ import {
3
+ asVoiceError,
4
+ isRecord,
5
+ numberField,
6
+ requestHeaders,
7
+ stringField
8
+ } from "../openai/wire.js";
9
+ import {
10
+ TranscriptionEventStream
11
+ } from "../transcription.js";
12
+ import { priceAudio } from "../usage.js";
13
+ import {
14
+ awaitOpen,
15
+ connectSocket,
16
+ copiedBytes,
17
+ encodingName,
18
+ messageText,
19
+ sameFormat,
20
+ socketUrl
21
+ } from "./wire.js";
22
+ function terms(options) {
23
+ const vocabulary = options?.vocabulary;
24
+ if (!vocabulary) return [];
25
+ return vocabulary;
26
+ }
27
+ function sttUrl(model, format, options) {
28
+ const url = socketUrl(model.baseUrl, "stt");
29
+ const params = new URLSearchParams();
30
+ params.set("model", model.id);
31
+ params.set("sample_rate", String(format.sampleRate));
32
+ params.set("encoding", encodingName(format.encoding));
33
+ params.set("interim_results", "true");
34
+ if (model.turnDetection === "semantic") params.set("smart_turn", "0.5");
35
+ if (model.diarization) params.set("diarize", "true");
36
+ if (options?.language) params.set("language", options.language);
37
+ for (const term of terms(options)) params.append("keyterm", term);
38
+ url.search = params.toString();
39
+ return url.toString();
40
+ }
41
+ function chosenFormat(model, chunk) {
42
+ const format = chunk === void 0 ? model.inputFormats[0] : chunk.format;
43
+ if (!format) throw new Error("No input format");
44
+ encodingName(format.encoding);
45
+ const known = model.inputFormats.some((item) => sameFormat(item, format));
46
+ if (!known) throw new Error(`Unsupported audio format ${format.encoding}`);
47
+ return format;
48
+ }
49
+ function textOr(event, key) {
50
+ const text = stringField(event, key);
51
+ if (text === void 0) return "";
52
+ return text;
53
+ }
54
+ function applyListen(event, state, push) {
55
+ const type = stringField(event, "type");
56
+ if (type === "transcript.created") {
57
+ state.ready = true;
58
+ return;
59
+ }
60
+ if (type === "transcript.partial") {
61
+ const spoken = textOr(event, "text");
62
+ if (!state.started) {
63
+ state.started = true;
64
+ const start = numberField(event, "start");
65
+ push({ type: "speech_start", at: start === void 0 ? 0 : start * 1e3 });
66
+ }
67
+ if (event.is_final === true) {
68
+ const segmentId = String(state.segment);
69
+ state.segment += 1;
70
+ state.turns.push(spoken);
71
+ push({ type: "final", segmentId, text: spoken });
72
+ if (event.speech_final === true) {
73
+ state.started = false;
74
+ push({ type: "turn_end", text: spoken, at: 0 });
75
+ }
76
+ return;
77
+ }
78
+ push({ type: "partial", segmentId: String(state.segment), text: spoken });
79
+ return;
80
+ }
81
+ if (type === "transcript.done") {
82
+ const text = stringField(event, "text");
83
+ state.doneText = text === void 0 ? state.turns.join(" ") : text;
84
+ const duration = numberField(event, "duration");
85
+ if (duration !== void 0) state.duration = duration;
86
+ return;
87
+ }
88
+ if (type === "error") {
89
+ const message = stringField(event, "message");
90
+ state.failed = true;
91
+ push({
92
+ type: "error",
93
+ reason: "error",
94
+ error: message === void 0 ? "xAI transcription failed" : message
95
+ });
96
+ }
97
+ }
98
+ function finish(model, format, state, push) {
99
+ if (state.failed || state.completed) return;
100
+ state.completed = true;
101
+ const heard = chunkSeconds({ data: new Uint8Array(state.bytes), format, timestamp: 0 });
102
+ const seconds = state.duration === void 0 ? heard : state.duration;
103
+ const text = state.doneText === void 0 ? state.turns.join(" ") : state.doneText;
104
+ push({
105
+ type: "done",
106
+ transcript: { text, usage: priceAudio(model.audioCost, { inputSeconds: seconds }) }
107
+ });
108
+ }
109
+ function listenXAI(model, audio, options) {
110
+ const stream = new TranscriptionEventStream();
111
+ void pumpListen(model, audio, options, stream);
112
+ return stream;
113
+ }
114
+ async function pumpListen(model, audio, options, stream) {
115
+ const state = {
116
+ turns: [],
117
+ segment: 0,
118
+ started: false,
119
+ bytes: 0,
120
+ opened: false,
121
+ ready: false,
122
+ clientDone: false,
123
+ failed: false,
124
+ completed: false,
125
+ duration: void 0,
126
+ doneText: void 0
127
+ };
128
+ let settled = false;
129
+ const push = (event) => {
130
+ if (settled) return;
131
+ if (event.type === "done" || event.type === "error") settled = true;
132
+ stream.push(event);
133
+ };
134
+ let socket;
135
+ const readyWait = Promise.withResolvers();
136
+ const doneWait = Promise.withResolvers();
137
+ const wake = () => {
138
+ if (state.ready || state.failed) readyWait.resolve();
139
+ if (state.failed || state.doneText !== void 0) doneWait.resolve();
140
+ };
141
+ try {
142
+ if (options?.signal?.aborted) throw new DOMException("aborted", "AbortError");
143
+ const iterator = audio[Symbol.asyncIterator]();
144
+ const first = await iterator.next();
145
+ const format = chosenFormat(model, first.done ? void 0 : first.value);
146
+ socket = connectSocket(sttUrl(model, format, options), requestHeaders(model, options));
147
+ let incoming = Promise.resolve();
148
+ socket.addEventListener("message", (event) => {
149
+ incoming = incoming.then(() => onMessage(event.data, state, push, wake));
150
+ });
151
+ socket.addEventListener("close", () => {
152
+ if (state.opened && !state.failed && !state.completed && !state.clientDone) {
153
+ state.failed = true;
154
+ push({ type: "error", reason: "error", error: "xAI transcription socket closed" });
155
+ }
156
+ wake();
157
+ if (state.clientDone) doneWait.resolve();
158
+ });
159
+ await awaitOpen(socket, "xAI transcription", (message) => {
160
+ state.failed = true;
161
+ push({ type: "error", reason: "error", error: message });
162
+ wake();
163
+ });
164
+ if (state.failed) return;
165
+ state.opened = true;
166
+ if (!state.ready) await readyWait.promise;
167
+ if (state.failed) return;
168
+ if (!first.done) sendChunk(socket, first.value, format, state);
169
+ while (!state.failed) {
170
+ if (options?.signal?.aborted) throw new DOMException("aborted", "AbortError");
171
+ const next = await iterator.next();
172
+ if (next.done) break;
173
+ sendChunk(socket, next.value, format, state);
174
+ }
175
+ if (state.failed) return;
176
+ state.clientDone = true;
177
+ socket.send(JSON.stringify({ type: "audio.done" }));
178
+ if (state.doneText === void 0) await doneWait.promise;
179
+ finish(model, format, state, push);
180
+ } catch (error) {
181
+ const voice = asVoiceError(error);
182
+ state.failed = true;
183
+ push({ type: "error", reason: voice.reason, error: voice.error });
184
+ } finally {
185
+ socket?.close();
186
+ }
187
+ }
188
+ function sendChunk(socket, chunk, format, state) {
189
+ if (!sameFormat(chunk.format, format)) {
190
+ throw new Error(`Unsupported audio format ${chunk.format.encoding}`);
191
+ }
192
+ state.bytes += chunk.data.byteLength;
193
+ socket.send(copiedBytes(chunk.data));
194
+ }
195
+ async function onMessage(data, state, push, wake) {
196
+ try {
197
+ const parsed = JSON.parse(await messageText(data));
198
+ if (!isRecord(parsed)) throw new Error("xAI transcription event was not JSON");
199
+ applyListen(parsed, state, push);
200
+ wake();
201
+ } catch (error) {
202
+ const voice = asVoiceError(error);
203
+ state.failed = true;
204
+ push({ type: "error", reason: voice.reason, error: voice.error });
205
+ wake();
206
+ }
207
+ }
208
+ export {
209
+ listenXAI
210
+ };
211
+ //# sourceMappingURL=listen.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/xai/listen.ts"],
4
+ "sourcesContent": ["import type { AudioChunk, AudioFormat } from '../audio.ts';\nimport { chunkSeconds } from '../audio.ts';\nimport type { TranscriptionModel } from '../models.ts';\nimport {\n asVoiceError,\n isRecord,\n numberField,\n requestHeaders,\n stringField,\n} from '../openai/wire.ts';\nimport {\n type ListenOptions,\n type TranscriptionEvent,\n TranscriptionEventStream,\n} from '../transcription.ts';\nimport { priceAudio } from '../usage.ts';\nimport {\n awaitOpen,\n connectSocket,\n copiedBytes,\n encodingName,\n messageText,\n sameFormat,\n socketUrl,\n} from './wire.ts';\n\ninterface ListenState {\n turns: string[];\n segment: number;\n started: boolean;\n bytes: number;\n opened: boolean;\n ready: boolean;\n clientDone: boolean;\n failed: boolean;\n completed: boolean;\n duration: number | undefined;\n doneText: string | undefined;\n}\n\nfunction terms(options: ListenOptions | undefined): string[] {\n const vocabulary = options?.vocabulary;\n if (!vocabulary) return [];\n return vocabulary;\n}\n\nfunction sttUrl(\n model: TranscriptionModel<string>,\n format: AudioFormat,\n options: ListenOptions | undefined\n): string {\n const url = socketUrl(model.baseUrl, 'stt');\n const params = new URLSearchParams();\n params.set('model', model.id);\n params.set('sample_rate', String(format.sampleRate));\n params.set('encoding', encodingName(format.encoding));\n params.set('interim_results', 'true');\n if (model.turnDetection === 'semantic') params.set('smart_turn', '0.5');\n if (model.diarization) params.set('diarize', 'true');\n if (options?.language) params.set('language', options.language);\n for (const term of terms(options)) params.append('keyterm', term);\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 encodingName(format.encoding);\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 textOr(event: Record<string, unknown>, key: string): string {\n const text = stringField(event, key);\n if (text === undefined) return '';\n return text;\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 === 'transcript.created') {\n state.ready = true;\n return;\n }\n if (type === 'transcript.partial') {\n const spoken = textOr(event, 'text');\n if (!state.started) {\n state.started = true;\n const start = numberField(event, 'start');\n push({ type: 'speech_start', at: start === undefined ? 0 : start * 1000 });\n }\n if (event.is_final === true) {\n const segmentId = String(state.segment);\n state.segment += 1;\n state.turns.push(spoken);\n push({ type: 'final', segmentId, text: spoken });\n if (event.speech_final === true) {\n state.started = false;\n push({ type: 'turn_end', text: spoken, at: 0 });\n }\n return;\n }\n push({ type: 'partial', segmentId: String(state.segment), text: spoken });\n return;\n }\n if (type === 'transcript.done') {\n const text = stringField(event, 'text');\n state.doneText = text === undefined ? state.turns.join(' ') : text;\n const duration = numberField(event, 'duration');\n if (duration !== undefined) state.duration = duration;\n return;\n }\n if (type === 'error') {\n const message = stringField(event, 'message');\n state.failed = true;\n push({\n type: 'error',\n reason: 'error',\n error: message === undefined ? 'xAI transcription failed' : message,\n });\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 const seconds = state.duration === undefined ? heard : state.duration;\n const text = state.doneText === undefined ? state.turns.join(' ') : state.doneText;\n push({\n type: 'done',\n transcript: { text, usage: priceAudio(model.audioCost, { inputSeconds: seconds }) },\n });\n}\n\nexport function listenXAI(\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 segment: 0,\n started: false,\n bytes: 0,\n opened: false,\n ready: false,\n clientDone: false,\n failed: false,\n completed: false,\n duration: undefined,\n doneText: 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 = () => {\n if (state.ready || state.failed) readyWait.resolve();\n if (state.failed || state.doneText !== undefined) 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, format, options), requestHeaders(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: 'xAI transcription socket closed' });\n }\n wake();\n if (state.clientDone) doneWait.resolve();\n });\n await awaitOpen(socket, 'xAI transcription', (message) => {\n state.failed = true;\n push({ type: 'error', reason: 'error', error: message });\n wake();\n });\n if (state.failed) return;\n state.opened = true;\n if (!state.ready) await readyWait.promise;\n if (state.failed) return;\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 state.clientDone = true;\n socket.send(JSON.stringify({ type: 'audio.done' }));\n if (state.doneText === undefined) 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(copiedBytes(chunk.data));\n}\n\nasync function onMessage(\n data: unknown,\n state: ListenState,\n push: (event: TranscriptionEvent) => void,\n wake: () => void\n) {\n try {\n const parsed = JSON.parse(await messageText(data)) as unknown;\n if (!isRecord(parsed)) throw new Error('xAI transcription event was not JSON');\n applyListen(parsed, state, push);\n wake();\n } catch (error) {\n const voice = asVoiceError(error);\n state.failed = true;\n push({ type: 'error', reason: voice.reason, error: voice.error });\n wake();\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,oBAAoB;AAE7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EAGE;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAgBP,SAAS,MAAM,SAA8C;AAC3D,QAAM,aAAa,SAAS;AAC5B,MAAI,CAAC,WAAY,QAAO,CAAC;AACzB,SAAO;AACT;AAEA,SAAS,OACP,OACA,QACA,SACQ;AACR,QAAM,MAAM,UAAU,MAAM,SAAS,KAAK;AAC1C,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,SAAS,MAAM,EAAE;AAC5B,SAAO,IAAI,eAAe,OAAO,OAAO,UAAU,CAAC;AACnD,SAAO,IAAI,YAAY,aAAa,OAAO,QAAQ,CAAC;AACpD,SAAO,IAAI,mBAAmB,MAAM;AACpC,MAAI,MAAM,kBAAkB,WAAY,QAAO,IAAI,cAAc,KAAK;AACtE,MAAI,MAAM,YAAa,QAAO,IAAI,WAAW,MAAM;AACnD,MAAI,SAAS,SAAU,QAAO,IAAI,YAAY,QAAQ,QAAQ;AAC9D,aAAW,QAAQ,MAAM,OAAO,EAAG,QAAO,OAAO,WAAW,IAAI;AAChE,MAAI,SAAS,OAAO,SAAS;AAC7B,SAAO,IAAI,SAAS;AACtB;AAEA,SAAS,aACP,OACA,OACa;AACb,QAAM,SAAS,UAAU,SAAY,MAAM,aAAa,CAAC,IAAI,MAAM;AACnE,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,iBAAiB;AAC9C,eAAa,OAAO,QAAQ;AAC5B,QAAM,QAAQ,MAAM,aAAa,KAAK,CAAC,SAAS,WAAW,MAAM,MAAM,CAAC;AACxE,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,4BAA4B,OAAO,QAAQ,EAAE;AACzE,SAAO;AACT;AAEA,SAAS,OAAO,OAAgC,KAAqB;AACnE,QAAM,OAAO,YAAY,OAAO,GAAG;AACnC,MAAI,SAAS,OAAW,QAAO;AAC/B,SAAO;AACT;AAEA,SAAS,YACP,OACA,OACA,MACA;AACA,QAAM,OAAO,YAAY,OAAO,MAAM;AACtC,MAAI,SAAS,sBAAsB;AACjC,UAAM,QAAQ;AACd;AAAA,EACF;AACA,MAAI,SAAS,sBAAsB;AACjC,UAAM,SAAS,OAAO,OAAO,MAAM;AACnC,QAAI,CAAC,MAAM,SAAS;AAClB,YAAM,UAAU;AAChB,YAAM,QAAQ,YAAY,OAAO,OAAO;AACxC,WAAK,EAAE,MAAM,gBAAgB,IAAI,UAAU,SAAY,IAAI,QAAQ,IAAK,CAAC;AAAA,IAC3E;AACA,QAAI,MAAM,aAAa,MAAM;AAC3B,YAAM,YAAY,OAAO,MAAM,OAAO;AACtC,YAAM,WAAW;AACjB,YAAM,MAAM,KAAK,MAAM;AACvB,WAAK,EAAE,MAAM,SAAS,WAAW,MAAM,OAAO,CAAC;AAC/C,UAAI,MAAM,iBAAiB,MAAM;AAC/B,cAAM,UAAU;AAChB,aAAK,EAAE,MAAM,YAAY,MAAM,QAAQ,IAAI,EAAE,CAAC;AAAA,MAChD;AACA;AAAA,IACF;AACA,SAAK,EAAE,MAAM,WAAW,WAAW,OAAO,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC;AACxE;AAAA,EACF;AACA,MAAI,SAAS,mBAAmB;AAC9B,UAAM,OAAO,YAAY,OAAO,MAAM;AACtC,UAAM,WAAW,SAAS,SAAY,MAAM,MAAM,KAAK,GAAG,IAAI;AAC9D,UAAM,WAAW,YAAY,OAAO,UAAU;AAC9C,QAAI,aAAa,OAAW,OAAM,WAAW;AAC7C;AAAA,EACF;AACA,MAAI,SAAS,SAAS;AACpB,UAAM,UAAU,YAAY,OAAO,SAAS;AAC5C,UAAM,SAAS;AACf,SAAK;AAAA,MACH,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,OAAO,YAAY,SAAY,6BAA6B;AAAA,IAC9D,CAAC;AAAA,EACH;AACF;AAEA,SAAS,OACP,OACA,QACA,OACA,MACA;AACA,MAAI,MAAM,UAAU,MAAM,UAAW;AACrC,QAAM,YAAY;AAClB,QAAM,QAAQ,aAAa,EAAE,MAAM,IAAI,WAAW,MAAM,KAAK,GAAG,QAAQ,WAAW,EAAE,CAAC;AACtF,QAAM,UAAU,MAAM,aAAa,SAAY,QAAQ,MAAM;AAC7D,QAAM,OAAO,MAAM,aAAa,SAAY,MAAM,MAAM,KAAK,GAAG,IAAI,MAAM;AAC1E,OAAK;AAAA,IACH,MAAM;AAAA,IACN,YAAY,EAAE,MAAM,OAAO,WAAW,MAAM,WAAW,EAAE,cAAc,QAAQ,CAAC,EAAE;AAAA,EACpF,CAAC;AACH;AAEO,SAAS,UACd,OACA,OACA,SAC0B;AAC1B,QAAM,SAAS,IAAI,yBAAyB;AAC5C,OAAK,WAAW,OAAO,OAAO,SAAS,MAAM;AAC7C,SAAO;AACT;AAEA,eAAe,WACb,OACA,OACA,SACA,QACA;AACA,QAAM,QAAqB;AAAA,IACzB,OAAO,CAAC;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACA,MAAI,UAAU;AACd,QAAM,OAAO,CAAC,UAA8B;AAC1C,QAAI,QAAS;AACb,QAAI,MAAM,SAAS,UAAU,MAAM,SAAS,QAAS,WAAU;AAC/D,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,MAAI;AACJ,QAAM,YAAY,QAAQ,cAAoB;AAC9C,QAAM,WAAW,QAAQ,cAAoB;AAC7C,QAAM,OAAO,MAAM;AACjB,QAAI,MAAM,SAAS,MAAM,OAAQ,WAAU,QAAQ;AACnD,QAAI,MAAM,UAAU,MAAM,aAAa,OAAW,UAAS,QAAQ;AAAA,EACrE;AACA,MAAI;AACF,QAAI,SAAS,QAAQ,QAAS,OAAM,IAAI,aAAa,WAAW,YAAY;AAC5E,UAAM,WAAW,MAAM,OAAO,aAAa,EAAE;AAC7C,UAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,UAAM,SAAS,aAAa,OAAO,MAAM,OAAO,SAAY,MAAM,KAAK;AACvE,aAAS,cAAc,OAAO,OAAO,QAAQ,OAAO,GAAG,eAAe,OAAO,OAAO,CAAC;AACrF,QAAI,WAAW,QAAQ,QAAQ;AAC/B,WAAO,iBAAiB,WAAW,CAAC,UAAU;AAC5C,iBAAW,SAAS,KAAK,MAAM,UAAU,MAAM,MAAM,OAAO,MAAM,IAAI,CAAC;AAAA,IACzE,CAAC;AACD,WAAO,iBAAiB,SAAS,MAAM;AACrC,UAAI,MAAM,UAAU,CAAC,MAAM,UAAU,CAAC,MAAM,aAAa,CAAC,MAAM,YAAY;AAC1E,cAAM,SAAS;AACf,aAAK,EAAE,MAAM,SAAS,QAAQ,SAAS,OAAO,kCAAkC,CAAC;AAAA,MACnF;AACA,WAAK;AACL,UAAI,MAAM,WAAY,UAAS,QAAQ;AAAA,IACzC,CAAC;AACD,UAAM,UAAU,QAAQ,qBAAqB,CAAC,YAAY;AACxD,YAAM,SAAS;AACf,WAAK,EAAE,MAAM,SAAS,QAAQ,SAAS,OAAO,QAAQ,CAAC;AACvD,WAAK;AAAA,IACP,CAAC;AACD,QAAI,MAAM,OAAQ;AAClB,UAAM,SAAS;AACf,QAAI,CAAC,MAAM,MAAO,OAAM,UAAU;AAClC,QAAI,MAAM,OAAQ;AAClB,QAAI,CAAC,MAAM,KAAM,WAAU,QAAQ,MAAM,OAAO,QAAQ,KAAK;AAC7D,WAAO,CAAC,MAAM,QAAQ;AACpB,UAAI,SAAS,QAAQ,QAAS,OAAM,IAAI,aAAa,WAAW,YAAY;AAC5E,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAI,KAAK,KAAM;AACf,gBAAU,QAAQ,KAAK,OAAO,QAAQ,KAAK;AAAA,IAC7C;AACA,QAAI,MAAM,OAAQ;AAClB,UAAM,aAAa;AACnB,WAAO,KAAK,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC,CAAC;AAClD,QAAI,MAAM,aAAa,OAAW,OAAM,SAAS;AACjD,WAAO,OAAO,QAAQ,OAAO,IAAI;AAAA,EACnC,SAAS,OAAO;AACd,UAAM,QAAQ,aAAa,KAAK;AAChC,UAAM,SAAS;AACf,SAAK,EAAE,MAAM,SAAS,QAAQ,MAAM,QAAQ,OAAO,MAAM,MAAM,CAAC;AAAA,EAClE,UAAE;AACA,YAAQ,MAAM;AAAA,EAChB;AACF;AAEA,SAAS,UAAU,QAAmB,OAAmB,QAAqB,OAAoB;AAChG,MAAI,CAAC,WAAW,MAAM,QAAQ,MAAM,GAAG;AACrC,UAAM,IAAI,MAAM,4BAA4B,MAAM,OAAO,QAAQ,EAAE;AAAA,EACrE;AACA,QAAM,SAAS,MAAM,KAAK;AAC1B,SAAO,KAAK,YAAY,MAAM,IAAI,CAAC;AACrC;AAEA,eAAe,UACb,MACA,OACA,MACA,MACA;AACA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,MAAM,YAAY,IAAI,CAAC;AACjD,QAAI,CAAC,SAAS,MAAM,EAAG,OAAM,IAAI,MAAM,sCAAsC;AAC7E,gBAAY,QAAQ,OAAO,IAAI;AAC/B,SAAK;AAAA,EACP,SAAS,OAAO;AACd,UAAM,QAAQ,aAAa,KAAK;AAChC,UAAM,SAAS;AACf,SAAK,EAAE,MAAM,SAAS,QAAQ,MAAM,QAAQ,OAAO,MAAM,MAAM,CAAC;AAChE,SAAK;AAAA,EACP;AACF;",
6
+ "names": []
7
+ }