新增图片生成apimart 和 其他 格式请求
This commit is contained in:
parent
9254a4e650
commit
e7d7b0ffd6
@ -26,6 +26,7 @@
|
||||
"@ai-sdk/deepseek": "^2.0.17",
|
||||
"@ai-sdk/google": "^3.0.20",
|
||||
"@ai-sdk/openai": "^3.0.25",
|
||||
"@ai-sdk/openai-compatible": "^2.0.27",
|
||||
"@aigne/core": "^1.72.0",
|
||||
"@aigne/openai": "^0.16.16",
|
||||
"@langchain/core": "^1.1.15",
|
||||
|
||||
@ -18,13 +18,14 @@ export default router.post(
|
||||
const { modelName, apiKey, baseURL, manufacturer } = req.body;
|
||||
try {
|
||||
const image = await u.ai.image({
|
||||
prompt: "生成16:9 四宫格图片,第一宫格是一只猫,第二宫格是一只狗, 第三宫格是一只老虎,第四宫格是猪。保证宫格图片标准等分",
|
||||
prompt: "生成16:9 四宫格图片,第一宫格是一只猫,第二宫格是一只狗, 第三宫格是一只老虎,第四宫格是猪。保证四宫格图片标准四等分",
|
||||
imageBase64: [],
|
||||
aspectRatio: "16:9",
|
||||
size: "1K",
|
||||
});
|
||||
res.status(200).send(success(image));
|
||||
} catch (e: any) {
|
||||
console.log("%c Line:28 🥒 e", "background:#fca650", e);
|
||||
return res.status(500).send(error(e?.response?.data ?? e?.message ?? "生成失败"));
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@ import kling from "./owned/kling";
|
||||
import gemini from "./owned/gemini";
|
||||
import vidu from "./owned/vidu";
|
||||
import runninghub from "./owned/runninghub";
|
||||
import apimart from "./owned/apimart";
|
||||
import other from "./owned/other";
|
||||
interface AIConfig {
|
||||
model?: string;
|
||||
apiKey?: string;
|
||||
@ -27,7 +29,8 @@ const modelInstance = {
|
||||
kling: kling,
|
||||
vidu: vidu,
|
||||
runninghub: runninghub,
|
||||
apimart: null,
|
||||
apimart: apimart,
|
||||
other
|
||||
} as const;
|
||||
|
||||
export default async (input: ImageConfig, config?: AIConfig) => {
|
||||
@ -35,11 +38,10 @@ export default async (input: ImageConfig, config?: AIConfig) => {
|
||||
const { model, apiKey, baseURL, manufacturer } = { ...sqlTextModelConfig, ...config };
|
||||
const manufacturerFn = modelInstance[manufacturer as keyof typeof modelInstance];
|
||||
if (!manufacturerFn) if (!manufacturerFn) throw new Error("不支持的图片厂商");
|
||||
const owned = modelList.find((m) => m.model === model);
|
||||
if (!owned) throw new Error("不支持的模型");
|
||||
// const owned = modelList.find((m) => m.model === model);
|
||||
// if (!owned) throw new Error("不支持的模型");
|
||||
|
||||
let imageUrl = await manufacturerFn(input, { model, apiKey, baseURL });
|
||||
console.log("%c Line:41 🍅 imageUrl", "background:#ed9ec7", imageUrl);
|
||||
if (!input.resType) input.resType = "b64";
|
||||
if (input.resType === "b64" && imageUrl.startsWith("http")) imageUrl = await urlToBase64(imageUrl);
|
||||
return imageUrl;
|
||||
|
||||
31
src/utils/ai/image/owned/apimart.ts
Normal file
31
src/utils/ai/image/owned/apimart.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import axios from "axios";
|
||||
import u from "@/utils";
|
||||
import FormData from "form-data";
|
||||
import axiosRetry from "axios-retry";
|
||||
import { OpenAIChatModel, type OpenAIChatModelOptions } from "@aigne/openai";
|
||||
import sharp from "sharp";
|
||||
import { pollTask } from "@/utils/ai/utils";
|
||||
|
||||
axiosRetry(axios, { retries: 3, retryDelay: () => 200 });
|
||||
|
||||
export default async (input: ImageConfig, config: AIConfig): Promise<string> => {
|
||||
if (!config.apiKey) throw new Error("缺少API Key");
|
||||
const apiKey = config.apiKey.replace("Bearer ", "");
|
||||
const taskRes = await axios.post(
|
||||
`https://api.apimart.ai/v1/images/generations`,
|
||||
{ model: "gemini-3-pro-image-preview", prompt: input.prompt, size: input.aspectRatio, n: 1, resolution: input.size },
|
||||
{ headers: { Authorization: apiKey } },
|
||||
);
|
||||
|
||||
if (taskRes.data.code !== 200 || !taskRes.data.data?.[0]?.task_id) throw new Error("任务创建失败: " + JSON.stringify(taskRes.data));
|
||||
|
||||
const taskId = taskRes.data.data[0].task_id;
|
||||
return pollTask(async () => {
|
||||
const res = await axios.get(`https://api.apimart.ai/v1/tasks/${taskId}`, { headers: { Authorization: apiKey }, params: { language: "en" } });
|
||||
if (res.data.code !== 200) return { completed: false, error: `查询失败: ${JSON.stringify(res.data)}` };
|
||||
const { status, result } = res.data.data;
|
||||
if (status === "completed") return { completed: true, imageUrl: result?.images?.[0]?.url?.[0] };
|
||||
if (status === "failed" || status === "cancelled") return { completed: false, error: `任务${status}` };
|
||||
return { completed: false };
|
||||
});
|
||||
};
|
||||
@ -16,13 +16,6 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
||||
// 构建完整的提示词
|
||||
const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt;
|
||||
|
||||
// 根据 size 配置映射到具体尺寸
|
||||
const sizeMap: Record<string, `${number}x${number}`> = {
|
||||
"1K": "1024x1024",
|
||||
"2K": "2048x2048",
|
||||
"4K": "4096x4096",
|
||||
};
|
||||
|
||||
const result = await generateText({
|
||||
model: google.languageModel(config.model),
|
||||
prompt: fullPrompt + `请直接输出图片`,
|
||||
|
||||
76
src/utils/ai/image/owned/other.ts
Normal file
76
src/utils/ai/image/owned/other.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import "../type";
|
||||
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
||||
import { generateImage, generateText } from "ai";
|
||||
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
||||
|
||||
export default async (input: ImageConfig, config: AIConfig): Promise<string> => {
|
||||
if (!config.model) throw new Error("缺少Model名称");
|
||||
if (!config.apiKey) throw new Error("缺少API Key");
|
||||
if (!config.baseURL) throw new Error("缺少baseUrl");
|
||||
|
||||
const apiKey = config.apiKey.replace("Bearer ", "");
|
||||
|
||||
const otherProvider = createOpenAICompatible({
|
||||
name: "xixixi",
|
||||
baseURL: config.baseURL,
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
});
|
||||
|
||||
// 根据 size 配置映射到具体尺寸
|
||||
const sizeMap: Record<string, `${number}x${number}`> = {
|
||||
"1K": "1024x1024",
|
||||
"2K": "2048x2048",
|
||||
"4K": "4096x4096",
|
||||
};
|
||||
// 构建完整的提示词
|
||||
const fullPrompt = input.systemPrompt ? `${input.systemPrompt}\n\n${input.prompt}` : input.prompt;
|
||||
const model = config.model;
|
||||
if (model.includes("gemini") || model.includes("nano")) {
|
||||
const result = await generateText({
|
||||
model: otherProvider.languageModel(model),
|
||||
prompt: fullPrompt + `请直接输出图片`,
|
||||
providerOptions: {
|
||||
google: {
|
||||
imageConfig: {
|
||||
...(config.model == "gemini-2.5-flash-image"
|
||||
? { aspectRatio: input.aspectRatio }
|
||||
: { aspectRatio: input.aspectRatio, imageSize: input.size }),
|
||||
},
|
||||
responseModalities: ["IMAGE"],
|
||||
},
|
||||
},
|
||||
});
|
||||
if (result.files && result.files.length) {
|
||||
let imageBase64;
|
||||
for (const item of result.files) {
|
||||
imageBase64 = `data:${item.mediaType};base64,${item.base64}`;
|
||||
}
|
||||
// 返回生成的图片 base64
|
||||
return imageBase64!;
|
||||
} else {
|
||||
if (!result.text) {
|
||||
console.error(JSON.stringify(result.response, null, 2));
|
||||
throw new Error("图片生成失败");
|
||||
}
|
||||
const match = result.text.match(/base64,([A-Za-z0-9+/=]+)/);
|
||||
const base64Str = match && match[1] ? match[1] : result.text;
|
||||
|
||||
// 返回生成的图片 base64
|
||||
return "data:image/jpeg;base64," + base64Str!;
|
||||
}
|
||||
} else {
|
||||
const { image } = await generateImage({
|
||||
model: otherProvider.imageModel(model),
|
||||
prompt:
|
||||
input.imageBase64 && input.imageBase64.length
|
||||
? { text: fullPrompt + `请直接输出图片`, images: input.imageBase64 }
|
||||
: fullPrompt + `请直接输出图片`,
|
||||
aspectRatio: input.aspectRatio as "1:1" | "3:4" | "4:3" | "9:16" | "16:9",
|
||||
size: sizeMap[input.size] ?? "1024x1024",
|
||||
});
|
||||
|
||||
return image.base64;
|
||||
}
|
||||
};
|
||||
@ -21,7 +21,7 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
||||
if (!config.model) throw new Error("缺少Model名称");
|
||||
if (!config.apiKey) throw new Error("缺少API Key");
|
||||
|
||||
const apiKey = "Token " + config.apiKey.replace(/Bearer\s+/g, "").trim();
|
||||
const apiKey = "Token " + config.apiKey.replace(/Token\s+/g, "").trim();
|
||||
const viduq2Ratio = ["16:9", "9:16", "1:1", "3:4", "4:3", "21:9", "2:3", "3:2"];
|
||||
const viduq1Ratio = ["16:9", "9:16", "1:1", "3:4", "4:3"];
|
||||
let images: string[] = [];
|
||||
@ -51,7 +51,6 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
||||
else size = input.size;
|
||||
if (!viduq2Ratio.includes(input.aspectRatio)) throw new Error("不支持的图片比例:" + input.aspectRatio);
|
||||
}
|
||||
console.log("%c Line:23 🍔 size", "background:#ffdd4d", size);
|
||||
|
||||
const body: Record<string, any> = {
|
||||
model: config.model,
|
||||
@ -60,16 +59,15 @@ export default async (input: ImageConfig, config: AIConfig): Promise<string> =>
|
||||
resolution: size,
|
||||
...(images.length && { images: images }),
|
||||
};
|
||||
console.log("%c Line:27 🍷 body", "background:#6ec1c2", body);
|
||||
|
||||
const urlObj = getApiUrl(config.baseURL!);
|
||||
try {
|
||||
const { data } = await axios.post(urlObj.requestUrl, body, { headers: { Authorization: apiKey } });
|
||||
console.log("%c Line:35 🥕 data", "background:#93c0a4", data);
|
||||
|
||||
const queryUrl = template({ id: data.task_id }, urlObj.queryUrl);
|
||||
console.log("%c Line:53 🍋 queryUrl", "background:#465975", queryUrl);
|
||||
|
||||
return await pollTask(async () => {
|
||||
const { data: queryData } = await axios.get(queryUrl, { headers: { Authorization: apiKey } });
|
||||
console.log("%c Line:42 🍐 queryData", "background:#4fff4B", queryData);
|
||||
|
||||
if (queryData.state !== 0) {
|
||||
return { completed: false, error: queryData.message || "查询任务失败" };
|
||||
|
||||
@ -40,6 +40,14 @@
|
||||
"@ai-sdk/provider" "3.0.7"
|
||||
"@ai-sdk/provider-utils" "4.0.13"
|
||||
|
||||
"@ai-sdk/openai-compatible@^2.0.27":
|
||||
version "2.0.27"
|
||||
resolved "https://registry.npmmirror.com/@ai-sdk/openai-compatible/-/openai-compatible-2.0.27.tgz#55c6bf3c59d71e71d9c337dbef8b764fa69e7ccd"
|
||||
integrity sha512-YpAZe7OQuMkYqcM/m1BMX0xFn4QdhuL4qGo8sNaiLq1VjEeU/pPfz51rnlpCfCvYanUL5TjIZEbdclBUwLooSQ==
|
||||
dependencies:
|
||||
"@ai-sdk/provider" "3.0.7"
|
||||
"@ai-sdk/provider-utils" "4.0.13"
|
||||
|
||||
"@ai-sdk/openai@^3.0.25":
|
||||
version "3.0.25"
|
||||
resolved "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-3.0.25.tgz#452c8f8ed597468048569ec9476a0b5641888d2a"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user