@kaana.ai/contracts 0.0.0-stage → 4.3.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/LICENSE +673 -0
- package/NOTICE +21 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +29 -0
- package/dist/internal/attribution.d.ts +116 -0
- package/dist/internal/attribution.js +82 -0
- package/dist/internal/canonical.d.ts +31 -0
- package/dist/internal/canonical.js +57 -0
- package/dist/internal/catalogue.d.ts +1030 -0
- package/dist/internal/catalogue.js +349 -0
- package/dist/internal/credentialControl.d.ts +329 -0
- package/dist/internal/credentialControl.js +256 -0
- package/dist/internal/decisions.d.ts +245 -0
- package/dist/internal/decisions.js +69 -0
- package/dist/internal/economics.d.ts +27 -0
- package/dist/internal/economics.js +26 -0
- package/dist/internal/embeddings.d.ts +164 -0
- package/dist/internal/embeddings.js +59 -0
- package/dist/internal/errors.d.ts +185 -0
- package/dist/internal/errors.js +211 -0
- package/dist/internal/grant.d.ts +696 -0
- package/dist/internal/grant.js +437 -0
- package/dist/internal/identifiers.d.ts +63 -0
- package/dist/internal/identifiers.js +65 -0
- package/dist/internal/privateAutoExecution.d.ts +158 -0
- package/dist/internal/privateAutoExecution.js +188 -0
- package/dist/internal/realtime.d.ts +1005 -0
- package/dist/internal/realtime.js +187 -0
- package/dist/internal/request.d.ts +1079 -0
- package/dist/internal/request.js +404 -0
- package/dist/internal/routing.d.ts +90 -0
- package/dist/internal/routing.js +139 -0
- package/dist/internal/scopedExecution.d.ts +74 -0
- package/dist/internal/scopedExecution.js +61 -0
- package/dist/internal/settlement.d.ts +205 -0
- package/dist/internal/settlement.js +71 -0
- package/dist/internal/streamEvents.d.ts +422 -0
- package/dist/internal/streamEvents.js +171 -0
- package/dist/internal/usage.d.ts +127 -0
- package/dist/internal/usage.js +109 -0
- package/dist/internal.d.ts +30 -0
- package/dist/internal.js +30 -0
- package/dist/public/audio.d.ts +347 -0
- package/dist/public/audio.js +236 -0
- package/dist/public/audioFormats.d.ts +64 -0
- package/dist/public/audioFormats.js +60 -0
- package/dist/public/catalogue.d.ts +914 -0
- package/dist/public/catalogue.js +516 -0
- package/dist/public/chatCompletions.d.ts +381 -0
- package/dist/public/chatCompletions.js +321 -0
- package/dist/public/decisions.d.ts +182 -0
- package/dist/public/decisions.js +257 -0
- package/dist/public/embeddings.d.ts +34 -0
- package/dist/public/embeddings.js +66 -0
- package/dist/public/errors.d.ts +195 -0
- package/dist/public/errors.js +274 -0
- package/dist/public/generations.d.ts +330 -0
- package/dist/public/generations.js +121 -0
- package/dist/public/identifiers.d.ts +139 -0
- package/dist/public/identifiers.js +160 -0
- package/dist/public/images.d.ts +36 -0
- package/dist/public/images.js +36 -0
- package/dist/public/messages.d.ts +297 -0
- package/dist/public/messages.js +251 -0
- package/dist/public/money.d.ts +308 -0
- package/dist/public/money.js +237 -0
- package/dist/public/policy.d.ts +19 -0
- package/dist/public/policy.js +20 -0
- package/dist/public/realtime.d.ts +2006 -0
- package/dist/public/realtime.js +797 -0
- package/dist/public/responses.d.ts +253 -0
- package/dist/public/responses.js +95 -0
- package/dist/public/streamEvents.d.ts +372 -0
- package/dist/public/streamEvents.js +157 -0
- package/dist/public/version.d.ts +177 -0
- package/dist/public/version.js +177 -0
- package/openapi.json +6967 -0
- package/package.json +44 -4
- package/README.md +0 -3
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `POST /v1/audio/speech` (with and without streaming) and
|
|
3
|
+
* `POST /v1/audio/transcriptions`.
|
|
4
|
+
*
|
|
5
|
+
* The speech request is moved from the Oxy edge
|
|
6
|
+
* (`packages/api/src/schemas/inferenceEdge.schemas.ts`) by Kaana ADR 0002;
|
|
7
|
+
* streaming speech (decision 8), the voice limits checked before a grant
|
|
8
|
+
* (decision 9) and transcription are new in contract set 4.0.0.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { audioInputMediaTypeSchema, languageTagSchema, speechFormatSchema, speechMediaType, } from './audioFormats.js';
|
|
12
|
+
import { publicErrorSchema } from './errors.js';
|
|
13
|
+
import { modelReferenceSchema, PADDED_BASE64_PATTERN, requestIdSchema } from './identifiers.js';
|
|
14
|
+
import { usageSchema } from './money.js';
|
|
15
|
+
/* -------------------------------------------------------------------------- */
|
|
16
|
+
/* Speech */
|
|
17
|
+
/* -------------------------------------------------------------------------- */
|
|
18
|
+
/** The longest text one speech request may carry, before any model's own limit. */
|
|
19
|
+
export const MAX_SPEECH_INPUT_CHARACTERS = 100_000;
|
|
20
|
+
/**
|
|
21
|
+
* How a streamed speech response is carried:
|
|
22
|
+
*
|
|
23
|
+
* - `audio` (OpenAI-compatible): `200` with `Transfer-Encoding: chunked` and the
|
|
24
|
+
* raw bytes. A failure before the first byte is an HTTP status with an error
|
|
25
|
+
* body; one after it cuts the connection and the generation record keeps the
|
|
26
|
+
* code.
|
|
27
|
+
* - `sse` (what `@kaana.ai/sdk` uses): {@link speechStreamEventSchema} frames,
|
|
28
|
+
* so a failure mid-stream arrives typed.
|
|
29
|
+
*/
|
|
30
|
+
export const speechStreamFormatSchema = z.enum(['audio', 'sse']);
|
|
31
|
+
/**
|
|
32
|
+
* The formats speech can be streamed in: `audio/mpeg` and
|
|
33
|
+
* `audio/pcm;rate=24000`, the two containers that can be played as they arrive.
|
|
34
|
+
*/
|
|
35
|
+
export const STREAMABLE_SPEECH_FORMATS = ['mp3', 'pcm'];
|
|
36
|
+
/**
|
|
37
|
+
* The request, in the shape a stock OpenAI client sends.
|
|
38
|
+
*
|
|
39
|
+
* `model` is a concrete model: a voice belongs to a model, so a power level,
|
|
40
|
+
* which may choose any of several, could not be validated against one.
|
|
41
|
+
*/
|
|
42
|
+
export const speechRequestSchema = z
|
|
43
|
+
.object({
|
|
44
|
+
model: modelReferenceSchema,
|
|
45
|
+
/** Bounded so one request cannot drive the hold arbitrarily high. */
|
|
46
|
+
input: z.string().min(1).max(MAX_SPEECH_INPUT_CHARACTERS),
|
|
47
|
+
voice: z.string().min(1).max(64),
|
|
48
|
+
/** Absent means `mp3`. */
|
|
49
|
+
response_format: speechFormatSchema.optional(),
|
|
50
|
+
/** The contract's outer bound; each model publishes its own range. */
|
|
51
|
+
speed: z.number().min(0.25).max(4).optional(),
|
|
52
|
+
stream: z.boolean().optional(),
|
|
53
|
+
/** Only with `stream: true`. Absent means `audio`. */
|
|
54
|
+
stream_format: speechStreamFormatSchema.optional(),
|
|
55
|
+
/** OpenAI's end-user attribution field: the delegated user id, attribution only. */
|
|
56
|
+
user: z.string().min(1).max(64).optional(),
|
|
57
|
+
})
|
|
58
|
+
.strict()
|
|
59
|
+
.superRefine((request, ctx) => {
|
|
60
|
+
if (request.stream_format !== undefined && request.stream !== true) {
|
|
61
|
+
ctx.addIssue({
|
|
62
|
+
code: 'custom',
|
|
63
|
+
path: ['stream_format'],
|
|
64
|
+
message: 'stream_format applies only to a streamed request (stream: true)',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const format = request.response_format ?? 'mp3';
|
|
68
|
+
if (request.stream === true &&
|
|
69
|
+
!STREAMABLE_SPEECH_FORMATS.includes(format)) {
|
|
70
|
+
ctx.addIssue({
|
|
71
|
+
code: 'custom',
|
|
72
|
+
path: ['response_format'],
|
|
73
|
+
message: `streamed speech is ${STREAMABLE_SPEECH_FORMATS.join(' or ')}; ${format} exists only whole`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
/** One chunk of audio, in order, as soon as the provider produced it. */
|
|
78
|
+
export const speechAudioDeltaEventSchema = z
|
|
79
|
+
.object({
|
|
80
|
+
type: z.literal('speech.audio.delta'),
|
|
81
|
+
/** Standard padded base64 of at most 49 152 bytes of audio. */
|
|
82
|
+
audio: z.string().min(4).max(65_536).regex(PADDED_BASE64_PATTERN),
|
|
83
|
+
})
|
|
84
|
+
.strict();
|
|
85
|
+
/** The last event of a successful stream: what served it and what it consumed. */
|
|
86
|
+
export const speechAudioDoneEventSchema = z
|
|
87
|
+
.object({
|
|
88
|
+
type: z.literal('speech.audio.done'),
|
|
89
|
+
requestId: requestIdSchema,
|
|
90
|
+
/** The revision that actually served the request. */
|
|
91
|
+
model: modelReferenceSchema,
|
|
92
|
+
usage: usageSchema,
|
|
93
|
+
})
|
|
94
|
+
.strict();
|
|
95
|
+
/** The terminal failure of a stream, after which nothing follows. */
|
|
96
|
+
export const speechStreamErrorEventSchema = z
|
|
97
|
+
.object({
|
|
98
|
+
type: z.literal('error'),
|
|
99
|
+
error: publicErrorSchema,
|
|
100
|
+
})
|
|
101
|
+
.strict();
|
|
102
|
+
/**
|
|
103
|
+
* The frames of `stream_format: 'sse'`. The media type is not repeated: it is
|
|
104
|
+
* a function of the request's `response_format` ({@link speechMediaType}).
|
|
105
|
+
*/
|
|
106
|
+
export const speechStreamEventSchema = z.discriminatedUnion('type', [
|
|
107
|
+
speechAudioDeltaEventSchema,
|
|
108
|
+
speechAudioDoneEventSchema,
|
|
109
|
+
speechStreamErrorEventSchema,
|
|
110
|
+
]);
|
|
111
|
+
/**
|
|
112
|
+
* Check a speech request against the model's published audio capabilities
|
|
113
|
+
* (Kaana ADR 0002, decision 9). Kaana's handler refuses the request with
|
|
114
|
+
* `invalid_request` and the first issue's `param` BEFORE asking Oxy for a
|
|
115
|
+
* grant, so a `speed` of 1.5 for a model that publishes 0.7–1.2 holds no money;
|
|
116
|
+
* a client may run the same check first.
|
|
117
|
+
*
|
|
118
|
+
* Returns every issue, in field order; an empty list means the model accepts
|
|
119
|
+
* the request. Characters are counted in UTF-16 code units, as `length` does.
|
|
120
|
+
*/
|
|
121
|
+
export function checkSpeechRequest(request, audio) {
|
|
122
|
+
const issues = [];
|
|
123
|
+
if (audio.maxInputCharacters !== undefined && request.input.length > audio.maxInputCharacters) {
|
|
124
|
+
issues.push({
|
|
125
|
+
param: 'input',
|
|
126
|
+
message: `input is ${request.input.length} characters; this model reads at most ${audio.maxInputCharacters}`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (!audio.voices.some((voice) => voice.id === request.voice)) {
|
|
130
|
+
issues.push({ param: 'voice', message: `this model has no voice ${request.voice}` });
|
|
131
|
+
}
|
|
132
|
+
const format = request.response_format ?? 'mp3';
|
|
133
|
+
if (!audio.audioFormats.output.includes(speechMediaType(format))) {
|
|
134
|
+
issues.push({ param: 'response_format', message: `this model does not produce ${format}` });
|
|
135
|
+
}
|
|
136
|
+
if (request.speed !== undefined) {
|
|
137
|
+
if (audio.speed === undefined) {
|
|
138
|
+
issues.push({ param: 'speed', message: 'this model accepts no speed control' });
|
|
139
|
+
}
|
|
140
|
+
else if (request.speed < audio.speed.min || request.speed > audio.speed.max) {
|
|
141
|
+
issues.push({
|
|
142
|
+
param: 'speed',
|
|
143
|
+
message: `speed must be between ${audio.speed.min} and ${audio.speed.max} for this model`,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return issues;
|
|
148
|
+
}
|
|
149
|
+
/* -------------------------------------------------------------------------- */
|
|
150
|
+
/* Transcription */
|
|
151
|
+
/* -------------------------------------------------------------------------- */
|
|
152
|
+
/** The largest audio file one transcription request may upload: 20 MiB. */
|
|
153
|
+
export const MAX_TRANSCRIPTION_FILE_BYTES = 20 * 1024 * 1024;
|
|
154
|
+
/**
|
|
155
|
+
* The text fields of the `multipart/form-data` request. The audio itself is the
|
|
156
|
+
* `file` part, at most {@link MAX_TRANSCRIPTION_FILE_BYTES}, whose content type
|
|
157
|
+
* is one of `audioInputMediaTypeSchema`; it is binary and so is not a Zod shape.
|
|
158
|
+
* Synchronous: the transcription is the response.
|
|
159
|
+
*/
|
|
160
|
+
export const transcriptionRequestSchema = z
|
|
161
|
+
.object({
|
|
162
|
+
model: modelReferenceSchema,
|
|
163
|
+
/** The spoken language, when known; validated against the model's `audio.languages`. */
|
|
164
|
+
language: languageTagSchema.optional(),
|
|
165
|
+
/** Vocabulary or context that helps the model; never an instruction. */
|
|
166
|
+
prompt: z.string().max(4096).optional(),
|
|
167
|
+
/** Absent means `none`. */
|
|
168
|
+
timestamps: z.enum(['none', 'segment', 'word']).optional(),
|
|
169
|
+
})
|
|
170
|
+
.strict();
|
|
171
|
+
/**
|
|
172
|
+
* The longest audio one transcription request may carry, when its container
|
|
173
|
+
* states a duration (WAV, raw PCM at a known rate). A file whose container does
|
|
174
|
+
* not state one is bounded by {@link MAX_TRANSCRIPTION_FILE_BYTES} alone: Kaana
|
|
175
|
+
* never guesses a duration from a byte count. New in contract set 4.2.0.
|
|
176
|
+
*/
|
|
177
|
+
export const MAX_TRANSCRIPTION_AUDIO_MILLISECONDS = 30 * 60 * 1000;
|
|
178
|
+
/**
|
|
179
|
+
* The longest padded base64 the JSON form may carry: exactly the encoding of
|
|
180
|
+
* {@link MAX_TRANSCRIPTION_FILE_BYTES}.
|
|
181
|
+
*/
|
|
182
|
+
export const MAX_TRANSCRIPTION_AUDIO_BASE64_LENGTH = Math.ceil(MAX_TRANSCRIPTION_FILE_BYTES / 3) * 4;
|
|
183
|
+
/**
|
|
184
|
+
* The JSON form of `POST /v1/audio/transcriptions` (`Content-Type:
|
|
185
|
+
* application/json`): the same fields as the multipart form, with the audio
|
|
186
|
+
* inline as padded base64. For runtimes where building a multipart body from
|
|
187
|
+
* bytes is unreliable (React Native); the two forms mean the same request and
|
|
188
|
+
* hash the same way. New in contract set 4.2.0.
|
|
189
|
+
*/
|
|
190
|
+
export const transcriptionJsonRequestSchema = transcriptionRequestSchema
|
|
191
|
+
.extend({
|
|
192
|
+
audio: z
|
|
193
|
+
.object({
|
|
194
|
+
mediaType: audioInputMediaTypeSchema,
|
|
195
|
+
data: z
|
|
196
|
+
.string()
|
|
197
|
+
.min(4)
|
|
198
|
+
.max(MAX_TRANSCRIPTION_AUDIO_BASE64_LENGTH)
|
|
199
|
+
.regex(PADDED_BASE64_PATTERN),
|
|
200
|
+
})
|
|
201
|
+
.strict(),
|
|
202
|
+
})
|
|
203
|
+
.strict();
|
|
204
|
+
const timedSpanFields = {
|
|
205
|
+
startMs: z.number().int().nonnegative().safe(),
|
|
206
|
+
endMs: z.number().int().nonnegative().safe(),
|
|
207
|
+
};
|
|
208
|
+
/** The response. Segments or words are present only when the request asked for them. */
|
|
209
|
+
export const transcriptionSchema = z
|
|
210
|
+
.object({
|
|
211
|
+
schemaVersion: z.literal(1),
|
|
212
|
+
requestId: requestIdSchema,
|
|
213
|
+
/** The revision that actually served the request. */
|
|
214
|
+
model: modelReferenceSchema,
|
|
215
|
+
text: z.string(),
|
|
216
|
+
/** The language the model heard, when it reports one. */
|
|
217
|
+
language: languageTagSchema.optional(),
|
|
218
|
+
durationMs: z.number().int().nonnegative().safe().optional(),
|
|
219
|
+
segments: z.array(z.object({ ...timedSpanFields, text: z.string() }).strict()).optional(),
|
|
220
|
+
words: z.array(z.object({ ...timedSpanFields, word: z.string() }).strict()).optional(),
|
|
221
|
+
usage: usageSchema,
|
|
222
|
+
})
|
|
223
|
+
.strict()
|
|
224
|
+
.superRefine((transcription, ctx) => {
|
|
225
|
+
for (const field of ['segments', 'words']) {
|
|
226
|
+
for (const [index, span] of (transcription[field] ?? []).entries()) {
|
|
227
|
+
if (span.endMs < span.startMs) {
|
|
228
|
+
ctx.addIssue({
|
|
229
|
+
code: 'custom',
|
|
230
|
+
path: [field, index, 'endMs'],
|
|
231
|
+
message: 'a span cannot end before it starts',
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The audio vocabulary shared by the catalogue and the audio endpoints:
|
|
3
|
+
* language tags, the media types a transcription accepts, and the mapping from
|
|
4
|
+
* a speech request's `response_format` to the media type it produces.
|
|
5
|
+
*
|
|
6
|
+
* New in contract set 4.0.0 (Kaana ADR 0002, decisions 8 and 9).
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { type InferenceAudioMediaType } from './streamEvents.js';
|
|
10
|
+
/**
|
|
11
|
+
* A BCP 47 language tag (`en`, `es-ES`, `zh-Hant-TW`), as voices, models and
|
|
12
|
+
* transcription requests declare languages. Validated by its grammar only: the
|
|
13
|
+
* catalogue is the authority on which tags a model accepts.
|
|
14
|
+
*/
|
|
15
|
+
export declare const languageTagSchema: z.ZodString;
|
|
16
|
+
/** The formats a speech request names in `response_format`. */
|
|
17
|
+
export declare const speechFormatSchema: z.ZodEnum<{
|
|
18
|
+
mp3: "mp3";
|
|
19
|
+
opus: "opus";
|
|
20
|
+
aac: "aac";
|
|
21
|
+
flac: "flac";
|
|
22
|
+
wav: "wav";
|
|
23
|
+
pcm: "pcm";
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* The media types an uploaded audio file may have
|
|
27
|
+
* (`POST /v1/audio/transcriptions`).
|
|
28
|
+
*/
|
|
29
|
+
export declare const audioInputMediaTypeSchema: z.ZodEnum<{
|
|
30
|
+
"audio/mpeg": "audio/mpeg";
|
|
31
|
+
"audio/wav": "audio/wav";
|
|
32
|
+
"audio/ogg": "audio/ogg";
|
|
33
|
+
"audio/aac": "audio/aac";
|
|
34
|
+
"audio/flac": "audio/flac";
|
|
35
|
+
"audio/pcm": "audio/pcm";
|
|
36
|
+
"audio/mp4": "audio/mp4";
|
|
37
|
+
"audio/webm": "audio/webm";
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* The audio encodings a realtime session carries, in both directions. Named by
|
|
41
|
+
* what they ARE (sample format, rate) because a realtime stream has no
|
|
42
|
+
* container to say so.
|
|
43
|
+
*
|
|
44
|
+
* Declared here rather than in `realtime.ts` (where it was until contract set
|
|
45
|
+
* 4.1.0) because the catalogue publishes which of them a model takes, and the
|
|
46
|
+
* catalogue cannot import the realtime module that imports it.
|
|
47
|
+
*/
|
|
48
|
+
export declare const realtimeAudioFormatSchema: z.ZodEnum<{
|
|
49
|
+
pcm16_24khz: "pcm16_24khz";
|
|
50
|
+
g711_ulaw: "g711_ulaw";
|
|
51
|
+
g711_alaw: "g711_alaw";
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* The media type a speech request's `response_format` produces. A client
|
|
55
|
+
* knows it before the first byte, which is why the speech stream events do
|
|
56
|
+
* not repeat it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function speechMediaType(format: z.infer<typeof speechFormatSchema>): InferenceAudioMediaType;
|
|
59
|
+
export type LanguageTag = z.infer<typeof languageTagSchema>;
|
|
60
|
+
export type SpeechFormat = z.infer<typeof speechFormatSchema>;
|
|
61
|
+
export type AudioInputMediaType = z.infer<typeof audioInputMediaTypeSchema>;
|
|
62
|
+
export type RealtimeAudioFormat = z.infer<typeof realtimeAudioFormatSchema>;
|
|
63
|
+
/** The media types speech produces; the contract calls the same set `inferenceAudioMediaTypeSchema`. */
|
|
64
|
+
export type AudioMediaType = InferenceAudioMediaType;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The audio vocabulary shared by the catalogue and the audio endpoints:
|
|
3
|
+
* language tags, the media types a transcription accepts, and the mapping from
|
|
4
|
+
* a speech request's `response_format` to the media type it produces.
|
|
5
|
+
*
|
|
6
|
+
* New in contract set 4.0.0 (Kaana ADR 0002, decisions 8 and 9).
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { inferenceAudioMediaTypeSchema } from './streamEvents.js';
|
|
10
|
+
/**
|
|
11
|
+
* A BCP 47 language tag (`en`, `es-ES`, `zh-Hant-TW`), as voices, models and
|
|
12
|
+
* transcription requests declare languages. Validated by its grammar only: the
|
|
13
|
+
* catalogue is the authority on which tags a model accepts.
|
|
14
|
+
*/
|
|
15
|
+
export const languageTagSchema = z
|
|
16
|
+
.string()
|
|
17
|
+
.max(35)
|
|
18
|
+
.regex(/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/, 'must be a BCP 47 language tag');
|
|
19
|
+
/** The formats a speech request names in `response_format`. */
|
|
20
|
+
export const speechFormatSchema = z.enum(['mp3', 'opus', 'aac', 'flac', 'wav', 'pcm']);
|
|
21
|
+
/**
|
|
22
|
+
* The media types an uploaded audio file may have
|
|
23
|
+
* (`POST /v1/audio/transcriptions`).
|
|
24
|
+
*/
|
|
25
|
+
export const audioInputMediaTypeSchema = z.enum([
|
|
26
|
+
'audio/mpeg',
|
|
27
|
+
'audio/mp4',
|
|
28
|
+
'audio/wav',
|
|
29
|
+
'audio/ogg',
|
|
30
|
+
'audio/webm',
|
|
31
|
+
'audio/flac',
|
|
32
|
+
'audio/aac',
|
|
33
|
+
'audio/pcm',
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* The audio encodings a realtime session carries, in both directions. Named by
|
|
37
|
+
* what they ARE (sample format, rate) because a realtime stream has no
|
|
38
|
+
* container to say so.
|
|
39
|
+
*
|
|
40
|
+
* Declared here rather than in `realtime.ts` (where it was until contract set
|
|
41
|
+
* 4.1.0) because the catalogue publishes which of them a model takes, and the
|
|
42
|
+
* catalogue cannot import the realtime module that imports it.
|
|
43
|
+
*/
|
|
44
|
+
export const realtimeAudioFormatSchema = z.enum(['pcm16_24khz', 'g711_ulaw', 'g711_alaw']);
|
|
45
|
+
const SPEECH_MEDIA_TYPES = {
|
|
46
|
+
mp3: 'audio/mpeg',
|
|
47
|
+
opus: 'audio/ogg',
|
|
48
|
+
aac: 'audio/aac',
|
|
49
|
+
flac: 'audio/flac',
|
|
50
|
+
wav: 'audio/wav',
|
|
51
|
+
pcm: 'audio/pcm',
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* The media type a speech request's `response_format` produces. A client
|
|
55
|
+
* knows it before the first byte, which is why the speech stream events do
|
|
56
|
+
* not repeat it.
|
|
57
|
+
*/
|
|
58
|
+
export function speechMediaType(format) {
|
|
59
|
+
return inferenceAudioMediaTypeSchema.parse(SPEECH_MEDIA_TYPES[format]);
|
|
60
|
+
}
|