SpringCloudAliaba生成式JavaAI应用开发文生问答音像

news/2024/9/17 19:04:48/ 标签: spring boot, gradle, Spring Cloud AI, Ali LLM, VUE, intellij-idea

采用SpringCloudAliabaAI型式大模型LLM,进行生成式JavaAI应用开发,实现文生问答、图像和语音合成,Web应用页面交互展现。SpringBootGradle软件框架,Idea集成开发环境,API_Post嵌入插件一体测试。

1 工效展示[文生-答/图/音]

2 软件体系架构[SpringBootGradle]

3 Idea开发环境项目导入

4 SpringBootAlibabaAI依赖添加

5 application.yml调度配置

6 AI服务支撑

6.1 AI答/图/音服务接口编码

6.2 AI答/图/音服务实现编码

关键的LLM运用编码如下:

@Override

public String completion(String message) {

    Prompt prompt = new Prompt(new UserMessage(message));

    return chatClient.call(prompt).getResult().getOutput().getContent();

}

@Override

public ImageResponse genImg(String imgPrompt) {

    var prompt = new ImagePrompt(imgPrompt);

    return imageClient.call(prompt);

}

@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());

}

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;

}

6.3 Saas服务/Web展现编码

核心的文生问答/音像部分的SaaS支撑编码如下:

private final TongYiService tongYiService;

public TongYiController(TongYiService tongYiService) {

    this.tongYiService = tongYiService;

}

@GetMapping("/chat")

public String completion(@RequestParam(value = "message",  defaultValue = "Tell me a joke") String message) {

    return tongYiService.completion(message);

}

@GetMapping("/stream")

public Map<String, String> streamCompletion(@RequestParam(

    value = "message", defaultValue = "请告诉我西红柿炖牛腩怎么做?")  String message) {

    return tongYiService.streamCompletion(message);

}

@GetMapping("/genImg")

public ImageResponse genImg(@RequestParam(value = "prompt",

    defaultValue = "Painting a picture of blue water and blue sky.")  String imgPrompt) {

    return tongYiService.genImg(imgPrompt);

}

@GetMapping("/getImgUrl")

public String getImgUrl(@RequestParam(value = "prompt",

    defaultValue = "Painting a picture of blue water and blue sky.")  String imgPrompt) {

    ImageResponse imageResponse = tongYiService.genImg(imgPrompt);

    return imageResponse.getResult().getOutput().getUrl();

}

@GetMapping("/getImgEtt")

public ResponseEntity<byte[]> getImgEtt(@RequestParam(value = "msg",

    defaultValue = "动漫女主图片") String imgPrompt){

    ImageResponse imageResponse = tongYiService.genImg(imgPrompt);

    String b64Json = imageResponse.getResult().getOutput().getB64Json();

    byte[] decode = Base64.getDecoder().decode(b64Json);

    HttpHeaders httpHeaders = new HttpHeaders();

    httpHeaders.setContentType(MediaType.IMAGE_PNG);

    return new ResponseEntity<>(decode,httpHeaders, HttpStatus.OK);

}

@GetMapping("/genAudio")

public String genAudio(@RequestParam(value = "prompt",

    defaultValue = "你好,Spring Cloud Alibaba AI 框架!") String prompt) {

    return tongYiService.genAudio(prompt);

}

@GetMapping("/speech")

public void speech(@RequestParam(value = "prompt",  defaultValue = "Tell me a joke") String prompt,

    HttpServletResponse response) throws IOException {

    String audio = tongYiService.genAudio(prompt);

    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();

}

//文字输入语音输出答案

@GetMapping("/cvtMp3")

public void cvtMp3(@RequestParam(value = "message",  defaultValue = "Tell me a joke") String message,

    HttpServletResponse response) throws IOException {

    String completion = tongYiService.completion(message);

    String audio = tongYiService.genAudio(completion);

    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();

}

7 服务功能测调试

逐一测试,核心的文生问答/音像部分的控制器SaaS支撑服务调用函数,下面列出不同方式的典型截图。

7.1 API_Post

Idea插件API_Post,针对getImg的测试截图,如下:

完全的API_Post环境,针对getImg的测试截图,如下:

7.2 浏览器端

8 Web交互应用实现

8.1 文生问答

单轮、多轮或流式文生问答展现,以多轮文生问答为例,相关编码如下:

