赞
踩
2024-3-20 19:41:47
使用百度千帆平台的大模型,完成一个简单的AI对话聊天
以下内容源自《【人工智能】》
仅供学习交流使用
禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://jsss-1.blog.csdn.net
禁止其他平台发布时删除以上此话
Gitee项目地址: 日星月云 / AI对话
通过上篇,我们成功地完成了初次对大模型的使用
本篇,我将带大家开发一个AI对话聊天框
输入用户名,点击登录
返回“登录成功”
查询状态
页面
输入内容,点击回车即可提问
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
ai.sql
create table conversation
(
id int auto_increment
primary 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.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 mapper PUBLIC "-//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.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 { @Autowired ChatMapper chatMapper; @Override public void addChat(Conversation conversation) { chatMapper.insert(conversation); } @Override public List<Conversation> searchByUsername(String username) { return chatMapper.getByUsername(username); } }
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; @Bean public 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 { @Autowired Qianfan 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())); // 流式迭代,并打印消息 } }
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") @ResponseBody public String login(HttpServletRequest request,String username){ HttpSession session = request.getSession(); session.setAttribute("username",username); return "登录成功"; } @GetMapping("/logout") @ResponseBody public String logout(HttpServletRequest request,String username){ HttpSession session = request.getSession(); session.removeAttribute("username"); return "登出成功"; } @GetMapping("/status") @ResponseBody public 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()))); // } @Autowired QianfanUtil qianfanUtil; @Autowired ChatService 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/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(); } });
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
迎着日光月光星光,直面风霜雨霜雪霜。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。