Laravel AI SDK 图像生成实战
摘要
Laravel AI SDK 提供了统一的图像生成 API,支持 DALL-E、Stable Diffusion 等多种图像生成模型。本文将深入讲解如何使用 Laravel AI SDK 进行图像生成,包括:
- 图像生成 API 基础用法
- 支持的图像生成模型
- 图像尺寸与质量控制
- 图像编辑与变体生成
- 批量图像生成
- 实战案例:构建 AI 图像生成器
本文适合希望在 Laravel 应用中集成图像生成功能的开发者。
1. 图像生成概述
1.1 支持的模型
| 模型 | 提供商 | 特点 |
|---|
| DALL-E 3 | OpenAI | 高质量、创意性强 |
| DALL-E 2 | OpenAI | 编辑功能、变体生成 |
| Stable Diffusion | 多提供商 | 开源、可定制 |
| Imagen | Google | 真实感强 |
| Midjourney 风格 | 兼容 API | 艺术风格 |
1.2 基本用法
1 2 3 4 5
| use Laravel\Ai\Image;
$image = Image::of('A serene mountain landscape at sunset')->generate();
$rawContent = (string) $image;
|
1.3 保存图像
1 2 3
| $image = Image::of('A cute cat wearing a hat')->generate();
Storage::put('generated/cat.png', $image->toBinary());
|
2. 图像生成配置
2.1 模型选择
1 2 3
| $image = Image::of('A futuristic city') ->usingModel('dall-e-3') ->generate();
|
2.2 尺寸设置
1 2 3 4 5 6 7 8 9 10 11 12
| $image = Image::of('A beautiful garden') ->size(1024, 1024) ->generate();
$image = Image::of('A portrait') ->size('portrait') ->generate();
$image = Image::of('A landscape') ->size('landscape') ->generate();
|
2.3 质量设置
1 2 3
| $image = Image::of('A detailed illustration') ->quality('hd') ->generate();
|
2.4 风格设置
1 2 3
| $image = Image::of('A sunset over the ocean') ->style('vivid') ->generate();
|
3. 图像编辑
3.1 基于图像编辑
1 2 3
| $image = Image::edit($existingImage) ->prompt('Add a rainbow in the sky') ->generate();
|
3.2 蒙版编辑
1 2 3 4
| $image = Image::edit($existingImage) ->mask($maskImage) ->prompt('Replace with a sunset') ->generate();
|
3.3 局部重绘
1 2 3 4
| $image = Image::inpaint($originalImage) ->mask($maskImage) ->prompt('A beautiful flower') ->generate();
|
4. 图像变体
4.1 生成变体
1 2 3 4 5 6 7
| $variants = Image::of($originalImage) ->variations(4) ->generate();
foreach ($variants as $variant) { Storage::put('variants/' . uniqid() . '.png', $variant); }
|
4.2 变体配置
1 2 3 4
| $variants = Image::of($originalImage) ->variations(3) ->size(512, 512) ->generate();
|
5. 批量生成
5.1 批量提示词
1 2 3 4 5 6 7 8 9 10 11 12 13
| $prompts = [ 'A cat wearing a hat', 'A dog wearing glasses', 'A bird wearing a bowtie', ];
$images = Image::batch($prompts) ->size(512, 512) ->generate();
foreach ($images as $index => $image) { Storage::put("batch/image_{$index}.png", $image); }
|
5.2 队列处理
1 2 3 4 5 6
| use Laravel\Ai\Jobs\GenerateImage;
foreach ($prompts as $prompt) { GenerateImage::dispatch($prompt) ->onQueue('image-generation'); }
|
6. 高级功能
6.1 负面提示词
1 2 3
| $image = Image::of('A beautiful woman') ->negativePrompt('blurry, low quality, distorted') ->generate();
|
6.2 种子控制
1 2 3
| $image = Image::of('A random pattern') ->seed(12345) ->generate();
|
6.3 步数控制
1 2 3
| $image = Image::of('A detailed painting') ->steps(50) ->generate();
|
6.4 CFG Scale
1 2 3
| $image = Image::of('A fantasy castle') ->cfgScale(7.5) ->generate();
|
7. 实战案例:AI 图像生成器
7.1 控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| <?php
namespace App\Http\Controllers;
use Laravel\Ai\Image; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage;
class ImageGeneratorController extends Controller { public function generate(Request $request) { $validated = $request->validate([ 'prompt' => 'required|string|max:1000', 'size' => 'nullable|in:256,512,1024,portrait,landscape', 'quality' => 'nullable|in:standard,hd', 'style' => 'nullable|in:vivid,natural', ]); $image = Image::of($validated['prompt']) ->size($validated['size'] ?? '1024') ->quality($validated['quality'] ?? 'standard') ->style($validated['style'] ?? 'vivid') ->generate(); $filename = 'generated/' . uniqid() . '.png'; Storage::put($filename, $image->toBinary()); return response()->json([ 'url' => Storage::url($filename), 'revised_prompt' => $image->revisedPrompt(), ]); } public function edit(Request $request) { $validated = $request->validate([ 'image' => 'required|image|max:4096', 'prompt' => 'required|string|max:1000', 'mask' => 'nullable|image|max:4096', ]); $imagePath = $request->file('image')->store('temp'); $imageContent = Storage::get($imagePath); $edited = Image::edit($imageContent) ->prompt($validated['prompt']) ->when($request->hasFile('mask'), function ($image) use ($request) { $maskPath = $request->file('mask')->store('temp'); return $image->mask(Storage::get($maskPath)); }) ->generate(); $filename = 'edited/' . uniqid() . '.png'; Storage::put($filename, $edited->toBinary()); Storage::delete([$imagePath]); if ($request->hasFile('mask')) { Storage::delete([$maskPath ?? null]); } return response()->json([ 'url' => Storage::url($filename), ]); } public function variations(Request $request) { $validated = $request->validate([ 'image' => 'required|image|max:4096', 'count' => 'nullable|integer|min:1|max:4', ]); $imagePath = $request->file('image')->store('temp'); $imageContent = Storage::get($imagePath); $variants = Image::of($imageContent) ->variations($validated['count'] ?? 1) ->generate(); $urls = []; foreach ($variants as $index => $variant) { $filename = 'variants/' . uniqid() . '.png'; Storage::put($filename, $variant->toBinary()); $urls[] = Storage::url($filename); } Storage::delete($imagePath); return response()->json(['urls' => $urls]); } }
|
7.2 Livewire 组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <?php
namespace App\Http\Livewire;
use Livewire\Component; use Livewire\WithFileUploads; use Laravel\Ai\Image; use Illuminate\Support\Facades\Storage;
class ImageGenerator extends Component { use WithFileUploads; public string $prompt = ''; public string $size = '1024'; public string $quality = 'standard'; public string $style = 'vivid'; public $generatedImage = null; public bool $generating = false; public function generate() { $this->validate([ 'prompt' => 'required|min:10|max:1000', ]); $this->generating = true; try { $image = Image::of($this->prompt) ->size($this->size) ->quality($this->quality) ->style($this->style) ->generate(); $filename = 'generated/' . uniqid() . '.png'; Storage::put($filename, $image->toBinary()); $this->generatedImage = Storage::url($filename); } finally { $this->generating = false; } } public function render() { return view('livewire.image-generator'); } }
|
7.3 视图模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <div class="image-generator"> <div class="form-group"> <label>Prompt</label> <textarea wire:model="prompt" class="form-control" rows="3" placeholder="Describe the image you want to generate..." ></textarea> </div> <div class="row"> <div class="col-md-4"> <label>Size</label> <select wire:model="size" class="form-control"> <option value="256">256x256</option> <option value="512">512x512</option> <option value="1024" selected>1024x1024</option> <option value="portrait">Portrait (1024x1792)</option> <option value="landscape">Landscape (1792x1024)</option> </select> </div> <div class="col-md-4"> <label>Quality</label> <select wire:model="quality" class="form-control"> <option value="standard">Standard</option> <option value="hd">HD</option> </select> </div> <div class="col-md-4"> <label>Style</label> <select wire:model="style" class="form-control"> <option value="vivid">Vivid</option> <option value="natural">Natural</option> </select> </div> </div> <button wire:click="generate" wire:loading.attr="disabled" class="btn btn-primary mt-3" > <span wire:loading.remove>Generate Image</span> <span wire:loading>Generating...</span> </button> @if($generatedImage) <div class="mt-4"> <img src="{{ $generatedImage }}" class="img-fluid rounded" alt="Generated image"> <a href="{{ $generatedImage }}" download class="btn btn-success mt-2"> Download </a> </div> @endif </div>
|
8. 图像处理管道
8.1 处理流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class ImagePipeline { public function process(string $prompt): array { $results = []; foreach (['dall-e-3', 'stable-diffusion'] as $model) { $image = Image::of($prompt) ->usingModel($model) ->generate(); $filename = "pipeline/{$model}_" . uniqid() . '.png'; Storage::put($filename, $image->toBinary()); $results[$model] = Storage::url($filename); } return $results; } }
|
8.2 后处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| use Intervention\Image\Facades\Image as Intervention;
class ImagePostProcessor { public function process($generatedImage): string { $img = Intervention::make($generatedImage); $img->resize(800, null, function ($constraint) { $constraint->aspectRatio(); }); $img->insert( public_path('watermark.png'), 'bottom-right', 10, 10 ); return $img->encode('png'); } }
|
9. 成本控制
9.1 成本估算
1 2 3 4 5 6 7 8 9
| use Laravel\Ai\Cost;
$cost = Cost::forImageGeneration( size: '1024x1024', quality: 'hd', model: 'dall-e-3' );
echo $cost->inDollars();
|
9.2 用户配额
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class ImageGenerationService { public function canGenerate(User $user): bool { $dailyLimit = $user->subscription->daily_image_limit; $todayCount = $user->generatedImages() ->whereDate('created_at', today()) ->count(); return $todayCount < $dailyLimit; } public function generate(User $user, string $prompt): Image { if (!$this->canGenerate($user)) { throw new QuotaExceededException('Daily image limit reached'); } $image = Image::of($prompt)->generate(); $user->generatedImages()->create([ 'prompt' => $prompt, 'path' => $this->store($image), ]); return $image; } }
|
10. 最佳实践
10.1 提示词优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class PromptOptimizer { public function enhance(string $prompt): string { $enhancements = [ 'highly detailed', 'professional photography', '8k resolution', 'dramatic lighting', ]; return $prompt . ', ' . implode(', ', $enhancements); } }
|
10.2 错误处理
1 2 3 4 5 6 7 8 9
| try { $image = Image::of($prompt)->generate(); } catch (ContentPolicyException $e) { return back()->with('error', 'Your prompt violates content policy'); } catch (RateLimitException $e) { return back()->with('error', 'Too many requests. Please try again later'); } catch (AiException $e) { return back()->with('error', 'Image generation failed'); }
|
10.3 缓存策略
1 2 3 4 5 6 7 8 9 10 11 12 13
| use Illuminate\Support\Facades\Cache;
function getCachedImage(string $prompt): string { $key = 'image:' . md5($prompt); return Cache::remember($key, now()->addDays(7), function () use ($prompt) { $image = Image::of($prompt)->generate(); $filename = 'cached/' . uniqid() . '.png'; Storage::put($filename, $image->toBinary()); return Storage::url($filename); }); }
|
11. 总结
Laravel AI SDK 的图像生成功能为 Laravel 应用提供了强大的 AI 绘画能力:
- 统一 API:支持多种图像生成模型
- 灵活配置:尺寸、质量、风格可定制
- 编辑能力:支持图像编辑和变体生成
- 批量处理:队列支持大规模生成
- 成本控制:内置成本估算和配额管理
通过本指南,您已经掌握了 Laravel AI SDK 图像生成的核心功能,可以开始构建自己的 AI 图像生成应用了。
参考资料