利用 SSE 实现流式 AI 聊天交互(三)
在 AI 赋能的时代,即时交互式对话体验成为众多应用的核心功能之一。本文将介绍如何使用 流式 SSE (Server-Sent Events) 技术,实现高效的 AI 聊天交互,提供更加丝滑的用户体验。
一、SSE 介绍
SSE (Server-Sent Events) 是一种基于 HTTP 的服务器推送技术,适用于需要实时更新但数据流量较小的场景,例如 AI 对话、股票行情、新闻推送等。它的主要特点包括:
单向通信:服务器可以主动向客户端推送消息,而客户端仅能接收。
轻量级:相比 WebSocket,SSE 使用 HTTP 连接,无需额外协议支持。
自动重连:连接断开时,浏览器会自动尝试重新建立连接。
相比 WebSocket,SSE 更适合 AI 聊天等对实时性要求较高但数据方向单一的场景。
二、实现思路
传统的 AI 聊天一般是用户发送请求后,后端计算完成后一次性返回结果。但对于长文本生成,这种方式可能导致较长的响应延迟。
相比之下,流式响应 (Streaming) 可以让 AI 逐步输出生成内容,从而提升用户体验。
我们的实现基于 Odoo 18 + OpenAI API,通过 SSE (Server-Sent Events) 让前端实时接收 AI 生成的内容,达到流畅的交互效果。
三、后端实现
在 Odoo 的 @http.route 中,我们定义了一个流式接口,负责与 AI 进行通信,并通过 SSE 将生成内容逐步推送到前端。
后端代码:请求 AI 生成内容
@http.route('/ai/stream_chat', type='http', auth='public', cors='*')
def ai_stream_chat(self, **kwargs):
user_id = request.session.uid
user_message = kwargs.get('user_message')
file_content = kwargs.get('file_content', '')
api_url = request.env['ir.config_parameter'].sudo().get_param('ai_chat_url')
api_key = request.env['ir.config_parameter'].sudo().get_param('ai_chat_api_key')
ai_model = request.env['ir.config_parameter'].sudo().get_param('ai_chat_model')
# 初始化 OpenAI 客户端
client = OpenAI(base_url=api_url, api_key=api_key)
messages = [
{"role": "system", "content": "我是一个AI助手,我的名字叫小加!"},
{"role": "user", "content": file_content[:5000]},
{"role": "user", "content": user_message}
]
def event_stream():
try:
completion = client.chat.completions.create(
model=ai_model,
messages=messages,
stream=True,
extra_headers={
"HTTP-Referer": "DeepSeek R1",
"X-Title": "Odoo AIChat"
}
)
response_text = ""
for chunk in completion:
delta = chunk.choices[0].delta
if delta and delta.content:
response_text += delta.content
yield f"data: {chunk.model_dump_json()}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
yield f"data: {{\"error\": \"{str(e)}\"}}\n\n"
return Response(event_stream(), content_type='text/event-stream')
实现细节:
参数获取:前端传递
user_message和file_content。AI 请求:使用 OpenAI API 发起流式请求。
SSE 事件流:遍历 AI 生成结果并逐步推送。
异常处理:防止请求失败导致 SSE 断开。
四、前端实现
前端使用 EventSource 监听 SSE 事件流,逐步渲染 AI 回复内容。
前端代码:接收 AI 数据并实时渲染
function startAIStream(userMessage, fileContent, base64File, fileName) {
const chatBox = document.getElementById('chat-box');
const botMessageDiv = document.createElement('div');
botMessageDiv.classList.add('message', 'bot');
botMessageDiv.innerHTML = `
<img src="./image/icon1.gif" alt="Bot">
<span id="bot-response">AI 正在思考...</span>
<span id="bot-time" style="font-size: 10px; color: #888; margin-left: 10px;"></span>`;
chatBox.appendChild(botMessageDiv);
chatBox.scrollTop = chatBox.scrollHeight;
const botResponseSpan = botMessageDiv.querySelector("#bot-response");
const botTimeSpan = botMessageDiv.querySelector("#bot-time");
const params = new URLSearchParams({
user_message: userMessage,
file_content: fileContent
});
const eventSource = new EventSource(`/ai/stream_chat?${params.toString()}`);
let fullBotMessage = "";
botResponseSpan.innerText = "";
eventSource.onmessage = function (event) {
if (event.data === "[DONE]") {
eventSource.close();
botTimeSpan.innerText = new Date().toLocaleTimeString();
createHistoryRecord(userMessage, fullBotMessage, base64File, fileName);
return;
}
try {
const jsonData = JSON.parse(event.data);
const deltaContent = jsonData.choices[0]?.delta?.content;
if (deltaContent) {
fullBotMessage += deltaContent;
requestAnimationFrame(() => {
botResponseSpan.innerHTML = marked.parse(fullBotMessage);
chatBox.scrollTop = chatBox.scrollHeight;
});
}
} catch (e) {
console.error("解析数据出错:", e);
}
};
eventSource.onerror = function (err) {
console.error("SSE 连接错误:", err);
eventSource.close();
botResponseSpan.innerText += "\n[连接已断开]";
};
}
五、效果展示
当用户发送消息后,前端立即显示 AI 正在思考...,随后 AI 逐步返回内容,并以 Markdown 解析进行美化。如下图所示:

