当前位置: 首页 > news >正文

Flask or FastAPI? Python服务端初体验

1. 引言

最近由于工作需要,又去了解了一下简单的python服务搭建的相关工作,主要是为了自己开发的模型或者工具给同组的人使用。之前介绍的针对于数据科学研究比较友好的一个可以展示的前端框架Streamlit可以说是一个利器。不过,随着ChatGPT的流行,基于chat的服务越来越多了起来,streamlit有一个chat衍生物streamlit-chat,但是它能提供的只是一个简单的聊天功能,并不能具有更高级显示,例如支持markdown和流式输出等。因此,更加适合大模型前端的FastChat可能是更好的选择。

话说回来,前端只是一个展示的界面,而真正提供服务的,需要后端才行。严格意义上讲,后端都是提供数据服务的,也就是对数据进行增删查改的,本质是离不开的,但是现在不是和数据库链接,而是和模型或者模型服务链接了。

这时候,当我去搜索python的后端库的时候,最长用的中小应用web框架Flask出现在我面前。但是我感觉还是有点复杂,于是我想到了一个基于Starlette二次开发的FastAPI,也许更适合。(这里有他们之间的比较介绍,介绍1,介绍2,介绍3,介绍4)。当然,也有人指出,用Flask与FastAPI比较式不公平的,就像是比较苹果和橙汁哪个更甜一样。Flask作为通用web框架,应该和Starlette比。我关于这点也是认同的。但这更能说明,在一个需要快速开发而需求不是那么重的时候,FastAPI是一个更好的选择。(当然我也用Flask开发过多线程支持的服务,两者各有千秋。)

2. Hello world

正如任何语言的第一个案例一样,我们首先用一个非常简单的例子介绍使用FastAPI提供服务的。

第一步,准备代码app.py

from fastapi import FastAPI
from pydantic import BaseModel
from gpt import GPTapp = FastAPI()
model = GPT()class Message(BaseModel):new_message: strrole: str = ""args: dict = {}@app.post('/gpt')
def gpt_endpoint(message: Message):new_message = message.new_messagerole = message.roleargs = message.argsresponse = model.call(new_message=new_message, role=role, args=args)return response

从这段不足50行的代码里,凸显出了大部分的FastAPI的特性。可以看到主体app,自己的资源model以及一个数据类Message,一个post接口服务(名为/gpt),并做了一些操作,返回response。

这里的GPT是简化的类,其处理代码可以写到另一个文件中。

第二步,安装依赖库

pip install fastapi
pip install uvicorn
pip install pydantic

第三步,运行服务

uvicorn app:app --host 0.0.0.0 --port 8000

经历以上三步,一个FastAPI服务就搭建好了,访问地址例如:http://localhost:8000/gpt,如何快速的测试它呢?FastAPI自带了Docs,可以通过URL访问(http://localhost:8000/docs),如下图所示:
在这里插入图片描述

如果代码中注释写的足够多的话,都不用另写手册了。

但是刚才的代码只是向我们简单的介绍了一下FastAPI的特性,如果我需要构建更加复杂的服务呢?下面我们通过2个实战例子更加全面的介绍FastAPI的使用。

3. 扩充实战

3.1 使用FastAPI提供增删查改的例子

假设我们正在开发一个简单的待办事项管理应用程序。我们希望实现以下功能:

  • 获取所有待办事项的列表
  • 创建一个新的待办事项
  • 更新特定待办事项的内容
  • 标记特定待办事项为已完成
  • 删除特定待办事项

我们可以使用FastAPI来实现这些功能。以下是使用不同类型装饰器定义的API端点的示例代码:

from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()# 待办事项数据模型
class TodoItem(BaseModel):id: inttitle: strcompleted: bool = False# 模拟的待办事项存储
todo_items = []# 获取所有待办事项的列表
@app.get("/todos")
def get_todo_list():return todo_items# 创建一个新的待办事项
@app.post("/todos")
def create_todo_item(item: TodoItem):todo_items.append(item)return item# 更新特定待办事项的内容
@app.put("/todos/{item_id}")
def update_todo_item(item_id: int, item: TodoItem):for i in range(len(todo_items)):if todo_items[i].id == item_id:todo_items[i] = itemreturn item# 标记特定待办事项为已完成
@app.patch("/todos/{item_id}")
def complete_todo_item(item_id: int):for item in todo_items:if item.id == item_id:item.completed = Truereturn item# 删除特定待办事项
@app.delete("/todos/{item_id}")
def delete_todo_item(item_id: int):for item in todo_items:if item.id == item_id:todo_items.remove(item)return {"message": "Item deleted"}

