介绍

Midjourney 以其强大的文生图能力革新了 AI 生成图像的世界。虽然 Midjourney 主要通过 Discord 机器人交互,但现在开发者可以使用 API 将其图像生成能力直接集成到自己的应用中。本指南将带你从零开始,使用 Midjourney 的 API 构建一个文生图工具。

前置条件

在开始之前,请确保你已经具备:

  • JavaScript/TypeScript 的基础知识
  • 已在系统中安装 Node.js
  • 一个可用的 API Key
  • 对 REST API 与异步编程的基本理解

快速开始

1. 安装

首先安装必要的 SDK。本文使用 ImaginePro SDK,它为 Midjourney API 交互提供了简洁的接口:

npm install imaginepro

2. 基础配置

创建新项目并进行基本配置:

import ImagineProSDK from 'imaginepro';

const midjourneyClient = new ImagineProSDK({
    apiKey: 'your-imaginepro-api-key',
});

核心功能

文生图生成(Text-to-Image)

主要功能是根据文本提示词生成图像:

async function generateImage(prompt) {
    try {
        // 启动生成任务
        const response = await midjourneyClient.imagine({
            prompt: prompt,
        });
        
        console.log('生成已启动:', response.messageId);
        
        // 等待完成并获取结果
        const result = await midjourneyClient.fetchMessage(response.messageId);
        
        return result;
    } catch (error) {
        console.error('生成失败:', error);
        throw error;
    }
}

// 使用示例
const imageResult = await generateImage('一条雄伟的巨龙在日落时分飞越中世纪城堡');
console.log('生成的图片地址:', imageResult.uri);

高级提示词工程(Prompt Engineering)

Midjourney 对详细且具体的提示词响应更好。以下是一些最佳实践:

// 良好的提示词结构
const goodPrompt = '一幅写实风格的睿智老法师肖像,戏剧性打光,细节丰富,8K 分辨率,电影级构图';

// 加入风格修饰词
const styledPrompt = '未来主义城市景观,赛博朋克美学,霓虹灯,雨后湿漉街道,电影级光影';

// 指定宽高比与质量
const detailedPrompt = '金色时刻的宁静山景,16:9 宽高比,高质量,纹理细节丰富';

图像处理功能

超分辨率放大(Upscale)

提升生成图像的分辨率:

async function upscaleImage(messageId, index = 1) {
    try {
        const result = await midjourneyClient.upscale({
            messageId: messageId,
            index: index // 对应 U1、U2、U3、U4 按钮
        });
        
        return result;
    } catch (error) {
        console.error('超分失败:', error);
        throw error;
    }
}

生成变体(Variants)

基于已有图像生成替代版本:

async function createVariant(messageId, index = 1) {
    try {
        const result = await midjourneyClient.variant({
            messageId: messageId,
            index: index // 对应 V1、V2、V3、V4 按钮
        });
        
        return result;
    } catch (error) {
        console.error('变体生成失败:', error);
        throw error;
    }
}

重新生成(Reroll)

使用相同提示词重新生成:

async function rerollImage(messageId) {
    try {
        const result = await midjourneyClient.reroll({
            messageId: messageId
        });
        
        return result;
    } catch (error) {
        console.error('重新生成失败:', error);
        throw error;
    }
}

构建完整的文生图工具

1. 创建主应用

class TextToImageTool {
    constructor(apiKey) {
        this.client = new ImagineProSDK({
            apiKey: apiKey,
            timeout: 300000,
        });
        this.generationHistory = [];
    }
    
    async generateImage(prompt, options = {}) {
        const generationId = Date.now().toString();
        
        try {
            // 启动生成
            const response = await this.client.imagine({
                prompt: prompt,
                ref: generationId,
                webhookOverride: options.webhookUrl
            });
            
            // 记录生成历史
            this.generationHistory.push({
                id: generationId,
                messageId: response.messageId,
                prompt: prompt,
                status: 'processing',
                startTime: new Date()
            });
            
            // 等待完成
            const result = await this.client.fetchMessage(response.messageId);
            
            // 更新历史记录
            const historyItem = this.generationHistory.find(item => item.id === generationId);
            if (historyItem) {
                historyItem.status = result.status;
                historyItem.result = result;
                historyItem.completionTime = new Date();
            }
            
            return result;
        } catch (error) {
            console.error('图像生成失败:', error);
            throw error;
        }
    }
    
    async enhanceImage(messageId, enhancementType, index = 1) {
        switch (enhancementType) {
            case 'upscale':
                return await this.client.upscale({ messageId, index });
            case 'variant':
                return await this.client.variant({ messageId, index });
            case 'reroll':
                return await this.client.reroll({ messageId });
            default:
                throw new Error('未知的增强类型');
        }
    }
    
    getGenerationHistory() {
        return this.generationHistory;
    }
}

2. Webhook 集成

在生产环境中,建议使用 Webhook 异步处理生成结果:

// 设置 Webhook 端点
app.post('/webhook/midjourney', (req, res) => {
    const { messageId, status, uri, prompt, ref } = req.body;
    
    if (status === 'DONE') {
        // 成功生成
        console.log(`提示词已生成图片:${prompt}`);
        console.log(`图片链接:${uri}`);
        
        // 更新数据库、发送通知等
        updateUserGallery(ref, uri);
    } else if (status === 'FAIL') {
        // 生成失败
        console.error(`生成失败:${prompt}`);
        notifyUserOfFailure(ref);
    }
    
    res.status(200).send('OK');
});

