@ai-sdk/openai-compatible 2.0.84 → 2.0.85
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/CHANGELOG.md +11 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +61 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +66 -15
- package/dist/index.mjs.map +1 -1
- package/docs/index.mdx +5 -0
- package/package.json +2 -2
- package/src/image/openai-compatible-image-model.ts +82 -19
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
InvalidResponseDataError,
|
|
3
|
+
type ImageModelV3,
|
|
4
|
+
type ImageModelV3File,
|
|
5
|
+
type SharedV3ProviderOptions,
|
|
6
|
+
type SharedV3Warning,
|
|
6
7
|
} from '@ai-sdk/provider';
|
|
7
8
|
import { toCamelCase } from '../utils/to-camel-case';
|
|
8
9
|
import {
|
|
9
10
|
combineHeaders,
|
|
10
11
|
convertBase64ToUint8Array,
|
|
11
12
|
convertToFormData,
|
|
13
|
+
createBinaryResponseHandler,
|
|
12
14
|
createJsonErrorResponseHandler,
|
|
13
15
|
createJsonResponseHandler,
|
|
16
|
+
createStatusCodeErrorResponseHandler,
|
|
14
17
|
downloadBlob,
|
|
18
|
+
getFromApi,
|
|
15
19
|
postFormDataToApi,
|
|
16
20
|
postJsonToApi,
|
|
17
21
|
type FetchFunction,
|
|
@@ -96,15 +100,18 @@ export class OpenAICompatibleImageModel implements ImageModelV3 {
|
|
|
96
100
|
const currentDate = this.config._internal?.currentDate?.() ?? new Date();
|
|
97
101
|
|
|
98
102
|
const args = this.getArgs(providerOptions);
|
|
103
|
+
const isEditing = files != null && files.length > 0;
|
|
104
|
+
const url = this.config.url({
|
|
105
|
+
path: isEditing ? '/images/edits' : '/images/generations',
|
|
106
|
+
modelId: this.modelId,
|
|
107
|
+
});
|
|
108
|
+
const requestHeaders = combineHeaders(this.config.headers(), headers);
|
|
99
109
|
|
|
100
110
|
// Image editing mode - use form data and /images/edits endpoint
|
|
101
|
-
if (
|
|
111
|
+
if (isEditing) {
|
|
102
112
|
const { value: response, responseHeaders } = await postFormDataToApi({
|
|
103
|
-
url
|
|
104
|
-
|
|
105
|
-
modelId: this.modelId,
|
|
106
|
-
}),
|
|
107
|
-
headers: combineHeaders(this.config.headers(), headers),
|
|
113
|
+
url,
|
|
114
|
+
headers: requestHeaders,
|
|
108
115
|
formData: convertToFormData<OpenAICompatibleFormDataInput>({
|
|
109
116
|
model: this.modelId,
|
|
110
117
|
prompt,
|
|
@@ -125,7 +132,11 @@ export class OpenAICompatibleImageModel implements ImageModelV3 {
|
|
|
125
132
|
});
|
|
126
133
|
|
|
127
134
|
return {
|
|
128
|
-
images: response.data
|
|
135
|
+
images: await this.getImages(response.data, {
|
|
136
|
+
url,
|
|
137
|
+
headers: requestHeaders,
|
|
138
|
+
abortSignal,
|
|
139
|
+
}),
|
|
129
140
|
warnings,
|
|
130
141
|
response: {
|
|
131
142
|
timestamp: currentDate,
|
|
@@ -137,11 +148,8 @@ export class OpenAICompatibleImageModel implements ImageModelV3 {
|
|
|
137
148
|
|
|
138
149
|
// Standard image generation mode - use JSON and /images/generations endpoint
|
|
139
150
|
const { value: response, responseHeaders } = await postJsonToApi({
|
|
140
|
-
url
|
|
141
|
-
|
|
142
|
-
modelId: this.modelId,
|
|
143
|
-
}),
|
|
144
|
-
headers: combineHeaders(this.config.headers(), headers),
|
|
151
|
+
url,
|
|
152
|
+
headers: requestHeaders,
|
|
145
153
|
body: {
|
|
146
154
|
model: this.modelId,
|
|
147
155
|
prompt,
|
|
@@ -161,7 +169,11 @@ export class OpenAICompatibleImageModel implements ImageModelV3 {
|
|
|
161
169
|
});
|
|
162
170
|
|
|
163
171
|
return {
|
|
164
|
-
images: response.data
|
|
172
|
+
images: await this.getImages(response.data, {
|
|
173
|
+
url,
|
|
174
|
+
headers: requestHeaders,
|
|
175
|
+
abortSignal,
|
|
176
|
+
}),
|
|
165
177
|
warnings,
|
|
166
178
|
response: {
|
|
167
179
|
timestamp: currentDate,
|
|
@@ -170,12 +182,63 @@ export class OpenAICompatibleImageModel implements ImageModelV3 {
|
|
|
170
182
|
},
|
|
171
183
|
};
|
|
172
184
|
}
|
|
185
|
+
|
|
186
|
+
private async getImages(
|
|
187
|
+
data: z.infer<typeof openaiCompatibleImageResponseSchema>['data'],
|
|
188
|
+
options: {
|
|
189
|
+
url: string;
|
|
190
|
+
headers: Record<string, string | undefined>;
|
|
191
|
+
abortSignal: AbortSignal | undefined;
|
|
192
|
+
},
|
|
193
|
+
): Promise<string[] | Uint8Array[]> {
|
|
194
|
+
// Preserve base64 responses without conversion
|
|
195
|
+
if (data.every(image => image.b64_json != null)) {
|
|
196
|
+
return data.map(image => image.b64_json!);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return Promise.all(
|
|
200
|
+
data.map(async image => {
|
|
201
|
+
if (image.b64_json != null) {
|
|
202
|
+
return convertBase64ToUint8Array(image.b64_json);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (image.url == null) {
|
|
206
|
+
throw new InvalidResponseDataError({
|
|
207
|
+
data: image,
|
|
208
|
+
message: 'Expected url in the image response',
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const { value } = await getFromApi({
|
|
213
|
+
url: image.url,
|
|
214
|
+
validateUrl: true,
|
|
215
|
+
trustedOrigin: options.url,
|
|
216
|
+
credentialedOrigin: options.url,
|
|
217
|
+
headers: options.headers,
|
|
218
|
+
abortSignal: options.abortSignal,
|
|
219
|
+
fetch: this.config.fetch,
|
|
220
|
+
successfulResponseHandler: createBinaryResponseHandler(),
|
|
221
|
+
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
222
|
+
});
|
|
223
|
+
return value;
|
|
224
|
+
}),
|
|
225
|
+
);
|
|
226
|
+
}
|
|
173
227
|
}
|
|
174
228
|
|
|
175
229
|
// minimal version of the schema, focussed on what is needed for the implementation
|
|
176
230
|
// this approach limits breakages when the API changes and increases efficiency
|
|
177
231
|
const openaiCompatibleImageResponseSchema = z.object({
|
|
178
|
-
data: z.array(
|
|
232
|
+
data: z.array(
|
|
233
|
+
z
|
|
234
|
+
.object({
|
|
235
|
+
b64_json: z.string().nullish(),
|
|
236
|
+
url: z.string().nullish(),
|
|
237
|
+
})
|
|
238
|
+
.refine(image => image.b64_json != null || image.url != null, {
|
|
239
|
+
message: 'Expected b64_json or url in the image response',
|
|
240
|
+
}),
|
|
241
|
+
),
|
|
179
242
|
});
|
|
180
243
|
|
|
181
244
|
type OpenAICompatibleFormDataInput = {
|