文章链接:

基于GPT搭建私有知识库聊天机器人(一)实现原理

基于GPT搭建私有知识库聊天机器人(二)环境安装

基于GPT搭建私有知识库聊天机器人(三)向量数据训练

基于GPT搭建私有知识库聊天机器人(四)问答实现

基于GPT搭建私有知识库聊天机器人(五)函数调用


在前几篇文章中,我们已经了解了如何使用 GPT 模型来搭建一个简单的聊天机器人,并在后端使用私有知识库来提供答案。

现在,我们将继续改进我们的聊天界面,实现类似chatGPT打字机的效果聊天,避免长时间等待接口数据返回,以提升用户体验。

1、效果展示

PS:一本正经的胡说八道

2、Server-Sent Events (SSE) 技术简介

在本篇文章中,我们将使用 SSE 技术来实现打字机效果输出。SSE 是一种 HTML5 技术,允许服务器向客户端推送数据,而不需要客户端主动请求。通过 SSE,我们可以在服务器端有新消息时,实时将消息推送到前端,从而实现动态的聊天效果。

3、前端代码

首先,我们需要编写前端的JavaScript 代码,以便使用 SSE 技术与服务器进行实时通信。

<!DOCTYPE html>
<html>
<head>
<title>ChatGPT-like Interface</title>
<link rel="stylesheet" href="static/styles.css">
</head>
<body>
<div class="chat-container">
<div class="chat-history" id="chatHistory">
<!-- Chat messages will be dynamically added here -->
</div>
<div class="user-input">
<input type="text" id="userInput" placeholder="请输入您的问题...">
<button id="sendButton">发送</button>
</div>
</div> <script>
// Your existing chat interface code here... // Server communication code
var eventSource; // Declare the eventSource variable outside the click handler document.getElementById("sendButton").addEventListener("click", function () {
var userMessage = document.getElementById("userInput").value.trim();
if (userMessage === '') {
alert('Please enter a message!');
return;
} appendMessage('user', userMessage); // Add the user's message to the chat history // Close the previous SSE connection (if exists)
if (eventSource) {
eventSource.close();
} // Establish SSE connection with the user's message as a parameter
eventSource = new EventSource(`/print_stream?question=${encodeURIComponent(userMessage)}`); eventSource.onmessage = function (event) {
var botMessage = event.data;
appendMessage('bot', botMessage);
}; eventSource.onerror = function (error) {
console.error("Error occurred with SSE connection:", error);
// Handle the error if necessary
isFirstToken = true;
eventSource.close();
};
document.getElementById("userInput").value = '';
});
var chatHistoryDiv = document.getElementById("chatHistory"); // 获取 chatHistory 的元素
var isFirstToken = true; // 用于跟踪是否是第一次返回 token
function appendMessage(sender, message) {
if (isFirstToken) {
// 如果是第一次返回 token,创建新的 <div> 元素,并将 isFirstToken 设置为 false
var messageDiv = document.createElement('div');
messageDiv.className = `chat-message ${sender === 'user' ? 'user-message' : 'bot-message'}`;
chatHistoryDiv.appendChild(messageDiv);
if(sender === 'bot') {
isFirstToken = false;
}
} else {
// 如果不是第一次返回 token,直接获取最后一个 <div> 元素,将新的消息内容追加到现有的元素中
var messageDiv = chatHistoryDiv.lastElementChild;
}
messageDiv.innerText += message; // 将新的消息内容追加到 <div> 中
chatHistoryDiv.scrollTop = chatHistoryDiv.scrollHeight; // 将滚动条滚动到最底部
}
</script>
</body>
</html>

为了实现对话效果,我们需要调整 CSS 样式表中的部分样式。以下是 CSS 样式表:

body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
} .chat-container {
width: 800px;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
background-color: #fff;
overflow: hidden;
} .chat-history {
max-height: 800px;
overflow-y: auto;
padding: 10px;
} .chat-message {
margin-bottom: 10px;
padding: 8px 12px;
border-radius: 20px;
max-width: 70%; /* 设置最大宽度,使得消息在一行中不会过长 */
align-self: flex-end; /* 靠右显示 */
word-wrap: break-word; /* 处理长文本的自动换行 */
overflow-wrap: break-word; /* 处理长文本的自动换行 */
} .user-message {
color: #007bff;
background-color: #e6e6e6; /* 用户消息气泡背景色 */
text-align: right; /* 靠右显示文本内容 */
align-self: flex-end; /* 靠右显示气泡 */
margin-left: auto; /* 添加额外的间距,让气泡靠右 */
} .bot-message {
color: #555;
background-color: #d9edf7; /* 机器人消息气泡背景色 */
text-align: left; /* 靠左显示文本内容 */
align-self: flex-start; /* 靠左显示气泡 */
margin-right: auto; /* 添加额外的间距,让气泡靠左 */
} .user-input {
display: flex;
align-items: center;
padding: 10px;
} #userInput {
flex-grow: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 5px;
margin-right: 10px;
} #sendButton {
padding: 8px 15px;
border: none;
border-radius: 5px;
background-color: #007bff;
color: #fff;
cursor: pointer;
} #sendButton:hover {
background-color: #0056b3;
}

