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); } }) } }