@ai-sdk/fish-audio 0.0.0 → 2.0.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,149 @@
1
+ import type { SharedV3Warning, TranscriptionModelV3 } from '@ai-sdk/provider';
2
+ import {
3
+ combineHeaders,
4
+ convertBase64ToUint8Array,
5
+ createJsonResponseHandler,
6
+ mediaTypeToExtension,
7
+ parseProviderOptions,
8
+ postFormDataToApi,
9
+ } from '@ai-sdk/provider-utils';
10
+ import { z } from 'zod/v4';
11
+ import type { FishAudioConfig } from './fish-audio-config';
12
+ import { fishAudioFailedResponseHandler } from './fish-audio-error';
13
+ import { fishAudioTranscriptionModelOptionsSchema } from './fish-audio-transcription-model-options';
14
+ import type { FishAudioTranscriptionModelId } from './fish-audio-transcription-options';
15
+
16
+ interface FishAudioTranscriptionModelConfig extends FishAudioConfig {
17
+ _internal?: {
18
+ currentDate?: () => Date;
19
+ };
20
+ }
21
+
22
+ export class FishAudioTranscriptionModel implements TranscriptionModelV3 {
23
+ readonly specificationVersion = 'v3';
24
+
25
+ get provider(): string {
26
+ return this.config.provider;
27
+ }
28
+
29
+ constructor(
30
+ readonly modelId: FishAudioTranscriptionModelId,
31
+ private readonly config: FishAudioTranscriptionModelConfig,
32
+ ) {}
33
+
34
+ private async getArgs({
35
+ audio,
36
+ mediaType,
37
+ providerOptions,
38
+ }: Parameters<TranscriptionModelV3['doGenerate']>[0]) {
39
+ const warnings: SharedV3Warning[] = [];
40
+
41
+ const fishAudioOptions = await parseProviderOptions({
42
+ provider: 'fishAudio',
43
+ providerOptions,
44
+ schema: fishAudioTranscriptionModelOptionsSchema,
45
+ });
46
+
47
+ const formData = new FormData();
48
+ const blob =
49
+ audio instanceof Uint8Array
50
+ ? new Blob([audio])
51
+ : new Blob([convertBase64ToUint8Array(audio)]);
52
+
53
+ formData.append(
54
+ 'audio',
55
+ new File([blob], 'audio', { type: mediaType }),
56
+ `audio.${mediaTypeToExtension(mediaType)}`,
57
+ );
58
+
59
+ if (fishAudioOptions?.language != null) {
60
+ formData.append('language', fishAudioOptions.language);
61
+ }
62
+
63
+ // Fish Audio defaults `ignore_timestamps` to true, which leaves the
64
+ // transcription result without segments. Request timestamps by default and
65
+ // let callers opt back out.
66
+ formData.append(
67
+ 'ignore_timestamps',
68
+ String(fishAudioOptions?.ignoreTimestamps ?? false),
69
+ );
70
+
71
+ return { formData, warnings };
72
+ }
73
+
74
+ async doGenerate(
75
+ options: Parameters<TranscriptionModelV3['doGenerate']>[0],
76
+ ): Promise<Awaited<ReturnType<TranscriptionModelV3['doGenerate']>>> {
77
+ const currentDate = this.config._internal?.currentDate?.() ?? new Date();
78
+ const { formData, warnings } = await this.getArgs(options);
79
+
80
+ const {
81
+ value: response,
82
+ responseHeaders,
83
+ rawValue: rawResponse,
84
+ } = await postFormDataToApi({
85
+ url: this.config.url({ path: '/v1/asr', modelId: this.modelId }),
86
+ headers: combineHeaders(this.config.headers?.(), options.headers),
87
+ formData,
88
+ failedResponseHandler: fishAudioFailedResponseHandler,
89
+ successfulResponseHandler: createJsonResponseHandler(
90
+ fishAudioTranscriptionResponseSchema,
91
+ ),
92
+ abortSignal: options.abortSignal,
93
+ fetch: this.config.fetch,
94
+ });
95
+
96
+ const segments =
97
+ response.segments?.map(segment => ({
98
+ text: segment.text,
99
+ startSecond: segment.start,
100
+ endSecond: segment.end,
101
+ })) ?? [];
102
+
103
+ return {
104
+ text: response.text,
105
+ segments,
106
+ // `language_code` is absent from the documented response schema but is
107
+ // returned in practice, and reflects the detected language rather than
108
+ // the requested one.
109
+ language: response.language_code ?? undefined,
110
+ durationInSeconds: response.duration ?? undefined,
111
+ warnings,
112
+ response: {
113
+ timestamp: currentDate,
114
+ modelId: this.modelId,
115
+ headers: responseHeaders,
116
+ body: rawResponse,
117
+ },
118
+ ...(response.language != null && {
119
+ providerMetadata: {
120
+ fishAudio: {
121
+ // Human-readable display name, e.g. `English`. Its exact form is
122
+ // not guaranteed, so `language` above (the ISO-639-1 code) is the
123
+ // value to branch on.
124
+ language: response.language,
125
+ },
126
+ },
127
+ }),
128
+ };
129
+ }
130
+ }
131
+
132
+ const fishAudioTranscriptionResponseSchema = z.object({
133
+ text: z.string(),
134
+ // `language` and `language_code` are undocumented but returned in practice.
135
+ // Human-readable name, e.g. `English`.
136
+ language: z.string().nullish(),
137
+ // ISO-639-1 code, e.g. `en`.
138
+ language_code: z.string().nullish(),
139
+ duration: z.number().nullish(),
140
+ segments: z
141
+ .array(
142
+ z.object({
143
+ text: z.string(),
144
+ start: z.number(),
145
+ end: z.number(),
146
+ }),
147
+ )
148
+ .nullish(),
149
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Fish Audio transcription model ID.
3
+ *
4
+ * `POST /v1/asr` currently exposes no model selector and serves a single
5
+ * model, so `transcribe-1` is a routing label rather than a wire value: it is
6
+ * not sent to the API. Fish Audio expects to add more ASR models and to select
7
+ * them with the `model` HTTP header, matching `/v1/tts`.
8
+ *
9
+ * https://docs.fish.audio/api-reference/endpoint/openapi-v1/speech-to-text
10
+ */
11
+ export type FishAudioTranscriptionModelId = 'transcribe-1' | (string & {});
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ export { createFishAudio, fishAudio } from './fish-audio-provider';
2
+ export type {
3
+ FishAudioProvider,
4
+ FishAudioProviderSettings,
5
+ } from './fish-audio-provider';
6
+ export { FishAudioSpeechModel } from './fish-audio-speech-model';
7
+ export { FishAudioTranscriptionModel } from './fish-audio-transcription-model';
8
+ export type {
9
+ FishAudioSpeechModelId,
10
+ FishAudioSpeechVoiceId,
11
+ } from './fish-audio-speech-options';
12
+ export type { FishAudioSpeechModelOptions } from './fish-audio-speech-model-options';
13
+ export type { FishAudioTranscriptionModelId } from './fish-audio-transcription-options';
14
+ export type { FishAudioTranscriptionModelOptions } from './fish-audio-transcription-model-options';
15
+ export { VERSION } from './version';
package/src/version.ts ADDED
@@ -0,0 +1,6 @@
1
+ // Version string of this package injected at build time.
2
+ declare const __PACKAGE_VERSION__: string | undefined;
3
+ export const VERSION: string =
4
+ typeof __PACKAGE_VERSION__ !== 'undefined'
5
+ ? __PACKAGE_VERSION__
6
+ : '0.0.0-test';
package/index.js DELETED
@@ -1 +0,0 @@
1
- export {};