百度智能云+SpringBoot=AI对话【人工智能】
- 前言
- 版权
- 推荐
- 百度智能云+SpringBoot=AI对话【人工智能】
- 效果演示
- 登录
- AI对话
- 项目结构
- 后端开发
- pom和properties
- sql_table和entity
- dao和mapper
- service和impl
- config和util
- LoginController和ChatController
- 前端开发
- css和js
- login.html和chat.html
- 后言
- 最后
前言
2024-3-20 19:41:47
使用百度千帆平台的大模型,完成一个简单的AI对话聊天
以下内容源自《【人工智能】》
仅供学习交流使用
版权
禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://jsss-1.blog.csdn.net
禁止其他平台发布时删除以上此话
推荐
Gitee项目地址: 日星月云 / AI对话
GitHub项目地址:jsss-1/qianfan
百度千帆模型初次体验【人工智能】
百度智能云+SpringBoot=AI对话【人工智能】
通过上篇,我们成功地完成了初次对大模型的使用
本篇,我将带大家开发一个AI对话聊天框
效果演示
登录
输入用户名,点击登录
返回“登录成功”
查询状态
AI对话
页面
输入内容,点击回车即可提问
项目结构
后端开发
pom和properties
pom.xml
SpringBoot2.4.2+JDK8
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.2</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>qianfan</artifactId><version>0.0.1-SNAPSHOT</version><name>qianfan</name><description>qianfan</description><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 千帆大模型平台--><dependency><groupId>com.baidubce</groupId><artifactId>qianfan</artifactId><version>0.0.1</version></dependency><!-- thymeleaf 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- lombok 依赖--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- mysql 依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- mybatis 依赖--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
application.properties
spring.application.name=qianfan# Qianfan
QIANFAN_ACCESS_KEY=你的AK
QIANFAN_SECRET_KEY=你的SK# ServerProperties
server.port=8080
server.servlet.context-path=# ThymeleafProperties
spring.thymeleaf.cache=false# mysql
spring.datasource.url=jdbc:mysql://localhost:3306/ai?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# MyBatis
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.jsss.entity
# 生成主键
mybatis.configuration.useGeneratedKeys=true
# 驼峰命名
mybatis.configuration.mapUnderscoreToCamelCase=true
sql_table和entity
ai.sql
create table conversation
(id int auto_incrementprimary key,username varchar(16) null,user_message text null,bot_message text null,create_time varchar(32) null
);
**enntity.Conversation **
package com.jsss.qianfan.entity;import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Conversation {private Integer id;private String username;private String userMessage;private String botMessage;private String createTime;}
dao和mapper
**dao.ChatMapper **
package com.jsss.qianfan.dao;import com.jsss.qianfan.entity.Conversation;
import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface ChatMapper {List<Conversation> getByUsername(String username);void insert(Conversation conversation);}
**mapper/ChatMapper.xml **
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.jsss.qianfan.dao.ChatMapper"><!-- 定义SQL映射关系 --><!-- 根据username查询conversation记录 --><select id="getByUsername" resultType="com.jsss.qianfan.entity.Conversation" parameterType="string">SELECT * FROM conversation WHERE username = #{username}</select><!-- 插入新的conversation记录 --><insert id="insert" parameterType="com.jsss.qianfan.entity.Conversation">INSERT INTO conversation (username, user_message, bot_message, create_time) VALUES (#{username},#{userMessage},#{botMessage},#{createTime})</insert></mapper>
service和impl
service.ChatService
package com.jsss.qianfan.service;import com.jsss.qianfan.entity.Conversation;import java.util.List;public interface ChatService {void addChat(Conversation conversation);List<Conversation> searchByUsername(String username);}
impl.ChatServiceImpl
package com.jsss.qianfan.service.impl;import com.jsss.qianfan.dao.ChatMapper;
import com.jsss.qianfan.entity.Conversation;
import com.jsss.qianfan.service.ChatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class ChatServiceImpl implements ChatService {@AutowiredChatMapper chatMapper;@Overridepublic void addChat(Conversation conversation) {chatMapper.insert(conversation);}@Overridepublic List<Conversation> searchByUsername(String username) {return chatMapper.getByUsername(username);}
}
config和util
configuration.QianfanConfig
package com.jsss.qianfan.configuration;import com.baidubce.qianfan.Qianfan;
import com.baidubce.qianfan.core.auth.Auth;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class QianfanConfig {@Value("${QIANFAN_ACCESS_KEY}")String ak;@Value("${QIANFAN_SECRET_KEY}")String sk;@Beanpublic Qianfan qianFan() {return new Qianfan(Auth.TYPE_OAUTH, ak, sk);}
}
util.QianfanUtil
package com.jsss.qianfan.util;import com.baidubce.qianfan.Qianfan;
import com.baidubce.qianfan.model.chat.ChatResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class QianfanUtil {@AutowiredQianfan qianfan;public String addMessage(String content) {ChatResponse response = qianfan.chatCompletion()//.model("ERNIE-Bot-4") //使用model指定预置模型 默认模型是ERNIE-Bot-turbo.addMessage("user", content) // 添加用户消息 (此方法可以调用多次,以实现多轮对话的消息传递).temperature(0.7) // 自定义超参数.execute(); // 发起请求return response.getResult();}public void executeStream(String content) {qianfan.chatCompletion().addMessage("user", content).executeStream() // 发起流式请求.forEachRemaining(chunk -> System.out.print(chunk.getResult())); // 流式迭代,并打印消息}}
LoginController和ChatController
controller.LoginController
package com.jsss.qianfan.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;@Controller
public class LoginController {@GetMapping("/login")public String login(){return "login";}@PostMapping("/login")@ResponseBodypublic String login(HttpServletRequest request,String username){HttpSession session = request.getSession();session.setAttribute("username",username);return "登录成功";}@GetMapping("/logout")@ResponseBodypublic String logout(HttpServletRequest request,String username){HttpSession session = request.getSession();session.removeAttribute("username");return "登出成功";}@GetMapping("/status")@ResponseBodypublic String status(HttpServletRequest request){HttpSession session = request.getSession();String username =(String)session.getAttribute("username");if (username!=null&&!username.isEmpty()){return username;}else {return "没有登录";}}
}
controller.ChatController
package com.jsss.qianfan.controller;import com.jsss.qianfan.entity.Conversation;
import com.jsss.qianfan.service.ChatService;
import com.jsss.qianfan.util.QianfanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;@Controller
@RequestMapping("chat")
public class ChatController {// List<Conversation> conversations=new ArrayList<>();
//
// static int id=1;
//
// {
// conversations.add(new Conversation(id++,"1","你好","抱歉,网络出现异常,请你重试或联系客服!TooManyRequests", format(new Date())));
// conversations.add(new Conversation(id++,"1","你好","抱歉,网络出现异常,请你重试或联系客服!TooManyRequests", format(new Date())));
// }@AutowiredQianfanUtil qianfanUtil;@AutowiredChatService chatService;private String format(Date date){return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);}@GetMapping("/list")public String getChat(HttpServletRequest request,Model model){String username= (String) request.getSession().getAttribute("username");List<Conversation> conversations=chatService.searchByUsername(username);model.addAttribute("conversations",conversations);return "chat";}@PostMapping("/chat")public String chat(HttpServletRequest httpServletRequest,@RequestBody Map<String, String> request){String username= (String) httpServletRequest.getSession().getAttribute("username");String content = request.get("content");System.out.println(content);// String res="回复";
// Conversation conversation = new Conversation(id++,username, content, res, format(new Date());
// conversations.add(conversation);String res = qianfanUtil.addMessage(content);Conversation conversation = new Conversation(null, username, content, res, format(new Date()));chatService.addChat(conversation);return "redirect:list";}}
前端开发
css和js
css/style.css
/* 设置用户发送消息的样式 */
.user-message {background-color: #4CAF50; /* 绿色背景 */color: white;padding: 10px;margin: 10px;border-radius: 10px;white-space: pre;
}/* 设置ChatGPT发送消息的样式 */
.bot-message {background-color: #f2f2f2; /* 灰色背景 */padding: 10px;margin: 10px;border-radius: 10px;white-space: pre;
}.question-container {display: flex;justify-content: flex-end;
}.question {display: flex;flex-direction: row;align-items: center;
}.question td:first-child {margin-left: auto;
}.answer-container {display: flex;justify-content: flex-start;
}.answer {display: flex;flex-direction: row;align-items: center;
}.answer td:last-child {margin-left: auto;
}/* 设置提问和回复消息的表格样式 */
.question, .answer {display: flex;align-items: center;padding: 10px;border-radius: 10px;
}/* 设置输入框和发送按钮的样式 */
.form-container {display: flex;justify-content: center;align-items: center;position: fixed;bottom: 0;width: 100%;padding: 10px;background-color: #f9f9f9;border-top: 1px solid #ccc;
}.form-row {display: flex;flex: 1;
}.form-group {flex: 1;margin-right: 10px;
}.form-group input {width: 100%;padding: 10px;border: 1px solid #ccc;border-radius: 5px;outline: none;
}.message-container {max-height: 700px; /* 设置最大高度,超出部分可滚动 */overflow-y: auto; /* 竖直方向溢出部分可滚动 */
}.send-message-container {flex: 1; /* 占据剩余空间 */display: flex;align-items: center;background-color: #f5f5f5;
}textarea {width: 1800px; /* 设置输入框的宽度为300像素,您可以根据需要调整这个值 */height: 100px; /* 设置输入框的高度为200像素,您可以根据需要调整这个值 */font-size: 16px; /* 设置输入框中文字的字体大小为16像素,您可以根据需要调整这个值 */resize: none; /* 禁止用户调整输入框的尺寸 */
}
js/onload.js
window.onload = function() {// 找到消息容器var messageContainer = document.querySelector(".message-container");// 找到消息容器中最后一个子元素var lastMessage = messageContainer.lastElementChild;// 将最后一个子元素滚动到可见区域lastMessage.scrollIntoView();
};
js/textarea.js
var textarea = document.getElementById("messageInput");textarea.addEventListener("keydown", function(event) {if (event.key === "Enter" && !event.shiftKey) {event.preventDefault();var message = textarea.value.trim();textarea.value = "";// 发送 POST 请求fetch('/chat/chat', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({ content: message })}).then(function(response) {// 刷新页面location.reload();});}
});textarea.addEventListener("keydown", function(event) {if (event.key === "Enter" && event.shiftKey) {// 在 Shift+Enter 情况下允许换行textarea.value += "\n";event.preventDefault();}
});
login.html和chat.html
html/login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"><head><title>AI对话</title></head><body><div class="chat-container"><h1 class="title">登录</h1><div class="login-container"><form th:action="@{/login}" method="post"><div class="form-container"><div class="form-row"><span class="form-group no-border"><input id="username" name="username" placeholder="输入用户名"></span><button>登录</button></div></div></form></div></div></body></html>
html/chat.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"><head><link rel="stylesheet" th:href="@{/css/style.css}"><title>AI对话</title></head><body><div class="chat-container"><h1 class="title">AI 对话</h1><div class="message-container"><!-- 用户消息和ChatGPT消息显示部分 --><div th:each="conversation:${conversations}"><div class="question-container"><table class="question"><td><span th:utext="${conversation.createTime}"></span><div class="user-message" th:utext="${conversation.userMessage}"></div></td><td type="text" th:text="${conversation.username}">提问</td></table></div><div class="answer-container"><table class="answer"><td type="text">AI</td><td><span th:utext="${conversation.createTime}"></span><div class="bot-message" th:utext="${conversation.botMessage}"></div></td></table></div></div></div><div class="send-message-container"><!-- 发送消息部分 --><form th:action="@{/chat/chat}" method="post"><div class="form-container"><div class="form-row"><span class="form-group no-border"><textarea id="messageInput" placeholder="问我任何问题...(Shift + Enter 换行,按下Enter 发送)"></textarea></span></div></div></form></div></div></body><script th:src="@{/js/onload.js}"></script><script th:src="@{/js/textarea.js}"></script></html>
后言
待完善的功能:
-
用户对话之后,需要等待回复,才能弹出对话内容
-
等待期间,还能输入聊天框
-
并且,没有终止生成
-
没有左边框-新建对话
-
没有md格式的复制
最后
2024-3-20 21:06:39
迎着日光月光星光,直面风霜雨霜雪霜。