Spring AI多模态接口开发

文章目录

项目地址

创建项目

  1. 打开IDEA创建一个新的spring boot项目,填写项目名称和位置,类型选择maven,组、工件、软件包名称可以自定义,JDK选择17+即可,java语言标准和JDK相同即可
  2. 配置Spring Boot版本和开发所需的依赖,主要如下图所示
    • Spring Boot版本可以选择3.2.5或者更高的版本(作者使用3.2.5和3.2.6(SNAPSHOT)可以正常开发)
    • Spring Boot DevTools:spring项目热部署工具,修改完代码(不含application和pom配置文件)即刻热部署项目
    • Lombok:通过配置快速配置对象的get、set、toString
    • Spring AI:Spring AI是一个用于AI工程的应用框架
  3. 创建完成后,项目结构大体如下(这里删除了无用的maven文件内容、修改application的文件格式为yaml)

配置项目

  • 注意:修改pom文件,重新下载spring ai依赖需要科学上网,请确保网络连接没有问题
  1. 打开项目的pom文件,修改spring ai的版本(项目默认使用稳定版0.8.1)
    • 主要注意默认的spring ai版本和配置依赖jar包仓库(maven仓库中还没有spring ai的依赖)
xml 复制代码
<properties>
    <java.version>21</java.version>
    <spring-ai.version>0.8.1</spring-ai.version>
</properties>

