SpringBoot调用通义千问

news2024/9/20 15:24:43

提示:今日花了2个小时搞定了一个简易版的AI对话功能

文章目录

目录

文章目录

SpringBoot代码

引入库

controller

返回对象类

工具类

前端代码

 ​编辑

 效果展示

 后端返回



SpringBoot代码

当然我只做了一个简易版的AI对话,你可以在我的基础之上进行改动

引入库

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dashscope-sdk-java</artifactId>
            <version>2.13.0</version>
        </dependency>

controller

package com.xinggui.demo.controller;


import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.xinggui.demo.domain.Response;
import com.xinggui.demo.util.ApiTestUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
@CrossOrigin(origins = "http://127.0.0.1:5500") // 假设前端在3000端口运行
public class test {
    @PostMapping("/test")
    public Response test(String problem){
        if(problem.length() == 0){
            return new Response("-1","请输入问题",null);
        }
        String result = null;
        try {
            result = ApiTestUtil.getProblem(problem);
        } catch (NoApiKeyException e) {
            log.error("apiKey错误");
        } catch (InputRequiredException e) {
            log.error("输入为空");
        }
        return new Response("0","success",result);
    }
}

返回对象类

package com.xinggui.demo.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Response {

    private String code;
    private String msg;
    private Object data;

}

工具类

package com.xinggui.demo.util;

import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import com.alibaba.dashscope.utils.JsonUtils;
import io.reactivex.Flowable;

import java.util.Arrays;
import java.util.concurrent.Semaphore;

public class ApiTestUtil {

