我用GPT-Image-1.5做了个批量生图工具,成本低到离谱

最近OpenAI的DALL-E 3 API价格降了不少,我就琢磨着能不能做个批量生图的工具,既能满足自己的需求,又能顺便赚点服务器钱。折腾了几天,还真做出来了,今天来分享一下整个开发过程。

为什么要做批量生图?

做自媒体的都知道,配图是个大问题。写一篇文章需要好几张配图,一张一张生成太慢了。市面上的AI绘图工具要么太贵,要么功能太复杂,我就想做个简单直接的批量生图工具。

核心需求就三个:

  1. 批量生成:一次生成1-10张图
  2. 可控成本:不同质量不同价格,用户自己选
  3. 支持参考图:能上传参考图控制风格

技术选型

后端用的FastAPI,前端就简单的Vue 3,AI模型用的是OpenAI的GPT-Image-1.5(其实就是DALL-E 3的升级版)。

为什么选GPT-Image-1.5?

  • 生成速度快,平均5-8秒一张
  • 质量稳定,不像SD那样需要反复调参
  • API简单,不用自己搭模型

核心代码实现

1. 后端API设计

先搞个基础的FastAPI框架:

python 复制代码
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.middleware.cors import CORSMiddleware
from typing import List, Optional
import openai
import asyncio
from pydantic import BaseModel

app = FastAPI(title="批量生图API")

# 跨域配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class ImageGenerationRequest(BaseModel):
    prompt: str
    size: str = "1024x1024"  # 1024x1024, 1536x1024, 1024x1536
    quality: str = "standard"  # standard, hd
    count: int = 1  # 1-10
    reference_images: Optional[List[str]] = None

@app.post("/api/generate-images")
async def generate_images(request: ImageGenerationRequest):
    """批量生成图片"""
    return await batch_generate(request)

2. 批量生成逻辑

这是核心部分,要处理并发生成和错误重试:

python 复制代码
import aiohttp
import base64
from pathlib import Path

async def batch_generate(request: ImageGenerationRequest):
    """异步批量生成图片"""
    
    # 构建完整的prompt
    full_prompt = request.prompt
    
    # 如果有参考图,先分析参考图
    if request.reference_images:
        style_description = await analyze_reference_images(
            request.reference_images
        )
        full_prompt = f"{request.prompt}, style: {style_description}"
    
    # 计算费用
    cost = calculate_cost(request.size, request.quality, request.count)
    
    # 并发生成多张图片
    tasks = []
    for i in range(request.count):
        task = generate_single_image(
            prompt=full_prompt,
            size=request.size,
            quality=request.quality,
            index=i
        )
        tasks.append(task)
    
    # 等待所有任务完成
    results = await asyncio.gather(*tasks, return_exceptions=True)
    
    # 过滤掉失败的任务
    success_images = [r for r in results if not isinstance(r, Exception)]
    failed_count = len(results) - len(success_images)
    
    return {
        "success": True,
        "total": request.count,
        "generated": len(success_images),
        "failed": failed_count,
        "cost": cost,
        "images": success_images
    }

async def generate_single_image(
    prompt: str, 
    size: str, 
    quality: str, 
    index: int,
    max_retries: int = 3
) -> dict:
    """生成单张图片,支持重试"""
    
    for attempt in range(max_retries):
        try:
            response = await openai.Image.acreate(
                model="dall-e-3",
                prompt=prompt,
                size=size,
                quality=quality,
                n=1
            )
            
            image_url = response.data[0].url
            
            # 下载图片到本地
            async with aiohttp.ClientSession() as session:
                async with session.get(image_url) as resp:
                    image_data = await resp.read()
            
            # 保存图片
            filename = f"generated_{index}_{int(time.time())}.png"
            file_path = Path(f"static/images/{filename}")
            file_path.parent.mkdir(parents=True, exist_ok=True)
            
            with open(file_path, "wb") as f:
                f.write(image_data)
            
            return {
                "index": index,
                "url": f"/images/{filename}",
                "revised_prompt": response.data[0].revised_prompt
            }
            
        except Exception as e:
            if attempt == max_retries - 1:
                raise e
            await asyncio.sleep(2 ** attempt)  # 指数退避
    
    raise Exception(f"Failed to generate image {index}")

3. 参考图分析

这个功能是亮点,用GPT-4 Vision分析参考图的风格:

python 复制代码
async def analyze_reference_images(image_paths: List[str]) -> str:
    """分析参考图片,提取风格特征"""
    
    # 读取图片并转base64
    image_contents = []
    for path in image_paths[:3]:  # 最多分析3张
        with open(path, "rb") as f:
            base64_image = base64.b64encode(f.read()).decode()
            image_contents.append({
                "type": "image_url",
                "image_url": {
                    "url": f"data:image/jpeg;base64,{base64_image}"
                }
            })
    
    # 调用GPT-4 Vision
    response = await openai.ChatCompletion.acreate(
        model="gpt-4-vision-preview",
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": "分析这些图片的视觉风格,包括色调、构图、光影、艺术风格等,用简洁的英文描述,用于AI绘图的风格参考。"
                    },
                    *image_contents
                ]
            }
        ],
        max_tokens=200
    )
    
    return response.choices[0].message.content

4. 价格计算

根据不同尺寸和质量计算费用:

