文章目录
- AI介绍
-
- Spring AI简介
- Spring Cloud Alibaba AI 简介
- 案例
-
- 1.开发环境
- 2.创建工程
-
- 2.1 创建父工程
-
- 2.1.1 创建项目就是正常的Maven项目
- 2.1.2 引入依赖
- 2.2 创建子工程
-
- 2.2.1 创建子工程就是正常的maven项目(选中父工程右键)
- 2.2.2 引入依赖
- 2.2.3 添加配置文件
- 3.案例
-
- 3.1 单轮对话
-
- 3.1.1 编写业务层接口
- 3.1.2 编写业务层抽象类
- 3.1.3 编写业务层实现类
- 3.1.4 编写业务层实现类
- 3.1.5 编写控制层
- 3.1.6 测试
- 3.1.7 可以整合Vue输入
- 3.2 多轮对话
-
- 3.2.1 编写业务层接口
- 3.2.2 编写业务层抽象类
- 3.2.3 编写业务层实现类
- 3.2.4 编写业务层实现类
- 3.2.5 编写控制层
- 3.2.6 编写前端
- 3.2.7 测试
- 3.3 文生图
-
- 3.3.1 编写业务层接口
- 3.3.2 编写业务层抽象类
- 3.3.3 编写业务层实现类
- 3.3.4 编写业务层实现类
- 3.3.5 编写控制层
- 3.3.6 编写前端
- 3.3.7 测试
- 3.4 文生语音
-
- 3.4.1 编写业务层接口
- 3.4.2 编写业务层抽象类
- 3.4.3 编写业务层实现类
- 3.4.4 编写业务层实现类
- 3.4.5 编写控制层
- 3.4.6 编写前端
- 3.4.7 测试
AI介绍
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提供包括模型推理、模型微调训练在内的多种模型服务。目前支持的模型主要有:对话、文生图、文生语音,更多功能特性正在适配中。那以上介绍完之后咱们就完成一些案例来看看效果吧
案例
1.开发环境
这里说下我本地的环境,阿里要求JDK为17+
JDK17,Maven3.5以上,Spring Boot2.0+,Spring Cloud2021+
2.创建工程
2.1 创建父工程
2.1.1 创建项目就是正常的Maven项目
2.1.2 引入依赖
?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>
2.2 创建子工程
2.2.1 创建子工程就是正常的maven项目(选中父工程右键)
2.2.2 引入依赖
?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>
2.2.3 添加配置文件
主要配置阿里云申请的api-key
阿里云Api-Key申请
spring:
cloud:
ai:
tongyi:
api-key: your api-key #自己在阿里云官网申请的api-key
server:
port: 8081
3.案例
以下所有案例均在一个项目中编写,小伙伴们不要整懵了哈
3.1 单轮对话
3.1.1 编写业务层接口
public interface TongYiService {
//聊天对话
String completion(String message);
3.1.2 编写业务层抽象类
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());
}
3.1.3 编写业务层实现类
@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());
}
3.1.4 编写业务层实现类
@Override
public String completion(String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return chatClient.call(prompt).getResult().getOutput().getContent();
}
3.1.5 编写控制层
@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;
}
}
3.1.6 测试
可以在地址栏输入地址进行访问
http://localhost:8081/ai/example?message=讲一个笑话
以上就是Spring Cloud Alibaba AI入门案例
3.1.7 可以整合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>
3.2 多轮对话
3.2.1 编写业务层接口
/**
* 多轮对话
* @param message 用户问题.
* @return AI 答案.
*/
String multiCompletion(String message);
3.2.2 编写业务层抽象类
@Override
public String multiCompletion(String message) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName());
}
3.2.3 编写业务层实现类
@Override
public String multiCompletion(String message) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread().getStackTrace()[2].getMethodName());
}
3.2.4 编写业务层实现类
@Override
public String multiCompletion(String message) {
//判断当前线程的消息列表是否为空
if (multiMessage.get() == null) {
//初始化当前线程的消息列表
multiMessage.set(new ArrayList>());
}
//获取当前线程的消息列表
ListMessage> userMessages = multiMessage.get();
//将用户输入的消息添加到消息列表中
multiMessage.get().add(new UserMessage(message));
//创建Prompt对象,并把整个消息列表作为参数
Prompt prompt = new Prompt(userMessages);
return chatClient.call(prompt).getResult().getOutput().getContent();
}
3.2.5 编写控制层
/**
* 多轮聊天应用
*
* @param message
* @return
*/
@GetMapping("/multi")
public String multi(@RequestParam String message) {
String completion = tongYiMultiServiceImpl.multiCompletion(message);
return completion;
}
3.2.6 编写前端
DOCTYPE html>
html>
head>
meta charset="UTF-8">
script src="js/marked.min.js">script>
title>SCA AI Example Fronttitle>
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 AIh1>
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>
3.2.7 测试
输入一个问题,回答后接着第一个问题继续提问
3.3 文生图
输入文字,最后输出图片
3.3.1 编写业务层接口
// 生成图片
ImageResponse genImg(String imgPrompt);
3.3.2 编写业务层抽象类
@Override
public ImageResponse genImg(String imgPrompt) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
3.3.3 编写业务层实现类
@Override
public ImageResponse genImg(String imgPrompt) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
3.3.4 编写业务层实现类
@Override
public ImageResponse genImg(String imgPrompt) {
var prompt = new ImagePrompt(imgPrompt);
return imageClient.call(prompt);
}
3.3.5 编写控制层
/**
* 文生图应用
* @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;
}
3.3.6 编写前端
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>
3.3.7 测试
3.4 文生语音
输入文字,转换成语音,且用语音回答答案
3.4.1 编写业务层接口
// 生成音频
String genAudio(String text);
3.4.2 编写业务层抽象类
@Override
public String genAudio(String text) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
3.4.3 编写业务层实现类
@Override
public String genAudio(String text) {
throw new RuntimeException(INFO_PREFIX + Thread.currentThread()
.getStackTrace()[2].getMethodName() + INFO_SUFFIX);
}
3.4.4 编写业务层实现类
@Override
public String genAudio(String text) {
logger.info("gen audio prompt is: {}", text);
var resWAV = speechClient.call(text);
return save(resWAV, SpeechSynthesisAudioFormat.WAV.getValue());
}
//生成的语音存入当前项目中
private String save(ByteBuffer audio, String type) {
String currentPath = System.getProperty("user.dir");
currentPath = currentPath+"\aliai\src\main\resources\static\audio";
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd-HH-mm-ss");
String fileName = currentPath + File.separator + now.format(formatter) + "." + type;
File file = new File(fileName);
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(audio.array());
}
catch (Exception e) {
throw new RuntimeException(e);
}
return fileName;
}
3.4.5 编写控制层
/**
* 文字问题输入语音文字输出
* @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);
}
}
3.4.6 编写前端
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>
3.4.7 测试
以上就是一些基本案例,后期陆续更新!!!