FastAPI: websocket的用法及举例

server/2024/10/21 3:06:33/

1. Websocket

1.1 Websocket介绍

  WebSocket 是一种在单个TCP连接上进行全双工通信的协议,允许客户端和服务器之间相互发送数据,而不需要像传统的HTTP请求-响应模型那样频繁建立和断开连接。
全双工通信(Full-Duplex Communication)是一种通信模式,允许通信双方同时发送和接收数据。换句话说,数据可以同时从两端双向传输,而不会相互阻塞或干扰。

1.2 FastAPI中的Websocket

  FastAPI提供了对WebSocket的原生支持,允许你轻松构建高效的实时应用,如聊天室、实时数据更新等。

1.2.1 装饰器

  FastAPI中与WebSocket相关的主要装饰器为 @app.websocket。该装饰器的作用和参数如下:

  • 作用:将一个路径(如/ws)与一个处理WebSocket请求的函数关联。当客户端通过WebSocket连接该路径时,FastAPI会调用该函数处理连接和通信。
  • 参数:它接受的参数与其他路由装饰器相同,主要是路径(URL),可选地也能设置依赖项、权限等。

代码举例如下(当客户端通过WebSocket连接/ws路径时,FastAPI将执行下面的websocket_endpoint函数):

from fastapi import FastAPI, WebSocket
app = FastAPI()
# 定义一个 WebSocket 路由
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):await websocket.accept()  # 接受 WebSocket 连接while True:data = await websocket.receive_text()  # 接收来自客户端的消息await websocket.send_text(f"Message text was: {data}")  # 回复消息给客户端
websocket_23">1.2.2 websocket相关方法

  FastAPI提供了处理WebSocket各种事件的方法,包括接受消息、发送消息、关闭连接等。具体如下:

  • websocket.accept:接受WebSocket连接请求。
  • websocket.receive_text:接收客户端发来的文本消息。
  • websocket.send_text:向客户端发送文本消息。
  • websocket.close:关闭WebSocket连接。

2. 构建对话机器人

  这里我们用FastAPI和React构建一个聊天机器人的聊天界面。这里关于机器人的后端处理逻辑这里不做详细介绍,而前端部分主要介绍App.tsx和ChatPag.tsx内容,不介绍CSS部分。具体代码如下:
React中App.tsx代码如下:

import './App.css';
import ChatPage from './components/ChatPage';function App() {return (<div className="App"><div className="header"><div className="header-logo"><img src="https://cdn.builder.io/api/v1/image/assets/TEMP/b0db057162d379f22892cd5ae4d13c509717e0a81da39be3f65cb94e15556ed7?apiKey=0682bce60b3549f085131079f1bf89f0&&apiKey=0682bce60b3549f085131079f1bf89f0" alt="Chainlit" /> <div className="header-title">SmartRecommend服务推荐助手</div></div></div><div className='body-container'><div className="main"><div className='chatpage'><ChatPage /></div></div></div></div>);
}
export default App;

React中ChatPage.tsx代码如下:

import "./ChatPage.css";
import { useEffect, useState} from "react";
import { nanoid } from 'nanoid';interface Message{id:string,name:string,type:string,output:string,createdAt:number|string,
}
function ChatPage() {const [inputValue, setInputValue] = useState("");const [messages,setMessages] = useState<Message[]>([]);const [socket,setSocket] = useState<WebSocket|null>(null);useEffect(() => {const ws = new WebSocket("ws://localhost:8000/ws/chat");ws.onopen = () => {console.log("websocket链接已建立!");};ws.onmessage = (event) => {const message = JSON.parse(event.data);setMessages((prevMessages) => [...prevMessages, message]);};ws.onerror = (error) => {console.log('WebSocket错误:', error);};ws.onclose=()=>{console.log("websocket链接已关闭!");}setSocket(ws);return () => {ws.close();}},[]);const handleSendMessage = () => {const content = inputValue.trim();if (content) {const message: Message={id: nanoid(),name: "User",type: "user_message",output: content,createdAt: Date.now(),};setMessages((prevMessages) => [...prevMessages, message]);socket?.send(JSON.stringify(message));}setInputValue("");};const renderMessage = (message:Message,index:number) => {const dateOptions: Intl.DateTimeFormatOptions = {hour: "2-digit",minute: "2-digit",};const date = new Date(message.createdAt).toLocaleTimeString(undefined,dateOptions);if(message.type === "user_message") {return (<div key={message.id} className="chat-box-user"><div className="user-avatar">U</div><div className="bot-user-content"><div className="user-icon"><div className="bot-user-name">{message.name}</div><div className="bot-user-time">{date}</div></div><div className="user-chat-message">{message.output}</div></div></div>);} else {return (<div key={message.id} className="chat-box-bot"><div className="bot-avatar">B</div><div className="bot-user-content"><div className="bot-icon"><div className="bot-user-name">{message.name}</div><div className="bot-user-time">{date}</div></div><div className="bot-chat-message">{message.output}</div></div></div>);};};return (<div className="chat-container"><div className="chat-box">{messages.map(renderMessage)}</div><div className="fixed-bottom"><input className="fixed-bottom-input" type="text"value={inputValue}placeholder="你可以输入“你好”唤醒服务"onChange={(e) => setInputValue(e.target.value)}onKeyUp={(e) => {if (e.key === "Enter") {handleSendMessage();}}}></input><button onClick={handleSendMessage} className="button" type="submit">Send</button></div></div>); 
}
export default ChatPage;