<!DOCTYPE html>

<html lang="zh">

  <head>

    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

    <meta name="viewport" content="user-scalable=no, initial-scale=1,

      maximum-scale=1, minimum-scale=1, width=device-width">

    <title>文生问答</title>

    <script src="js/marked.min.js"></script>

    <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 }

      .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>

  </body>

  <script>

    let loader = document.getElementById("loader")

    document.getElementById("form").addEventListener("submit", function(event) {

      event.preventDefault()

      let messageInput = document.getElementById("message")

      let message = messageInput.value; messageInput.value = ""

      let chatBox = document.getElementById("chat-box")

      let userMessage = document.createElement("div")

      userMessage.className = "message user-message"

      userMessage.textContent = "用户: " + message

      chatBox.appendChild(userMessage)

      chatBox.scrollTop = chatBox.scrollHeight

      loader.style.display = "block"

      let xhr = new XMLHttpRequest()

      xhr.open("GET", "http://localhost:9320/chat?message=" + encodeURIComponent(message), true)

      xhr.onreadystatechange = function() {

        if (xhr.readyState === 4) {

          loader.style.display = "none"

          if (xhr.status === 200) {

            let response = xhr.responseText, botMessage = document.createElement("div")

            botMessage.className = "message bot-message"

            let 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) {

            let error = JSON.parse(xhr.responseText)

            let errorMessage = document.createElement("div")

            errorMessage.className = "message bot-message"

            errorMessage.textContent = "Bot: " + error.message

            chatBox.appendChild(errorMessage); chatBox.scrollTop = chatBox.scrollHeight

          } else {

            let 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>

</html>

8.2 文生图

<!DOCTYPE html>

<html lang="zh">

  <head>

    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

    <meta name="viewport" content="user-scalable=no, initial-scale=1,

      maximum-scale=1, minimum-scale=1, width=device-width">

    <title>文生图片</title>

    <link rel="stylesheet" href="./css/element-ui.2.15.14.css">

    <script type="text/javascript" src="./js/vue.min.js"></script>

    <script type="text/javascript" src="./js/axios.min.js"></script>

    <script type="text/javascript" src="./js/element-ui.2.15.14.js"></script>

  </head>

  <body style="background: #F0FFFF;">

   <div id="app" >

    <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>

    </div>  

  </body>

  <script>

   new Vue({

    el: "#app", data: { imgtext: '', imgresponse: '' },

    methods: {

      fetchAnswer: function() {          //生成图片

        let vm = this;

        axios.get("http://localhost:9320/getImgUrl?prompt="+ this.imgtext).then(function(response) {

          vm.imgresponse = response.data

        }).catch(function(error) {

          console.log(error);

        })

      },

    }

   })

  </script>

</html>

8.3 文生语音合成

<!DOCTYPE html>

<html lang="zh">

  <head>

    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

    <meta name="viewport" content="user-scalable=no, initial-scale=1,

      maximum-scale=1, minimum-scale=1, width=device-width">

    <title>文生语音</title>

    <link rel="stylesheet" href="./css/element-ui.2.15.14.css">

    <script type="text/javascript" src="./js/vue.min.js"></script>

    <script type="text/javascript" src="./js/axios.min.js"></script>

    <script type="text/javascript" src="./js/element-ui.2.15.14.js"></script>

  </head>

  <body style="background: #F0FFFF;">

   <div id="app" >

    <!--文字转语音-->

    <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>

   </div>   

  </body>

  <script>

   new Vue({

    el: "#app", data: { mp3text:'', mp3response:'', mp3text2response:'' },

    methods: {

      Mp3Answer: function() {         //文字转语音

        let vm = this

        axios({

          url:'http://localhost:9320/speech?prompt='+this.mp3text, responseType:'blob'

        }).then(result=>{

          vm.mp3response = window.URL.createObjectURL(result.data)

        })               

        axios({                       //文字输出结果

          url:'http://localhost:9320/cvtMp3?message='+this.mp3text, responseType:'blob'

        }).then(result=>{

          vm.mp3text2response = window.URL.createObjectURL(result.data)

        })

      }

    }

   })

  </script>

</html>

9 浏览器运行交互测试

9.1 文生问答

9.2 文生图

9.3 文生语音合成

参考

快速开发生成式JavaAI应用--https://sca.aliyun.com/?spm=0.29160081.0.0.282a291fH6ibeR

SpringAI使用通义千问的具体步骤和方法--https://sca.aliyun.com/blog/faq/sca-user-question-history15328/

阿里出击SpringCloudAlibabaAI初体验,https://blog.csdn.net/m0_63171455/article/details/140976640,2024.8.7

10分钟接入AI大模型SpringCloudAlibaba,https://blog.csdn.net/qq_17153885/article/details/140835601,2024.8.1

让你快速入门SpringCloudAlibabaAI,https://blog.csdn.net/qq_34742146/article/details/140503128,2024.7.29

阿里也出手了SpringCloudAlibabaAI问世,https://blog.csdn.net/rong09_13/article/details/139723097,2024.6.26

AI框架之SpringAI与SpringCloudAlibabaAI使用讲解,https://blog.csdn.net/u012060033/article/details/139461527,2024.6.6

spring-cloud-starter-alibaba-ai无法引入如何处理--https://sca.aliyun.com/blog/faq/sca-user-question-history15816/


http://www.ppmy.cn/news/1523008.html

相关文章

使用 Docker 部署和运行 RabbitMQ

使用 Docker 部署和运行 RabbitMQ 在本篇博客中&#xff0c;我将介绍如何通过 Docker 来运行 RabbitMQ 并使用其管理界面。还会讨论我在操作过程中遇到的常见问题及其解决方案。RabbitMQ 是一个开源的消息代理&#xff0c;用于跨应用程序发送、接收消息。在容器化环境中运行 R…

中秋之美——html5+css+js制作中秋网页

中秋之美——html5cssjs制作中秋网页 一、前言二、功能展示三、系统实现四、其它五、源码下载 一、前言 八月十五&#xff0c;秋已过半&#xff0c;是为中秋。 “但愿人长久&#xff0c;千里共婵娟”&#xff0c;中秋时节&#xff0c;气温已凉未寒&#xff0c;天高气爽&#x…

大数据之Flink(三)

9.3、转换算子 9.3.1、基本转换算子 9.3.1.1、映射map 一一映射 package transform;import bean.WaterSensor; import org.apache.flink.streaming.api.datastream.DataStreamSource; import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; impor…

Rust 操作符及示例

Rust 操作符 Rust 提供了一系列操作符&#xff08;operators&#xff09;&#xff0c;每种操作符都有特定的功能和应用场景。 1. 算术操作符 这些操作符用于基本的数学运算&#xff1a; : 加法&#xff0c;用于两个数相加。 示例: let sum 5 10; - : 减法&#xff0c;用于…

SprinBoot+Vue旅游网站的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

FFmpeg打印基本音视频信息

1. 编写可执行文件 vim mediainfo_new.c#include<stdio.h> #include<libavutil/log.h> #include <libavformat/avformat.h>int main(int argc, char *argv[]) {int err_code;AVFormatContext *fmt_ctx NULL;av_log_set_level(AV_LOG_DEBUG);if(argc < …

51单片机的无线病床呼叫系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温湿度传感器模块矩阵按键时钟模块等模块构成。适用于病床呼叫系统、16床位呼叫等相似项目。 可实现基本功能: 1、LCD1602实时显示北京时间、温湿度信息、呼叫床位等信息&#xff1b; 2、DHT11采集病房温湿度信息&…

Linux echo命令讲解及与重定向符搭配使用方法,tail命令及日志监听方式详解

echo echo具有回声&#xff0c;回响的意思&#xff0c;在linux系统中echo一般可以输出指定字符或用于命令执行 echo命令的用法为 echo 输出字符串 或 echo 命令 若参数为字符串则进行字符串输出&#xff0c;注意若字符串中含空格最好将其用引号括起&#xff0c;防止echo命…

揭秘尖端PCB制造:猎板PCB精工细作铸就电子创新之基

随着科技的不断进步&#xff0c;电子设备正变得越来越小巧、功能越来越强大&#xff0c;这背后离不开精密印刷电路板&#xff08;PCB&#xff09;的制造技术。PCB&#xff0c;作为电子组件的载体&#xff0c;其制造工艺的精细程度直接决定了电子产品的性能和可靠性。本文将带您…

如何做好网络安全

随着互联网技术的飞速发展&#xff0c;网站已成为企业对外展示、交流和服务的重要窗口。然而&#xff0c;随之而来的网站安全问题也日益凸显&#xff0c;给企业的业务发展和用户数据安全带来了巨大威胁。因此&#xff0c;高度重视网站安全已成为网络安全的首要任务。今天我们就…

uni-app开发微信小程序时 - 地理位置接口流程调整

在开发微信小程序时&#xff0c;控制台报“chooseLocation:fail the api need to be declared in the requiredPrivateInfos field in app.json/ext.json”错误&#xff0c;意思要使用chooseLocation前需要在requiredprivateinfo中先声明。 一、声明接口 由于小程序地理位置很…

结构型设计模式—组合模式

结构型设计模式—组合模式 欢迎长按图片加好友&#xff0c;我会第一时间和你分享持续更多的开发知识&#xff0c;面试资源&#xff0c;学习方法等等。 组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许你将对象组合成树形结构来表示…

GMT绘图笔记:在地图上绘制直线而不是大圆弧

问题&#xff1a;利用GMT地图上绘制两点之间的直线&#xff0c;如果跨度过大会出现大圆弧线&#xff0c;而通常在备注地图图例的时候&#xff0c;通常需要强制绘制为直线。 在GMT&#xff08;Generic Mapping Tools&#xff09;中&#xff0c;使用plot命令绘制大跨度的范围线段…

让Mac更Mac|明基MA系列显示器上市

凭借出色的性能和设计&#xff0c;MacBook成为了很多人的心头好。可13~16英寸的屏幕&#xff0c;时常让人感到视野受限&#xff0c;就像无边创意中的一道隐形壁垒。想要外接显示大屏&#xff0c;但除了Studio Display等苹果显示器之外&#xff0c;其他品牌的外接显示屏&#xf…

llvm后端之td定义指令信息

llvm后端之td定义指令信息 引言1 定义指令2 定义Operand3 定义SDNode4 PatFrags4.1 ImmLeaf4.2 PatLeaf 5 ComplexPattern6 谓词条件7 理解dag 引言 llvm后端通过td定义指令信息&#xff0c;并通过dag匹配将IR节点转换为平台相关的指令。 1 定义指令 td通过class Instructio…

c语言和c++的区别

在计算机编程领域&#xff0c;C语言和C无疑是两座重要的里程碑。尽管它们在很多方面有着相似之处&#xff0c;但在设计理念、功能特性以及应用场景上&#xff0c;两者又存在着显著的差异。小编将从多个角度深入探讨C语言和C的区别&#xff0c;帮助读者更好地理解这两种编程语言…

不小心从 Android 设备中删除了重要消息,恢复永久删除的消息知识

您是否曾经不小心从 Android 设备中删除了重要消息&#xff0c;并迫切希望能够恢复它们&#xff1f;好吧&#xff0c;好消息是你可以&#xff01;通过一些简单的步骤和正确的工具&#xff0c;您可以恢复那些已删除的消息并找回您认为永远丢失的信息。在本教程中&#xff0c;我将…

Linux操作系统下的一些常用命令分享(ubuntu16.04)

注意一般Linux命令字符与字符之间都是空格来隔开的&#xff0c;所以千万不能忘记打空格&#xff0c;而且Linux区分大小写。&#xff08;目录就是文件夹&#xff09; 1、pwd 查看当前所在目录 2、查看帮助 命令 --help 但是这个命令会把所有内容一次性全部显示我们看帮助时很…

【应急响应】webshell的排查与处置

❤️博客主页&#xff1a; iknow181 &#x1f525;系列专栏&#xff1a; 网络安全、 Python、JavaSE、JavaWeb、CCNP &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐评论✍ 引言 Webshell 是攻击者入侵 Web 服务器后常用的远程控制工具&#xff0c;它通过一段恶意代码&#xff…

12.1.1.案例专题-数据流图

大纲 数据流图 DFD 基本图形元素 外部实体、加工、数据存储、数据流 灰洞、黑洞、奇迹 考题中如果出现黑洞&#xff0c;说明至少缺一条输出 考题中如果出现奇迹&#xff0c;说明至少缺一条输入 考题中几乎不会考到 灰洞 顶层图、0层图、1层图 考试中不会出现 1层图&#x…