Files
Amazon_img/index.js
2026-01-03 14:18:48 +08:00

339 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const axios = require('axios');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
// 配置
const config = {
apiKey: process.env.API_KEY,
apiBaseUrl: process.env.API_BASE_URL || 'https://api.wuyinkeji.com',
generateApi: process.env.GENERATE_API || '/api/img/nanoBanana-pro',
queryApi: process.env.QUERY_API || '/api/img/drawDetail',
sourceImageUrl: process.env.SOURCE_IMAGE_URL,
imageSize: process.env.IMAGE_SIZE || '2K',
aspectRatio: process.env.ASPECT_RATIO || '1:1',
queryInterval: parseInt(process.env.QUERY_INTERVAL) || 5000,
maxQueryCount: parseInt(process.env.MAX_QUERY_COUNT) || 60,
outputDir: path.join(__dirname, 'img_2')
};
// 确保输出目录存在
if (!fs.existsSync(config.outputDir)) {
fs.mkdirSync(config.outputDir, { recursive: true });
}
// 亚马逊主图prompt模板
const MAIN_IMAGE_PROMPTS = [
{
name: 'main_image_white_bg',
prompt: 'Create a professional Amazon product main image with pure white background. The product should be centered, well-lit, showing all key features clearly. High quality commercial photography style, clean and minimalist.',
aspectRatio: '1:1'
},
{
name: 'main_image_lifestyle',
prompt: 'Create a lifestyle Amazon product main image showing the product in a natural, appealing setting. Professional product photography, bright and inviting atmosphere.',
aspectRatio: '1:1'
}
];
// 亚马逊产品图prompt模板
const PRODUCT_IMAGE_PROMPTS = [
{
name: 'product_detail_1',
prompt: 'Create a detailed Amazon product image showing close-up details and features. Professional product photography, white background, high resolution.',
aspectRatio: '1:1'
},
{
name: 'product_detail_2',
prompt: 'Create an Amazon product image showing different angles and perspectives. Clean white background, professional lighting, showcasing product quality.',
aspectRatio: '1:1'
},
{
name: 'product_in_use',
prompt: 'Create an Amazon product image showing the product in use scenario. Natural setting, professional photography, highlighting product benefits.',
aspectRatio: '4:3'
},
{
name: 'product_features',
prompt: 'Create an Amazon product image highlighting key features and specifications. Clean layout, professional design, easy to understand.',
aspectRatio: '16:9'
}
];
/**
* 调用生图API
*/
async function generateImage(prompt, imageConfig) {
try {
const url = `${config.apiBaseUrl}${config.generateApi}`;
const requestData = {
prompt: prompt.prompt,
aspectRatio: imageConfig.aspectRatio || prompt.aspectRatio || config.aspectRatio,
imageSize: imageConfig.imageSize || config.imageSize
};
// 如果提供了源图片URL添加到请求中
if (config.sourceImageUrl) {
requestData.img_url = config.sourceImageUrl;
}
console.log(`\n正在生成图片: ${prompt.name}`);
console.log(`Prompt: ${prompt.prompt.substring(0, 100)}...`);
console.log(`请求URL: ${url}`);
const response = await axios.post(url, requestData, {
headers: {
'Content-Type': 'application/json;charset:utf-8;',
'Authorization': config.apiKey
},
timeout: 30000
});
if (response.data && response.data.code === 200) {
const taskId = response.data.data?.id || response.data.data?.taskId || response.data.taskId;
console.log(`✅ 任务提交成功任务ID: ${taskId}`);
return { success: true, taskId, name: prompt.name };
} else {
console.error(`❌ 任务提交失败:`, response.data);
return { success: false, error: response.data };
}
} catch (error) {
console.error(`❌ 生成图片时出错:`, error.message);
if (error.response) {
console.error(`响应数据:`, error.response.data);
}
return { success: false, error: error.message };
}
}
/**
* 查询图片生成结果
*/
async function queryImageResult(taskId, imageName) {
let queryCount = 0;
return new Promise((resolve, reject) => {
const queryInterval = setInterval(async () => {
queryCount++;
if (queryCount > config.maxQueryCount) {
clearInterval(queryInterval);
reject(new Error(`查询超时,已查询${queryCount}`));
return;
}
try {
// 根据API文档: https://api.wuyinkeji.com/doc/9
// 接口地址: https://api.wuyinkeji.com/api/img/drawDetail
// 请求方式: GET
// 请求参数: id (必填, int类型) - 图片ID
// 返回格式: data.status (0:排队中1:生成中2:成功3:失败)
// data.image_url (生成的图片地址)
const queryUrl = `${config.apiBaseUrl}${config.queryApi}?id=${taskId}`;
console.log(`[${queryCount}/${config.maxQueryCount}] 查询任务状态: ID=${taskId}`);
const response = await axios.get(queryUrl, {
headers: {
'Content-Type': 'application/json;charset:utf-8;',
'Authorization': config.apiKey
},
timeout: 10000
});
const data = response.data;
// 根据API文档响应格式:
// code: 状态码
// msg: 状态信息
// data.status: 0:排队中1:生成中2:成功3:失败
// data.image_url: 生成的图片地址
if (data.code === 200 && data.data) {
const status = data.data.status;
const imageUrl = data.data.image_url;
// status: 2 表示成功
if (status === 2) {
if (imageUrl) {
clearInterval(queryInterval);
console.log(`✅ 图片生成成功: ${imageName}`);
console.log(`图片URL: ${imageUrl}`);
resolve({ imageUrl, taskId, imageName });
} else {
console.log(`⏳ 图片生成成功但URL未返回继续等待...`);
}
}
// status: 3 表示失败
else if (status === 3) {
clearInterval(queryInterval);
reject(new Error(`图片生成失败: ${data.msg || data.data.msg || '未知错误'}`));
}
// status: 0 排队中, 1 生成中
else {
const statusText = status === 0 ? '排队中' : status === 1 ? '生成中' : `未知状态${status}`;
console.log(`${statusText}...`);
}
} else if (data.code !== 200) {
// API返回错误
console.log(`⚠️ 查询返回错误: ${data.msg || '未知错误'} (code: ${data.code})`);
// 继续重试,不立即失败
} else {
console.log(`⏳ 等待中... (响应: ${data.msg || '处理中'})`);
}
} catch (error) {
if (error.response && error.response.status === 404) {
// 任务可能还在处理中
console.log(`⏳ 任务处理中,继续等待...`);
} else {
console.error(`查询时出错:`, error.message);
// 不立即失败,继续重试
}
}
}, config.queryInterval);
});
}
/**
* 下载并保存图片
*/
async function downloadAndSaveImage(imageUrl, imageName) {
try {
console.log(`\n开始下载图片: ${imageUrl}`);
const response = await axios({
url: imageUrl,
method: 'GET',
responseType: 'stream',
timeout: 60000
});
// 确定文件扩展名
const contentType = response.headers['content-type'];
let extension = '.jpg';
if (contentType) {
if (contentType.includes('png')) extension = '.png';
else if (contentType.includes('webp')) extension = '.webp';
}
const filename = `${imageName}${extension}`;
const filepath = path.join(config.outputDir, filename);
const writer = fs.createWriteStream(filepath);
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on('finish', () => {
console.log(`✅ 图片已保存: ${filepath}`);
resolve(filepath);
});
writer.on('error', (error) => {
console.error(`❌ 保存图片失败:`, error);
reject(error);
});
});
} catch (error) {
console.error(`❌ 下载图片失败:`, error.message);
throw error;
}
}
/**
* 处理单个图片生成任务
*/
async function processImageGeneration(prompt) {
try {
// 1. 提交生成任务
const generateResult = await generateImage(prompt, {
aspectRatio: prompt.aspectRatio,
imageSize: config.imageSize
});
if (!generateResult.success) {
throw new Error('任务提交失败');
}
// 2. 查询生成结果
const queryResult = await queryImageResult(generateResult.taskId, prompt.name);
// 3. 下载并保存图片
await downloadAndSaveImage(queryResult.imageUrl, queryResult.imageName);
return { success: true, name: prompt.name };
} catch (error) {
console.error(`处理图片 ${prompt.name} 时出错:`, error.message);
return { success: false, name: prompt.name, error: error.message };
}
}
/**
* 主工作流
*/
async function main() {
console.log('🚀 开始亚马逊产品图生成工作流...\n');
console.log('配置信息:');
console.log(`- API地址: ${config.apiBaseUrl}`);
console.log(`- 源图片: ${config.sourceImageUrl || '使用本地图片'}`);
console.log(`- 输出目录: ${config.outputDir}`);
console.log(`- 图片尺寸: ${config.imageSize}`);
console.log(`- 查询间隔: ${config.queryInterval}ms\n`);
if (!config.apiKey) {
console.error('❌ 错误: 未设置API_KEY请在.env文件中配置');
process.exit(1);
}
if (!config.sourceImageUrl) {
console.warn('⚠️ 警告: 未设置SOURCE_IMAGE_URL');
console.warn('提示: 请将P1191464.JPG上传到图床服务然后在.env中设置SOURCE_IMAGE_URL');
console.warn('或者修改代码以支持直接上传本地图片\n');
}
const allPrompts = [...MAIN_IMAGE_PROMPTS, ...PRODUCT_IMAGE_PROMPTS];
const results = [];
// 顺序处理每个图片生成任务
for (const prompt of allPrompts) {
const result = await processImageGeneration(prompt);
results.push(result);
// 在任务之间稍作延迟,避免请求过快
if (allPrompts.indexOf(prompt) < allPrompts.length - 1) {
console.log('\n等待3秒后处理下一个任务...\n');
await new Promise(resolve => setTimeout(resolve, 3000));
}
}
// 输出总结
console.log('\n' + '='.repeat(50));
console.log('📊 工作流执行总结:');
console.log('='.repeat(50));
const successCount = results.filter(r => r.success).length;
const failCount = results.filter(r => !r.success).length;
console.log(`✅ 成功: ${successCount}/${results.length}`);
console.log(`❌ 失败: ${failCount}/${results.length}`);
if (failCount > 0) {
console.log('\n失败的任务:');
results.filter(r => !r.success).forEach(r => {
console.log(` - ${r.name}: ${r.error}`);
});
}
console.log('='.repeat(50));
}
// 运行主工作流
if (require.main === module) {
main().catch(error => {
console.error('❌ 工作流执行失败:', error);
process.exit(1);
});
}
module.exports = {
generateImage,
queryImageResult,
downloadAndSaveImage,
processImageGeneration
};