353-Spring AI Alibaba ARK 多模型示例

本示例将展示如何使用 Spring AI Alibaba 集成 ARK 多模型能力,实现图像理解、视频内容分析等多模态 AI 功能。ARK 是字节跳动提供的大模型服务平台,支持多种 AI 模型能力。

1. 示例目标

我们将创建一个包含多个核心功能的 Web 应用:

  1. 图像理解 (/api/image):通过上传图片或提供图片 URL,让 AI 模型识别并描述图片内容。
  2. 流式图像理解 (/api/stream/image):以流式方式返回图像理解结果。
  3. 视频内容分析 (/api/video):从视频中提取关键帧,让 AI 模型分析并描述视频内容。

2. 技术栈与核心依赖

  • Spring Boot 3.x
  • Spring AI Alibaba (用于对接字节跳动 ARK 大模型)
  • OpenAI 兼容接口 (ARK 提供与 OpenAI 兼容的 API 接口)
  • JavaCV (用于视频处理和帧提取)
  • Maven (项目构建工具)

pom.xml 中,你需要引入以下核心依赖:

复制代码
<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Open AI 兼容接口 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>

    <!-- JavaCV 用于视频处理 -->
    <dependency>
        <groupId>org.bytedeco</groupId>
        <artifactId>javacv-platform</artifactId>
        <version>1.5.9</version>
    </dependency>

    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3. 项目配置

src/main/resources/application.yml 文件中,配置你的 ARK API Key 和模型信息。

复制代码
spring:
  ai:
    openai:
      # API Key Configuration
      api-key: ${ARK_API_KEY:your-api-key}
      # Ark LLM API Base URL
      base-url: https://ark.cn-beijing.volces.com/api/
      chat:
        options:
          # Model ID, replace with actual access point ID
          model: ${ARK_MODEL_ID:your-model-id}
        # Chat API path, consistent with OpenAI interface
        completions-path: /v3/chat/completions

server:
  port: 7878

logging:
  level:
    org:
      springframework:
        ai:
          chat:
            client:
              advisor: DEBUG

重要提示 :请将 ARK_API_KEYARK_MODEL_ID 环境变量设置为你从 ARK 平台获取的有效 API Key 和模型 ID。你也可以直接将其写在配置文件中,但这不推荐用于生产环境。

4. 准备资源文件

src/main/resources 目录下创建以下文件结构:

复制代码
src/main/resources/
└── multimodel/
    ├── dog_and_girl.jpeg
    └── video.mp4

4.1 multimodel/dog_and_girl.jpeg

这是用于图像理解的示例图片,包含一只狗和一个小女孩。

4.2 multimodel/video.mp4

这是用于视频内容分析的示例视频。系统会自动提取视频帧并进行分析。

5. 编写 Java 代码

5.1 ArkMultiModelApplication.java

主应用程序类,用于启动 Spring Boot 应用。

复制代码
package com.alibaba.cloud.ai.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * ARK Multi-Model Application
 * 支持聊天、图像生成、文本向量等多种模型能力
 * 
 * @author brian xiadong
 */
@SpringBootApplication
public class ArkMultiModelApplication {

    public static void main(String[] args) {
        SpringApplication.run(ArkMultiModelApplication.class, args);
    }
}

5.2 MultiModelController.java

实现多模型功能的核心控制器类。

复制代码
package com.alibaba.cloud.ai.example.controller;

import com.alibaba.cloud.ai.example.controller.helper.FrameExtraHelper;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.content.Media;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.List;

/**
 * ark Multi-Model REST Controller
 * 提供聊天、图片生成、文本向量等多个模型能力的API接口
 * 
 */
@RestController
@RequestMapping("/api")
public class MultiModelController {

    private static final String DEFAULT_PROMPT = "这些是什么?";
    private static final String DEFAULT_VIDEO_PROMPT = "这是一组从视频中提取的图片帧,请描述此视频中的内容。";

    @Autowired
    private ChatModel chatModel;

    private ChatClient openAiChatClient;

    public MultiModelController(ChatModel chatModel) {
        this.chatModel = chatModel;

        // 构造时,可以设置 ChatClient 的参数
        this.openAiChatClient = ChatClient.builder(chatModel)
                // 实现 Chat Memory 的 Advisor
                // 在使用 Chat Memory 时,需要指定对话 ID,以便 Spring AI 处理上下文。
                .defaultAdvisors(
                        MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build()
                )
                // 实现 Logger 的 Advisor
                .defaultAdvisors(
                        new SimpleLoggerAdvisor()
                )
                // 设置 ChatClient 中 ChatModel 的 Options 参数
                .defaultOptions(
                        OpenAiChatOptions.builder()
                                .topP(0.7)
                                .build()
                )
                .build();
    }

    @GetMapping("/image")
    public String image(
            @RequestParam(value = "prompt", required = false, defaultValue = DEFAULT_PROMPT)
            String prompt
    ) throws Exception {

        List<Media> mediaList = List.of(
                new Media(
                        MimeTypeUtils.IMAGE_PNG,
                        new URI("https://dashscope.oss-cn-beijing.aliyuncs.com/images/dog_and_girl.jpeg").toURL()
                                .toURI()
                )
        );

        UserMessage message = UserMessage.builder().text(prompt).media(mediaList).build();

        ChatResponse response = openAiChatClient.prompt(
                new Prompt(
                        message
                )
        ).call().chatResponse();

        return response.getResult().getOutput().getText();
    }

    @GetMapping("/stream/image")
    public String streamImage(
            @RequestParam(value = "prompt", required = false, defaultValue = DEFAULT_PROMPT)
            String prompt
    ) {

        UserMessage message = UserMessage.builder().text(prompt).media(
                new Media(
                        MimeTypeUtils.IMAGE_JPEG,
                        new ClassPathResource("multimodel/dog_and_girl.jpeg")
                )).build();

        List<ChatResponse> response = openAiChatClient.prompt(
                new Prompt(
                        message
                )
        ).stream().chatResponse().collectList().block();

        StringBuilder result = new StringBuilder();
        if (response != null) {
            for (ChatResponse chatResponse : response) {
                String outputContent = chatResponse.getResult().getOutput().getText();
                result.append(outputContent);
            }
        }

        return result.toString();
    }

    @GetMapping("/video")
    public String video(
            @RequestParam(value = "prompt", required = false, defaultValue = DEFAULT_VIDEO_PROMPT)
            String prompt
    ) {

        List<Media> mediaList = FrameExtraHelper.createMediaList(10);

        UserMessage message = UserMessage.builder().text(prompt).media(mediaList).build();

        ChatResponse response = openAiChatClient.prompt(
                new Prompt(
                        message
                )
        ).call().chatResponse();

        return response.getResult().getOutput().getText();
    }
}

5.3 FrameExtraHelper.java

视频帧提取辅助类,用于从视频中提取关键帧。

复制代码
package com.alibaba.cloud.ai.example.controller.helper;

import jakarta.annotation.PreDestroy;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.ai.content.Media;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.io.PathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.MimeType;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static org.bytedeco.javacpp.Loader.deleteDirectory;

@Component
public final class FrameExtraHelper implements ApplicationRunner {

    private FrameExtraHelper() {
    }

    private static final Map<String, List<String>> IMAGE_CACHE = new ConcurrentHashMap<>();

    private static final File videoUrl = new File("spring-ai-alibaba-multi-model-example/dashscope-multi-model/src/main/resources/multimodel/video.mp4");

    private static final String framePath = "spring-ai-alibaba-multi-model-example/dashscope-multi-model/src/main/resources/multimodel/frame/";

    private static final Logger log = LoggerFactory.getLogger(FrameExtraHelper.class);

    public static void getVideoPic() {

        List<String> strList = new ArrayList<>();
        File dir = new File(framePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        try (
                FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoUrl.getPath());
                Java2DFrameConverter converter = new Java2DFrameConverter()
        ) {
            ff.start();
            ff.setFormat("mp4");

            int length = ff.getLengthInFrames();

            Frame frame;
            for (int i = 1; i < length; i++) {
                frame = ff.grabFrame();
                if (frame.image == null) {
                    continue;
                }
                BufferedImage image = converter.getBufferedImage(frame); ;
                String path = framePath + i + ".png";
                File picFile = new File(path);
                ImageIO.write(image, "png", picFile);
                strList.add(path);
            }
            IMAGE_CACHE.put("img", strList);
            ff.stop();
        }
        catch (Exception e) {
            log.error(e.getMessage());
        }

    }

    @Override
    public void run(ApplicationArguments args) throws Exception {

        log.info("Starting to extract video frames");

        getVideoPic();

        log.info("Extracting video frames is complete");

    }

    @PreDestroy
    public void destroy() {

        try {
            deleteDirectory(new File(framePath));
        }
        catch (IOException e) {
            log.error(e.getMessage());
        }

        log.info("Delete temporary files...");
    }

    public static List<String> getFrameList() {

        assert IMAGE_CACHE.get("img") != null;
        return IMAGE_CACHE.get("img");
    }

