227 lines
8.1 KiB
JavaScript
227 lines
8.1 KiB
JavaScript
import { request as requestUtils } from '../utils/request.js'
|
||
import * as clientApi from '../api/frontend/index.js'
|
||
import * as adminApi from '../api/FrontendDesigner'
|
||
import { GoogleGenAI, Type, Modality } from "@google/genai";
|
||
const API_KEY = 'AIzaSyBmPgJKMnG7afAXR9JW14I5XSkOd_NwCVM';
|
||
const ai = API_KEY ? new GoogleGenAI({ apiKey: API_KEY }) : null;
|
||
import { FileServer } from './fileserver';
|
||
// 获取环境变量中的
|
||
const getPorjectType = () => {
|
||
// 浏览器环境
|
||
if (typeof window !== 'undefined') {
|
||
// Vite 环境变量
|
||
return import.meta.env.VITE_PROJECTTYPE;
|
||
}
|
||
// Node.js 环境
|
||
if (typeof process !== 'undefined') {
|
||
return process.env.VITE_PROJECTTYPE ;
|
||
}
|
||
};
|
||
export class GiminiServer extends FileServer {
|
||
RULE = getPorjectType();
|
||
// 任务并发队列
|
||
static taskQueue = new Map();
|
||
//最高并发限制
|
||
static MAX_CONCURRENT_TASKS = 4;
|
||
constructor() {
|
||
super();
|
||
}
|
||
/**
|
||
* 从URL获取MIME类型
|
||
* @param {*} url 图片URL
|
||
* @returns MIME类型
|
||
*/
|
||
getMimeTypeFromUrl(url) {
|
||
// 检查url是否为字符串
|
||
if (typeof url !== 'string') {
|
||
return 'image/jpeg'; // 默认为jpeg
|
||
}
|
||
|
||
try {
|
||
const extension = url.split('.').pop().toLowerCase().split('?')[0];
|
||
const mimeTypes = {
|
||
'jpg': 'image/jpeg',
|
||
'jpeg': 'image/jpeg',
|
||
'png': 'image/png',
|
||
'gif': 'image/gif',
|
||
'bmp': 'image/bmp',
|
||
'webp': 'image/webp',
|
||
'svg': 'image/svg+xml'
|
||
};
|
||
return mimeTypes[extension] || 'image/jpeg'; // 默认为jpeg
|
||
} catch (error) {
|
||
return 'image/jpeg'; // 出错时返回默认类型
|
||
}
|
||
}
|
||
/**
|
||
* 将图片转换为GenerativePart
|
||
* @param {*} dataUrl 图片base64编码或者url
|
||
* @param {*} type 图片类型,base64或者url
|
||
* @returns GenerativePart对象
|
||
*/
|
||
dataUrlToGenerativePart =async (dataUrl,type='base64') => {
|
||
if (!dataUrl) return null;
|
||
|
||
// 确保dataUrl是字符串
|
||
if (typeof dataUrl !== 'string') {
|
||
throw new Error("dataUrl must be a string");
|
||
}
|
||
|
||
// 处理URL类型
|
||
if(type === 'url'){
|
||
return {
|
||
img_url: dataUrl,
|
||
img_type: await this.getMimeTypeFromUrl(dataUrl),
|
||
};
|
||
}
|
||
|
||
// 处理base64类型
|
||
if(type === 'base64'){
|
||
dataUrl = await this.fileToBase64(dataUrl);
|
||
}
|
||
|
||
const parts = dataUrl.split(',');
|
||
const mimeType = parts[0].match(/:(.*?);/)?.[1];
|
||
const base64Data = parts[1];
|
||
if (!mimeType || !base64Data) {
|
||
throw new Error("Invalid data URL format");
|
||
}
|
||
return {
|
||
inlineData: {
|
||
data: base64Data,
|
||
mimeType: mimeType,
|
||
},
|
||
};
|
||
};
|
||
//本地生图模型
|
||
generateImageFromMultipleImages = async (baseImages, prompt, options = {}) => {
|
||
return new Promise(async (resolve, reject) => {
|
||
const { maxImages = 5 } = options;
|
||
// 标准化输入:确保 baseImages 是数组
|
||
const images = Array.isArray(baseImages) ? baseImages : [baseImages];
|
||
try {
|
||
if (images.length > maxImages) {
|
||
reject(`参考图片数量不能超过 ${maxImages} 张`);
|
||
}
|
||
if (!prompt || !prompt.trim()) {
|
||
reject('请提供图片生成提示词');
|
||
}
|
||
// 处理多个参考图片
|
||
const imageParts = await Promise.all(images.map(async image =>{
|
||
return await this.dataUrlToGenerativePart(image);
|
||
} ));
|
||
// 构建请求的 parts 数组
|
||
const parts = [
|
||
...imageParts,
|
||
{ text: prompt }
|
||
];
|
||
// 执行AI请求
|
||
const response = await ai.models.generateContent({
|
||
model: 'gemini-2.5-flash-image',
|
||
contents: {
|
||
parts: parts,
|
||
},
|
||
config: {
|
||
responseModalities: [Modality.IMAGE],
|
||
},
|
||
});
|
||
console.log(response,'图片结果');
|
||
let resultImg ;//返回的图片
|
||
// 处理响应,提取图片数据
|
||
for (const part of response.candidates[0].content.parts) {
|
||
if (part.inlineData) {
|
||
const base64ImageBytes = part.inlineData.data;
|
||
const mimeType = part.inlineData.mimeType;
|
||
resultImg = `data:${mimeType};base64,${base64ImageBytes}`;
|
||
resolve(resultImg);
|
||
break;
|
||
}
|
||
}
|
||
|
||
} catch (error) {
|
||
reject(error);
|
||
console.log(error, 'errorerrorerrorerrorerrorerror');
|
||
}
|
||
})
|
||
};
|
||
//线上生图片模型
|
||
async generateImageFromMultipleImagesOnline(baseImages, prompt,config={}){
|
||
if(GiminiServer.taskQueue.size >= GiminiServer.MAX_CONCURRENT_TASKS){
|
||
window.setElMessage({
|
||
type:'warning',
|
||
message:'Concurrent limit reached'
|
||
})
|
||
return Promise.reject('Concurrent limit reached');
|
||
}
|
||
const taskId = new Date().getTime();
|
||
GiminiServer.taskQueue.set(taskId, taskId);
|
||
return new Promise(async (resolve, reject) => {
|
||
// 标准化输入:确保 baseImages 是数组
|
||
baseImages = Array.isArray(baseImages) ? baseImages : [baseImages];
|
||
const images = await Promise.all(baseImages.map(async (image) => {
|
||
// if(image.indexOf('tcww')!=-1){
|
||
// return this.concatUrl('/upload/3e1e9ac2f08b486faca094671d793e25');
|
||
// }
|
||
return await this.uploadFile(image);
|
||
}));
|
||
try {
|
||
if (images.length > 5) {
|
||
reject(`参考图片数量不能超过5张`);
|
||
}
|
||
if (!prompt || !prompt.trim()) {
|
||
reject('请提供图片生成提示词');
|
||
}
|
||
// 处理多个参考图片
|
||
const imageParts = await Promise.all(images.map(async image =>{
|
||
return await this.dataUrlToGenerativePart(image,'url');
|
||
} ));
|
||
const params = {
|
||
"aspect_ratio": "9:16",
|
||
"model": "gemini-2.5-flash-image",//models/gemini-3-pro-image-preview/"gemini-2.5-flash-image",
|
||
"location": "global",
|
||
"vertexai": true,
|
||
...config,
|
||
inputs: [
|
||
...imageParts,
|
||
{ text: prompt }
|
||
]
|
||
}
|
||
const requestUrl = this.RULE=='admin'?adminApi.default.GENERATE_IMAGE_ADMIN:clientApi.default.GENERATE_IMAGE;
|
||
const response = await requestUtils.common(requestUrl, params);
|
||
if(response.data.error){
|
||
reject(response.data.error.message);
|
||
return;
|
||
}
|
||
if(response.code!=0){
|
||
reject(response.msg);
|
||
return;
|
||
}
|
||
let data = response.data;
|
||
// let resultImg = this.concatUrl(data?.urls[0]?.url || '');
|
||
let resultImg = data?.urls[0]?.url
|
||
// 处理响应,提取图片数据
|
||
resolve(resultImg);
|
||
} catch (error) {
|
||
reject(error);
|
||
console.log(error, 'errorerrorerrorerrorerrorerror');
|
||
} finally {
|
||
// 任务完成后从队列中移除
|
||
GiminiServer.taskQueue.delete(taskId);
|
||
}
|
||
})
|
||
}
|
||
//模型生图功能
|
||
async handleGenerateImage(referenceImages = [], prompt = '',config) {
|
||
return new Promise(async (resolve,reject) => {
|
||
// let result = await this.generateImageFromMultipleImages(referenceImages, prompt);
|
||
try {
|
||
let result = await this.generateImageFromMultipleImagesOnline(referenceImages, prompt,config);
|
||
resolve(result);
|
||
} catch (error) {
|
||
reject(error);
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|