// 在生成时使用 Webhook
const result = await tool.generateImage('一幅美丽的日落', {
    webhookUrl: 'https://your-app.com/webhook/midjourney'
});

3. 错误处理与重试逻辑

async function generateWithRetry(prompt, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            return await tool.generateImage(prompt);
        } catch (error) {
            console.error(`${attempt} 次尝试失败:`, error.message);
            
            if (attempt === maxRetries) {
                throw new Error(`重试 ${maxRetries} 次后仍失败:${error.message}`);
            }
            
            // 重试前等待
            await new Promise(resolve => setTimeout(resolve, 2000 * attempt));
        }
    }
}

最佳实践

1. 提示词优化

  • 具体明确:与其写“猫”,不如写“金色毛发、端坐在阳光花园中的华丽波斯猫”
  • 加入风格关键词:“写实”、“电影感”、“艺术风”、“极简”
  • 指定光照与氛围:“戏剧性打光”、“柔和自然光”、“情绪化氛围”
  • 添加质量修饰词:“高分辨率”、“细节丰富”、“8K”、“专业摄影”

2. 性能优化

// 批量处理多张图
async function generateBatch(prompts) {
    const promises = prompts.map(prompt => 
        tool.generateImage(prompt).catch(error => ({
            error: error.message,
            prompt: prompt
        }))
    );
    
    return await Promise.allSettled(prompts);
}

// 简单限流器
class RateLimitedGenerator {
    constructor(tool, maxRequestsPerMinute = 10) {
        this.tool = tool;
        this.maxRequests = maxRequestsPerMinute;
        this.requestQueue = [];
        this.lastRequestTime = 0;
    }
    
    async generateImage(prompt) {
        const now = Date.now();
        const timeSinceLastRequest = now - this.lastRequestTime;
        const minInterval = 60000 / this.maxRequests; // 60 秒 / 最大请求数
        
        if (timeSinceLastRequest < minInterval) {
            await new Promise(resolve => 
                setTimeout(resolve, minInterval - timeSinceLastRequest)
            );
        }
        
        this.lastRequestTime = Date.now();
        return await this.tool.generateImage(prompt);
    }
}

3. 用户体验(UX)

// 进度跟踪
async function generateWithProgress(prompt, onProgress) {
    const response = await tool.client.imagine({ prompt });
    
    // 轮询进度
    const checkProgress = async () => {
        const result = await tool.client.fetchMessage(response.messageId);
        
        onProgress({
            status: result.status,
            progress: result.progress,
            messageId: response.messageId
        });
        
        if (result.status === 'PROCESSING' || result.status === 'QUEUED') {
            setTimeout(checkProgress, 2000);
        }
    };
    
    checkProgress();
    return await tool.client.fetchMessage(response.messageId);
}

// 使用
generateWithProgress('一片充满魔力的森林', (progress) => {
    console.log(`状态:${progress.status},进度:${progress.progress}%`);
});

高级能力

局部修复(Inpainting)

async function inpaintImage(messageId, mask) {
    try {
        const result = await midjourneyClient.inpainting({
            messageId: messageId,
            mask: mask // Base64 编码的遮罩图
        });
        
        return result;
    } catch (error) {
        console.error('局部修复失败:', error);
        throw error;
    }
}

自定义 Webhook 处理

class WebhookHandler {
    constructor() {
        this.pendingGenerations = new Map();
    }
    
    registerGeneration(generationId, callback) {
        this.pendingGenerations.set(generationId, callback);
    }
    
    handleWebhook(payload) {
        const { ref, status, uri, error } = payload;
        const callback = this.pendingGenerations.get(ref);
        
        if (callback) {
            callback({ status, uri, error });
            this.pendingGenerations.delete(ref);
        }
    }
}

常见问题排查

1. API 限流

// 指数退避(Exponential Backoff)
async function generateWithBackoff(prompt, maxRetries = 5) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            return await tool.generateImage(prompt);
        } catch (error) {
            if (error.message.includes('rate limit')) {
                const delay = Math.pow(2, attempt) * 1000; // 指数退避
                console.log(`触发限流,等待 ${delay}ms 后重试`);
                await new Promise(resolve => setTimeout(resolve, delay));
            } else {
                throw error;
            }
        }
    }
}

2. 网络问题

// 为网络问题增加超时与重试
const clientWithRetry = new ImagineProSDK({
    apiKey: 'your-api-key',
    timeout: 60000, // 1 分钟超时
    retryAttempts: 3,
    retryDelay: 1000
});

结语

使用 Midjourney API 构建文生图工具能为你的创意应用打开广阔空间。按照本指南,你将具备创建健壮、友好的图像生成工具的坚实基础。

请记住:

  • 始终优雅地处理错误
  • 实施合适的限流策略
  • 生产环境使用 Webhook
  • 优化提示词以获得更好结果
  • 监控 API 使用与成本

ImaginePro SDK 为 Midjourney API 提供了简洁、专业的接口,助你更轻松地构建企业级、可靠的图像生成应用。

更多资源

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