基于vue2 + flask实现对话大模型

基于vue2 + flask实现对话大模型


前言

这篇文章主要讲使用vue2 + flask实现对话大模型的实现历程。在实现过程中,我尝试了两种数据处理方式:
第一种方式是使用axios发送post请求,这种请求方式相对比较简单,前端只需要调用post接口,后端处理完毕后直接返回,前端拿到数据直接显示。
这种实现方式有一种弊端:在后台处理数据比较久时,前端一直会处于一个等待的状态,给用户带来不好的体验。为解决这个弊端,我又尝试了第二种方式。
第二种方式是使用fetch API进行流式返回和调用。这种方式就可以实现模型生成文本的同时逐步将结果发送给客户端,实现实时的交互体验。
注:查资料显示:Axios 是一个流行的 JavaScript HTTP 客户端,它本身并不直接支持流式数据处理

以下将介绍两种方式的实现方法:


一、通过axios请求的方式实现对话

后端

接口:

from flask import Flask
app = Flask(__name__)
app.secret_key = b'_dsay2L"F4Q8z\n\xec]/'

@app.route('/openAiDeekSeek', methods=['post'])
def getAisDataToOpenAi():
	requestParams = request.get_json()
	requestContext = requestParams.get('requestContext')
	openAiResponse = openAi_entry(requestContext)
	return jsonify(code=200, data=openAiResponse)

处理函数:

from openai import OpenAI
client = OpenAI(api_key="xxx", base_url="xxx")
def openAi_entry(requestContext):
	response = client.chat.completions.create(
		model="deepseek-chat",
   		messages=requestContext,
		stream=False
	)
	# 正常输出
    return response.choices[0].message.content

前端

<template>
<div class="diologMain" ref="diologMain">
	<div v-for="(msgItem, index) in message" :key="index">
        <div v-if="msgItem.role === 'user'" class="userContent">
            <div class="msgContent">{{ msgItem.content }}</div>
        </div>
        <div v-else-if="msgItem.role === 'assistant'" class="assistantContent">
            <div class="assisitantItem">
                <img class="assisstantIcon" src="@/assets/img/ui/ai.png" alt="">
                <span class="asssmsg">{{ msgItem.content }}</span>
            </div>
        </div>
    </div>
</div>
</template>

<script>
import { conversationByOnce } from '@/request/modules/dataApi.js'

export default{ 
	name: 'dialogIndex',
    data() {
        return {
            message: []
        }
    },
    methods: {
    	// 调用openai接口 - 一次性请求
        sendToAiRequest(requestData) {
            const that = this
            conversationByOnce(requestData).then(res => {
                if (res.status === 200) {
                    const responseData = res.data.data
                    const assistantMag = { 'role': 'assistant', content: responseData }
                    that.addChatMsgTo(assistantMag)
                } else {
                    that.isDiologLoading = false
                    const errorMsg = { 'role': 'assistant', content: '请求失败,请重试' }
                    that.addChatMsgTo(errorMsg)
                }
            })
        },
        // 增加对话记录
        addChatMsgTo(chatMsg) {
            this.message.push(chatMsg)
            this.userInput = ''
            this.$nextTick(() => {
                this.scrollToBottom()
            })
        },
        // 自动跳转到对话框底部
        scrollToBottom() {
            const diologMainContainer = this.$refs.diologMain
            diologMainContainer.scrollTop = diologMainContainer.scrollHeight
        },
    }
}
</script>

二、通过fetch API流式输出方式实现对话

后端

接口

from flask import Flask
app = Flask(__name__)
app.secret_key = b'_dsay2L"F4Q8z\n\xec]/'

@app.route('/openAiDeekSeek', methods=['post'])
def getAisDataToOpenAi():
	requestParams = request.get_json()
	requestContext = requestParams.get('requestContext')
	return openAi_entry_by_stream(requestContext)

处理函数

from openai import OpenAI
client = OpenAI(api_key="xxx", base_url="xxx")

def openAi_entry(requestType, jsonData, shipInfo):
    #  流式输出
	response = client.chat.completions.create(
		model="deepseek-chat",
		messages=jsonData,
		stream=True
	)
    def generate():
        for chunk in response:
            content = chunk.choices[0].delta.content
            if content:
                print("content:", content, end='', flush=True)
                yield content
    return Response(generate(), content_type="text/plain")

前端 - JavaScript