在上面的示例中,我们使用了以下不同类型的装饰器:

  1. @app.get(path: str):定义GET请求的端点。使用@app.get(“/todos”)装饰器定义了获取所有待办事项的列表的端点。这个端点不需要接收任何参数,直接返回待办事项列表。

  2. @app.post(path: str):定义POST请求的端点。使用@app.post(“/todos”)装饰器定义了创建新待办事项的端点。这个端点接收一个请求体参数item,它是一个TodoItem模型的实例,包含了待办事项的内容。在处理函数中,我们将新的待办事项添加到todo_items列表中,并返回添加的待办事项。

  3. @app.put(path: str):定义PUT请求的端点。使用@app.put(“/todos/{item_id}”)装饰器定义了更新待办事项的端点。这个端点接收一个路径参数item_id用于指定待办事项的ID,以及一个请求体参数item,它是一个TodoItem模型的实例,包含了待办事项的新内容。在处理函数中,我们遍历todo_items列表找到对应ID的待办事项,将其更新为新的内容,并返回更新后的待办事项。

  4. @app.patch(path: str):定义PATCH请求的端点。使用@app.patch(“/todos/{item_id}”)装饰器定义了标记待办事项为已完成的端点。这个端点接收一个路径参数item_id用于指定待办事项的ID。在处理函数中,我们遍历todo_items列表找到对应ID的待办事项,并将其标记为已完成(item.completed = True),然后返回已更新的待办事项。

  5. @app.delete(path: str):定义DELETE请求的端点。使用@app.delete(“/todos/{item_id}”)装饰器定义了删除待办事项的端点。这个端点接收一个路径参数item_id用于指定待办事项的ID。在处理函数中,我们遍历todo_items列表找到对应ID的待办事项,并将其从列表中删除,然后返回一个简单的消息表示删除成功。

  6. 这些装饰器允许我们根据HTTP方法(GET、POST、PUT、PATCH、DELETE)来定义不同类型的端点,并通过路径参数和请求体参数来接收和处理不同的数据。这样,我们可以使用统一的应用程序来处理各种操作,并根据RESTful API的原则设计我们的API。

这里,我们注意到PUT和PATCH方法是很相似的,都是用于更新的,但是两者有以下不同:

PUT请求用于完全替换(Replace)服务器上的资源或实体。当客户端发送一个PUT请求时,它需要提供完整的资源表示,包括要更新的所有字段。
如果资源不存在,则会创建一个新的资源;如果资源存在,则会完全替换(覆盖)现有资源的内容。
客户端通常应该提供完整的资源表示,即使只有部分字段发生更改。这意味着客户端需要提供所有字段,而不仅仅是要更改的字段。
PUT请求是幂等的,多次执行相同的PUT请求不会对资源产生额外的影响。

PATCH请求用于对服务器上的资源或实体进行部分更新。当客户端发送一个PATCH请求时,它只需要提供要更新的部分字段或属性。
PATCH请求可以用于增量更新资源的特定字段,而不需要发送整个资源的表示。这使得它适用于只更新部分字段的情况。
服务器根据客户端提供的更新内容,选择性地更新资源的相应字段。未提供的字段将保持不变。
PATCH请求可以是幂等的,但也可以是非幂等的,这取决于具体实现和使用情况。

在实际应用中,可以根据具体的业务需求和设计准则来选择使用PUT还是PATCH请求。如果要更新整个资源或实体,应该使用PUT请求。如果只需更新部分字段或属性,应该使用PATCH请求。

3.2 使用FastAPI提供GPU加载语言模型的例子

import uvicorn
import torch
from fastapi import FastAPI, BackgroundTasks
from pydantic import BaseModel# 示例GPT模型类
class GPTModel:def __init__(self):# 这里是你的GPT模型的初始化代码# ...def generate_text(self, input_text):# 这里是生成文本的代码# ...# 示例后台任务函数
def load_model(background_tasks):# 加载和初始化GPT模型model = GPTModel()device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model.to(device)model.eval()# 将模型保存到FastAPI应用的state中app.state.model = model# 示例请求模型的输入
class TextRequest(BaseModel):text: strapp = FastAPI()@app.post("/generate")
def generate_text(request: TextRequest, background_tasks: BackgroundTasks):# 在后台任务中加载模型background_tasks.add_task(load_model, background_tasks)# 从应用程序状态中获取模型model = app.state.model# 在GPU上进行推理input_text = request.textgenerated_text = model.generate_text(input_text)# 返回生成的文本结果return {"generated_text": generated_text}if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=8000)

