初始提交

This commit is contained in:
2026-01-03 14:18:48 +08:00
commit 282608a482
7 changed files with 815 additions and 0 deletions

338
index.js Normal file
View File

@@ -0,0 +1,338 @@
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
};