ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring AI Alibaba(上)

Spring AI Alibaba(上) 目录1. 介绍 Spring AI Alibaba2. 多模态3. 文生图同步调用4. 语音合成实时合成4.1 语音合成的概念4.2 实战单向流式调用5. 语音识别5.1 语音识别概念5.2 实战非流式调用5.3 实战 双向流式调用基于回调 (识别传入麦克风的声音) 6. 视频生成与编辑6.1 视频生成与编辑 概念6.2 万相3.0 系列 相关6.3 文生视频同步/异步6.4 图生视频6.4.1 基于首帧生成6.4.2 基于首尾帧生成6.5 全模态参考生视频1. 介绍 Spring AI AlibabaSpring AI Alibaba是基于Spring AI 研发用更高层级API帮助开发者简化AI应用开发。开发者通过dashscope调用阿里百炼云平台上的大模型。阿里百炼云平台是一个饭店dashscope就像店里面的厨师用户在前台点菜厨师做完菜你才能拿到。意思是dashscope是阿里百炼的引擎用户调用的模型都是它在返回给你。dashscope sdk 和 open ai一样都是独立的dashscope 不依赖、不兼容 open ai它也不只在spring boot框架中使用在什么地方都可以别的语言中也可以使用。强调一点spring-ai-alibaba-starter-dashscope 是原生dashscope sdk的高级封装但它是已经开源了社区维护版本更新速度相对于原生sdk来说它会慢得多就导致许多官方新鲜玩意它没有。下面都用目前最新的 dashscope-sdk-java 2.22.262. 多模态多模态指的是 模型 同时理解和处理文本、图像、音频和其他数据格式信息的能力。Spring AI官方提供了Message API它提供了多模态大语言模型LLM所需的所有抽象。多模态就像人的感官。人有 听、说、看、写等感知模型包含两种及以上感官能力的就叫多模态包含全部感官的就叫”全模态“多模态示例用户可通过 文字描述 生成音频可通过文字或加上图像、视频给AI读取作为参考生成图像、视频示例很多总之就是感官之间的相互搭配。下面代码示例“给AI图片通过文字叫它告诉我图片的内容视觉理解”controller层代码巨蛇神/JavaEE进阶 - 码云 - 开源中国pom.xml代码巨蛇神/JavaEE进阶 - 码云 - 开源中国application.yml配置巨蛇神/JavaEE进阶 - 码云 - 开源中国private final ChatClient chatClient; //构造注入 public MultiModelController(ChatClient.Builder builder) { this.chatClient builder.build(); } RequestMapping(/image) public String image(String message) throws URISyntaxException, MalformedURLException { String url https://img0.baidu.com/it/u783667476,75278391fm253fmtautoapp138fJPEG?w500h889; // String url https://img.shetu66.com/2023/07/19/1689756946086335.jpg; // String urlhttps://pic.rmb.bdstatic.com/bjh/news/116367f183dd830ed1fdb3feec901d48.png; //传入图片URL来解析图片不会被 MediaType 影响图片中会包含数据格式标识模型会根据标识解析。 //但是传入base64、byte[]、本地 ResourceMediaType 就很重要的是 ListMedia medias List.of(new Media(MediaType.IMAGE_JPEG,new URI(url).toURL().toURI())); //定义用户提示词 UserMessage user UserMessage.builder() .text(message) .media(medias) .build(); //调用大模型 String content chatClient.prompt(new Prompt(user)) .call() .content(); return content; }3. 文生图同步调用阿里百炼云平台提供自研的千问(Qwen)系列和万象(Wan)系列模型可进行文生图。目前 wan2.7-image-pro 和 wan2.7-image 及 wan2.6系列无法使用spring-ai-alibaba-starter-dashscope依赖使用。spring-ai-alibaba-starter-dashscope是对原生 dashscope-sdk-java的封装此时可能模型更新太快封装速度没跟上只能通过原生 dashscope-sdk-java 使用最新的万象 ”wan2.7-image-pro“。同、异步调用官方都有示例万相-图像生成与编辑2.7 API参考 - 阿里云百炼所需依赖巨蛇神/JavaEE进阶 - 码云 - 开源中国所需配置dashscope-sdk-java 不是spring框架的产物不能在配置文件中配置api-key和模型等。下面生成的图片虽然一点也不像韩立但可以传几张图片给模型作为参考再生成温馨提醒wan2.7-image-pro 文生图代码稍微修改就能图生图。在构建参数时组图生成参数parameters.enable_sequentialbool默认为 false。仅wan2.7-image-pro和wan2.7-image支持Qwen系列不可用。开启组图模式时thinking_mode和color_palette参数不可用。更多参数细节万相-图像生成与编辑2.7 API参考 - 阿里云百炼若用spring-ai-alibaba-starter-dashscope依赖生图非常简单还可以在yml文件中直接配置模型相关参数详细可见controller层巨蛇神/JavaEE进阶 - 码云 - 开源中国配置文件巨蛇神/JavaEE进阶 - 码云 - 开源中国所需依赖dependencies dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter-dashscope/artifactId /dependency !-- 必需 -- dependency groupIdorg.springframework/groupId artifactIdspring-webflux/artifactId /dependency /dependencies !-- spring-ai-alibaba-starter-dashscope 1.0.0.2以后bom换成了spring-ai-extensions-bom -- dependencyManagement dependencies dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-bom/artifactId version1.0.0.2/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement4. 语音合成实时合成4.1 语音合成的概念语音合成指的是Text To SpeechTTS也就是文本转语音。TTS生成的音频只有一个音色也是就是只有一个人在说话。但是音频合成可以一同营造周围环境的声音比如“两个人正在说话旁边有鸟在鸣叫、大爷在唱歌”目前阿里百炼语音合成主要有三款系列模型Qwen-Audio-TTS / CosyVoice / Qwen 系列模型Qwen-Audio-TTS/CosyVoice 系列模型使用同一模型名称同时支持 WebSocket 和 HTTP 两种接入方式Qwen 系列模型通过模型名称区分带-realtime后缀的为 WebSocket 接入不带后缀的为 HTTP 接入。CosyVoice 系列模型还支持通过 AOQ 协议接入各模型系列的各个版本都有对应可使用的音色版本甚至系列之间的音色混用。目前几乎只有Qwen-Audio-TTS / CosyVoice 支持使用声音复刻和使用声音设计注使用声音复刻当已有目标人物的录音素材希望在合成中还原该音色时。使用声音设计当没有录音素材希望根据文字描述从零创建全新音色时。4.2 实战单向流式调用使用模型qwen-audio-3.1-tts-flash需添依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.alibaba/groupId artifactIddashscope-sdk-java/artifactId version2.22.26/version /dependencypackage com.jusheshen.alibaba.controller; import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult; import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; import com.alibaba.dashscope.common.ResultCallback; import java.io.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.concurrent.CountDownLatch; class TimeUtils { private static final DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss.SSS); public static String getTimestamp() { return LocalDateTime.now().format(formatter); } } public class AudioTTSController { // 模型 private static String model qwen-audio-3.0-tts-flash; // 音色 private static String voice longanhuan_v3.6; //音频存储的文件路径 public static String audioFileLoad System.getProperty(user.dir)/audio.mp3; //File private static final File file new File(audioFileLoad); public static void streamAudioDataToSpeaker() { CountDownLatch latch new CountDownLatch(1); // 实现回调接口ResultCallback ResultCallbackSpeechSynthesisResult callback new ResultCallbackSpeechSynthesisResult() { Override public void onEvent(SpeechSynthesisResult result) { if (result.getAudioFrame() ! null) { // 此处实现保存音频数据到本地的逻辑 try(OutputStream output new FileOutputStream(file,true)){//每帧都会重新打开 OutputStream 设置为true前面的帧才不会被覆盖 //获取音频字节数组并写入文件 output.write(result.getAudioFrame().array()); //刷新缓冲区数据真正写入文件 output.flush(); }catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } System.out.println(TimeUtils.getTimestamp() 收到音频); } // 获取输出信息包含事件类型和原始文本 if (result.getOutput() ! null result.getOutput().has(type)) { System.out.println(事件类型: result.getOutput().get(type).getAsString() , 原始文本: (result.getOutput().has(original_text) ? result.getOutput().get(original_text).getAsString() : )); } } Override public void onComplete() { System.out.println(TimeUtils.getTimestamp() 收到Complete语音合成结束); latch.countDown(); } Override public void onError(Exception e) { System.out.println(出现异常 e.toString()); latch.countDown(); } }; // 请求参数 SpeechSynthesisParam param SpeechSynthesisParam.builder() // 新加坡和北京地域的API Key不同。获取API Keyhttps://help.aliyun.com/zh/model-studio/get-api-key // 若没有配置环境变量请用百炼API Key将下行替换为.apiKey(sk-xxx) .apiKey(System.getenv(DASHSCOPE_API_KEY)) .model(qwen-audio-3.1-tts-flash) // 模型 .voice(loongstella_v3.1) // 音色 .build(); // 第二个参数callback传入回调即启用异步模式 SpeechSynthesizer synthesizer new SpeechSynthesizer(param, callback); // 非阻塞调用立即返回null实际结果通过回调接口异步传递在回调接口的onEvent方法中实时获取二进制音频 try { synthesizer.call(今天天气怎么样); // 等待合成完成 latch.await(); // 等待播放线程全部播放完 } catch (Exception e) { throw new RuntimeException(e); } finally { // 任务结束后关闭websocket连接 synthesizer.getDuplexApi().close(1000, bye); } // 首次发送文本时需建立 WebSocket 连接因此首包延迟会包含连接建立的耗时 System.out.println( [Metric] requestId为 synthesizer.getLastRequestId() 首包延迟毫秒为 synthesizer.getFirstPackageDelay()); } public static void main(String[] args) { // 以下为华北2北京地域的配置调用时请将{WorkspaceId}替换为真实的业务空间ID各地域的配置不同。 // Constants.baseWebsocketApiUrl wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference; streamAudioDataToSpeaker(); //关闭进程 System.exit(0); } }SpeechSynthesizer是语音合成的一个重要类想进一步了解它可到Qwen-Audio-TTS Java SDK - 阿里云百炼更多示例在alibabacloud-bailian-speech-demo/samplesGitHub上面代码的解析补充但其实也没补充些啥5. 语音识别5.1 语音识别概念语音识别指的是Speech To TextSTT也就是语音转文本与语音合成相反。模型有如下功能实时识别和非实时识别处理专业术语。多个领域可能出现相同的术语在系统提示词中描述你的领域背景模型在每次请求时自适应。说话人声分离。归类哪些人说了哪些话。一个模型可能有多个功能但也可能你想要的功能们在一个模型上没有比如“实时人声分离“目前没有一个模型同时拥有。现2026/10/1阿里云百炼官方语音识别概述 - 阿里云百炼5.2 实战非流式调用所需依赖与语音生成一样。notice不同模型在RecognitionParam param手动配置参数方面可能不完全一致例如下面的”qwen-audio-3.1-asr-flash-streaming“ 的参数需要手动写入将要识别音频的采样率。RequestMapping(/stt1) //非流式调用提交单个语音实时转写任务通过传入本地文件的方式同步阻塞地拿到转写结果。 public void stt1(){ Gson gson new Gson(); // 创建Recognition实例 Recognition recognizer new Recognition(); // 创建RecognitionParam RecognitionParam param RecognitionParam.builder() .model(qwen-audio-3.1-asr-flash-streaming) // 新加坡和北京地域的API Key不同。获取API Keyhttps://help.aliyun.com/zh/model-studio/get-api-key // 若没有配置环境变量请用百炼API Key将下行替换为.apiKey(sk-xxx) .apiKey(System.getenv(DASHSCOPE_API_KEY)) .format(mp3) .sampleRate(22050) //.parameter(language_hints, new String[]{zh}) .build(); File file new File(System.getProperty(user.dir)/audio.mp3); try { String callStr recognizer.call(param, file); //call返回 System.out.println(识别结果 callStr); JsonObject jsonObject gson.fromJson(callStr, JsonObject.class); if (jsonObject.has(sentences)) { JsonArray sentences jsonObject.get(sentences).getAsJsonArray(); //取出 sentences数组的最后一个元素并把它转成对象 JsonObject elementJson sentences.get(sentences.size()-1).getAsJsonObject(); //取出 ”text“ 键对应的值并转成字符串 String text elementJson.get(text).getAsString(); //打印 System.out.println(最终识别的完整结果展示text); } } catch (Exception e) { e.printStackTrace(); } finally { // 任务结束后关闭 WebSocket 连接 recognizer.getDuplexApi().close(1000, bye); } System.out.println( [Metric] requestId: recognizer.getLastRequestId() , first package delay ms: recognizer.getFirstPackageDelay() , last package delay ms: recognizer.getLastPackageDelay()); System.exit(0); }上述代码进一步解析5.3 实战 双向流式调用基于回调 (识别传入麦克风的声音) 以下是官方示例Qwen-Audio-ASR-Stream 系列模型的 “双向流式调用基于回调” 的识别传入麦克风的声音代码这个代码比较多代码逻辑比较复杂请看GiteeAudioTranscription.stt2()巨蛇神/JavaEE进阶 - 码云 - 开源中国utilsRealtimeRecognitionTask巨蛇神/JavaEE进阶 - 码云 - 开源中国前端巨蛇神/JavaEE进阶 - 码云 - 开源中国notice官方示例 Qwen-Audio-ASR-Streaming实时语音识别 没有实现如何返回给前端的代码我的代码中简单实现了但比较粗糙看我下面的解析后大家可以自行丰富或修改。目前粗糙项目存在的问题前端显示的文本间没有明确分隔前端/后端 处理不够好导致没有识别内容的文本也发送其实是我懒得做了......stt2()中的部分代码是官方示例的代码他给的代码可能是为了让人好理解要说资源利用这块还是开发者自己操心。6. 视频生成与编辑6.1 视频生成与编辑 概念视频生成与视频编辑是两个大类就像文生图与语音合成除此之外Wan3.0系列模型还有一个视频延长可向前、向后或前后延长视频。视频生成包含文生视频图生视频 其中图生视频分为基于首尾帧和基于首帧生成参考生视频以上都支持传入音频下面解释这三种生成的含义视频编辑就叫视频编辑没有子集视频编辑比如可以 “修改背景风格”、“添加视频元素”、“删除元素”和“修改元素”等改变视频内容的能力1. 文生视频直接通过提示词生成视频。详细文生视频 - 阿里云百炼2. 图片生成—基于首尾帧提供两张图片一张作为视频首帧另一张作为视频尾帧视频中间的内容通过提示词描述生成。详细图生视频-基于首尾帧 - 阿里云百炼3. 图片生成—基于首帧提供一张图片作为视频首帧视频的内容通过提示词描述生成。详细万相-图生视频-基于首帧 - 阿里云百炼4. 参考生视频可通过传入多张图片多个视频多个音频资源根据提示词相互作用生成也可只使用单种资源生成。相对于前几种这个组合生成方式比较多详细参考生视频 - 阿里云百炼阿里目前最新的视频生成模型支持 全模态输入 生成视频它就是万相3.0 wan3.0-video / wan3.0-video-prime使用这个模型你可以使用视频生成和编辑的全部功能nb不用来回切换模型了。注意注意要用万相3.0系列模型 需dashscope-java-sdk 版本在2.22.31或以上Wan 3.0包含更多type参数这些参数有些不能随意搭配例如first_frame/last_frame与reference_image/reference_video/reference_audio/file/link类型互斥不能在同一请求中混用。官方给出了详细的素材组合参数组合万相3.0-视频生成API参考 - 阿里云百炼需要注意一次请求 type参数的值只能file、link二选一且只能最多一个就不能多个file 或 多个link。综上type共有7种值详细参数说明可看官方 万相3.0-视频生成API参考 - 阿里云百炼官方有请求/响应包示例6.2 万相3.0 系列 相关Wan3.0系列模型都只有30秒免费额度生成失败的话不算入。要用Wan3.0系列模型 需dashscope-java-sdk 版本在2.22.31或以上。不允许生成含有真人脸的视频模型在生成视频时会检测生成的视频是否含有若含有就不会返回视频。一次只能输出一个视频。6.3 文生视频同步/异步代码老简单了巨蛇神/JavaEE进阶 - Gitee.com6.4 图生视频6.4.1 基于首帧生成基于首帧可以通过图像URL、本地文件路径、Base64编码字符串三种方式构建media生成视频。代码非常简单巨蛇神/JavaEE进阶 - 码云 - 开源中国由于first_frame与reference_audio不能共存所以要想视频出现想要的音效只能通过提示词描述这也是官方在文档中明确提到的。我的代码只展示了同步调用的代码示例但异步调用轮询等待的操作应该与上面的文生视频一模一样因为这个模型没有第二个asyncCall方法。Wan3.0系列模型不能像 Wan2.5/Wan2.7系列模型 一样通过指定视频特效生成含有该特效的视频。6.4.2 基于首尾帧生成基于首尾帧 只需在 基于首帧 生成视频的代码上额外添加几行代码notice首尾帧的两张图片资源必须要分开放到两个Media。其实不仅是图片资源要分放Media一个Media仅代表一个资源例如下面要讲的参考生视频传入的每种的每个 视频、图片和音频 资源都独享一个Media。6.5 全模态参考生视频万相3.0系列模型可参考图片/视频/音频生成视频也可参考文件或网页生成。参考文件或网页生成视频type分别为file 与 link这两个非常好用。如传入ppt URL让模型根据ppt生成视频。对于参考生视频图像的传入支持以下1,2,3视频和音频传入仅支持1,2参考文件传入也仅支持1,2可同样支持官方示例解说官方上传了公网URL临时URLBase64 编码字符串阿里官方给出的示例很详细万相3.0-视频生成 - 阿里云百炼。暂时停止......
返回列表