Spring AI简介
Spring AI是一个面向AI工程的应用框架。其目标是将可移植性和模块化设计等设计原则应用于AI领域的Spring生态系统, 转换为人话来说就是:Spring出了一个AI框架,帮助我们快速调用AI,从而实现各种功能场景。
但是重点:对于国内开发者不太友好已经不太支持了。于是乎Spring Cloud Alibaba AI
出世了!
Spring Cloud Alibaba AI 简介
Spring Cloud Alibaba AI
基于 Spring AI 0.8.1
版本完成通义系列大模型的接入。DashScope灵积模型服务建立在 模型即服务(Model-as-a-Service
,MaaS)的理念基础之上,围绕AI各领域模型,通过标准化的API提供包括模型推理、模型微调训练在内的多种模型服务。
目前支持的模型主要有:对话、文生图、文生语音
,更多功能特性正在适配中。那以上介绍完之后咱们就完成一些案例来看看效果吧
开发环境
这里说下我本地的环境,阿里要求JDK为17+
JDK17,Maven3.5以上,Spring Boot2.0+,Spring Cloud2021+
创建工程
创建父工程
创建项目就是正常的Maven项目
引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tongyi</groupId>
<artifactId>tongyi2</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>aliai</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<spring-boot.version>2.7.18</spring-boot.version>
<spring-cloud.version>2021.0.8</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
</properties>
<!-- springboot、springcloud、springcloud alibaba-->
<dependencyManagement>
<dependencies>
<!-- SpringCloud 微服务 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud Alibaba 微服务 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringBoot 依赖配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
创建子工程
创建子工程就是正常的maven项目(选中父工程右键)
引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tongyi2</artifactId>
<groupId>com.tongyi</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>aliai</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-ai</artifactId>
<version>2023.0.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.18</version>
<configuration>
<mainClass>com.usian.AliApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
添加配置文件
主要配置阿里云申请的api-key:
https://dashscope.console.aliyun.com/model
![a0a4658422564a4406307a844457e801.jpeg](https://img-blog.csdnimg.cn/img_convert/a0a4658422564a4406307a844457e801.jpeg)
spring:
cloud:
ai:
tongyi:
api-key: your api-key #自己在阿里云官网申请的api-key
server:
port: 8081
案例
以下所有案例均在一个项目中编写,小伙伴们不要整懵了哈
单轮对话
编写业务层接口
public interface TongYiService {
//聊天对话
String completion(String message);
}
编写业务层抽象类
public abstract class AbstractTongYiServiceImpl implements TongYiService {
private static final String INFO_PREFIX = "please implement ";
private static final String INFO_SUFFIX = "() method.";
@Override
public String completion(String message) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName());
}
}
编写业务层实现类
@Service
public class TongYiServiceImpl implements TongYiService{
private static final String INFO_PREFIX = "please implement ";
private static final String INFO_SUFFIX = "() method.";
@Override
public String completion(String message) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName());
}
}
编写控制层
@RestController
@RequestMapping("/ai")
@CrossOrigin
public class TongYiController {
/**
* 聊天对话应用 单轮对话
* @param message
* @return
*/
@GetMapping("/example")
public String completion(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message,HttpServletRequest request,HttpServletResponse response) {
String completion = tongYiSimpleService.completion(message);
return completion;
}
}
测试
可以在地址栏输入地址进行访问http://localhost:8081/ai/example?message=讲一个笑话
![ab01dfdfa1257dbf85a4c260a6d5a775.jpeg](https://img-blog.csdnimg.cn/img_convert/ab01dfdfa1257dbf85a4c260a6d5a775.jpeg)
以上就是Spring Cloud Alibaba AI
入门案例
可以整合Vue输入
<div id="app" >
<template>
<div >
<h1 >单轮输出</h1>
<el-form :inline="true">
<el-form-item label="问题">
<el-input v-model="singletext" placeholder="请输入问题"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="SingleAnswer">提问</el-button>
</el-form-item>
</el-form>
{{singleresponse}}
</div>
</template>
</div>
<script>
new Vue({
el: "#app",
data: {
singletext:'',//单轮输入值
singleresponse:'',//单轮输出结果
},
methods: {
//单轮对话
SingleAnswer: function() {
var vm = this;
axios.get("http://localhost:8081/ai/example?message="+this.singletext).then(function(response) {
vm.singleresponse = response.data;
}).catch(function(error) {
console.log(error);
});
}
}
});
</script>
![b6c32bcbb993ff6e63007a49c769c851.jpeg](https://img-blog.csdnimg.cn/img_convert/b6c32bcbb993ff6e63007a49c769c851.jpeg)
多轮对话
编写业务层接口
/**
* 多轮对话
* @param message 用户问题.
* @return AI 答案.
*/
String multiCompletion(String message);
编写业务层抽象类
@Override
public String multiCompletion(String message) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName());
}
编写业务层实现类
@Override
public String multiCompletion(String message) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName());
}
编写控制层
/**
* 多轮聊天应用
*
* @param message
* @return
*/
@GetMapping("/multi")
public String multi(@RequestParam String message) {
String completion = tongYiMultiServiceImpl.multiCompletion(message);
return completion;
}
编写前端
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="js/marked.min.js"></script>
<title>SCA AI Example Front</title>
<style>
body {
background-color: #f8f9fa;
font-family: Arial, sans-serif;
}
.container {
margin: 50px auto;
width: 800px;
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
h1 {
color: #2ecc71;
text-align: center;
margin-bottom: 30px;
}
label {
display: block;
margin-bottom: 10px;
color: #333;
}
input[type="text"] {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 3px;
}
input[type="submit"] {
background-color: #2ecc71;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 3px;
cursor: pointer;
width: 100%;
}
.chat-box {
width: 100%;
height: 500px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 3px;
overflow-y: scroll;
}
.message {
margin-bottom: 10px;
padding: 10px;
background-color: #f1f1f1;
border-radius: 3px;
}
.user-message {
background-color: #2ecc71;
color: #fff;
}
.bot-message {
background-color: #3498db;
color: #fff;
}
.loader {
text-align: center;
}
.loader::after {
content: "";
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #ccc;
border-top-color: #2ecc71;
animation: spin 1s infinite linear;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="container">
<h1>Spring Cloud Alibaba AI</h1>
<form id="form">
<label for="message">输入信息:</label>
<input type="text" id="message" name="message" placeholder="输入信息!">
<br>
<br>
<input type="submit" value="提问">
</form>
<br>
<div id="loader" class="loader" style="display: none;"></div>
<div id="chat-box" class="chat-box"></div>
</div>
<script>
var loader = document.getElementById("loader");
document.getElementById("form").addEventListener("submit", function(event) {
event.preventDefault();
var messageInput = document.getElementById("message");
var message = messageInput.value;
messageInput.value = "";
var chatBox = document.getElementById("chat-box");
var userMessage = document.createElement("div");
userMessage.className = "message user-message";
userMessage.textContent = "用户: " + message;
chatBox.appendChild(userMessage);
chatBox.scrollTop = chatBox.scrollHeight;
loader.style.display = "block";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:8081/ai/example?message=" + encodeURIComponent(message), true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
loader.style.display = "none";
if (xhr.status === 200) {
var response = xhr.responseText;
var botMessage = document.createElement("div");
botMessage.className = "message bot-message";
var botMessageText = document.createElement("span");
botMessageText.className = "message-text";
botMessage.appendChild(botMessageText);
botMessageText.innerHTML = marked.marked(response);
chatBox.appendChild(botMessage);
chatBox.scrollTop = chatBox.scrollHeight;
} else if (xhr.status === 400) {
var error = JSON.parse(xhr.responseText);
var errorMessage = document.createElement("div");
errorMessage.className = "message bot-message";
errorMessage.textContent = "Bot: " + error.message;
chatBox.appendChild(errorMessage);
chatBox.scrollTop = chatBox.scrollHeight;
} else {
var errorMessage = document.createElement("div");
errorMessage.className = "message bot-message";
errorMessage.textContent = "Bot: Failed to connect to the backend service. Please make sure the backend service is running.";
chatBox.appendChild(errorMessage);
chatBox.scrollTop = chatBox.scrollHeight;
}
}
};
xhr.onloadstart = function() {
loader.style.display = "block";
};
xhr.onloadend = function() {
loader.style.display = "none";
};
xhr.send();
});
</script>
</body>
</html>
测试
输入一个问题,回答后接着第一个问题继续提问
![41356f278732ce79d60f1aea2403fbf0.jpeg](https://img-blog.csdnimg.cn/img_convert/41356f278732ce79d60f1aea2403fbf0.jpeg)
文生图
输入文字,最后输出图片
编写业务层接口
// 生成图片
ImageResponse genImg(String imgPrompt);
编写业务层抽象类
@Override
public ImageResponse genImg(String imgPrompt) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
编写业务层实现类
@Override
public ImageResponse genImg(String imgPrompt) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
编写控制层
/**
* 文生图应用
* @param imgPrompt
* @return
*/
@GetMapping("/img")
public String genImg(@RequestParam(value = "prompt", defaultValue = "Painting a picture of blue water and blue sky.") String imgPrompt) {
ImageResponse imageResponse = tongYiImgService.genImg(imgPrompt);
String url = imageResponse.getResult().getOutput().getUrl();
return url;
}
编写前端
<div id="app" >
<template>
<!--生成图片-->
<div >
<h1 >生成图片</h1>
<el-form :inline="true">
<el-form-item label="问题">
<el-input v-model="imgtext" placeholder="请输入问题"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="fetchAnswer">提问</el-button>
</el-form-item>
</el-form>
<div v-if="imgresponse!=''">
<img :src="imgresponse" alt="生成的图片" width="300px" height="300px">
</div>
</div>
</template>
</div>
<script>
new Vue({
el: "#app",
data: {
imgtext: '',//图片输入问题
imgresponse: '',//图片返回结果
},
methods: {
//生成图片
fetchAnswer: function() {
var vm = this;
axios.get("http://localhost:8081/ai/img?prompt="+ this.imgtext).then(function(response) {
vm.imgresponse = response.data;
}).catch(function(error) {
console.log(error);
});
},
}
});
</script>
测试
![79f0838f77e053a6d5cf8ab1cce321b6.jpeg](https://img-blog.csdnimg.cn/img_convert/79f0838f77e053a6d5cf8ab1cce321b6.jpeg)
文生语音
输入文字,转换成语音,且用语音回答答案
编写业务层接口
// 生成音频
String genAudio(String text);
编写业务层抽象类
@Override
public String genAudio(String text) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
编写业务层实现类
@Override
public String genAudio(String text) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
编写控制层
/**
* 文字问题输入语音文字输出
* @param message
* @param request
* @param response
* @return
*/
@GetMapping("/audio/speech")
public void genAudio(@RequestParam(value = "prompt") String prompt, HttpServletRequest request, HttpServletResponse response) {
String audio = tongYiAudioService.genAudio(prompt);
try {
FileInputStream is = new FileInputStream(audio);
int i = is.available(); // 得到文件大小
byte data[] = new byte[i];
is.read(data); // 读数据
is.close();
response.setContentType("audio/wav"); // 设置返回的文件类型
OutputStream toClient = response.getOutputStream(); // 得到向客户端输出二进制数据的对象
toClient.write(data); // 输出数据
toClient.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 文字输入语音输出答案
* @param message
* @param request
* @param response
* @return
*/
@GetMapping("/exampleToMp3")
public void exampleToMp3(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message,HttpServletRequest request,HttpServletResponse response) {
String completion = tongYiSimpleService.completion(message);
String audio = tongYiAudioService.genAudio(completion);
try {
FileInputStream is = new FileInputStream(audio);
int i = is.available(); // 得到文件大小
byte data[] = new byte[i];
is.read(data); // 读数据
is.close();
response.setContentType("audio/wav"); // 设置返回的文件类型
OutputStream toClient = response.getOutputStream(); // 得到向客户端输出二进制数据的对象
toClient.write(data); // 输出数据
toClient.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
编写前端
<div id="app" >
<template>
<!--文字转语音-->
<div >
<h1 >文字转语音</h1>
<el-form :inline="true">
<el-form-item label="问题">
<el-input v-model="mp3text" placeholder="请输入问题"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="Mp3Answer">提问</el-button>
</el-form-item>
</el-form>
<div v-if="mp3response!=''">
<audio :src="mp3response" controls id="audio_demo" ></audio>
</div>
<div v-if="mp3text2response!=''">
<audio :src="mp3text2response" controls id="audio_demo1" ></audio>
</div>
</div>
</template>
</div>
<script>
new Vue({
el: "#app",
data: {
mp3text:'',//语音输入问题
mp3response:'',//语音返回结果
mp3text2response:''//文字输入语音输出结果
},
methods: {
//文字转语音
Mp3Answer: function() {
var vm = this;
axios({
url:'http://localhost:8081/ai/audio/speech?prompt='+this.mp3text,
responseType:'blob'
}).then(result=>{
vm.mp3response = window.URL.createObjectURL(result.data);
})
//文字输出结果
axios({
url:'http://localhost:8081/ai/exampleToMp3?message='+this.mp3text,
responseType:'blob'
}).then(result=>{
vm.mp3text2response = window.URL.createObjectURL(result.data);
})
}
}
});
</script>
测试
![972570497b563edae527f332e4f00eb8.jpeg](https://img-blog.csdnimg.cn/img_convert/972570497b563edae527f332e4f00eb8.jpeg)
以上就是一些基本案例。
来源:https://blog.csdn.net/qq_34742146