<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>
  1. 配置application文件(api-key的获取参考Spring AI开发前期开发指导
xml 复制代码
spring:
  application:
    name: ChatMultiModel
  ai:
    openai:
      api-key: hk-xxx #请使用自己的api-key
      base-url: https://api.openai-hk.com
server:
  port: 8084

接口开发

java 复制代码
import jakarta.annotation.Resource;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.Media;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@RestController
public class MultiModelController {

    @Resource
    private ChatClient chatClient;
    @PostMapping("/ai/multiChatTest")
    public Object multiChatTest() throws IOException {
        byte[] imageData = new ClassPathResource("/multimodal.test.png").getContentAsByteArray();

        var userMessage = new UserMessage("请解释在图片中有什么?",
                List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageData)));

        ChatResponse response = chatClient.call(
                new Prompt(
                        List.of(userMessage),
                        OpenAiChatOptions
                                .builder()
                                .withModel(OpenAiApi.ChatModel.GPT_4_VISION_PREVIEW.getValue())
                                .build()
                )
        );
        return response.getResult().getOutput();
    }

    /**
     * 多模态对话
     * @param msg 文本信息
     * @param imageUrl 在线图片地址信息
     */
    @PostMapping("/ai/multiChat")
    public Object multiChat(String msg,String imageUrl){
        // 一张电脑主板背部接口的图片地址 https://img-blog.csdnimg.cn/direct/761932564968468690c3d52c889f329a.png
        UserMessage userMessage = new UserMessage(msg, List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl)));
        ChatResponse response = chatClient.call(
                new Prompt(
                        List.of(userMessage),
                        OpenAiChatOptions
                                .builder()
                                .withModel(OpenAiApi.ChatModel.GPT_4_VISION_PREVIEW.getValue())
                                .build()
                )
        );
        return response.getResult().getOutput();
    }

    /**
     * 多模态批量图片上传对话
     * @param msg 文本信息
     * @param imageFiles 图片内容 图片过大提示错误
     */
    @PostMapping("/ai/multiChat2")
    public Object multiChatWithUploadImage(String msg, List<MultipartFile> imageFiles) {
        List<Media> mediaList = new ArrayList<>();

        for (MultipartFile file : imageFiles) {
            try {
                byte[] imageData = file.getBytes();
                MediaType mediaType = MediaType.valueOf(Objects.requireNonNull(file.getContentType()));
                mediaList.add(new Media(mediaType, imageData));
            } catch (IOException e) {
                // 处理读取图片文件时的异常
                e.printStackTrace();
            }
        }

        UserMessage userMessage = new UserMessage(msg, mediaList);

        ChatResponse response = chatClient.call(
                new Prompt(
                        List.of(userMessage),
                        OpenAiChatOptions
                                .builder()
                                .withModel(OpenAiApi.ChatModel.GPT_4_VISION_PREVIEW.getValue())
                                .build()
                )
        );

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

结果测试

测试接口测试

  • http://localhost:8084/ai/multiChatTest
json 复制代码
{
    "messageType": "ASSISTANT",
    "metadata": {
        "finishReason": "STOP",
        "role": "ASSISTANT",
        "id": "chatcmpl-9NbNVih5y0iFMCmC2UBJpc8D9kLms",
        "messageType": "ASSISTANT"
    },
    "content": "图片中是一个金属制的水果篮,篮子的设计简约但优雅,呈现出一种现代感。水果篮中放着两根黄色的香蕉和至少一个红色的苹果。香蕉的表面有斑点,显示它们成熟了,这通常意味着它们会更加甜。背景是模糊的,所以我们无法确定具体的环境,但可以猜测这可能是家庭厨房或餐厅的一角。",
    "media": []
}

在线图片接口测试

json 复制代码
{
    "messageType": "ASSISTANT",
    "metadata": {
        "finishReason": "STOP",
        "role": "ASSISTANT",
        "id": "chatcmpl-9NbZyTNrExouUI9hwaEkLMQKR5mzh",
        "messageType": "ASSISTANT"
    },
    "content": "这张图片展示的是一台计算机的后部接口面板。从左至右,我们可以看到:\n\n- 一个PS/2接口,通常用于连接键盘或鼠标。\n- 两个蓝色的USB 3.1或更高版本接口。\n- 一个DisplayPort接口,用于连接显示器。\n- 一个HDMI接口,同样用于连接显示器。\n- 四个红色的USB 3.2 Gen2接口,提供高速数据传输能力。\n- 一个USB Type-C接口。\n- 一个以太网接口,标有\"2.5 Gbps LAN\",表示其支持最高2.5吉比特每秒的网络速度。\n- 一组音频接口,包括麦克风输入(粉色)、线出(绿色)、以及其他音频输入/输出(橙色、灰色、蓝色)。\n- 两个Wi-Fi天线连接口,用于连接无线网络。\n- 一个内置Wi-Fi模块的标识,有无线网络信号的图标。\n\n整个面板设计呈现出现代化和高性能的特点,适用于高端桌面计算机主板。",
    "media": []
}

本地图片接口测试

json 复制代码
{
    "messageType": "ASSISTANT",
    "metadata": {
        "finishReason": "STOP",
        "role": "ASSISTANT",
        "id": "chatcmpl-9Nc3JZ3cVGCIlsdJrlHnJYT7O5rbu",
        "messageType": "ASSISTANT"
    },
    "content": "第一张图片是一幅数字艺术作品,展示了一个多边形风格的狼头图案。这幅图使用了丰富的颜色和几何形状,表现了一种现代和抽象的风格。背景是纯黑色的,突出了狼头的彩色轮廓。\n\n第二张图片显示的是一个电脑系统信息的截图,界面是中文。根据截图上的信息,这台电脑运行的是64位的Windows 10操作系统,版本为22H2,支持DirectX 12。处理器是英特尔Xeon E5-2698B v3,频率为2.00GHz,共有22个核心。内存为128GB,使用的是DDR3类型,频率为1866MHz,是32GB内存条组成的四通道配置。图形卡为NVIDIA GeForce RTX 3060,带12GB显存。主板型号是华硕X99M-PLUS D3,芯片组为Lynx Point Q87。存储方面,有一块2TB(2048GB)的固态硬盘。网络接口为Realtek RTL8168/8111/8112 Gigabit Ethernet Controller。声卡是High Definition Audio。系统版本底部提示有Win11的升级提示。",
    "media": []
}
相关推荐
Rookie也要加油19 分钟前
01_SQLite
数据库·sqlite
liuxin3344556623 分钟前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
看山还是山,看水还是。1 小时前
MySQL 管理
数据库·笔记·mysql·adb
fishmemory7sec1 小时前
Koa2项目实战2(路由管理、项目结构优化)
数据库·mongodb·koa
momo小菜pa1 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke2 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
小宇成长录2 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.3 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构
程序猿小D3 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa