feat(config/ai.json): add imageMode for selecting image generation method

 feat(lib/ai/imageProcessor.js): implement image generation via OpenAI and chat methods
This commit is contained in:
Jerry 2025-12-06 23:32:53 +08:00
parent cb27aec4f1
commit f1215fc32e
2 changed files with 127 additions and 7 deletions

View File

@ -77,6 +77,8 @@
"imageConfig": { "imageConfig": {
"?enabled": "是否启用图像生成功能", "?enabled": "是否启用图像生成功能",
"enabled": true, "enabled": true,
"?imageMode": "图像生成模式: 'openai'使用/v1/images/generations接口, 'chat'使用对话式生图模型(如gemini-3-pro-image-preview)",
"imageMode": "openai",
"?model": "图像生成模型名称(支持gemini-3-pro-image-preview等)", "?model": "图像生成模型名称(支持gemini-3-pro-image-preview等)",
"model": "gemini-3-pro-image-preview", "model": "gemini-3-pro-image-preview",
"?baseApi": "图像生成API基础地址(不加v1后面的)", "?baseApi": "图像生成API基础地址(不加v1后面的)",

View File

@ -50,18 +50,40 @@ class ImageProcessor {
} }
/** /**
* 生成图像 - 使用OpenAI标准接口 * 生成图像 - 根据imageMode选择不同的调用方式
* @param {string} prompt - 图像描述 * @param {string} prompt - 图像描述
* @param {Object} config - 配置对象 * @param {Object} config - 配置对象
* @returns {Promise<Object>} 生成结果 * @returns {Promise<Object>} 生成结果
*/ */
async generateImage(prompt, config) { async generateImage(prompt, config) {
try { try {
logger.info(`[crystelf-ai] 开始生成图像: ${prompt}`); if (config.imageMode === 'chat') {
return await this.generateImageByChat(prompt, config);
} else {
return await this.generateImageByOpenAI(prompt, config);
}
} catch (error) {
logger.error(`[crystelf-ai] 图像生成失败: ${error.message}`);
return {
success: false,
error: `图像生成失败: ${error.message}`
};
}
}
/**
* 使用OpenAI标准接口生成图像
* @param {string} prompt - 图像描述
* @param {Object} config - 配置对象
* @returns {Promise<Object>} 生成结果
*/
async generateImageByOpenAI(prompt, config) {
try {
logger.info(`[crystelf-ai] 使用OpenAI接口生成图像: ${prompt}`);
const requestBody = { const requestBody = {
prompt: prompt, prompt: prompt,
model: config.model || 'gemini-3-pro-image-preview', model: config.model || 'dall-e-3',
n: config.n || 1, n: config.n || 1,
size: config.size || '1024x1024', size: config.size || '1024x1024',
quality: config.quality || 'standard', quality: config.quality || 'standard',
@ -86,13 +108,13 @@ class ImageProcessor {
const imageData = response.data.data[0]; const imageData = response.data.data[0];
const imageUrl = imageData.url || imageData.b64_json; const imageUrl = imageData.url || imageData.b64_json;
logger.info(`[crystelf-ai] 图像生成成功: ${imageUrl ? 'URL' : 'Base64数据'}`); logger.info(`[crystelf-ai] OpenAI接口图像生成成功: ${imageUrl ? 'URL' : 'Base64数据'}`);
return { return {
success: true, success: true,
imageUrl: imageUrl, imageUrl: imageUrl,
revisedPrompt: imageData.revised_prompt, revisedPrompt: imageData.revised_prompt,
description: prompt, description: prompt,
model: config.model || 'gemini-3-pro-image-preview', model: config.model || 'Qwen/Qwen-Image',
rawResponse: response.data rawResponse: response.data
}; };
} else { } else {
@ -103,10 +125,106 @@ class ImageProcessor {
}; };
} }
} catch (error) { } catch (error) {
logger.error(`[crystelf-ai] 图像生成失败: ${error.message}`); logger.error(`[crystelf-ai] OpenAI接口图像生成失败: ${error.message}`);
return { return {
success: false, success: false,
error: `图像生成失败: ${error.message}` error: `OpenAI接口图像生成失败: ${error.message}`
};
}
}
/**
* 使用对话式接口生成图像如gemini-3-pro-image-preview
* @param {string} prompt - 图像描述
* @param {Object} config - 配置对象
* @returns {Promise<Object>} 生成结果
*/
async generateImageByChat(prompt, config) {
try {
logger.info(`[crystelf-ai] 使用对话接口生成图像: ${prompt}`);
const messages = [
{
role: 'system',
content: '请你根据用户的描述生成高质量且准确的图像,条件允许的情况下,请先思考用户的意图再生成图像,请直接返回图像url,不要任何其他内容'
},
{
role: 'user',
content: prompt
}
];
const requestBody = {
model: config.model || 'google/gemini-3-pro-image-preview',
messages: messages,
max_tokens: config.maxTokens || 4000,
temperature: config.temperature || 0.7,
modalities: config.modalities || ['text', 'image'],
size: config.size || '1024x1024',
response_format: config.responseFormat || 'url'
};
const response = await axios.post(
`${config.baseApi}/v1/chat/completions`,
requestBody,
{
headers: {
'Authorization': `Bearer ${config.apiKey}`,
'Content-Type': 'application/json'
},
timeout: config.timeout || 60000
}
);
if (response.data && response.data.choices && response.data.choices.length > 0) {
const choice = response.data.choices[0];
if (choice.message && choice.message.images && choice.message.images.length > 0) {
const imageData = choice.message.images[0];
const imageUrl = imageData.image_url ? imageData.image_url.url : null;
if (imageUrl) {
logger.info(`[crystelf-ai] 对话接口图像生成成功: ${imageUrl.substring(0, 50)}...`);
return {
success: true,
imageUrl: imageUrl,
description: prompt,
model: config.model || 'google/gemini-3-pro-image-preview',
rawResponse: response.data
};
}
}
if (choice.message && choice.message.content) {
const imageUrl = this.extractImageUrl(choice.message.content);
if (imageUrl) {
logger.info(`[crystelf-ai] 从响应内容中提取到图像URL: ${imageUrl}`);
return {
success: true,
imageUrl: imageUrl,
description: prompt,
model: config.model || 'google/gemini-3-pro-image-preview',
rawResponse: response.data
};
} else {
logger.info(`[crystelf-ai] 收到文本响应: ${choice.message.content}`);
return {
success: true,
response: choice.message.content,
description: prompt,
model: config.model || 'google/gemini-3-pro-image-preview',
rawResponse: response.data
};
}
}
} else {
logger.error(`[crystelf-ai] 无效的API响应格式: ${JSON.stringify(response.data)}`);
return {
success: false,
error: '无效的API响应格式'
};
}
} catch (error) {
logger.error(`[crystelf-ai] 对话接口图像生成失败: ${error.message}`);
return {
success: false,
error: `对话接口图像生成失败: ${error.message}`
}; };
} }
} }