4、后端代码

本文依旧使用的langchain框架实现访问openAI,以及利用回调函数接收token数据。

首先,是API入口:

from flask import Flask, request, Response, stream_with_context

@app.route("/print_stream")
def print_stream():
question = request.args.get('question')
ans = search_schedule(question) return Response(stream_with_context(ans), content_type='text/event-stream')

其次,是访问openAI代码(不太了解的可以看下前几篇文章):

def search_schedule(query: str) -> str:
stream_to_web = StreamToWeb()
llm = ChatOpenAI(temperature=0,
model="gpt-3.5-turbo-0613",
callback_manager=CallbackManager([stream_to_web]),
streaming=True
)
bus_tools = [BusTool()]
open_ai_agent = initialize_agent(bus_tools,
llm,
agent=AgentType.OPENAI_FUNCTIONS,
verbose=True)
chain_thread = threading.Thread(target=process_query,
kwargs={"question": query,
"open_ai_agent": open_ai_agent})
chain_thread.start()
resp = stream_to_web.generate_tokens()
return resp

注意:上面调用openai部分代码必须使用异步执行,才能做到一边接收返回token,一边返回前端,否则无法实现打字机效果。

最后,打字机效果核心代码:

class StreamToWeb(StreamingStdOutCallbackHandler):
def __init__(self):
self.tokens = []
# 记得结束后这里置true
self.finish = False def on_llm_new_token(self, token: str, **kwargs):
self.tokens.append(token) def on_llm_end(self, response: any, **kwargs: any) -> None:
self.finish = 1 def on_llm_error(self, error: Exception, **kwargs: any) -> None:
print(str(error))
self.tokens.append(str(error)) def generate_tokens(self):
while not self.finish or self.tokens:
if self.tokens:
data = self.tokens.pop(0)
yield f"data: {data}\n\n"
else:
pass

注意:yield f"data: {data}\n\n" ,data是前端接受数据的参数,\n\n在SSE要求中必须添加。

5、总结

通过使用 SSE 技术和打字机样式输出,我们成功改进了聊天机器人的界面,实现了更加动态和流畅的聊天体验。这样的用户界面使得聊天机器人更加接近真实对话,提升了用户体验。

