基于 Openai + Vue2 + Python Flask 搭建智能聊天应用流程
声明: 本项目(包含但不限于其代码、文档资料、设计思路以及所集成的各项功能等)仅作为学习交流用途而创建和分享,旨在帮助使用者提升相关知识与技能水平。未经书面授权,任何个人、组织或企业严禁将本项目用于商业用途,包括但不限于以盈利为目的进行售卖、二次开发后售卖、应用于商业产品或服务以获取经济收益等行为。若违反本声明规定,由此引发的一切法律责任将由违规使用者自行承担。
希望大家能够秉持合法、合规以及尊重知识产权的原则,合理利用本项目所提供的内容进行学习探索。
目录
目录
基于 Openai + Vue2 + Python Flask 搭建智能聊天应用流程
对话历史存储与时间相关问题处理函数(此处获取了系统当前时间)
一、项目概述
本项目旨在创建一个智能聊天应用,通过前端 Vue2 框架搭建用户界面,后端 Python Flask 框架处理业务逻辑,并集成 OpenAI 的 GPT-3.5-turbo 模型来实现智能对话功能,同时具备处理时间相关问题的能力。
二、获取Key
方法1: 详见官方文档(需要充值购买Token):OpenAI官方文档
方法2: 公益项目(自行获取Key):GitCode - 全球开发者的开源社区,开源代码托管平台
三、环境搭建
后端(Python)
确保已安装 Python3.x 版本(本文开发用的是3.x),使用 pip 安装所需依赖:
pip install flask flask_cors openai
前端(Vue2)
安装 Node.js,确保 npm 可用。使用 vue-cli 创建 Vue2 项目:
vue create chat-app
进入项目目录后,安装项目依赖:
npm install axios marked highlight.js
四、后端代码实现
导入模块与初始化 Flask 应用
import openai
from flask import Flask, request, jsonify
from datetime import datetime
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
对话历史存储与时间相关问题处理函数(此处获取了系统当前时间)
# 全局变量用于存储对话历史
conversation_history = []
def is_time_related_question(user_input):
"""
判断用户问题是否与时间或日期相关
"""
time_keywords = ["今天", "星期几", "几号", "几天", "多少天", "过年", "现在", "几点"]
for keyword in time_keywords:
if keyword in user_input:
return True
return False
def handle_time_related_question(user_input):
"""
根据用户的时间相关问题生成答案
"""
now = datetime.now()
if "星期几" in user_input:
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"]
return f"今天是{weekdays[now.weekday()]}"
elif "几号" in user_input or "今天" in user_input:
return f"今天是{now.strftime('%Y年%m月%d日')}"
elif "几点" in user_input or "现在" in user_input:
return f"现在是{now.strftime('%H点%M分')}"
elif "过年" in user_input or "多少天" in user_input:
new_year = datetime(now.year + 1, 1, 1)
days_until_new_year = (new_year - now).days
return f"距离过年还有{days_until_new_year}天"
return None
与 OpenAI 交互函数
def get_response_from_api(user_input):
"""
处理与模型对话的逻辑
"""
openai.api_key = "key" //自行替换
openai.base_url = "url" //自行替换
# 构造 messages 参数,包括历史对话和当前输入
global conversation_history
messages = conversation_history + [{"role": "user", "content": user_input}]
# 调用 OpenAI 接口
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages
)
# 获取回复
assistant_reply = completion.choices[0].message.content
# 将用户输入和模型回复添加到对话历史
conversation_history.append({"role": "user", "content": user_input})
conversation_history.append({"role": "assistant", "content": assistant_reply})
if len(conversation_history) > 20:
conversation_history = conversation_history[-20:]
return assistant_reply
路由定义与请求处理
@app.route('/ask', methods=['POST'])
def ask():
# 获取前端传过来的问题
user_input = request.json.get('question')
if not user_input:
return jsonify({"error": "问题不能为空"}), 400
# 判断是否是时间相关的问题
if is_time_related_question(user_input):
# 直接处理时间相关问题
response_text = handle_time_related_question(user_input)
else:
# 调用 API 获取非时间问题的回复
response_text = get_response_from_api(user_input)
return jsonify({"response": response_text})
启动应用
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0',port=5003)
五、前端代码实现
模板结构搭建
<template>
<div class="chat-container">
<el-header class="chat-header">
xxx
</el-header>
<el-main class="chat-messages" ref="chatMessages">
<div v-for="(message, index) in messages" :key="index" :class="['message', message.type]">
<div class="bubble" v-html="renderMessage(message.text)"></div>
</div>
</el-main>
<el-footer class="chat-footer">
<el-input
v-model="userInput"
placeholder="请输入消息..."
@keyup.enter="sendMessage"
style="flex: 1;"
/>
<i @click="sendMessage" class="el-icon-s-promotion icon-large"></i>
</el-footer>
</div>
</template>
脚本逻辑编写
<script>
import axios from 'axios';
import {marked} from 'marked';
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css';
marked.setOptions({
highlight: function(code, lang) {
return hljs.highlight(lang, code).value; // 使用highlight.js进行高亮
}
});
export default {
name: 'ChatApp',
data() {
return {
userInput: '',
messages: [
{ text: '你好,有什么需要帮助的吗?', type: 'received' }
]
};
},
methods: {
async sendMessage() {
const userInput = this.userInput.trim();
if (userInput) {
this.messages.push({ text: userInput, type: 'sent' });
this.userInput = '';
this.scrollToBottom();
try {
const response = await axios.post('http://localhost:5003/ask', {
question: userInput
});
const assistantReply = response.data.response;
this.messages.push({ text: assistantReply, type: 'received' });
this.scrollToBottom();
} catch (error) {
console.error('发送请求时发生错误:', error);
this.messages.push({text: '抱歉,出现了错误。', type: 'received'});
this.scrollToBottom();
}
}
},
scrollToBottom() {
this.$nextTick(() => {
const chatMessages = this.$refs.chatMessages;
chatMessages.scrollTop = chatMessages.scrollHeight;
});
},
renderMessage(message) {
// 使用 marked 渲染 Markdown
let html = marked(message);
// 使用 highlight.js 高亮所有代码块
html = html.replace(/<pre><code class="language-(\w+)">([\s\S]*?)<\/code><\/pre>/g, (match, lang, code) => {
const highlightedCode = hljs.highlight(lang, code).value; // 高亮代码
return `<pre><code class="hljs ${lang}">${highlightedCode}</code></pre>`; // 返回高亮的代码块
});
return html;
}
}
};
</script>
样式设置
<style scoped>
.chat-container {
width: 100%;
height: 700px;
max-width: 600px;
margin: 20px auto;
background-color: #fff;
border-radius: 30px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-header {
background-color: #007b5f;
color: white;
text-align: center;
padding: 10px;
font-size: 18px;
}
.chat-messages {
flex: 1;
padding: 10px;
overflow-y: auto;
background-color: #f9f9f9;
}
.message {
display: flex;
margin-bottom: 10px;
}
.message.sent {
justify-content: flex-end;
}
.message.sent.bubble {
background-color: #dcf8c6;
margin-left: 10px;
}
.message.received.bubble {
background-color: #fff;
margin-right: 10px;
border: 1px solid #e0e0e0;
}
.chat-footer {
display: flex;
padding: 10px;
background-color: #fff;
border-top: 1px solid #e0e0e0;
}
.icon-large {
font-size: 32px;
cursor: pointer;
color: #007b5f;
margin-left: 10px;
}
pre {
background-color: #2d2d2d;
color: white;
padding: 10px;
border-radius: 5px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
box-sizing: border-box;
}
code {
font-family: "Courier New", Courier, monospace;
}
</style>
六、测试
本地测试
启动后端 Flask 应用:在后端项目目录下执行 python app.py(假设后端主文件为 app.py),确保后端服务正常运行,监听在 http://0.0.0.0:5003。
启动前端开发服务器:在前端项目目录下,执行 npm run serve,在浏览器中访问前端应用地址(通常为 http://localhost:8080),进行聊天功能测试,检查是否能正常发送消息、接收回复,时间相关问题是否能正确处理,以及界面显示是否正常。