4. 小结

本文主要简单的介绍了FastAPI的一些简单用法,方便快速搭建原型服务。

(随着ChatGPT等大模型逐渐渗透到我们的生活中,可能如此记录技术细节的博客愈发的没有用了。因为不会的东西ChatGPT可以交互式的给予指导,而不需要再这样看博客了。尽管这博客也离不开ChatGPT的指示,我还是看了一些相关博客,也自己亲手试了ChatGPT给的代码,多少增加一些可信度。)

相关文章:

Flask or FastAPI? Python服务端初体验

1. 引言 最近由于工作需要,又去了解了一下简单的python服务搭建的相关工作,主要是为了自己开发的模型或者工具给同组的人使用。之前介绍的针对于数据科学研究比较友好的一个可以展示的前端框架Streamlit可以说是一个利器。不过,随着ChatGPT的…...

《计算机组成原理》唐朔飞 第7章 指令系统 - 学习笔记

写在前面的话:此系列文章为笔者学习计算机组成原理时的个人笔记,分享出来与大家学习交流。使用教材为唐朔飞第3版,笔记目录大体与教材相同。 网课 计算机组成原理(哈工大刘宏伟)135讲(全)高清_…...

Linux:apache网页优化

Linux:apache网页优化 一、Apache 网页优化二、网页压缩2.1 检查是否安装 mod_deflate 模块2.2 如果没有安装mod_deflate 模块,重新编译安装 Apache 添加 mod_deflate 模块2.3 配置 mod_deflate 模块启用2.4 检查安装情况,启动服务2.5 测试 m…...

涨点技巧:注意力机制---Yolov8引入Resnet_CBAM,CBAM升级版

1.计算机视觉中的注意力机制 一般来说,注意力机制通常被分为以下基本四大类: 通道注意力 Channel Attention 空间注意力机制 Spatial Attention 时间注意力机制 Temporal Attention 分支注意力机制 Branch Attention 1.1.CBAM:通道注意力和空间注意力的集成者 轻量级…...

solr教程

一:安装配置 下载完成之后,解压solr文件,解压tomcat 1.1 在tomcat安装solr,并且建立solrCore 把solr5.5目录下的server/solr-webapp/webapp 重命名为solr,并且放置到tomcat/webapp的目录下。 打开tomcat/webapp/solr/WEB-INF/web.xml新建…...

基于java语言编写的爬虫程序

Java语言可以使用Jsoup、HttpClient等库进行网络爬虫开发,其中Jsoup提供了HTML解析和DOM操作的功能,HttpClient则提供了HTTP协议的支持。你可以通过使用这些库,构建网络爬虫程序来爬取指定网站的数据。需要注意的是,应该遵守网站的…...

UM2082F08 125k三通道低频无线唤醒ASK接收功能的SOC芯片 汽车PKE钥匙

1产品描述 UM2082F08是基于单周期8051内核的超低功耗8位、具有三通道低频无线唤醒ASK接收功能的SOC芯片。芯片可检测30KHz~300KHz范围的LF (低频)载波频率数据并触发唤醒信号,同时可以调节接收灵敏度,确保在各种应用环境下实现可靠唤醒,其拥…...

【SpringBoot_Project_Actual combat】 Summary of Project experience_需要考虑的问题

无论是初学者还是有经验的专业人士,在学习一门新的IT技术时,都需要采取一种系统性的学习方法。那么作为一名技术er,你是如何系统的学习it技术的呢。 一、DB Problems 数据库数据类型与java中数据类型对应问题? MySql数据库和java…...

恒容容器放气的瞬时流量的计算与合金氢化物放氢流量曲线的计算

有时候,你会遇到一个问题,该问题的描述如下: 你有一个已知体积的容器,设容器体积为V,里面装有一定压力(初始压力)的气体,如空气或氢气等,设初始压力为1MPa,容器出口连接着一个阀门开…...

网络编程_UDP通信