    public static List<Media> createMediaList(int numberOfImages) {

        List<String> imgList = IMAGE_CACHE.get("img");

        int totalFrames = imgList.size();
        int interval = Math.max(totalFrames / numberOfImages, 1);

        return IntStream.range(0, numberOfImages)
                .mapToObj(i -> imgList.get(i * interval))
                .map(image -> new Media(
                        MimeType.valueOf("image/png"),
                        new PathResource(image)
                ))
                .collect(Collectors.toList());
    }
}

6. 运行与测试

  1. 启动应用:运行你的 Spring Boot 主程序。
  2. 使用浏览器或 API 工具(如 Postman, curl)进行测试

测试 1:图像理解

访问以下 URL,让 AI 模型分析图片内容。

复制代码
http://localhost:7878/api/image?prompt=请描述这张图片中的内容

预期响应

这张图片中有一个小女孩和一只狗。女孩看起来很年轻,可能正在与狗互动。狗似乎是一只金毛寻回犬或类似的品种,毛发呈金黄色。他们可能在一个户外环境中,背景看起来有些模糊,但可能是草地或公园。整体氛围看起来很温馨,展现了人与宠物之间的亲密关系。

测试 2:流式图像理解

访问以下 URL,以流式方式获取图像理解结果。

复制代码
http://localhost:7878/api/stream/image?prompt=图片中有哪些动物和人物?

预期响应

图片中有一只狗和一个小女孩。狗看起来是一只金毛寻回犬,毛发呈金黄色。小女孩看起来年龄很小,可能只有几岁。他们似乎在一个户外环境中,女孩可能正在与狗互动或玩耍。图片整体呈现出一种温馨的氛围,展现了儿童与宠物之间的友好关系。

测试 3:视频内容分析

访问以下 URL,让 AI 模型分析视频内容。

复制代码
http://localhost:7878/api/video?prompt=请描述这个视频中发生了什么

预期响应

根据视频帧分析,这个视频似乎记录了一个户外场景。视频中可能包含人物活动或自然景观。由于只提取了部分关键帧,无法提供完整的视频内容描述,但从这些帧可以看出视频可能涉及一些动态场景或事件。如果需要更详细的分析,建议提供更具体的视频内容或增加提取的帧数。

7. 实现思路与扩展建议

实现思路

本示例的核心思想是**"多模态 AI 能力集成"**。通过 Spring AI Alibaba 框架,我们能够轻松集成 ARK 平台提供的多模态 AI 能力,包括:

  • 图像理解:通过将图像作为输入,让 AI 模型识别并描述图像内容。
  • 视频分析:通过提取视频关键帧,让 AI 模型理解视频内容。
  • 流式响应:支持流式返回 AI 模型的分析结果,提升用户体验。

扩展建议

  • 多图像处理:扩展系统以支持同时处理多张图像,实现更复杂的图像理解场景。
  • 视频摘要生成:基于视频内容分析,自动生成视频摘要或关键信息提取。
  • 音频集成:添加音频处理能力,实现视频中的语音识别和情感分析。
  • 实时视频流分析:集成实时视频流处理能力,适用于监控、直播等场景。
  • 多模型对比:集成多个 AI 模型,对比不同模型在相同任务上的表现。
  • 自定义模型微调:基于特定领域数据,对 ARK 模型进行微调,提升特定场景的识别准确率。
相关推荐
丁学文武3 小时前
如何把ChatGPT嵌入到自己的应用中?
人工智能·chatgpt·编码·大模型应用·ai替代
深圳南柯电子3 小时前
纯电汽车EMC整改:预防性设计节省47%预算|深圳南柯电子
网络·人工智能·汽车·互联网·实验室·emc
bst@微胖子3 小时前
阿里通义千问推理优化上下文缓存之隐式缓存和显式缓存
java·spring·缓存
ss2733 小时前
手写Spring第20弹:JDK动态代理:深入剖析Java代理模式
后端·spring·代理模式
说私域3 小时前
定制开发开源AI智能名片S2B2C商城系统:新零售革命下云零售模式的创新实践
人工智能·开源·零售
后端小张3 小时前
【JAVA 进阶】重生之我要学会 JUC 并发编程
java·spring boot·spring·java-ee·并发编程·安全架构·juc
zzZ65653 小时前
U-net 系列算法总结
人工智能·深度学习·机器学习
AI科技星3 小时前
基于空间螺旋运动假设的水星近日点进动理论推导与验证
数据结构·人工智能·经验分享·算法·计算机视觉