@ai-ml.api/aimlapi-vercel-ai
Version:
AI SDK provider for AI/ML API: 300+ models via OpenAI-compatible API.
181 lines (178 loc) • 5.87 kB
JavaScript
// src/aimlapi-provider.ts
import {
OpenAICompatibleChatLanguageModel,
OpenAICompatibleCompletionLanguageModel,
OpenAICompatibleEmbeddingModel
} from "@ai-sdk/openai-compatible";
import "@ai-sdk/provider";
import {
loadApiKey,
withoutTrailingSlash
} from "@ai-sdk/provider-utils";
// src/aimlapi-error.ts
import { z } from "zod";
var aimlapiErrorSchema = z.object({
error: z.object({
message: z.string(),
code: z.string().optional(),
type: z.string().optional()
})
});
// src/aimlapi-image-model.ts
import {
combineHeaders,
createJsonErrorResponseHandler,
createJsonResponseHandler,
postJsonToApi,
resolve
} from "@ai-sdk/provider-utils";
import { z as z2 } from "zod";
var AimlapiImageModel = class {
constructor(modelId, settings = {}, config) {
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
specificationVersion = "v2";
maxImagesPerCall = 1;
get provider() {
return this.config.provider;
}
async doGenerate({ prompt, n, aspectRatio, size, seed, providerOptions, headers, abortSignal }) {
const warnings = [];
const modelSupportsAspectRatio = true;
if (!modelSupportsAspectRatio && aspectRatio != null) {
warnings.push({
type: "unsupported-setting",
setting: "aspectRatio",
details: "This model does not support `aspectRatio`. Use `size` instead."
});
}
if (size != null && aspectRatio != null) {
warnings.push({
type: "other",
message: "Both `size` and `aspectRatio` were provided. The API will prioritize `size`."
});
}
const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
const splitSize = size?.split("x");
const resolvedProviderHeaders = await resolve(this.config.headers);
const { value: response, responseHeaders } = await postJsonToApi({
url: `${this.config.baseURL}/images/generations`,
headers: combineHeaders(resolvedProviderHeaders, headers),
body: {
model: this.modelId,
prompt,
seed,
n,
...splitSize && {
width: parseInt(splitSize[0], 10),
height: parseInt(splitSize[1], 10)
},
...aspectRatio && { aspect_ratio: aspectRatio },
// Don't force base64: some models will return the url anyway
...providerOptions?.aimlapi ?? {}
},
successfulResponseHandler: createJsonResponseHandler(aimlapiImageResponseSchema),
failedResponseHandler: createJsonErrorResponseHandler({
errorSchema: aimlapiErrorSchema,
errorToMessage: (e) => e.error.message,
isRetryable: (res, e) => {
if (res.status === 429) return true;
if (res.status >= 500) return true;
if (e?.error?.code === "overloaded" || e?.error?.code === "timeout") return true;
return false;
}
}),
abortSignal,
fetch: this.config.fetch
});
return {
images: response.normalized,
warnings,
response: {
timestamp: currentDate,
modelId: this.modelId,
headers: responseHeaders
}
};
}
};
var aimlapiImageResponseSchema = z2.union([
// Option A: OpenAI-compatible base64
z2.object({
data: z2.array(z2.object({ b64_json: z2.string() }))
}).transform((v) => ({ normalized: v.data.map((d) => d.b64_json) })),
// Option B: AIMLAPI format with images (url or b64_json)
z2.object({
images: z2.array(
z2.object({
b64_json: z2.string().optional(),
url: z2.string().url().optional()
})
)
}).transform((v) => ({
normalized: v.images.map((i) => i.b64_json ?? i.url ?? "").filter((x) => x.length > 0)
}))
]);
// src/aimlapi-provider.ts
import "zod";
var defaultBaseURL = "https://api.aimlapi.com/v1";
var aimlapiErrorStructure = {
errorSchema: aimlapiErrorSchema,
errorToMessage: (data) => data.error.message
// isRetryable: (res) => res.status === 429 || res.status >= 500,
};
function createAIMLAPI(options = {}) {
const rawBaseURL = options.baseURL ?? defaultBaseURL;
const strictBaseURL = withoutTrailingSlash(rawBaseURL) ?? defaultBaseURL;
const getHeadersLoose = () => ({
Authorization: `Bearer ${loadApiKey({
apiKey: options.apiKey,
environmentVariableName: "AIMLAPI_API_KEY",
description: "AIMLAPI API key"
})}`,
"X-Title": "vercel",
...typeof options.headers === "function" ? options.headers() : options.headers
});
const getHeadersStrict = () => Object.fromEntries(
Object.entries(getHeadersLoose()).filter(
([, v]) => v !== void 0
)
);
const getCommonModelConfig = (modelType) => ({
provider: `aimlapi.${modelType}`,
url: ({ path }) => `${strictBaseURL}${path}`,
headers: getHeadersStrict,
fetch: options.fetch,
errorStructure: aimlapiErrorStructure
});
const createChat = (modelId) => new OpenAICompatibleChatLanguageModel(modelId, getCommonModelConfig("chat"));
const createCompletion = (modelId) => new OpenAICompatibleCompletionLanguageModel(
modelId,
getCommonModelConfig("completion")
);
const createEmbedding = (modelId) => new OpenAICompatibleEmbeddingModel(
modelId,
getCommonModelConfig("embedding")
);
const createImage = (modelId, settings = {}) => new AimlapiImageModel(modelId, settings, {
provider: "aimlapi.image",
baseURL: strictBaseURL,
headers: getHeadersStrict,
fetch: options.fetch
});
const providerFunc = (modelId) => createChat(modelId);
providerFunc.chat = createChat;
providerFunc.completion = createCompletion;
providerFunc.languageModel = createChat;
providerFunc.textEmbeddingModel = createEmbedding;
providerFunc.imageModel = createImage;
return providerFunc;
}
var aimlapi = createAIMLAPI();
export {
aimlapi,
createAIMLAPI
};
//# sourceMappingURL=index.mjs.map