首页 > 人工智能 > 人工智能 > 大模型问答助手前端实现打字机效果
来源:京东云开发者

| WebSockets | ||
id: 123event: updatedata: {"message": "This is a test message"}
const options = {withCredentials: true // 允许跨域请求携带凭证};// 创建一个 EventSource 对象以开始监听const eventSource = new EventSource('your_server_url', options);
// 监听连接打开事件eventSource.onopen = function(event) {console.log('Connection to SSE server established!');};// 监听标准消息事件eventSource.onmessage = function(event) {console.log('Received data from server: ', event.data);};// 监听错误事件eventSource.onerror = function(event) {console.error('An error occurred while receiving data:', event);};
// 监听一个名为 "update" 的自定义事件eventSource.addEventListener('update', function(event) { console.log('Received update event:', event.data);});eventSource.close();
const http = require('http');const fs = require('fs');// 初始化 HTTP 服务器http.createServer((req, res) => {// 为了简洁,将响应方法抽离成函数function serveFile(filePath, contentType) {fs.readFile(filePath, (err, data) => {if (err) {res.writeHead(500);res.end('Error loading the file');} else {res.writeHead(200, {'Content-Type': contentType});res.end(data);}});}function handleSSEConnection() {res.writeHead(200, {'Content-Type': 'text/event-stream','Cache-Control': 'no-cache','Connection': 'keep-alive'});let id = 0;const intervalId = setInterval(() => {const message = {event: 'customEvent',id: id++,retry: 30000,data: { id, time: new Date().toISOString() }};for (let key in message) {if (key !== 'data') {res.write(`${key}: ${message[key]}\n`);} else {res.write(`data: ${JSON.stringify(message.data)}\n\n`);}}}, 1000);req.on('close', () => {clearInterval(intervalId);res.end();});}switch (req.url) {case '/':serveFile('index.html', 'text/html');break;case '/events':handleSSEConnection();break;default:res.writeHead(404);res.end();break;}}).listen(3000);console.log('Server listening on port 3000');
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>SSE Demotitle>head><body><h1>SSE Demoh1><button onclick="connectSSE()">建立 SSE 连接button><button onclick="closeSSE()">断开 SSE 连接button><br /><br /><div id="message">div><script>const messageElement = document.getElementById('message');let eventSource;// 连接 SSEfunction connectSSE() {eventSource = new EventSource('/events');eventSource.addEventListener('customEvent', handleReceivedMessage);eventSource.onopen = handleConnectionOpen;eventSource.onerror = handleConnectionError;}// 断开 SSE 连接function closeSSE() {eventSource.close();appendMessage(`SSE 连接关闭,状态${eventSource.readyState}`);}// 处理从服务端收到的消息function handleReceivedMessage(event) {const data = JSON.parse(event.data);appendMessage(`${data.id} --- ${data.time}`);}// 连接建立成功的处理函数function handleConnectionOpen() {appendMessage(`SSE 连接成功,状态${eventSource.readyState}`);}// 连接发生错误的处理函数function handleConnectionError() {appendMessage(`SSE 连接错误,状态${eventSource.readyState}`);}// 将消息添加到页面上function appendMessage(message) {messageElement.innerHTML += `${message}
`;}script>body>html>

/*** Utf8ArrayToStr: 将Uint8Array的数据转为字符串* @param {Uint8Array} array - Uint8Array数据* @return {string} - 转换后的字符串*/function Utf8ArrayToStr(array) {const decoder = new TextDecoder();return decoder.decode(array);}/*** fetchStream: 建立一个SSE连接,并支持多种HTTP请求方式* @param {string} url - 请求的URL地址* @param {object} params - 请求的参数,包括HTTP方法、头部、主体内容等* @return {Promise} - 返回一个Promise对象*/const fetchStream = (url, params) => {const { onmessage, onclose, ...otherParams } = params;return fetch(url, otherParams).then(response => {let reader = response.body?.getReader();return new ReadableStream({start(controller) {function push() {reader?.read().then(({ done, value }) => {if (done) {controller.close();onclose?.();return;}const decodedData = Utf8ArrayToStr(value);console.log(decodedData);onmessage?.(decodedData);controller.enqueue(value);push();});}push();}});}).then(stream => {return new Response(stream, {headers: { "Content-Type": "text/html" }}).text();});};// 示例:调用fetchStream函数fetchStream("/events", {method: "POST", // 使用POST方法headers: {"content-type": "application/json"},credentials: "include",body: JSON.stringify({// 这里列出了一些示例数据,实际业务场景请替换为你的数据boxId: "exampleBoxId",sessionId: "exampleSessionId",queryContent: "exampleQueryContent"}),onmessage: res => {console.log(res); // 当接收到消息时的回调},onclose: () => {console.log("Connection closed."); // 当连接关闭时的回调}});
// 定义请求主体的接口,需要根据具体的应用场景定义具体的属性interface RequestBody {// 示例属性,具体属性需要根据实际需求定义key?: string;}// 错误响应的结构interface ErrorResponse {error: string;detail: string;}// 返回值类型定义type TextStream = ReadableStreamDefaultReader<Uint8Array>;// 获取数据并返回TextStreamasync function fetchData(url: string,body: RequestBody,accessToken: string,onError: (message: string) => void): Promise<TextStream | undefined> {try {// 尝试发起请求const response = await fetch(url, {method: "POST",cache: "no-cache",keepalive: true,headers: {"Content-Type": "application/json",Accept: "text/event-stream",Authorization: `Bearer ${accessToken}`,},body: JSON.stringify(body),});// 检查是否有冲突,例如重复请求if (response.status === 409) {const error: ErrorResponse = await response.json();onError(error.detail);return undefined;}return response.body?.getReader();} catch (error) {onError(`Failed to fetch: ${error.message}`);return undefined;}}// 读取流数据async function readStream(reader: TextStream): Promise<string | null> {const result = await reader.read();return result.done ? null : new TextDecoder().decode(result.value);}// 处理文本流数据async function processStream(reader: TextStream,onStart: () => void,onText: (text: string) => void,onError: (error: string) => void,shouldClose: () => boolean): Promise<void> {try {// 开始处理数据onStart();while (true) {if (shouldClose()) {await reader.cancel();return;}const text = await readStream(reader);if (text === null) break;onText(text);}} catch (error) {onError(`Processing stream failed: ${error.message}`);}}/*** 主要的导出函数,用于处理流式文本数据。** @param url 请求的URL。* @param body 请求主体内容。* @param accessToken 访问令牌。* @param onStart 开始处理数据时的回调。* @param onText 接收到数据时的回调。* @param onError 错误处理回调。* @param shouldClose 判断是否需要关闭流的函数。*/export async function streamText(url: string,body: RequestBody,accessToken: string,onStart: () => void,onText: (text: string) => void,onError: (error: string) => void,shouldClose: () => boolean): Promise<void> {const reader = await fetchData(url, body, accessToken, onError);if (!reader) {console.error("Reader is undefined!");return;}await processStream(reader, onStart, onText, onError, shouldClose);}

-end-
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70027828/viewspace-2993077/ ,如需转载,请注明出处,否则将追究法律责任。