@ai-ecoverse/pi-audio 1.18.1 → 1.20.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,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/google/speak.ts"],
4
+ "sourcesContent": ["import type { ProviderRequestOptions } from '@earendil-works/pi-ai';\nimport type { AudioFormat } from '../audio.ts';\nimport { chunkSeconds } from '../audio.ts';\nimport { decodeAudioBase64 } from '../convert.ts';\nimport type { SpeechModel } from '../models.ts';\nimport {\n applyPayload,\n asVoiceError,\n endpoint,\n isRecord,\n readJson,\n requestSignal,\n stringField,\n} from '../openai/wire.ts';\nimport { SpeechEventStream, type SpeechInput } from '../speech.ts';\nimport { type AudioCounters, priceAudio } from '../usage.ts';\nimport { googleHeaders, sameFormat, speechMime } from './wire.ts';\n\nfunction resolveFormat(\n model: SpeechModel<string>,\n requested: AudioFormat | undefined\n): AudioFormat {\n const fallback = model.outputFormats[0];\n if (!fallback) throw new Error('No output format');\n if (!requested) return fallback;\n const match = model.outputFormats.find((format) => sameFormat(format, requested));\n if (!match) throw new Error(`Unsupported speech format ${requested.encoding}`);\n return match;\n}\n\nfunction speechBody(text: string, voice: string, format: AudioFormat): Record<string, unknown> {\n return {\n contents: [{ role: 'user', parts: [{ text }] }],\n generationConfig: {\n responseModalities: ['AUDIO'],\n responseFormat: { audio: { mimeType: speechMime(format) } },\n speechConfig: {\n voiceConfig: { prebuiltVoiceConfig: { voiceName: voice } },\n },\n },\n };\n}\n\nasync function readText(\n text: string | AsyncIterable<string>,\n signal: AbortSignal | undefined\n): Promise<string> {\n if (typeof text === 'string') return text;\n let combined = '';\n for await (const part of text) {\n if (signal?.aborted) throw new DOMException('aborted', 'AbortError');\n combined += part;\n }\n return combined;\n}\n\nfunction errorText(text: string, status: number): string {\n if (text === '') return `HTTP ${status}`;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return text;\n }\n if (!isRecord(parsed) || Array.isArray(parsed)) return text;\n const direct = stringField(parsed, 'message');\n if (direct !== undefined) return direct;\n const error = parsed.error;\n if (typeof error === 'string') return error;\n if (isRecord(error) && !Array.isArray(error)) {\n const nested = stringField(error, 'message');\n if (nested !== undefined) return nested;\n }\n return text;\n}\n\nfunction inlineData(part: Record<string, unknown>): string | undefined {\n const camel = part.inlineData;\n const snake = part.inline_data;\n const inline = isRecord(camel) && !Array.isArray(camel) ? camel : snake;\n if (!isRecord(inline) || Array.isArray(inline)) return undefined;\n return stringField(inline, 'data');\n}\n\nfunction audioParts(body: Record<string, unknown>): string[] {\n const candidates = body.candidates;\n if (!Array.isArray(candidates)) return [];\n const first = candidates[0];\n if (!isRecord(first) || Array.isArray(first)) return [];\n const content = first.content;\n if (!isRecord(content) || Array.isArray(content)) return [];\n const parts = content.parts;\n if (!Array.isArray(parts)) return [];\n const chunks: string[] = [];\n for (const part of parts) {\n if (!isRecord(part) || Array.isArray(part)) continue;\n const data = inlineData(part);\n if (data === undefined || data === '') continue;\n chunks.push(data);\n }\n return chunks;\n}\n\nfunction concat(chunks: Uint8Array[]): Uint8Array {\n const length = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n const out = new Uint8Array(length);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n\nasync function googleFetch(\n model: SpeechModel<string>,\n options: ProviderRequestOptions | undefined,\n url: string,\n body: string\n): Promise<Response> {\n const headers = googleHeaders(model, options);\n headers['Content-Type'] = 'application/json';\n const fetchImpl = options?.fetch ?? globalThis.fetch;\n const response = await fetchImpl(url, {\n method: 'POST',\n headers,\n body,\n signal: requestSignal(options),\n });\n await options?.onResponse?.({ status: response.status, headers: {} }, model as never);\n if (!response.ok) {\n const text = await response.text();\n throw new Error(errorText(text, response.status));\n }\n return response;\n}\n\nexport function speakGoogle(\n model: SpeechModel<string>,\n input: SpeechInput,\n options?: ProviderRequestOptions\n): SpeechEventStream {\n const stream = new SpeechEventStream();\n void pumpSpeech(model, input, options, stream);\n return stream;\n}\n\nasync function pumpSpeech(\n model: SpeechModel<string>,\n input: SpeechInput,\n options: ProviderRequestOptions | undefined,\n stream: SpeechEventStream\n) {\n try {\n if (options?.signal?.aborted) throw new DOMException('aborted', 'AbortError');\n const format = resolveFormat(model, input.format);\n const text = await readText(input.text, options?.signal);\n await postSpeech(model, text, input.voice, format, options, stream);\n } catch (error) {\n const voice = asVoiceError(error);\n stream.push({ type: 'error', reason: voice.reason, error: voice.error });\n }\n}\n\nasync function postSpeech(\n model: SpeechModel<string>,\n text: string,\n voice: string,\n format: AudioFormat,\n options: ProviderRequestOptions | undefined,\n stream: SpeechEventStream\n) {\n const payload = speechBody(text, voice, format);\n const body = await applyPayload(payload, model, options);\n if (!isRecord(body) || Array.isArray(body)) throw new Error('Speech payload was not JSON');\n const response = await googleFetch(\n model,\n options,\n endpoint(model.baseUrl, `models/${encodeURIComponent(model.id)}:generateContent`),\n JSON.stringify(body)\n );\n const parsed = await readJson(response);\n if (!isRecord(parsed) || Array.isArray(parsed)) throw new Error('Speech response had no audio');\n const encoded = audioParts(parsed);\n if (encoded.length === 0) throw new Error('Speech response had no audio');\n const data = concat(encoded.map((item) => decodeAudioBase64(item)));\n const seconds = chunkSeconds({ data, format, timestamp: 0 });\n const meters: AudioCounters = { characters: text.length };\n if (seconds > 0) meters.outputSeconds = seconds;\n stream.push({ type: 'start', format });\n stream.push({\n type: 'audio',\n chunk: { data, format, timestamp: 0 },\n span: { itemId: model.id, start: 0, end: text.length },\n });\n stream.push({ type: 'done', usage: priceAudio(model.audioCost, meters) });\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,43 @@
1
+ const mimes = {
2
+ wav: "AUDIO_WAV",
3
+ pcm16: "AUDIO_L16",
4
+ mulaw: "AUDIO_MULAW",
5
+ alaw: "AUDIO_ALAW"
6
+ };
7
+ function speechMime(format) {
8
+ const name = mimes[format.encoding];
9
+ if (!name) throw new Error(`Unsupported speech format ${format.encoding}`);
10
+ return name;
11
+ }
12
+ function sameFormat(left, right) {
13
+ return left.encoding === right.encoding && left.sampleRate === right.sampleRate && left.channels === right.channels;
14
+ }
15
+ function headerValue(headers, name) {
16
+ const expected = name.toLowerCase();
17
+ for (const [key, value] of Object.entries(headers)) {
18
+ if (key.toLowerCase() === expected && value.trim() !== "") return value;
19
+ }
20
+ return void 0;
21
+ }
22
+ function googleHeaders(model, options) {
23
+ const headers = { ...model.headers };
24
+ const extra = options?.headers;
25
+ if (extra) {
26
+ for (const [key, value] of Object.entries(extra)) {
27
+ if (value === null) delete headers[key];
28
+ else headers[key] = value;
29
+ }
30
+ }
31
+ if (headerValue(headers, "x-goog-api-key") === void 0) {
32
+ const apiKey = options?.apiKey;
33
+ if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
34
+ headers["x-goog-api-key"] = apiKey;
35
+ }
36
+ return headers;
37
+ }
38
+ export {
39
+ googleHeaders,
40
+ sameFormat,
41
+ speechMime
42
+ };
43
+ //# sourceMappingURL=wire.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/google/wire.ts"],
4
+ "sourcesContent": ["import type { ProviderRequestOptions } from '@earendil-works/pi-ai';\nimport type { AudioFormat } from '../audio.ts';\n\nconst mimes: Record<string, string> = {\n wav: 'AUDIO_WAV',\n pcm16: 'AUDIO_L16',\n mulaw: 'AUDIO_MULAW',\n alaw: 'AUDIO_ALAW',\n};\n\nexport function speechMime(format: AudioFormat): string {\n const name = mimes[format.encoding];\n if (!name) throw new Error(`Unsupported speech format ${format.encoding}`);\n return name;\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\nfunction headerValue(headers: Record<string, string>, name: string): string | undefined {\n const expected = name.toLowerCase();\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === expected && value.trim() !== '') return value;\n }\n return undefined;\n}\n\nexport function googleHeaders(\n model: { provider: string; headers?: Record<string, string> },\n options: ProviderRequestOptions | undefined\n): Record<string, string> {\n const headers: Record<string, string> = { ...model.headers };\n const extra = options?.headers;\n if (extra) {\n for (const [key, value] of Object.entries(extra)) {\n if (value === null) delete headers[key];\n else headers[key] = value;\n }\n }\n if (headerValue(headers, 'x-goog-api-key') === undefined) {\n const apiKey = options?.apiKey;\n if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);\n headers['x-goog-api-key'] = apiKey;\n }\n return headers;\n}\n"],
5
+ "mappings": "AAGA,MAAM,QAAgC;AAAA,EACpC,KAAK;AAAA,EACL,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AACR;AAEO,SAAS,WAAW,QAA6B;AACtD,QAAM,OAAO,MAAM,OAAO,QAAQ;AAClC,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,6BAA6B,OAAO,QAAQ,EAAE;AACzE,SAAO;AACT;AAEO,SAAS,WAAW,MAAmB,OAA6B;AACzE,SACE,KAAK,aAAa,MAAM,YACxB,KAAK,eAAe,MAAM,cAC1B,KAAK,aAAa,MAAM;AAE5B;AAEA,SAAS,YAAY,SAAiC,MAAkC;AACtF,QAAM,WAAW,KAAK,YAAY;AAClC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,IAAI,YAAY,MAAM,YAAY,MAAM,KAAK,MAAM,GAAI,QAAO;AAAA,EACpE;AACA,SAAO;AACT;AAEO,SAAS,cACd,OACA,SACwB;AACxB,QAAM,UAAkC,EAAE,GAAG,MAAM,QAAQ;AAC3D,QAAM,QAAQ,SAAS;AACvB,MAAI,OAAO;AACT,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,UAAI,UAAU,KAAM,QAAO,QAAQ,GAAG;AAAA,UACjC,SAAQ,GAAG,IAAI;AAAA,IACtB;AAAA,EACF;AACA,MAAI,YAAY,SAAS,gBAAgB,MAAM,QAAW;AACxD,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,4BAA4B,MAAM,QAAQ,EAAE;AACzE,YAAQ,gBAAgB,IAAI;AAAA,EAC9B;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export declare function registerFish(): () => void;
@@ -0,0 +1 @@
1
+ export { registerFish } from './catalog.ts';
@@ -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 speakFish(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 transcribeFish(model: TranscriptionModel<string>, input: AudioInput, options?: ProviderRequestOptions): Promise<Transcript>;
@@ -0,0 +1,27 @@
1
+ import type { ProviderRequestOptions } from '@earendil-works/pi-ai';
2
+ import type { AudioFormat } from '../audio.ts';
3
+ export type PackValue = null | boolean | number | string | Uint8Array | PackValue[] | {
4
+ [key: string]: PackValue;
5
+ };
6
+ export interface FishFile {
7
+ data: Uint8Array;
8
+ mimeType: string;
9
+ filename: string;
10
+ }
11
+ export declare function pack(value: PackValue): Uint8Array;
12
+ export declare function unpack(data: Uint8Array): PackValue;
13
+ export declare function mediaType(mimeType: string): string;
14
+ export declare function audioFilename(mimeType: string): string;
15
+ export declare function encodeForm(file: FishFile, fields: Record<string, string>): ArrayBuffer;
16
+ export declare function formType(): string;
17
+ export declare function fishHeaders(model: {
18
+ id: string;
19
+ provider: string;
20
+ headers?: Record<string, string>;
21
+ }, options: ProviderRequestOptions | undefined): Record<string, string>;
22
+ export declare function socketUrl(baseUrl: string, path: string): URL;
23
+ export declare function speechFormatName(format: AudioFormat): string;
24
+ export declare function connectSocket(url: string, headers: Record<string, string>): WebSocket;
25
+ export declare function awaitOpen(socket: WebSocket, label: string, fail: (message: string) => void): Promise<void>;
26
+ export declare function messageBytes(data: unknown): Promise<Uint8Array>;
27
+ export declare function sameFormat(left: AudioFormat, right: AudioFormat): boolean;
@@ -0,0 +1 @@
1
+ export declare function registerGoogle(): () => void;
@@ -0,0 +1 @@
1
+ export { registerGoogle } from './catalog.ts';
@@ -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 speakGoogle(model: SpeechModel<string>, input: SpeechInput, options?: ProviderRequestOptions): SpeechEventStream;
@@ -0,0 +1,8 @@
1
+ import type { ProviderRequestOptions } from '@earendil-works/pi-ai';
2
+ import type { AudioFormat } from '../audio.ts';
3
+ export declare function speechMime(format: AudioFormat): string;
4
+ export declare function sameFormat(left: AudioFormat, right: AudioFormat): boolean;
5
+ export declare function googleHeaders(model: {
6
+ provider: string;
7
+ headers?: Record<string, string>;
8
+ }, options: ProviderRequestOptions | undefined): Record<string, string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/pi-audio",
3
- "version": "1.18.1",
3
+ "version": "1.20.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",
@@ -54,6 +54,14 @@
54
54
  "types": "./dist/types/mistral/index.d.ts",
55
55
  "default": "./dist/mistral/index.js"
56
56
  },
57
+ "./fish": {
58
+ "types": "./dist/types/fish/index.d.ts",
59
+ "default": "./dist/fish/index.js"
60
+ },
61
+ "./google": {
62
+ "types": "./dist/types/google/index.d.ts",
63
+ "default": "./dist/google/index.js"
64
+ },
57
65
  "./durable": {
58
66
  "types": "./dist/types/durable/index.d.ts",
59
67
  "default": "./dist/durable/index.js"