基于GPT搭建私有知识库聊天机器人(六)仿chatGPT打字机效果的更多相关文章

  1. ChatGirl 一个基于 TensorFlow Seq2Seq 模型的聊天机器人[中文文档]

    ChatGirl 一个基于 TensorFlow Seq2Seq 模型的聊天机器人[中文文档] 简介 简单地说就是该有的都有了,但是总体跑起来效果还不好. 还在开发中,它工作的效果还不好.但是你可以直 ...

  2. 计算机网络课设之基于UDP协议的简易聊天机器人

    前言:2017年6月份计算机网络的课设任务,在同学的帮助和自学下基本搞懂了,基于UDP协议的基本聊天的实现方法.实现起来很简单,原理也很简单,主要是由于老师必须要求使用C语言来写,所以特别麻烦,而且C ...

  3. 基于Docker搭建大数据集群(六)Hive搭建

    基于Docker搭建大数据集群(六)Hive搭建 前言 之前搭建的都是1.x版本,这次搭建的是hive3.1.2版本的..还是有一点细节不一样的 Hive现在解析引擎可以选择spark,我是用spar ...

  4. 版本控制系统之基于httpd搭建私有git仓库

    在上一篇博客中,我们主要聊到了git的基本工作原理和一些常用的git命令的使用:回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13787701.html:今天我 ...

  5. 基于docer搭建私有gitlab服务器

    今天闲着无聊,于是乎想用最近很流行的docker容器搭建一个自己的gitlab的服务器,关于docker和gitlab就不多介绍了,网上查了很多资料,貌似没有一个统一的方法,很乱很杂,而且很容易误导人 ...

  6. 微信智能机器人助手,基于hook技术,自动聊天机器人

    下载地址: 链接:https://pan.baidu.com/s/1N5uQ3gaG2IZu7f6EGUmBxA 提取码:md7z 复制这段内容后打开百度网盘手机App,操作更方便哦 微信智能助手说明 ...

  7. 基于CentOS搭建私有云服务

    系统版本:CentOS 7.2 64 位操作系统 部署 XAMPP 服务 下载 XAMPP(XAMPP 是个集成了多个组件的开发环境,包括 Apache + MariaDB + PHP + Perl. ...

  8. 智能聊天机器人——基于RASA搭建

    前言: 最近了解了一下Rasa,阅读了一下官方文档,初步搭建了一个聊天机器人. 官方文档:https://rasa.com/docs/ 搭建的chatbot项目地址: https://github.c ...

  9. 0基础搭建基于OpenAI的ChatGPT钉钉聊天机器人

    前言:以下文章来源于我去年写的个人公众号.最近chatgpt又开始流行,顺便把原文内容发到博客园上遛一遛. 注意事项和指引: 注册openai账号,需要有梯子进行访问,最好是欧美国家的IP,亚洲国家容 ...

  10. 深度学习项目——基于循环神经网络(RNN)的智能聊天机器人系统

    基于循环神经网络(RNN)的智能聊天机器人系统 本设计研究智能聊天机器人技术,基于循环神经网络构建了一套智能聊天机器人系统,系统将由以下几个部分构成:制作问答聊天数据集.RNN神经网络搭建.seq2s ...

随机推荐

  1. Midjourney 提示词工具(10 个国内外最好最推荐的)

    Midjourney,是一个革命性的基于人工智能的艺术生成器,可以从被称为提示的简单文本描述中生成令人惊叹的图像.Midjourney已经迅速成为艺术家.设计师和营销人员的首选工具(包括像我这样根本不 ...

  2. 超声波、毫米波、ToF激光雷达——在低功耗场景的应用选型

    前言: 目前主要的测距方式有:光学测距,超声波和微波雷达测距. 光学测距又可以分为:双目,结构光,ToF.微波雷达,在消费类产品中,常见的是波长在毫米级别的毫米波雷达.超声波应用比较多的是在车载倒车雷 ...

  3. .gitignore 文件语法介绍

    .gitignore 文件的作用 A gitignore file specifies intentionally untracked files that Git should ignore. Fi ...

  4. 基于.NetCore开发博客项目 StarBlog - (27) 使用JWT保护接口

    前言 这是StarBlog系列在2023年的第二篇更新 这几个月都在忙,更新变得很不勤快,但是拖着不更新我的心里更慌,很久没写,要开头就变得很难 说回正题,之前的文章里,我们已经把博客关键的接口都开发 ...

  5. Python_16 配置文件与封装

    一.查缺补漏 1. ctrl + alt +L 规范格式 2. Python 使用 ini&yaml 配置文件 http://testingpai.com/article/1621245437 ...

  6. 高精度地形DEM数据下载(NASA数据 12.5米分辨率)

    本文介绍从NASA阿拉斯加卫星设备处网站下载高精度DEM数据,下载的数据精度是12.5米分辨率. 目前国内大部分可以下载的dem数据都是30米或90米分辨率的,对于更高精度的数据要不就是需要付费下载, ...

  7. 2022-10-10:以下go语言代码输出什么?A:[1 2 3 0 1 2];B:死循环;C:[1 2 3 1 2 3];D:[1 2 3]。 package main import “fmt“

    2022-10-10:以下go语言代码输出什么?A:[1 2 3 0 1 2]:B:死循环:C:[1 2 3 1 2 3]:D:[1 2 3]. package main import "f ...

  8. 2021-01-30:redis中,Pipeline有什么好处?

    福哥答案2021-01-30:可以将多次 IO 往返的时间缩减为一次,减少多次IO延迟的开销.前提是 pipeline 执行的指令之间没有因果相关性. 多个指令之间没有依赖关系,可以使用 pipeli ...

  9. 2022-01-04:一个无序数组长度为n,所有数字都不一样,并且值都在[0...n-1]范围上。 返回让这个无序数组变成有序数组的最小交换次数。 来自小红书。

    2022-01-04:一个无序数组长度为n,所有数字都不一样,并且值都在[0-n-1]范围上. 返回让这个无序数组变成有序数组的最小交换次数. 来自小红书. 答案2022-01-04: 下标循环怼. ...

  10. vue全家桶进阶之路41:Vue3 语法糖<script setup>

    <script setup> 是 Vue 3 中的一种语法糖,它可以使组件的脚本更加简洁.易读,并且减少了一些样板代码.使用 <script setup>,你可以将组件的 pr ...