Image Generation
Spring AI 通过 ImageModel 接口统一了 OpenAI DALL-E、Azure OpenAI、Stability AI 和 ZhiPuAI 四家厂商的图片生成能力,支持参数化控制尺寸、风格、生成数量。
1. 架构定位
ImageModel 是图片生成的统一入口,支持 OpenAI、Azure OpenAI、Stability AI 等厂商。通过自动注入即可使用,也可手动创建。
2. 图片生成模型
ImageModel 是单一方法的函数式接口。
2.1 自动注入
引入任一厂商 Starter 后,ImageModel 由 Spring Boot 自动配置提供。
- OpenAI
- Azure OpenAI
- Stability AI
- ZhiPuAI
| 配置项 | 说明 |
|---|---|
spring.ai.openai.api-key | OpenAI API 密钥 |
spring.ai.openai.image.options.model | 模型名称,如 dall-e-3 |
| 配置项 | 说明 |
|---|---|
spring.ai.azure.openai.api-key | Azure OpenAI API 密钥 |
spring.ai.azure.openai.endpoint | Azure OpenAI 服务端点 |
spring.ai.azure.openai.image.options.deployment-name | Azure 部署名称 |
| 配置项 | 说明 |
|---|---|
spring.ai.stabilityai.api-key | Stability AI API 密钥 |
spring.ai.stabilityai.image.options.model | 模型名称,如 stable-diffusion-v1-6 |
| 配置项 | 说明 |
|---|---|
spring.ai.zhipuai.api-key | ZhiPuAI API 密钥 |
spring.ai.zhipuai.image.options.model | 模型名称,如 cogview-3 |
@RestController
public class ImageController {
private final ImageModel imageModel;
public ImageController(ImageModel imageModel) {
this.imageModel = imageModel;
}
@GetMapping("/image")
public String generate(@RequestParam String prompt) {
ImageResponse response = imageModel.call(new ImagePrompt(prompt));
return response.getResult().getOutput().getUrl();
}
}
2.2 手动创建
当不使用 Spring Boot 自动配置时,可直接实例化具体实现。
完整示例:ManualImageDemo.java
ManualImageDemo.java
public class ManualImageDemo {
public static void main(String[] args) {
OpenAiImageApi imageApi = OpenAiImageApi.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.build();
OpenAiImageOptions options = OpenAiImageOptions.builder()
.model("dall-e-3")
.quality("hd")
.N(1)
.build();
OpenAiImageModel imageModel = OpenAiImageModel.builder()
.openAiImageApi(imageApi)
.defaultOptions(options)
.build();
ImageResponse response = imageModel.call(
new ImagePrompt("一只在月光下弹吉他的猫,赛博朋克风格"));
System.out.println("图片 URL: " + response.getResult().getOutput().getUrl());
}
}
3. 数据结构
3.1 提示词封装
ImagePrompt 封装提示词消息和选项,有 5 种构造方式。
// 最简:纯文本
ImagePrompt p1 = new ImagePrompt("一只坐在窗边的橘猫,梵高风格");
// 文本 + 选项
ImagePrompt p2 = new ImagePrompt("未来城市", ImageOptionsBuilder.builder()
.width(1024).height(1024).style("vivid").build());
// 单条加权消息 + 选项
ImagePrompt p3 = new ImagePrompt(
new ImageMessage("画面主体:橘猫", 1.5f),
ImageOptionsBuilder.builder().build());
// 多条加权消息
ImageMessage msg1 = new ImageMessage("画面主体:橘猫", 1.0f);
ImageMessage msg2 = new ImageMessage("背景:星空", 0.5f);
ImagePrompt p4 = new ImagePrompt(List.of(msg1, msg2));
// 多条消息 + 选项
ImagePrompt p5 = new ImagePrompt(
List.of(msg1, msg2),
ImageOptionsBuilder.builder().model("dall-e-3").build());
3.2 提示词消息
ImageMessage 封装一段提示词文本及其权重(权重对 Stability AI 的多提示词架构尤为重要)。
ImageMessage message = new ImageMessage("一只白猫", 1.0f);
String text = message.getText(); // "一只白猫"
Float weight = message.getWeight(); // 1.0
3.3 响应结果
ImageResponse response = imageModel.call(new ImagePrompt("未来城市"));
// 遍历所有生成结果
List<ImageGeneration> results = response.getResults();
for (ImageGeneration gen : results) {
Image image = gen.getOutput();
System.out.println("URL: " + image.getUrl());
System.out.println("Base64: " + image.getB64Json());
}
// 获取第一个结果
ImageGeneration first = response.getResult();
// 响应元数据
ImageResponseMetadata metadata = response.getMetadata();
System.out.println("创建时间: " + metadata.getCreated());
3.4 图片数据
一张生成的图片,包含 URL 或 Base64 编码数据。
Image image = new Image("https://example.com/image.png", null);
String url = image.getUrl(); // 图片访问 URL
String b64 = image.getB64Json(); // Base64 编码数据(Stability AI 以此为主)
4. 使用方式
4.1 基础图片生成
完整示例:SimpleImageDemo.java
SimpleImageDemo.java
@Component
public class SimpleImageDemo implements CommandLineRunner {
private final ImageModel imageModel;
public SimpleImageDemo(ImageModel imageModel) {
this.imageModel = imageModel;
}
@Override
public void run(String... args) {
ImageResponse response = imageModel.call(
new ImagePrompt("一座漂浮在云端的蒸汽朋克城市")
);
Image image = response.getResult().getOutput();
System.out.println("生成图片 URL: " + image.getUrl());
}
}
4.2 带参数控制
完整示例:ImageOptionsDemo.java
ImageOptionsDemo.java
@Component
public class ImageOptionsDemo implements CommandLineRunner {
private final ImageModel imageModel;
public ImageOptionsDemo(ImageModel imageModel) {
this.imageModel = imageModel;
}
@Override
public void run(String... args) {
ImageOptions options = ImageOptionsBuilder.builder()
.N(2)
.width(1024)
.height(1024)
.style("vivid")
.build();
ImagePrompt prompt = new ImagePrompt(
"一座建在巨树上的精灵城市,奇幻风格",
options
);
ImageResponse response = imageModel.call(prompt);
for (ImageGeneration gen : response.getResults()) {
System.out.println("URL: " + gen.getOutput().getUrl());
}
}
}
4.3 加权提示词(多段描述)
ImageMessage 的权重参数允许对提示词的不同部分施加不同影响力。权重越高,该段描述越被模型重视。此特性对 Stability AI 尤为关键,DALL-E 权重偏差影响较小但仍可用于逻辑分组。
完整示例:WeightedPromptDemo.java
WeightedPromptDemo.java
@Component
public class WeightedPromptDemo implements CommandLineRunner {
private final ImageModel imageModel;
public WeightedPromptDemo(ImageModel imageModel) {
this.imageModel = imageModel;
}
@Override
public void run(String... args) {
List<ImageMessage> messages = List.of(
new ImageMessage("一只可爱的柯基犬", 2.0f),
new ImageMessage("背景是樱花树下", 0.5f),
new ImageMessage("柔和的光线,浅景深", 0.3f)
);
ImagePrompt prompt = new ImagePrompt(
messages,
ImageOptionsBuilder.builder()
.model("dall-e-3")
.width(1024)
.height(1024)
.build()
);
ImageResponse response = imageModel.call(prompt);
System.out.println("URL: " + response.getResult().getOutput().getUrl());
}
}
5. 便携式选项
ImageOptions 是跨厂商的便携式选项接口,ImageOptionsBuilder 提供链式 API 构建选项。
ImageOptions options = ImageOptionsBuilder.builder()
.model("dall-e-3")
.width(1024)
.height(1024)
.N(1)
.style("vivid")
.build();
ImagePrompt prompt = new ImagePrompt("未来城市", options);
6. 完整综合示例
完整示例:ImageGenerationCompleteExample.java
ImageGenerationCompleteExample.java
@Component
public class ImageGenerationCompleteExample implements CommandLineRunner {
private final ImageModel imageModel;
public ImageGenerationCompleteExample(ImageModel imageModel) {
this.imageModel = imageModel;
}
@Override
public void run(String... args) {
record GenerationResult(String url, String revisedPrompt, Long created) {}
List<ImageMessage> messages = List.of(
new ImageMessage("一个未来科技公司办公室,玻璃幕墙,悬浮办公桌", 1.5f),
new ImageMessage("色调:蓝白为主,配合暖黄灯光", 0.8f)
);
ImageOptions options = ImageOptionsBuilder.builder()
.model("dall-e-3")
.N(1)
.width(1024)
.height(1024)
.style("vivid")
.responseFormat("url")
.build();
ImageResponse response = imageModel.call(new ImagePrompt(messages, options));
for (ImageGeneration gen : response.getResults()) {
Image image = gen.getOutput();
OpenAiImageGenerationMetadata metadata =
(OpenAiImageGenerationMetadata) gen.getMetadata();
System.out.println("图片 URL: " + image.getUrl());
System.out.println("优化提示词: " + metadata.getRevisedPrompt());
}
System.out.println("响应创建时间: " + response.getMetadata().getCreated());
}
}