后端FastAPI代码:

from fastapi import FastAPI, WebSocket,HTTPException
import uvicorn
from fastapi.middleware.cors import CORSMiddleware
from typing import List
import json
import datetime
from nanoid import generate
import httpxapp=FastAPI()
app.add_middleware(CORSMiddleware,allow_origins=["http://localhost:3000"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],
)
clients: List[WebSocket] = []RASA_API_URL="http://localhost:5005/webhooks/rest/webhook"@app.websocket("/ws/chat")
async def websocket_endpoint(websocket: WebSocket):await websocket.accept()clients.append(websocket)try:while True:data = await websocket.receive_text()for client in clients:text={"id": generate(),"name":"Bot","type":"bot_message","output":json.loads(data)["output"],"createdAt":int(datetime.datetime.now().timestamp()*1000)}text=json.dumps(text)await client.send_text(text)except Exception as e:print(e)clients.remove(websocket)if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=8000)

http://www.ppmy.cn/server/127378.html

相关文章

RabbitMQ的应用问题

一、幂等性保障 幂等性是数学和计算机科学中某些运算的性质, 它们可以被多次应⽤, ⽽不会改变初始应⽤的结果 数学上的幂等性: f(x)=f(f(x)) |x| 数据库操作幂等性: 数据库的 select 操作. 不同时间两次查询的结果可能不同, 但是这个操作是符合幂等性的. 幂等性指的是对资…

Windows环境 源码编译 FFmpeg

记录一下windows环境纯代码编译ffmeg的过程&#xff01; 目录 一、安装MSYS2 1.下载安装 2.配置 3.修改源 4.测试与更新 二、安装其他必要工具 1.安装MinGW-w64 2.安装git 3..安装make等工具 4.编译前的其他准备工作 ①.重命名link.exe ②.下载和安装YASM ③.安装…

小程序原生-利用setData()对不同类型的数据进行增删改

1. 声明和绑定数据 wxml文件 <view> {{school}} </view> <view>{{obj.name}}</view> <view id"{{id}}" > 绑定属性值 </view> <checkbox checked"{{isChecked}}"/> <!--算数运算--> <view>{{ id …

爬虫及数据可视化——运用Hadoop和MongoDB数据进行分析

作品详情  运用Hadoop和MongoDB对得分能力数据进行分析&#xff1b;  运用python进行机器学习的模型调理&#xff0c;利用Pytorch框架对爬取的评论进行情感分析预测&#xff1b;  利用python和MySQL对网站的数据进行爬取、数据清洗及可视化。

大数据毕业设计选题推荐-电影数据分析系统-数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

(undone) MIT6.824 Lab1

参考&#xff1a;http://nil.csail.mit.edu/6.824/2021/labs/lab-mr.html task1: 熟悉讲义&#xff0c;尤其是搞明白如何运行测试程序(完成) ------------------------------------------------ start 先看 Introduction 我们的目标&#xff1a;构建一个MapReduce系统。 细节&…

基于ESP8266—AT指令连接阿里云+MQTT透传数据(1)

在阿里云创建MQTT产品的过程涉及几个关键步骤,主要包括注册阿里云账号、实名认证、开通MQTT服务实例、创建产品与设备等。以下是详细的步骤说明: 一、准备工作 访问阿里云官网,点击注册按钮,填写相关信息(如账号、密码、手机号等)完成注册。注册完成后,需要对账号进行实…

Django一分钟:使用prefetch_related避免陷入大量的查询中导致严重的性能问题

本文将通过简单的示例介绍为什么要使用prefetch_related。 准备工作 创建模型 from django.db import modelsclass Product(models.Model):product_name models.CharField(max_length255)class Component(models.Model):product models.ForeignKey(Product, on_deletemode…