后端使用python flask,前端使用vue,本片文章所有代码均由tongyi lingma自动完成
后端搭建:
安装flask
pip install Flask
安装flask-cors(解决跨域问题)
pip install flask-cors
安装openai
pip install openai
安装环境变量配置包
pip install python-dotenv openai
创建.env文件,配置openai的key
创建py文件
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
from flask import Flask, request, jsonify
from flask_cors import CORS
# 加载 .env 文件中定义的环境变量
_ = load_dotenv(find_dotenv())
# 初始化 OpenAI 客户端
client = OpenAI() # 默认使用环境变量中的 OPENAI_API_KEY 和 OPENAI_BASE_URL
# 初始化 Flask 应用
app = Flask(__name__)
# 允许跨源请求
cors = CORS(app, resources={r"/api/*": {"origins": "http://localhost:8080"}})
def get_completion(prompt, response_format="text", model="gpt-3.5-turbo"):
messages = [{"role": "user", "content": prompt}] # 将 prompt 作为用户输入
response = client.chat.completions.create( # 注意这里是 ChatCompletion
model=model,
messages=messages,
temperature=0, # 模型输出的随机性,0 表示随机性最小
# 返回消息的格式,text 或 json_object
response_format={"type": response_format},
)
return response.choices[0].message.content # 返回模型生成的文本
@app.route('/api/answer', methods=['POST'])
def answer_question():
# 获取请求中的问题数据
question = request.json.get('question')
if not question:
return jsonify(error='Missing required parameter: question'), 400
# 调用 OpenAI GPT-3 模型
answer = get_completion(question, response_format="text")
return jsonify(answer=answer)
if __name__ == '__main__':
app.run(debug=True)
启动后端服务
前端搭建:
安装vue
npm install -g @vue/cli
安装axios
npm install axios
创建前端项目
npx @vue/cli create dialog-robot
添加router
npm install vue-router@next
src下新增router.js文件
import { createRouter, createWebHashHistory } from 'vue-router';
import Chat from '@/views/Chat.vue';
const routes = [
{
path: '/chat',
component: Chat,
},
{
path: '/', // 重定向路由
redirect: '/chat',
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;
修改main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
const app = createApp(App);
app.use(router);
app.mount('#app');
src下创建views目录,新增Chat.vue文件
<template>
<div class="chat-container">
<div class="chat-header">
<img :src="robotAvatar" alt="Robot Avatar" class="chat-avatar">
<h3 class="chat-title">对话机器人</h3>
</div>
<div class="chat-body">
<div v-for="(message, index) in chatHistory" :key="index" class="chat-message">
<img v-if="message.isBot" :src="robotAvatar" alt="Robot Avatar" class="chat-message-avatar">
<p v-if="!message.isBot" class="chat-message-user-avatar">您</p>
<div class="chat-message-content">
<span class="chat-message-timestamp">{{ message.timestamp }}</span>
<div>
<span v-html="message.text"></span>
</div>
</div>
</div>
</div>
<div class="chat-footer">
<textarea v-model="inputText" placeholder="请输入您的问题或留言..." @keydown.enter.prevent="sendMessage"></textarea>
<button @click="sendMessage" class="send-button">发送</button>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'ChatRobot',
data() {
return {
robotAvatar: require('@/assets/robot-avatar.png'), // 替换为实际机器人头像路径
chatHistory: [
// 初始聊天记录(可从后端API获取或模拟数据)
],
inputText: '',
};
},
methods: {
async sendMessage() {
if (!this.inputText.trim()) return;
const question = this.inputText;
this.chatHistory.push({ isBot: false, text: question, timestamp: new Date().toLocaleTimeString() });
this.inputText = '';
try {
const response = await axios.post('http://127.0.0.1:5000/api/answer', { question }, { timeout: 5000 }); // 设置超时时间(可选)
if (response.status === 200 && response.data.answer) {
const answer = response.data.answer;
this.chatHistory.push({ isBot: true, text: answer, timestamp: new Date().toLocaleTimeString() });
} else {
console.error('Failed to get answer from server:', response.statusText);
// 可以在这里添加错误处理,如显示错误消息或重试等
}
} catch (error) {
console.error('Error while sending request:', error.message);
// 可以在这里添加错误处理,如显示错误消息或重试等
}
},
},
};
</script>
<style scoped>
.chat-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.chat-header {
display: flex;
align-items: center;
padding: 1rem;
background-color: #f5f5f5;
}
.chat-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
margin-right: 1rem;
}
.chat-title {
font-size: 1.2rem;
font-weight: bold;
}
.chat-body {
flex-grow: 1;
overflow-y: auto;
padding: 1rem;
}
.chat-message {
display: flex;
align-items: flex-start;
margin-bottom: 1rem;
}
.chat-message-avatar,
.chat-message-user-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 1rem;
font-size: 0.9rem;
color: white;
background-color: #6c757d;
text-align: center;
}
.chat-message-avatar {
object-fit: cover;
}
.chat-message-content {
flex-grow: 1;
min-width: 0;
}
.chat-message-text {
display: inline-block;
max-width: ¾;
}
.chat-message-timestamp {
font-size: 0.½rem;
color: #6c757d;
margin-top: 0.25rem;
}
.chat-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background-color: #f5f5f5;
border-top: 1px solid #dee2e6;
}
textarea {
flex-grow: 1;
min-height: ¼;
padding: 0.5rem;
resize: none;
border: none;
outline: none;
}
.send-button {
padding: 0.5rem 1rem;
border: none;
background-color: #0d6efd;
color: white;
cursor: pointer;
}
</style>
项目结构
启动前端
npm run serve
本地访问http://localhost:8080/chat
开始聊天