六、项目特点
流式传输:AI 逐步生成内容,提升用户体验。
轻量级实现:基于 SSE,避免复杂的 WebSocket 连接管理。
Markdown 支持:使用
marked.js美化 AI 回复。自动重连:确保长时间使用时连接稳定。
如果你也在开发 AI 聊天功能,不妨尝试这种流式优化方案!
利用 SSE 实现流式 AI 聊天交互(三)的更多相关文章
- Android之利用HTTP网络通信实现与PHP的交互(三)
Android与PHP的交互是通过Http网络编程来实现的,利用php访问数据库,并且操作数据库中的数据,利用php作为接口,使Android连接数据库. 一般情况下,我们使用Json格式进行传输,利 ...
- 流式大数据处理的三种框架:Storm,Spark和Samza
许多分布式计算系统都可以实时或接近实时地处理大数据流.本文将对三种Apache框架分别进行简单介绍,然后尝试快速.高度概述其异同. Apache Storm 在Storm中,先要设计一个用于实时计算的 ...
- [转载]流式大数据处理的三种框架:Storm,Spark和Samza
许多分布式计算系统都可以实时或接近实时地处理大数据流.本文将对三种Apache框架分别进行简单介绍,然后尝试快速.高度概述其异同. Apache Storm 在Storm中,先要设计一个用于实时计算的 ...
- Java8 新特性之流式数据处理
一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助于流式处理可以在一行中实现.比如我们希望对一个包含整数的 ...
- Apple公司Darwin流式服务器源代码分析
当前,伴随着Internet的飞速发展,计算机网络已经进入到每一个普通人的家庭.在这个过程中,一个值得我们关注的现象是:Internet中存储和传输内容的构成已经发生了本质的改变,从传统的基于文本或少 ...
- Java8 新特性之流式数据处理(转)
转自:https://www.cnblogs.com/shenlanzhizun/p/6027042.html 一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作 ...
- java1.8新特性之stream流式算法
在Java1.8之前还没有stream流式算法的时候,我们要是在一个放有多个User对象的list集合中,将每个User对象的主键ID取出,组合成一个新的集合,首先想到的肯定是遍历,如下: List& ...
- Java1.8新特性 - Stream流式算法
一. 流式处理简介 在我接触到java8流式数据处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助于流式处理可以在一行中实现.比如我们希望对一个包 ...
- Java8 中的流式数据处理
java8的流式处理极大了简化我们对于集合.数组等结构的操作,让我们可以以函数式的思想去操作,本篇文章将探讨java8的流式数据处理的基本使用. 一. 流式处理简介 在我接触到java8流式处理的时候 ...
- JDK8新特性(二) 流式编程Stream
流式编程是1.8中的新特性,基于常用的四种函数式接口以及Lambda表达式对集合类数据进行类似流水线一般的操作 流式编程分为大概三个步骤:获取流 → 操作流 → 返回操作结果 流的获取方式 这里先了解 ...
随机推荐
- Windows 提权-SeBackupPrivilege 特权
本文通过 Google 翻译 Sebackupprivilege – Windows Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注 ...
- Jsoncpp的安装与使用方式
JsonCpp 是一个C++库,用于解析和生成JSON数据.它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式. 安装Jsoncpp 我们可以输入以下命令安装jsoncp ...
- AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
一.前言:AI编程时代的双雄争霸 2025年3月,字节跳动推出的Trae以"国内首个AI原生IDE"之名杀入战场,直指海外明星产品Cursor的软肋.这场工具革命背后,是免费与付费 ...
- 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
概述 先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车.可以坐汽车.可以坐火车.可以坐飞机. 作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多,可以选择Idea进 ...
- QSound、QSoundEffect播放WAV音频
QSound.QSoundEffect播放WAV音频 本文旨在介绍QSound.QSoundEffect的简单播放音频的方法以及对这两个类的一些基本介绍 文章目录 QSound.QSoundEffec ...
- [Qt基础-06] QButtonGroup
QButtonGroup 本文主要根据QT官方帮助文档以及日常使用,简单的介绍一下QButtonGroup的功能以及基本使用 文章目录 QButtonGroup 简介 信号和槽 简介 有的时候,我们会 ...
- 使用Shader画常见的数学函数
使用Shader画常见的数学函数 本篇博文的灵感来自于Shader Books这一小节:https://thebookofshaders.com/05/?lan=ch 代码运行网站:http://ed ...
- Ant Design Pro 中 点击子菜单的时候,其他菜单不自动收起来
记录一波自己在这段时间碰到的一个Ant Design Pro 的坑: 每次点击菜单都会将其他菜单自动收起来,导致一系列的用户体验不佳. 设置defaultOpenAll: true后依然不管用 经过各 ...
- RegisterClass注册后getclass总是nil,why?
这个问题有点老.但是有点烦人. 一般流程是 RegisterClass后通过getclass or findclass就会成功. 可是莫名其妙出现总是返回nil.咱也不清楚,网上找了好久,一个久远的帖 ...
- Excel百万数据如何快速导入?
前言 今天要讨论一个让无数人抓狂的话题:如何高效导入百万级Excel数据. 去年有家公司找到我,他们的电商系统遇到一个致命问题:每天需要导入20万条商品数据,但一执行就卡死,最长耗时超过3小时. 更魔 ...