python 复制代码
def calculate_cost(size: str, quality: str, count: int) -> float:
    """计算生成费用"""
    
    # 基础价格(单位:元)
    base_prices = {
        "1024x1024": {"standard": 0.04, "hd": 0.08},
        "1536x1024": {"standard": 0.08, "hd": 0.12},
        "1024x1536": {"standard": 0.08, "hd": 0.12}
    }
    
    unit_price = base_prices.get(size, {}).get(quality, 0.04)
    
    # 加上平台服务费(150%加价)
    final_price = unit_price * 2.5
    
    # 质量映射
    quality_map = {"standard": 0.1, "hd": 0.5}
    if quality == "hd":
        final_price = 1.5
    
    return round(count * final_price, 2)

5. 前端交互

前端用Vue 3写个简单的界面:

vue 复制代码
<template>
  <div class="image-generator">
    <h1>批量生图</h1>
    <p class="subtitle">GPT-Image-1.5 批量图片生成,快速高效</p>
    
    <!-- 提示词输入 -->
    <div class="prompt-section">
      <label>提示词</label>
      <textarea 
        v-model="prompt" 
        placeholder="例如:一只可爱的猫咪在樱花树下玩耍,动漫风格"
        rows="5"
      />
      <button @click="clearPrompt">清空提示词</button>
    </div>
    
    <!-- 参考图上传 -->
    <div class="reference-section">
      <label>参考图片</label>
      <div class="upload-area" @click="selectFiles">
        <i class="icon-upload"></i>
        <p>添加图片</p>
      </div>
      <input 
        ref="fileInput" 
        type="file" 
        multiple 
        accept="image/*"
        @change="handleFileUpload"
        style="display: none"
      />
    </div>
    
    <!-- 尺寸选择 -->
    <div class="size-section">
      <label>图像尺寸</label>
      <div class="options">
        <button 
          v-for="size in sizes" 
          :key="size"
          :class="{ active: selectedSize === size }"
          @click="selectedSize = size"
        >
          {{ size }}
        </button>
      </div>
    </div>
    
    <!-- 质量选择 -->
    <div class="quality-section">
      <label>质量</label>
      <div class="options">
        <button 
          :class="{ active: quality === 'standard' }"
          @click="quality = 'standard'"
        >
          低 (0.1元)
        </button>
        <button 
          :class="{ active: quality === 'hd' }"
          @click="quality = 'hd'"
        >
          高 (1.5元)
        </button>
      </div>
    </div>
    
    <!-- 数量滑块 -->
    <div class="count-section">
      <label>生成数量</label>
      <input 
        type="range" 
        v-model="count" 
        min="1" 
        max="10"
      />
      <span>{{ count }}</span>
    </div>
    
    <!-- 生成按钮 -->
    <button 
      class="generate-btn" 
      @click="generateImages"
      :disabled="loading"
    >
      {{ loading ? '生成中...' : `生成图片 (${totalCost}元)` }}
    </button>
    
    <!-- 结果展示 -->
    <div class="results" v-if="generatedImages.length">
      <h3>生成结果</h3>
      <div class="image-grid">
        <img 
          v-for="(img, index) in generatedImages" 
          :key="index"
          :src="img.url"
          :alt="`Generated ${index + 1}`"
        />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import axios from 'axios'

const prompt = ref('')
const selectedSize = ref('1024x1024')
const quality = ref('standard')
const count = ref(1)
const loading = ref(false)
const generatedImages = ref([])
const referenceImages = ref([])

const sizes = ['1024x1024', '1536x1024', '1024x1536']

const totalCost = computed(() => {
  const priceMap = {
    'standard': 0.1,
    'hd': 1.5
  }
  return (count.value * priceMap[quality.value]).toFixed(2)
})

const generateImages = async () => {
  if (!prompt.value.trim()) {
    alert('请输入提示词')
    return
  }
  
  loading.value = true
  
  try {
    const response = await axios.post('/api/generate-images', {
      prompt: prompt.value,
      size: selectedSize.value,
      quality: quality.value,
      count: count.value,
      reference_images: referenceImages.value
    })
    
    generatedImages.value = response.data.images
    
    alert(`成功生成 ${response.data.generated} 张图片!`)
  } catch (error) {
    alert('生成失败:' + error.message)
  } finally {
    loading.value = false
  }
}

const handleFileUpload = (event) => {
  const files = Array.from(event.target.files)
  // 处理文件上传逻辑
}
相关推荐
今天你AiPy了吗1 天前
OpenClaw平替来了!AiPy让AI办公更简单
人工智能·gpt·aigc·ai编程
羊仔AI探索1 天前
OpenAI反击谷歌,GPT-5.2-Codex无限记忆,突破AI编程新境界!
人工智能·gpt·ai·aigc·ai编程
智算菩萨2 天前
【论文复现】Applied Intelligence 2025:Auto-PU正例无标签学习的自动化实现与GPT-5.4辅助编程实战
论文阅读·python·gpt·学习·自动化·复现
li星野2 天前
GPT工作机制
人工智能·gpt·深度学习
kailp2 天前
无需本地显卡!跑GPT-SoVITS-V2Pro完整教程
人工智能·gpt·ai·大模型·云计算
智算菩萨2 天前
GPT-5.4 进阶思考模式全面解析:从推理等级到实战提示词,代码、论文、数据处理一站通
人工智能·gpt·深度学习·机器学习·语言模型·自然语言处理·chatgpt
康康的AI博客2 天前
深度:GPT-5.4实测,AI已自带“手脚”控电脑,这种混搭用法火了!
人工智能·gpt
前端大波3 天前
OpenClaw 本地安装与 GPT 模型接入计划(OpenAI 登录版)
gpt
智算菩萨3 天前
【论文复现】ML-MLM:基于PyTorch的多标签极小学习机完整复现教程(附GPT-5.4辅助科研提示词工程)
人工智能·pytorch·python·gpt·深度学习·论文笔记