网络编程_UDP通信 1. TCP与UDP2. 使用UDP通信3. sendto与recvfrom、recv4.实例实例1: 服务器接收、客户端发送实例2:服务器收发、客户方发送、接收。1. TCP与UDP 当使用网络套接字通信时, 套接字的“域”都取AF_INET; 套接字的type: SOCK_STREAM 此时,默认使用TCP协议进行…...

windows修改Pycharm的右键打开方式

title: windows中open floder as Pycharm太长了怎么修改 date: 2023-06-04 author: IoT_H2 tags: windows系统问题 categories: Markdown 问题描述: Pycharm这一栏这么长,长的我实在是很难受,事实上Jetbrains家的软件都是这个鸟模样 导…...

Python入门(十四)函数(二)

函数(二) 1.传递实参1.1 位置实参1.2 关键字实参1.3 默认值 作者:xiou 1.传递实参 函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。向函数传递实参的方式很多:可使用位置实参,这要求实参…...

Allure测试报告定制全攻略,优化你的Web自动化测试框架!

目录 前言: 1. Allure测试报告简介 2. Web自动化测试框架简介 3. 封装Web自动化框架 3.1 安装Selenium 3.2 封装Selenium 3.3 定制Allure测试报告 3.3.1 适配翻译插件 3.3.2 定制测试报告样式 4. 示例代码 5. 总结 前言: 随着现在Web应用的普…...

推荐系统算法详解

文章目录 基于人口统计学的推荐算法用户画像 基于内容的推荐算法相似度计算基于内容推荐系统的高层次结构特征工程数值型特征处理类别特征处理时间型特征处理统计型特征处理 推荐系统常见反馈数据基于UGC的推荐TF-IDFTF-IDF算法示例1. 引入依赖2. 定义数据和预处理3. 进行词数统…...

企业网站架构部署与优化之LAMP

LAMP LAMP概述1、各组件的主要作用2、各组件安装顺序 编译安装Apache http服务编译安装MySQL服务编译安装PHP解析环境安装论坛 LAMP概述 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整套系统和相关软件,能够提供静态和动态Web站点服务…...

攻防世界安卓逆向练习

文章目录 一.easy-so1. jadx分析程序逻辑2. ida查看so文件3. 解题脚本: 二.ezjni1. 程序逻辑分析2. 解题脚本: 三.easyjava1. 主函数逻辑2. getIndex函数3. getChar函数4.解题脚本 四.APK逆向1.程序逻辑分析2.解题脚本3.动态调试 Android2.0app3 一.easy-so 1. jadx分析程序逻…...

自然语言处理从入门到应用——自然语言处理的语言模型(Language Model,LM)

分类目录:《自然语言处理从入门到应用》总目录 语言模型(Language Model,LM)(也称统计语言模型)是描述自然语言概率分布的模型,是一个非常基础和重要的自然语言处理任务。利用语言模型&#xff…...

【MySql】InnoDB一棵B+树可以存放多少行数据?

文章目录 背景一、怎么得到InnoDB主键索引B树的高度?二、小结三、最后回顾一道面试题总结参考资料 背景 InnoDB一棵B树可以存放多少行数据?这个问题的简单回答是:约2千万。为什么是这么多呢?因为这是可以算出来的,要搞…...

【综述】视频无监督域自适应(VUDA)的小综述

【综述】视频无监督域自适应(VUDA)的小综述 一篇小综述,大家看个乐子就好,参考文献来自于一篇综述性论文 完整PPT已经上传资源:https://download.csdn.net/download/weixin_46570668/87848901?spm1001.2014.3001.550…...

《深入理解计算机系统(CSAPP)》第9章虚拟内存 - 学习笔记

写在前面的话:此系列文章为笔者学习CSAPP时的个人笔记,分享出来与大家学习交流,目录大体与《深入理解计算机系统》书本一致。因是初次预习时写的笔记,在复习回看时发现部分内容存在一些小问题,因时间紧张来不及再次整理…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

高保真组件库:开关

一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...

华为OD机考- 简单的自动曝光/平均像素

import java.util.Arrays; import java.util.Scanner;public class DemoTest4 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint[] arr Array…...

LangChain + LangSmith + DeepSeek 入门实战:构建代码生成助手

本文基于 Jupyter Notebook 实践代码&#xff0c;结合 LangChain、LangSmith 和 DeepSeek 大模型&#xff0c;手把手演示如何构建一个代码生成助手&#xff0c;并实现全流程追踪与优化。 一、环境准备与配置 1. 安装依赖 pip install langchain langchain_openai2. 设置环境变…...