Spring-ai-alibaba文生图

文章目录

Spring AI Alibaba 图像模型实战(文生图)

用 Spring AI Alibaba 接入阿里云百炼 DashScope,完成「文字 → 图片」。

版本

  • Spring Boot:3.4.5
  • spring-ai-alibaba-starter-dashscope:1.0.0.4
  • Java:17

Spring-ai更新速度快,请以官方为准

可参考网址:

一、依赖引入

xml 复制代码
<!-- Spring Web,提供 REST 接口 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring AI Alibaba:自动装配 DashScopeImageModel -->
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
    <version>1.0.0.4</version>
</dependency>

<!-- 官方 DashScope SDK(部分场景会用到) -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dashscope-sdk-java</artifactId>
    <version>2.22.18</version>
</dependency>

二、yml 配置

yaml 复制代码
# 复制为 application.yaml;密钥用环境变量,不要写死在仓库里
spring:
  application:
    name: spring-image-demo
  ai:
    dashscope:
      # IDEA Run Configuration → Environment:DASHSCOPE_API_KEY=sk-xxx
      api-key: ${DASHSCOPE_API_KEY}
      image:
        options:
          # DashScopeImageModel 兼容的万相文生图模型
          # 不要用 qwen-image-* 等多模态同步模型,会报 url error / 400
          model: wanx2.1-t2i-turbo

启动前设置环境变量:

powershell 复制代码
$env:DASHSCOPE_API_KEY="你的百炼API Key"

三、代码案例

1. 控制器:注入 ImageModel,三种接口

java 复制代码
@RestController
@RequestMapping("/example")
public class DashScopeImageController {

    /** 由 starter 自动配置注入(底层是 DashScopeImageModel) */
    private final ImageModel imageModel;

    private static final String DEFAULT_PROMPT = "为人工智能生成一张富有科技感的图片!";

    public DashScopeImageController(ImageModel imageModel) {
        this.imageModel = imageModel;
    }

    /**
     * 最简文生图:用默认 prompt 生成一张图,把远端 URL 的字节写回浏览器。
     * GET /example/image
     */
    @GetMapping("/image")
    public void image(HttpServletResponse response) {
        // 1)构造 ImagePrompt(只有提示词,模型走 yml 默认配置)
        ImageResponse imageResponse = imageModel.call(new ImagePrompt(DEFAULT_PROMPT));

        // 2)异步任务完成后,结果里一般是临时图片 URL
        String imageUrl = imageResponse.getResult().getOutput().getUrl();

        try {
            // 3)服务端打开 URL,把 PNG 字节写给前端(浏览器直接显示图片)
            URL url = URI.create(imageUrl).toURL();
            InputStream in = url.openStream();
            response.setHeader("Content-Type", MediaType.IMAGE_PNG_VALUE);
            response.getOutputStream().write(in.readAllBytes());
            response.getOutputStream().flush();
        } catch (IOException e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 同一 prompt 生成多张图,返回 URL 集合。
     * GET /example/image/multiPrompt?prompt=一只会编程的猫&count=2
     */
    @GetMapping("/image/multiPrompt")
    public ResponseEntity<Collection<String>> generateImageWithMultiPrompt(
            @RequestParam(value = "prompt", defaultValue = "一只会编程的猫") String prompt,
            @RequestParam(defaultValue = "2") int count) {

        // N:一次要几张图
        ImageOptions options = ImageOptionsBuilder.builder()
                .N(count)
                .build();

        ImageResponse response = imageModel.call(new ImagePrompt(prompt, options));

        // 每张结果取 URL,收集成 Set
        Set<String> imageSet = response.getResults().stream()
                .map(result -> result.getOutput().getUrl())
                .collect(Collectors.toSet());
        return ResponseEntity.ok(imageSet);
    }

    /**
     * 多条件拼 prompt + 宽高。
     * GET /example/image/multipleConditions?subject=猫&environment=办公室&style=生动
     */
    @GetMapping("/image/multipleConditions")
    public ResponseEntity<?> multipleConditions(
            @RequestParam(value = "subject", defaultValue = "一只会编程的猫") String subject,
            @RequestParam(value = "environment", defaultValue = "办公室") String environment,
            @RequestParam(value = "height", defaultValue = "1024") Integer height,
            @RequestParam(value = "width", defaultValue = "1024") Integer width,
            @RequestParam(value = "style", defaultValue = "生动") String style) {

        // 把多个参数拼成一句完整提示词
        String prompt = String.format(
                "一个%s,置身于%s的环境中,使用%s的艺术风格,高清4K画质,细节精致",
                subject, environment, style
        );

        ImageOptions options = ImageOptionsBuilder.builder()
                .height(height)
                .width(width)
                .build();

        try {
            ImageResponse response = imageModel.call(new ImagePrompt(prompt, options));
            // 成功时直接返回图片 URL 字符串
            return ResponseEntity.ok(response.getResult().getOutput().getUrl());
        } catch (Exception e) {
            // 失败时返回 JSON 错误信息,避免空白 500
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of(
                            "error", "图像生成失败",
                            "message", e.getMessage(),
                            "timestamp", LocalDateTime.now()
                    ));
        }
    }
}

2.(可选)图片未完成时的重试

万相文生图是异步任务。旧版在 pending 时可能抛 RuntimeException,默认 Retry 可能不够。可提供自定义 RetryTemplate:

java 复制代码
@Configuration
public class ImageRetryConfig {

    @Bean
    @Primary
    RetryTemplate imageRetryTemplate() {
        return RetryTemplate.builder()
                .maxAttempts(30) // 最多重试次数
                // 初始间隔 2s,倍率 1.5,上限 15s
                .exponentialBackoff(Duration.ofSeconds(2), 1.5, Duration.ofSeconds(15))
                .retryOn(RuntimeException.class)
                .build();
    }
}

注意:HTTP 401(Key 无效)、400(参数错误)属于不可恢复错误,靠加长重试解决不了。

相关推荐
WUYOUGYLU5 分钟前
大模型时代:人与智能的共同进化
人工智能
netkiller-BG7NYT6 分钟前
基于图像识别的人工智能中医望诊方案
人工智能·百度
W***259210 分钟前
Work Agent深度解读:AI长程任务的执行机制与落地形态
人工智能
能源革命28 分钟前
Hermes Agent 常用命令速查表
人工智能
sunshine22 girl35 分钟前
Java学习七 Java 项目实战1-项目创建和主页面搭建
java·开发语言·学习
code2cat38 分钟前
Java进阶篇之AtomicStampedReference:引用回到原值,版本戳仍能记住变化
java·cas·并发编程·aba
zhizhizhuzhuxia1 小时前
电视剧解说配音怎么选工具,从情绪表现到长文本稳定性的一次实测梳理
人工智能·语音识别
阿部多瑞 ABU1 小时前
复杂社会关系、三层结构与自反性
大数据·人工智能·ai写作
诺伦1 小时前
Manus 2.0 Cascade降本拆解:Token少用23.2%、成本降32%的工程手段,营销Agent编排能迁移什么 | RiseClaw玄策
人工智能·llm·ai agent·agent编排·增长运营
AI码农小姐姐1 小时前
一站式 AI 漫剧生产方案:知漫剧,降低多模态内容创作门槛
人工智能