Skip to content

项目:AI 图像生成器

级别: 初级 时间: 45 分钟 技术栈: Next.js, OpenAI (DALL-E 3)

概览

构建一个 Midjourney/DALL-E 的克隆版,用户输入提示词并获取图像。

核心概念:

  • 图像生成 API: 非流式 (通常)。
  • 资产管理: 托管 vs. 临时 URL。
  • 提示词增强: 使用 LLM 重写用户提示词以获得更好的图像。

步骤 1: API 路由

DALL-E 3 不支持流式传输。它需要 10-15 秒并返回一个 URL。

typescript
// app/api/generate/route.ts
import OpenAI from 'openai';

const openai = new OpenAI();

export async function POST(req: Request) {
  const { prompt } = await req.json();

  const response = await openai.images.generate({
    model: "dall-e-3",
    prompt: prompt,
    n: 1,
    size: "1024x1024",
  });

  return Response.json({ url: response.data[0].url });
}

步骤 2: 前端

tsx
'use client';
import { useState } from 'react';

export default function ImageGen() {
  const [prompt, setPrompt] = useState('');
  const [image, setImage] = useState('');
  const [loading, setLoading] = useState(false);

  const generate = async () => {
    setLoading(true);
    const res = await fetch('/api/generate', {
      method: 'POST',
      body: JSON.stringify({ prompt }),
    });
    const data = await res.json();
    setImage(data.url);
    setLoading(false);
  };

  return (
    <div className="flex flex-col items-center gap-4 p-8">
      <input 
        className="border p-2 rounded w-full max-w-lg"
        value={prompt} 
        onChange={e => setPrompt(e.target.value)} 
        placeholder="一座水晶制成的未来城市..."
      />
      <button 
        onClick={generate}
        disabled={loading}
        className="bg-black text-white px-4 py-2 rounded"
      >
        {loading ? '生成中...' : '创建'}
      </button>
      
      {image && <img src={image} alt="Generated" className="rounded-lg shadow-xl" />}
    </div>
  );
}

进阶:提示词魔法

用户写的提示词很糟糕。“一只猫”。 DALL-E 想要:“一只毛茸茸的暹罗猫坐在天鹅绒沙发上,电影级灯光,8k”。

解决方案: 在发送给 DALL-E 之前,使用 GPT-4o 重写提示词。

typescript
const refinedPrompt = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: `Enhance this image prompt for DALL-E: ${prompt}` }]
});

警告:临时 URL

OpenAI URL 在 60 分钟后过期。 生产环境修复: 下载图像 buffer 并立即将其上传到你自己的 S3/R2 存储桶。