    public static String getProblem(String problem) throws NoApiKeyException, InputRequiredException {
        Constants.apiKey = "请填写你自己的API-key";
        // 实例化生成器对象
        Generation gen = new Generation();
        // 构建用户消息,角色为USER,内容为中国首都的介绍
        Message userMsg =
                Message.builder().role(Role.USER.getValue()).content(problem).build();
        // 构建生成参数,包括模型名称、消息列表、结果格式等
        GenerationParam param = GenerationParam.builder()
                .model("qwen-max") // 选择使用的模型
                .messages(Arrays.asList(userMsg)) // 用户的询问消息
                .resultFormat(GenerationParam.ResultFormat.MESSAGE) // 结果以消息格式返回
                .topP(0.8).enableSearch(true) // 设置搜索启用及topP参数
                .incrementalOutput(true) // 以增量方式获取流式输出
                .build();
        // 调用生成器的流式调用方法,返回结果为一个Flowable流
        Flowable<GenerationResult> result = gen.streamCall(param);
        // 使用StringBuilder来拼接完整的回复内容
        StringBuilder fullContent = new StringBuilder();
        // 阻塞方式处理每一个流式输出的消息,并打印出来
        result.blockingForEach(message -> {
            // 将当前消息的内容追加到完整内容中
            fullContent.append(message.getOutput().getChoices().get(0).getMessage().getContent());
            // 打印当前的消息内容(JSON格式)
            System.out.println(JsonUtils.toJson(message));
        });
        // 打印最终的完整内容
        System.out.println("Full content: \n" + fullContent.toString());
        return fullContent.toString();
    }
}

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AI Chat Interface</title>
  <!-- 引入 Vue 3 的 CDN -->
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <style>
    /* 样式 */
    body {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      background-color: #f4f4f9;
      margin: 0;
      padding: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }

    .chat-container {
      display: flex;
      flex-direction: column;
      height: 80vh;
      width: 80vw;
      max-width: 600px;
      border: 1px solid #ccc;
      border-radius: 10px;
      overflow: hidden;
      background-color: #fff;
    }

    .chat-window {
      flex: 1;
      padding: 10px;
      overflow-y: auto;
      background-color: #f4f4f9;
      position: relative;
    }

    .chat-message {
      display: flex;
      margin-bottom: 10px;
      align-items: flex-start;
    }

    .message-left {
      flex-direction: row;
    }

    .message-right {
      flex-direction: row-reverse;
    }

    .avatar {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      background-color: #007bff;
      display: flex;
      justify-content: center;
      align-items: center;
      color: white;
      font-weight: bold;
      margin: 0 10px;
    }

    .message-bubble {
      max-width: 70%;
      padding: 10px;
      border-radius: 20px;
      background-color: #007bff;
      color: white;
      word-wrap: break-word;
    }

    .message-left .message-bubble {
      background-color: #e4e6eb;
      color: black;
    }

    .chat-input {
      display: flex;
      padding: 10px;
      border-top: 1px solid #ccc;
      background-color: #fff;
    }

    .chat-input input {
      flex: 1;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 20px;
      outline: none;
    }

    .chat-input button {
      margin-left: 10px;
      padding: 10px 20px;
      border: none;
      background-color: #007bff;
      color: white;
      border-radius: 20px;
      cursor: pointer;
      outline: none;
    }

    .chat-input button:hover {
      background-color: #0056b3;
    }

    /* From Uiverse.io by SchawnnahJ */ 
    .loader {
      position: relative;
      width: 2.5em;
      height: 2.5em;
      transform: rotate(165deg);
    }

    .loader:before, .loader:after {
      content: "";
      position: absolute;
      top: 50%;
      left: 50%;
      display: block;
      width: 0.5em;
      height: 0.5em;
      border-radius: 0.25em;
      transform: translate(-50%, -50%);
    }

    .loader:before {
      animation: before8 2s infinite;
    }

    .loader:after {
      animation: after6 2s infinite;
    }

    @keyframes before8 {
      0% {
        width: 0.5em;
        box-shadow: 1em -0.5em rgba(225, 20, 98, 0.75), -1em 0.5em rgba(111, 202, 220, 0.75);
      }

      35% {
        width: 2.5em;
        box-shadow: 0 -0.5em rgba(225, 20, 98, 0.75), 0 0.5em rgba(111, 202, 220, 0.75);
      }

      70% {
        width: 0.5em;
        box-shadow: -1em -0.5em rgba(225, 20, 98, 0.75), 1em 0.5em rgba(111, 202, 220, 0.75);
      }

      100% {
        box-shadow: 1em -0.5em rgba(225, 20, 98, 0.75), -1em 0.5em rgba(111, 202, 220, 0.75);
      }
    }

    @keyframes after6 {
      0% {
        height: 0.5em;
        box-shadow: 0.5em 1em rgba(61, 184, 143, 0.75), -0.5em -1em rgba(233, 169, 32, 0.75);
      }

      35% {
        height: 2.5em;
        box-shadow: 0.5em 0 rgba(61, 184, 143, 0.75), -0.5em 0 rgba(233, 169, 32, 0.75);
      }

      70% {
        height: 0.5em;
        box-shadow: 0.5em -1em rgba(61, 184, 143, 0.75), -0.5em 1em rgba(233, 169, 32, 0.75);
      }

      100% {
        box-shadow: 0.5em 1em rgba(61, 184, 143, 0.75), -0.5em -1em rgba(233, 169, 32, 0.75);
      }
    }

    .loading {
      position: relative;
      bottom: -20px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
  </style>
</head>
<body>
    <div id="app">
        <div class="chat-container">
          <div class="chat-window">
            <div v-for="(message, index) in messages" :key="index" class="chat-message" :class="{'message-left': message.isUser, 'message-right': !message.isUser}">
              <div class="avatar">{{ message.isUser ? '自己' : 'AI' }}</div>
              <div class="message-bubble">
                {{ message.text }}
              </div>
            </div>
            <div class="loading"  v-if="loading">
               <div style="display: flex;align-items: center;justify-content: center;">
                <div class="loader"></div>
                <div style="margin-left: 10px;font-weight: bold; color: #e64c87;">加载中</div>
               </div>
            </div>
          </div>
          <div class="chat-input">
            <input v-model="userInput" @keydown.enter="sendMessage" placeholder="Type your question..." />
            <button @click="sendMessage">Send</button>
          </div>
        </div>
      </div>
      
        <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
      <script>
        const { createApp } = Vue;
    
        createApp({
          data() {
            return {
              userInput: '',
              messages: [
                { text: '你有什么需要问的问题吗?', isUser: false }
              ],
              loading:false
            };
          },
          methods: {
            sendMessage() {
              if (this.userInput.trim()) {
                // 添加用户的消息
                this.messages.push({ text: this.userInput, isUser: true });
    
                // 模拟AI回复(你可以在这里调用AI的接口)
                this.simulateAIResponse(this.userInput);
    
                // 清空输入框
                this.userInput = '';
              }
            },
           async simulateAIResponse(userText) {
            this.loading = true;
                const res =await axios.post("http://localhost:8888/test", {
                "problem": this.userInput
            },{ headers: { "Content-Type": "multipart/form-data" } })
                this.messages.push({
                  text: `AI回答内容: ${res.data.data}`,
                  isUser: false,
                });
                this.loading = false;
              
            },
          },
          
        }).mount('#app');
      </script>
</body>
</html>

这里我使用VScode中的liveServer插件,启动项目

后端对http://127.0.0.1:5500做了跨域配置

 

 

 效果展示

 这里还添加了一个Loading效果

 

 后端返回

 今日时间2024年8月27日,希望可以帮助到你

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2080691.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode 1957 删除字符使字符串变好

leetcode 1957 删除字符使字符串变好 正文题目说明Python 常用技巧解题思路方法1方法2方法3 正文 题目说明 Python 常用技巧 Python 中在字符串中做删除元素的操作是很困难的&#xff0c;通常我们都会创建一个新的字符串或者列表&#xff0c;然后进行循环&#xff0c;将不需要…

简单分享下Python文件操作

1. 上传文件到服务器 场景描述: 使用 requests 库上传文件到服务器。 import requestsdef test_upload_file(): url "https://api.example.com/upload" file_path "path/to/file.txt" with open(file_path, "rb") as file: …

解决串口打印乱码:确保晶振频率设置正确

项目场景&#xff1a; GD32单片机通过USART1串口&#xff0c;以115200波特率每1秒发送自定义字符串&#xff08;“my_test”&#xff09;&#xff0c;PC机使用串口助手接收数据。 问题描述 使用串口助手软件&#xff08;sscom&#xff09;接收GD3232单片机通过UART发送的数据…

【STM32】PWR电源控制(低功耗模式)

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 PWR简介 修改主频 低功耗模式 睡眠模式 停止模式 待机模式 PWR简介 PWR&#xff08;Power Control&#xff09;电源控制 &#xff0c;负责管理STM32内部的电源供电部分&#xff0c;可…

基于麻雀SSA优化BP神经网络多输入多输出的数据回归预测Matlab程序SSA-BP 含预测新数据程序

基于麻雀SSA优化BP神经网络多输入多输出的数据回归预测Matlab程序SSA-BP 含预测新数据程序 文章目录 一、基本原理1. SSA&#xff08;麻雀搜索算法&#xff09;2. BP&#xff08;反向传播神经网络&#xff09;3. SSA-BP回归预测的整合 二、实验结果三、核心代码四、代码获取五、…

使用idea快速创建springbootWeb项目(springboot+springWeb+mybatis-Plus)

idea快速创建springbootWeb项目 详细步骤如下 1&#xff09;创建项目 2&#xff09;选择springboot版本 3&#xff09;添加web依赖 4&#xff09;添加Thymeleaf 5&#xff09;添加lombok依赖 然后点击create进入下一步 双击pom.xml文件 6&#xff09;添加mybatis-plus依赖 …

Ubuntu搭建FTP服务器

目录 1.ftp简介 2.vsftpd 2.1.介绍 2.2.安装与卸载 2.3.综合案例 - 本地用户模式 2.4.1.创建FTP用户 2.4.2.配置vsftpd 2.4.3.配置防火墙 1.ftp简介 一般来讲&#xff0c;人们将计算机联网的首要目的就是获取资料&#xff0c;而文件传输是一种非常重要的获取资料的方…

盘点 8 月份 火火火 的开源项目

01 Rnote&#xff1a;释放创意&#xff0c;手绘与笔记的开源之选 Rnote是一个基于矢量的开源绘图应用&#xff0c;专为手绘、手写笔记以及文档和图片注释设计。 它适用于学生、教师以及拥有绘图板的用户&#xff0c;提供了 PDF 和图片的导入导出功能&#xff0c;无限画布以及适…

单词拆分[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个字符串s和一个字符串列表wordDict作为字典。如果可以利用字典中出现的一个或多个单词拼接出s则返回true。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#x…

【第54课】XSS跨站Cookie盗取表单劫持网络钓鱼溯源分析项目平台框架

免责声明 本文发布的工具和脚本&#xff0c;仅用作测试和学习研究&#xff0c;禁止用于商业用途&#xff0c;不能保证其合法性&#xff0c;准确性&#xff0c;完整性和有效性&#xff0c;请根据情况自行判断。 如果任何单位或个人认为该项目的脚本可能涉嫌侵犯其权利&#xff0…

004、架构_计算节点

架构总览 重要线程 管理线程:主要负责元数据相关的管理,涉及启动、DDL、切换;执行线程:是CN最重要的核心线程组,涉及解析、执行计划、分发、聚合;路由线程:主要负责向DN节点分发语句,涉及读写分离、子语句;GTM代理线程:主要负责与GTM交互、涉及申请、活跃GTID查询、释…

YASKAWA机器人维修操作命令攻略-移动命令运用案例

移动命令 1. MOVJ 命令运用案例&#xff1a; MOVJ VJ50.00 PL2 NWAIT UNTIL IN(1)ON 含义&#xff1a;在这个点以关节坐标&#xff0c;按 50.00%的再现速度&#xff0c;定位精度为 2&#xff0c;同时执行下一条非移动 指令&#xff0c;判断输入信号 1 为 on 后&#xff0c;执行…

助力航运管理数字智能化,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建江面河道运输场景下来往航行船只自动检测识别系统

在全球化浪潮的推动下&#xff0c;物流行业作为连接世界的桥梁&#xff0c;其快速发展与进化不仅重塑了国际贸易的格局&#xff0c;更深刻影响着全球贸易金融的进程。其中&#xff0c;海运作为大宗商品跨国、全球化贸易的支柱性运输方式&#xff0c;其重要性不言而喻。随着各国…

ios去水印软件免费版,精选五大高效工具,告别水印烦恼!

随着社交媒体的普及&#xff0c;越来越多的人喜欢在网络上分享自己的生活点滴。在分享视频时&#xff0c;水印往往会影响美观。为了帮助大家解决这个问题&#xff0c;本文为您推荐五大高效免费的iOS去水印软件&#xff0c;让您轻松告别水印烦恼&#xff01; 软件一&#xff1a…

第137天:横向移动-Linux_ssh工具杂项Linux靶场环境搭建

实验环境及图解&#xff1a; 通过网盘分享的文件&#xff1a;137-Linux内网环境镜像文件 链接: https://pan.baidu.com/s/1W_5DvhbkGYMqML4mi1rjQA?pwdad6r 提取码: ad6r 一般情况下SSH密钥存放在~/.ssh/目录下&#xff0c;也可以文件中搜索已保存的SSH凭证 ~/.ssh/config ~/.…

eclipse下载安装与配置代码补全与中文版

eclipse下载安装与配置中文版 eclipse下载eclipse安装eclipse配置代码补全eclipse配置中文版 eclipse下载 首先我们从官网下载eclipse&#xff0c;点击后是如下页面 我们往下滑&#xff0c;选择自己需要的版本&#xff0c;在这里我们选择的是Windows的Java开发版本&#xff0c…

【自动驾驶】决策规划算法 | 数学基础(二)凸优化与非凸优化

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

机器学习||笔记

在学习机器学习之前&#xff0c;应具备以下基础&#xff1a; 编程技能&#xff1a;精通 Python&#xff0c;掌握数据结构、函数、面向对象编程&#xff0c;熟悉 Git 和 Jupyter Notebook。 数学基础&#xff1a; 线性代数&#xff1a;矩阵运算、特征值与特征向量。微积分&…

2009年

一、选择 B C D B A 答案 C 叶子节点可能出现在最下层和次下层 所以最多七层&#xff0c;前六层是满二叉树 C 答案 B A D A B 二、大题

JVM垃圾回收算法以及垃圾收集器

JVM垃圾回收算法 JVM垃圾回收算法分为三类&#xff1a;标记清除算法、标记整理算法、 复制算法 标记清除算法 垃圾回收分为2个阶段,分别是标记和清除,效率高有磁盘碎片,内存不连续 标记整理算法 标记清除算法一样,将存活对象都向内存另一端移动,然后清理边界以外的垃圾,无…