@ai-ecoverse/pi-audio 1.10.0 → 1.12.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,171 @@
1
+ const boundary = "pi-audio-xai-boundary";
2
+ const filenames = {
3
+ "audio/wav": "audio.wav",
4
+ "audio/wave": "audio.wav",
5
+ "audio/x-wav": "audio.wav",
6
+ "audio/mpeg": "audio.mp3",
7
+ "audio/mp3": "audio.mp3",
8
+ "audio/flac": "audio.flac",
9
+ "audio/ogg": "audio.ogg",
10
+ "audio/opus": "audio.opus",
11
+ "audio/pcm": "audio.pcm",
12
+ "audio/l16": "audio.pcm",
13
+ "audio/mulaw": "audio.mulaw",
14
+ "audio/basic": "audio.mulaw",
15
+ "audio/alaw": "audio.alaw",
16
+ "audio/mp4": "audio.mp4",
17
+ "audio/m4a": "audio.m4a",
18
+ "audio/aac": "audio.aac",
19
+ "audio/webm": "audio.webm"
20
+ };
21
+ function mediaType(mimeType) {
22
+ const type = mimeType.split(";")[0]?.trim().toLowerCase();
23
+ if (!type) throw new Error(`Unsupported audio type ${mimeType}`);
24
+ return type;
25
+ }
26
+ function audioFilename(mimeType) {
27
+ const name = filenames[mediaType(mimeType)];
28
+ if (!name) throw new Error(`Unsupported audio type ${mimeType}`);
29
+ return name;
30
+ }
31
+ function declaredRate(model, encoding) {
32
+ const match = model.inputFormats.find((format) => format.encoding === encoding);
33
+ if (!match) return "16000";
34
+ return String(match.sampleRate);
35
+ }
36
+ function parameter(mimeType, name) {
37
+ for (const part of mimeType.split(";").slice(1)) {
38
+ const pieces = part.split("=");
39
+ const key = pieces[0]?.trim().toLowerCase();
40
+ const value = pieces[1]?.trim();
41
+ if (key === name && value) return value;
42
+ }
43
+ return void 0;
44
+ }
45
+ function rawFields(mimeType, model) {
46
+ const type = mediaType(mimeType);
47
+ const rate = parameter(mimeType, "rate");
48
+ if (type === "audio/pcm" || type === "audio/l16") {
49
+ const sampleRate = rate === void 0 ? declaredRate(model, "pcm16") : rate;
50
+ return { audio_format: "pcm", sample_rate: sampleRate };
51
+ }
52
+ if (type === "audio/mulaw" || type === "audio/basic") {
53
+ const sampleRate = rate === void 0 ? declaredRate(model, "mulaw") : rate;
54
+ return { audio_format: "mulaw", sample_rate: sampleRate };
55
+ }
56
+ if (type === "audio/alaw") {
57
+ const sampleRate = rate === void 0 ? declaredRate(model, "alaw") : rate;
58
+ return { audio_format: "alaw", sample_rate: sampleRate };
59
+ }
60
+ return void 0;
61
+ }
62
+ function encodeForm(file, fields) {
63
+ const chunks = [];
64
+ const encoder = new TextEncoder();
65
+ const write = (value) => {
66
+ chunks.push(encoder.encode(value));
67
+ };
68
+ for (const [name, value] of Object.entries(fields)) {
69
+ write(`--${boundary}\r
70
+ Content-Disposition: form-data; name="${name}"\r
71
+ \r
72
+ ${value}\r
73
+ `);
74
+ }
75
+ write(
76
+ `--${boundary}\r
77
+ Content-Disposition: form-data; name="file"; filename="${file.filename}"\r
78
+ Content-Type: ${file.mimeType}\r
79
+ \r
80
+ `
81
+ );
82
+ chunks.push(file.data);
83
+ write(`\r
84
+ --${boundary}--\r
85
+ `);
86
+ const body = new Uint8Array(chunks.reduce((sum, chunk) => sum + chunk.length, 0));
87
+ let offset = 0;
88
+ for (const chunk of chunks) {
89
+ body.set(chunk, offset);
90
+ offset += chunk.length;
91
+ }
92
+ return body.buffer;
93
+ }
94
+ function formType() {
95
+ return `multipart/form-data; boundary=${boundary}`;
96
+ }
97
+ function socketUrl(baseUrl, path) {
98
+ const url = new URL(baseUrl);
99
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
100
+ url.pathname = `${url.pathname.replace(/\/$/, "")}/${path}`;
101
+ url.search = "";
102
+ return url;
103
+ }
104
+ function codecName(encoding) {
105
+ if (encoding === "pcm16") return "pcm";
106
+ if (encoding === "mp3") return "mp3";
107
+ if (encoding === "wav") return "wav";
108
+ if (encoding === "mulaw") return "mulaw";
109
+ if (encoding === "alaw") return "alaw";
110
+ throw new Error(`xAI speech cannot return ${encoding}`);
111
+ }
112
+ function encodingName(encoding) {
113
+ if (encoding === "pcm16") return "pcm";
114
+ if (encoding === "mulaw") return "mulaw";
115
+ if (encoding === "alaw") return "alaw";
116
+ throw new Error(`Unsupported audio format ${encoding}`);
117
+ }
118
+ function connectSocket(url, headers) {
119
+ const Socket = WebSocket;
120
+ return new Socket(url, { headers });
121
+ }
122
+ function awaitOpen(socket, label, fail) {
123
+ return new Promise((resolve) => {
124
+ let opened = false;
125
+ socket.addEventListener("open", () => {
126
+ opened = true;
127
+ resolve();
128
+ });
129
+ socket.addEventListener("error", () => {
130
+ fail(`${label} socket failed`);
131
+ if (!opened) resolve();
132
+ });
133
+ socket.addEventListener("close", () => {
134
+ if (!opened) {
135
+ fail(`${label} socket closed`);
136
+ resolve();
137
+ }
138
+ });
139
+ });
140
+ }
141
+ async function messageText(data) {
142
+ if (typeof data === "string") return data;
143
+ if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
144
+ if (data instanceof Uint8Array) return new TextDecoder().decode(data);
145
+ if (typeof Blob !== "undefined" && data instanceof Blob) return data.text();
146
+ throw new Error("Unsupported socket message");
147
+ }
148
+ function sameFormat(left, right) {
149
+ return left.encoding === right.encoding && left.sampleRate === right.sampleRate && left.channels === right.channels;
150
+ }
151
+ function copiedBytes(data) {
152
+ const copy = new ArrayBuffer(data.byteLength);
153
+ new Uint8Array(copy).set(data);
154
+ return copy;
155
+ }
156
+ export {
157
+ audioFilename,
158
+ awaitOpen,
159
+ codecName,
160
+ connectSocket,
161
+ copiedBytes,
162
+ encodeForm,
163
+ encodingName,
164
+ formType,
165
+ mediaType,
166
+ messageText,
167
+ rawFields,
168
+ sameFormat,
169
+ socketUrl
170
+ };
171
+ //# sourceMappingURL=wire.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/xai/wire.ts"],
4
+ "sourcesContent": ["import type { AudioFormat } from '../audio.ts';\nimport type { TranscriptionModel } from '../models.ts';\n\nconst boundary = 'pi-audio-xai-boundary';\n\nconst filenames: Record<string, string> = {\n 'audio/wav': 'audio.wav',\n 'audio/wave': 'audio.wav',\n 'audio/x-wav': 'audio.wav',\n 'audio/mpeg': 'audio.mp3',\n 'audio/mp3': 'audio.mp3',\n 'audio/flac': 'audio.flac',\n 'audio/ogg': 'audio.ogg',\n 'audio/opus': 'audio.opus',\n 'audio/pcm': 'audio.pcm',\n 'audio/l16': 'audio.pcm',\n 'audio/mulaw': 'audio.mulaw',\n 'audio/basic': 'audio.mulaw',\n 'audio/alaw': 'audio.alaw',\n 'audio/mp4': 'audio.mp4',\n 'audio/m4a': 'audio.m4a',\n 'audio/aac': 'audio.aac',\n 'audio/webm': 'audio.webm',\n};\n\nexport interface XaiFile {\n data: Uint8Array;\n mimeType: string;\n filename: string;\n}\n\nexport function mediaType(mimeType: string): string {\n const type = mimeType.split(';')[0]?.trim().toLowerCase();\n if (!type) throw new Error(`Unsupported audio type ${mimeType}`);\n return type;\n}\n\nexport function audioFilename(mimeType: string): string {\n const name = filenames[mediaType(mimeType)];\n if (!name) throw new Error(`Unsupported audio type ${mimeType}`);\n return name;\n}\n\nfunction declaredRate(\n model: TranscriptionModel<string>,\n encoding: AudioFormat['encoding']\n): string {\n const match = model.inputFormats.find((format) => format.encoding === encoding);\n if (!match) return '16000';\n return String(match.sampleRate);\n}\n\nfunction parameter(mimeType: string, name: string): string | undefined {\n for (const part of mimeType.split(';').slice(1)) {\n const pieces = part.split('=');\n const key = pieces[0]?.trim().toLowerCase();\n const value = pieces[1]?.trim();\n if (key === name && value) return value;\n }\n return undefined;\n}\n\nexport function rawFields(\n mimeType: string,\n model: TranscriptionModel<string>\n): Record<string, string> | undefined {\n const type = mediaType(mimeType);\n const rate = parameter(mimeType, 'rate');\n if (type === 'audio/pcm' || type === 'audio/l16') {\n const sampleRate = rate === undefined ? declaredRate(model, 'pcm16') : rate;\n return { audio_format: 'pcm', sample_rate: sampleRate };\n }\n if (type === 'audio/mulaw' || type === 'audio/basic') {\n const sampleRate = rate === undefined ? declaredRate(model, 'mulaw') : rate;\n return { audio_format: 'mulaw', sample_rate: sampleRate };\n }\n if (type === 'audio/alaw') {\n const sampleRate = rate === undefined ? declaredRate(model, 'alaw') : rate;\n return { audio_format: 'alaw', sample_rate: sampleRate };\n }\n return undefined;\n}\n\nexport function encodeForm(file: XaiFile, fields: Record<string, string>): ArrayBuffer {\n const chunks: Uint8Array[] = [];\n const encoder = new TextEncoder();\n const write = (value: string) => {\n chunks.push(encoder.encode(value));\n };\n for (const [name, value] of Object.entries(fields)) {\n write(`--${boundary}\\r\\nContent-Disposition: form-data; name=\"${name}\"\\r\\n\\r\\n${value}\\r\\n`);\n }\n write(\n `--${boundary}\\r\\nContent-Disposition: form-data; name=\"file\"; filename=\"${file.filename}\"\\r\\nContent-Type: ${file.mimeType}\\r\\n\\r\\n`\n );\n chunks.push(file.data);\n write(`\\r\\n--${boundary}--\\r\\n`);\n const body = new Uint8Array(chunks.reduce((sum, chunk) => sum + chunk.length, 0));\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.length;\n }\n return body.buffer;\n}\n\nexport function formType(): string {\n return `multipart/form-data; boundary=${boundary}`;\n}\n\nexport function socketUrl(baseUrl: string, path: string): URL {\n const url = new URL(baseUrl);\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';\n url.pathname = `${url.pathname.replace(/\\/$/, '')}/${path}`;\n url.search = '';\n return url;\n}\n\nexport function codecName(encoding: AudioFormat['encoding']): string {\n if (encoding === 'pcm16') return 'pcm';\n if (encoding === 'mp3') return 'mp3';\n if (encoding === 'wav') return 'wav';\n if (encoding === 'mulaw') return 'mulaw';\n if (encoding === 'alaw') return 'alaw';\n throw new Error(`xAI speech cannot return ${encoding}`);\n}\n\nexport function encodingName(encoding: AudioFormat['encoding']): string {\n if (encoding === 'pcm16') return 'pcm';\n if (encoding === 'mulaw') return 'mulaw';\n if (encoding === 'alaw') return 'alaw';\n throw new Error(`Unsupported audio format ${encoding}`);\n}\n\nexport function connectSocket(url: string, headers: Record<string, string>): WebSocket {\n const Socket = WebSocket as unknown as new (\n address: string,\n init: { headers: Record<string, string> }\n ) => WebSocket;\n return new Socket(url, { headers });\n}\n\nexport function awaitOpen(\n socket: WebSocket,\n label: string,\n fail: (message: string) => void\n): Promise<void> {\n return new Promise((resolve) => {\n let opened = false;\n socket.addEventListener('open', () => {\n opened = true;\n resolve();\n });\n socket.addEventListener('error', () => {\n fail(`${label} socket failed`);\n if (!opened) resolve();\n });\n socket.addEventListener('close', () => {\n if (!opened) {\n fail(`${label} socket closed`);\n resolve();\n }\n });\n });\n}\n\nexport async function messageText(data: unknown): Promise<string> {\n if (typeof data === 'string') return data;\n if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);\n if (data instanceof Uint8Array) return new TextDecoder().decode(data);\n if (typeof Blob !== 'undefined' && data instanceof Blob) return data.text();\n throw new Error('Unsupported socket message');\n}\n\nexport function sameFormat(left: AudioFormat, right: AudioFormat): boolean {\n return (\n left.encoding === right.encoding &&\n left.sampleRate === right.sampleRate &&\n left.channels === right.channels\n );\n}\n\nexport function copiedBytes(data: Uint8Array): ArrayBuffer {\n const copy = new ArrayBuffer(data.byteLength);\n new Uint8Array(copy).set(data);\n return copy;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/pi-audio",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "Voice bindings for pi: speech-to-text, text-to-speech and realtime speech for pi-coding-agent plugins and slicc-agent",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -49,6 +49,10 @@
49
49
  "./durable": {
50
50
  "types": "./dist/types/durable/index.d.ts",
51
51
  "default": "./dist/durable/index.js"
52
+ },
53
+ "./gemini-live": {
54
+ "types": "./dist/types/gemini-live/index.d.ts",
55
+ "default": "./dist/gemini-live/index.js"
52
56
  }
53
57
  },
54
58
  "files": [