文章目录
什么是 Spring Cloud Alibaba AI
原始的Spring AI并没有国内相关大模型的接入,对国内开发者不太友好。
总的来说,Spring Cloud Alibaba AI 目前基于Spring AI 0.8.1版本 API 完成通义系列大模型的接入。
在当前最新版本中,Spring Cloud Alibaba AI 主要完成了几种常见生成式模型的适配,包括对话、文生图、文生语音等,开发者可以使用 Spring Cloud Alibaba AI 开发基于通义的聊天、图片或语音生成 AI 应用,框架还提供 OutParser、Prompt Template、Stuff 等实用能力。
动手体验 Spring Cloud Alibaba AI
使用Ai的jdk最低版本17,使用老版本的需要重新下载jdk。
https://www.oracle.com/cn/java/technologies/downloads/#java17
jdk17的Windows版本链接已提供,只需要下载解压即可以使用。
1.创建maven项目 导入以下依赖
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-ai</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
因为 Spring AI 还没有正式发布到 maven 仓库,所以需要添加仓库配置项
<!-- 因为 Spring AI 还没有正式发布到 maven 仓库,所以需要添加此配置项 目前 maven 仓库为假的。
issue:https://github.com/spring-projects/spring-ai/issues/537
-->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
2.在Resource包中创建application.yml文件,并配置api-key
在正式开始体验之前,需要申请到模型的 api-key。申请地址:https://help.aliyun.com/zh/dashscope/developer-reference/activate-dashscope-and-create-an-api-key
申请完只有30天的免费试用。
spring:
cloud:
ai:
tongyi:
# api-key setting:
api-key: sk-xxxxxxxxxxxxxxxxxxx
3.创建Controller和service开始使用
聊天对话、图片生成、语音生成体验
Controller代码
@RestController
@CrossOrigin
@RequestMapping("/ai")
public class TongYiController {
@Resource
private TongYiService tongYiService;
/**
* 聊天对话体验
* @param msg
* @return
*/
@GetMapping("/getMsg")
public String getMessage(@RequestParam(value = "msg",defaultValue = "讲一个笑话") String msg){
return tongYiService.completion(msg);
}
/**
* 体验生成图片
* @param msg
* @return
*/
@GetMapping("/getImage")
public ResponseEntity<byte[]> getImage(@RequestParam(value = "msg",defaultValue = "动漫女主图片") String msg){
ResponseEntity<byte[]> responseEntity = tongYiService.genImg(msg);
return responseEntity;
}
/**
* 流式客户端形式
* @param message
* @return
*/
@GetMapping("/stream")
public Map<String, String> streamCompletion(
@RequestParam(value = "message", defaultValue = "请告诉我西红柿炖牛腩怎么做?") String message) {
return tongYiService.streamCompletion(message);
}
/**
* 生成语音
* @param prompt
* @return
*/
@GetMapping("/audio")
public String genAudio(@RequestParam(value = "prompt",
defaultValue = "你好,Spring Cloud Alibaba AI 框架!") String prompt) {
return tongYiService.genAudio(prompt);
}
}
service代码
public interface TongYiService {
/**
* 基本问答
*/
String completion(String message);
/**
* 文生图
*/
ResponseEntity<byte[]> genImg(String imgPrompt);
/**
* 语音合成
*/
String genAudio(String text);
/**
* 流式回答
* @param message
* @return
*/
Map<String, String> streamCompletion(String message);
}
service实现类代码(只能使用的构造器注入)推荐使用client封装一个工具类,而不是写在service里面。
@Service
public class TongYiSimpleServiceImpl implements TongYiService {
/**
* 自动注入ChatClient、imageClient、StreamingChatClient,屏蔽模型调用细节
*/
private final ChatClient chatClient;
private final ImageClient imageClient;
private final StreamingChatClient streamingChatClient;
@Autowired
public TongYiSimpleServiceImpl(ChatClient chatClient, StreamingChatClient streamingChatClient,ImageClient imageClient) {
this.chatClient = chatClient;
this.imageClient = imageClient;
this.streamingChatClient = streamingChatClient;
}
/**
* 具体实现:
*/
@Override
public String completion(String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return chatClient.call(prompt).getResult().getOutput().getContent();
}
@Override
public ResponseEntity<byte[]> genImg(String imgPrompt) {
ImagePrompt imagePrompt = new ImagePrompt(imgPrompt);
ImageResponse response = imageClient.call(imagePrompt);
//处理生成的图片base64码
String b64Json = response.getResult().getOutput().getB64Json();
//将b64转换成图片返回给前端
byte[] decode = Base64.getDecoder().decode(b64Json);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(decode,httpHeaders, HttpStatus.OK);
}
@Override
public Map<String, String> streamCompletion(String message) {
StringBuilder fullContent = new StringBuilder();
streamingChatClient.stream(new Prompt(message))
.flatMap(chatResponse -> Flux.fromIterable(chatResponse.getResults()))
.map(content -> content.getOutput().getContent())
.doOnNext(fullContent::append)
.last()
.map(lastContent -> Map.of(message, fullContent.toString()))
.block();
return Map.of(message, fullContent.toString());
}
@Override
public String genAudio(String text) {
var resWAV = speechClient.call(text);
return save(resWAV, SpeechSynthesisAudioFormat.WAV.getValue());
}
/**
* 将语音保存到本地的方法
*
* @param audio
* @param type
* @return
*/
private String save(ByteBuffer audio, String type) {
String currentPath = System.getProperty("user.dir");
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;
}
}
启动项目,浏览器输入地址测试
1.localhost:8080/ai/getMsg聊天对话测试
localhost:8080/ai/stream采用流式客户端方式测试(对话形式)
2.getImage (1024×1024)生成图片测试
- localhost:8080/ai/audio生成语音测试,返回路径(默认项目路径)
封装工具类
有了之前的实现,我们封装工具类就很方便
@Component
public class CloudAiUtil {
private final ChatClient chatClient;
//图片客户端
private final ImageClient imageClient;
//语言客户端
private final SpeechClient speechClient;
// stream 流式客户端
private final StreamingChatClient streamingChatClient;
@Autowired
public CloudAiUtil(ChatClient chatClient, StreamingChatClient streamingChatClient, ImageClient imageClient, SpeechClient speechClient) {
this.chatClient = chatClient;
this.imageClient = imageClient;
this.streamingChatClient = streamingChatClient;
this.speechClient = speechClient;
}
public String completion(String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return chatClient.call(prompt).getResult().getOutput().getContent();
}
public ResponseEntity<byte[]> genImg(String imgPrompt) {
ImagePrompt imagePrompt = new ImagePrompt(imgPrompt);
ImageResponse response = imageClient.call(imagePrompt);
//处理生成的图片base64码
String b64Json = response.getResult().getOutput().getB64Json();
//将b64转换成图片返回给前端
byte[] decode = Base64.getDecoder().decode(b64Json);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(decode, httpHeaders, HttpStatus.OK);
}
public Map<String, String> streamCompletion(String message) {
StringBuilder fullContent = new StringBuilder();
streamingChatClient.stream(new Prompt(message))
.flatMap(chatResponse -> Flux.fromIterable(chatResponse.getResults()))
.map(content -> content.getOutput().getContent())
.doOnNext(fullContent::append)
.last()
.map(lastContent -> Map.of(message, fullContent.toString()))
.block();
return Map.of(message, fullContent.toString());
}
public String genAudio(String 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");
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;
}
}
这样我们service代码就很简介,同时这个工具类可以在任意service使用
@Service
public class TongYiSimpleServiceImpl implements TongYiService {
@Resource
private CloudAiUtil cloudAiUtil;
@Override
public String completion(String message) {
return cloudAiUtil.completion(message);
}
}