// 流式发送请求
sendToAiRequest(userMsg, requestData) {
    const that = this
    fetch('/local/openAiDeekSeek', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(requestData)
    }).then(response => {
			if (response.ok) return response.body
            else throw new Error('Network response was not ok');
        })
        .then(stream => {
            const reader = stream.getReader()
            const decoder = new TextDecoder()
            const assistantMsgIndex = that.message.push({ role: 'assistant', content: '' }) - 1;
            async function readAndLog() {
                const { value, done } = await reader.read();
                if (done) return
                const chunk = decoder.decode(value, { stream: true });
                that.updateMessageAndScroll(chunk, assistantMsgIndex)
                await readAndLog();
            }
            readAndLog().catch(err => console.error('Failed to read stream: ', err));
        }).catch(error => console.error('Failed to fetch stream: ', error))
},

// 判断对话框是否在最底下
isScrolledToBottom(container) {
	return container.scrollTop + container.clientHeight >= container.scrollHeight - 5
},
// 更新数据并滚动
updateMessageAndScroll(chunk, assistantMsgIndex) {
    // 更新现有的对话对象的内容
    this.$set(this.message, assistantMsgIndex, {
        ...this.message[assistantMsgIndex],
        content: this.message[assistantMsgIndex].content + chunk
    });
    // 跳转到最下面
    const diologMainContainer = this.$refs.diologMain
    if (this.isScrolledToBottom(diologMainContainer)) {
        this.$nextTick(() => {
            diologMainContainer.scrollTop = diologMainContainer.scrollHeight;
        });
    }
},

总结

以上仅仅是部分代码作为参考,具体实现逻辑还需根据个人情况完善。总体来说,流式调用更加符合大模型对话中的用户体验,希望读者可以从中得到一些启发。如有问题欢迎各位大佬讨论。


2025年1月22日补充

记录一下部署到nginx服务器时,流式输出效果消失:
个人理解:nginx服务器默认并不支持流式接收数据,需要修改配置手动打开流式接收数据模式。
在服务器中,容器中的nginx配置项如果没有映射到宿主机上,则nginx配置项一般在容器中的路径/etc/nginx/nginx.conf,如果映射到宿主机上,在对应的代理处添加配置即可。
在配置中的代理添加以下配置:

		proxy_buffering     off; # 关键:关闭代理缓冲    
        proxy_http_version  1.1; # 使用 HTTP/1.1 支持分块传输
        proxy_set_header    Connection ""; # 清除 Connection 头,避免 close 导致问题
        proxy_set_header    Host $host;
  1. 配置入口文件:/etc/nginx/nginx.conf:
http {                       
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;                  
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '            
                      '"$http_user_agent" "$http_x_forwarded_for"';                                         
    access_log  /var/log/nginx/access.log  main;                                                                                     
    sendfile        on;                                                      
    #tcp_nopush     on;                                                                                            
    keepalive_timeout  65;                                                   
    #gzip  on;               
    include /etc/nginx/conf.d/default.conf; # 默认的配置路径
} 
  1. 默认配置文件:/etc/nginx/conf.d/default.conf
 location /openApi/ {            
        proxy_pass http://xxx/;      
                                
        proxy_buffering     off;     
        proxy_http_version  1.1;      
        proxy_set_header    Connection "";
        proxy_set_header    Host $host;
    } 
Vue.js(一个用于构建用户界面的前端框架)和Flask(一个轻量级的Python web服务器框架)结合下,搭建一个自动机器人对话窗口的基本步骤如下: 1. **安装依赖**: - 安装Vue CLI创建项目:`npm install -g @vue/cli` - 创建Vue应用:`vue create my-chatbot-app` - 安装Vue组件库(如Element UI)以快速构建UI:`cd my-chatbot-app && vue add element-ui` 2. **设置Flask后端**: - 使用pip安装Flask:`pip install flask` - 创建一个Flask应用,并配置路由处理HTTP请求(例如POST请求用于接收用户输入)。 ```python from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/dialog', methods=['POST']) def dialog(): user_input = request.json['message'] # 在这里编写处理用户输入并返回机器人工回复的逻辑 return jsonify(automated_response) if __name__ == '__main__': app.run(debug=True) ``` 3. **实现聊天逻辑**: - 对接服务:将Flask应用与一个自然语言处理(NLP) API(如Google Dialogflow、Microsoft Bot Framework或自建的NLP模型)连接起来。处理用户的输入并生成机器人的回复。 4. **Vue页面设计**: - 使用Vue或Element UI创建一个对话框组件,包含文本输入区域和显示聊天记录的部分。 - 当用户输入时,通过Ajax发送数据到Flask的`/dialog`端点,获取机器人的回复并更新界面。 5. **前后端通信**: - 在Vue组件里使用axios或其他HTTP客户端库与Flask后端交互。 - 可能需要将Flask的URL添加到跨域设置中,允许Vue应用程序从非同源请求数据。 6. **测试与部署**: - 在本地运行Vue应用和Flask服务器进行测试。 - 部署时,可以将Flask应用部署到AWS、Heroku等云平台,同时将Vue应用打包成静态文件部署。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值