FastAPI 作为H5中流式输出的后端

FastAPI 作为H5中流式输出的后端

最近大家都在玩LLM,我也凑了热闹,简单实现了一个本地LLM应用,分享给大家,百分百可以用哦~^ - ^

先介绍下我使用的三种工具:

Ollama:一个免费的开源框架,可以让大模型很容易的运行在本地电脑上
FastAPI:是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 并基于标准的 Python 类型提示
React:通过组件来构建用户界面的库
简单来说就类似于LLM(数据库)+FastAPI(服务端)+React(前端)
在这里插入图片描述

前端:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>SSE Demo with Fetch</title><style>#events {height: 200px;border: 1px solid #ccc;padding: 5px;overflow-y: scroll;white-space: pre-wrap; /* 保留空格和换行 */}</style><script src="./js/jquery-3.1.1.min.js"></script>
</head>
<body><h1>Server-Sent Events Test</h1>
<button id="start">Start Listening</button>
<label for="" >apiUrl</label>
<input type="text" name="" id="url" value="http://127.0.0.1:8563/llm_stream" >
<br>
<label> 返回内容</label>
<br>
<input type="text" name="" id="userText" value="" >
<br>
<input type="textarea" name="" id="outtext_talk" value="" style="width:400px; height: 200px;"></textarea>
<div id="events"></div><script>$("#start").click(async function() {console.log($("#userText").val());let text=$("#userText").val().trim();if(text==''){alert("用户输入不为空");return 0;}
const data={content:text,model:"gpt-3.5-turbo",stream:true
}$("#outtext_talk").val('')const res= await fetch($('#url').val(),{method:"POST",body:JSON.stringify(data),headers: {"Content-Type": "application/json",}
});const reader=res.body?.pipeThrough(new TextDecoderStream()).getReader();let count=0const textDecoder = new TextDecoder();while (count<10){let {done,value} = await reader.read()if (done) {
console.log("***********************done");break;}let parts = value.split('\r\n\r\n'); // 根据 SSE 的数据格式分割// 处理所有完整的消息console.log(parts);try{parts.slice(0,-1).forEach(part =>{console.log(part);if(part.startsWith('data:')){const data=part.replace('data:','')aiText=JSON.parse(data)$('#outtext_talk').val( $('#outtext_talk').val()+aiText.message)}})}catch(error){console.error("JSON解析出错",detext);count+=1;}}});
</script></body>
</html>

后端:

# -*- coding:utf-8 -*-
"""
@Author: 风吹落叶
@Contact: waitKey1@outlook.com
@Version: 1.0
@Date: 2024/6/11 22:51
@Describe: 
"""
import asyncio
import jsonfrom fastapi import FastAPI, Response
from fastapi.responses import StreamingResponse
import time
import uvicorn
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModelimport openai
import os
import os
from openai import OpenAIdef openai_reply(content,model="gpt-3.5-turbo"):client = OpenAI(# This is the default and can be omittedapi_key='sk-S7KwoLDoAzi5kwOs3b3e27A64eD4483bBaD5E2750a6e72E6',base_url='https://kksj.zeabur.app/v1')chat_completion = client.chat.completions.create(messages=[{"role": "user","content": content,}],model=model,)# print(chat_completion)return chat_completion.choices[0].message.contentapp = FastAPI()
# 启用CORS支持
app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"], # 或者只列出 ["POST", "GET", "OPTIONS", ...] 等allow_headers=["*"],
)class Req(BaseModel):text:strstream:booldef event_stream(reqs):for _ in range(10):  # 演示用,发送10次消息后关闭连接yield json.dumps({'text':f"data: Server time is {time.ctime()} s {reqs.text[:2]}"})time.sleep(1)@app.post("/events")
async def get_events(reqs:Req):return StreamingResponse(event_stream(reqs), media_type="application/json")class LLMReq(BaseModel):content:strmodel:strstream:booldef openai_stream(content,model='gpt-3.5-turbo'):client = OpenAI(# This is the default and can be omittedapi_key='sk-S7KwoLDoAzi5kwOs3b3e27A64eD6e72E6',base_url='https://kksj.zeabur.app/v1')stream = client.chat.completions.create(messages=[{"role": "user","content": content,}],  # 记忆model=model,stream=True,)return streamfrom starlette.requests import Request
from sse_starlette import EventSourceResponse
@app.post("/llm_stream")
async def flush_stream(req: LLMReq):async def event_generator(req: LLMReq):stream = openai_stream(req.content, req.model)for chunk in stream:if chunk.choices[0].delta.content is not None:word=chunk.choices[0].delta.contentyield json.dumps({"message": word}, ensure_ascii=False)await asyncio.sleep(0.001)return EventSourceResponse(event_generator(req))if __name__ == '__main__':uvicorn.run(app,port=8563)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/26813.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年护网行动全国各地面试题汇总(1)作者:————LJS

目录 1. SQL注入原理 2. SQL注入分类&#xff1a; 3. SQL注入防御&#xff1a; 4. SQL注入判断注入点的思路&#xff1a; 5. 报错注入的函数有哪些&#xff1a; 6. SQL注入漏洞有哪些利用手法&#xff1a; 1. 文件上传漏洞的绕过方法有以下几种&#xff1a; 2. 文件上传时突破前…

centos7 xtrabackup mysql 基本测试(4)---虚拟机环境 mysql 修改datadir(有问题)

centos7 xtrabackup mysql 基本测试&#xff08;4&#xff09;—虚拟机环境 mysql 修改datadir 参考 centos更改mysql数据库目录 https://blog.csdn.net/sinat_33151213/article/details/125079593 https://blog.csdn.net/jx_ZhangZhaoxuan/article/details/129139499 创建目…

锌,能否成为下一个“铜”?

光大期货认为&#xff0c;今年以来&#xff0c;市场关注锌能否接棒铜价牛市。铜需求增长空间大&#xff0c;而锌消费结构传统&#xff0c;缺乏新亮点。虽然在供应的扰动上锌强于铜&#xff0c;但因需求乏善可陈&#xff0c;金融属性弱势&#xff0c;锌很难接棒铜&#xff0c;引…

数据质量守护者:数据治理视角下的智能数据提取策略

一、引言 在信息化和数字化高速发展的今天&#xff0c;数据已成为企业决策、运营和创新的核心要素。然而&#xff0c;随着数据量的快速增长和来源的多样化&#xff0c;数据质量问题逐渐凸显&#xff0c;成为制约企业数据价值发挥的关键因素。数据治理作为确保数据质量、提升数…

KEIL5.39 5.40 fromelf 不能生成HEX bug

使用AC6 编译,只要勾选了生成HEX。 结果报如下错误 暂时没有好的解决办法 1.替换法 2.在编译完后用命令生成HEX

蚓链研究院告诉你:蚓链数字化营销如何帮助力助你打造品牌!

在打造产品品牌的过程中&#xff0c;数字化营销会带来哪些利弊影响&#xff1f;如何消除或减少弊端&#xff1f;蚓链来和你一起分析、解决。 利处&#xff1a; 1.高度精准的目标定位&#xff1a;凭借大数据和先进算法&#xff0c;能精确锁定潜在客户&#xff0c;使营销资源得到…

k8s_探针专题

关于探针 生产环境中一定要给pod设置探针,不然pod内的应用发生异常时,K8s将不会重启pod。 需要遵循以下几个原则(本人自己总结,仅供参考): 探针尽量简单,不要消耗过多资源。因为探针较为频繁的定期执行,过于复杂和消耗资源的探针对k8s和生产环境是不利的。探针返回的结…

数栈xAI:轻量化、专业化、模块化,四大功能革新 SQL 开发体验

在这个数据如潮的时代&#xff0c;SQL 已远远超越了简单的查询语言范畴&#xff0c;它已成为数据分析和决策制定的基石&#xff0c;成为撬动企业智慧决策的关键杠杆。SQL 的编写和执行效率直接关系到数据处理的速度和分析结果的深度&#xff0c;对企业洞察市场动态、优化业务流…

针对k8s集群已经加入集群的服务器进行驱逐

例如k8s 已经有很多服务器&#xff0c;现在由于服务器资源过剩&#xff0c;需要剥离一些服务器出来 查找节点名称&#xff1a; kubectl get nodes设置为不可调度&#xff1a; kubectl cordon k8s-node13恢复可调度 kubectl uncordon k8s-node13在驱逐之前先把需要剥离驱逐的节…

File及典型案例

File File对象表示一个路径&#xff0c;可以是文件的路径&#xff0c;也可以是文件夹的路径 这个路径可以是存在的&#xff0c;也允许不存在 常见的构造方法 图来自黑马程序员网课 package com.lazyGirl.filedemo;import java.io.File;public class Demo1 {public static vo…

立式护眼台灯十大品牌哪个好?立式护眼台灯十大品牌排行

立式护眼台灯十大品牌哪个好?根据国际市场的研究数据表明&#xff0c;我国在日常生活中对电子产品的依赖度极高&#xff0c;每天看电子产品的时间超过8小时&#xff0c;出现眼睛酸痛、干涩、视觉疲劳的人群也不再少数&#xff0c;而给眼睛带来伤害的除了电子产品中所含的蓝光之…

Vue3-滑动到最右验证功能

1、思路 1、在登录页面需要启动向右滑块验证 2、效果图 3、文章地址&#xff1a;滑动验证码的实现-vue-simple-verify 2、成分分析 1、由三块构成&#xff0c;分别是底部条、拖动条、拖动移动部分 2、底部条&#xff1a;整体容器&#xff0c;包括背景、边框和文字&#xf…

端午假期新房销售较去年下降16%,6月核心城市有望继续好转

内容提要 国常会强调政策措施落地见效&#xff0c;继续研究新去库存、稳市场政策。多城市二手房市场活跃&#xff0c;新房成交回暖缓慢。端午假期新房销售下降&#xff0c;核心城市市场有望好转。 文章正文 6月7日&#xff0c;国常会强调“着力推动已出台政策措施落地见效&am…

行列视(RCV)能解决哪些问题?

答&#xff1a;发电企业传统报表工作一般由Excel或WPS进行数据收集、合并、复制、人工核算和统计等工作方式完成&#xff0c;效率低、工作量大&#xff0c;且容易出错&#xff0c;与数字化、智能化发电厂的发展步伐逐步脱节。在此背景下本系统主要解决&#xff1a; 数据收集问…

AtCoder Beginner Contest 357 C - Sierpinski carpet

题目描述 题目链接 C 代码 #include<bits/stdc.h> using namespace std;const int N 750; char G[7][N][N];void Copy(char g1[][N], char g2[][N], int r1, int c1, int r2, int c2) {for(int i r1; i < r2; i )for(int j c1; j < c2; j )g1[i][j] g2[i - …

ai 人工智能免费网站免费生成图片生成ppt

豆包 Kimi.ai - 帮你看更大的世界 生成ppt 讯飞智文 - AI在线生成PPT、Word 大家如有其它免费的欢迎推荐!!!

五分钟看完WWDC24

大家好&#xff0c;我是小编阿文。欢迎您关注我们&#xff0c;经常分享有关Android出海&#xff0c;iOS出海&#xff0c;App市场政策实时更新&#xff0c;互金市场投放策略&#xff0c;最新互金新闻资讯等文章&#xff0c;期待与您共航世界之海。 北京时间6月11日凌晨1点&…

2024中国翻译行业发展报告

来源&#xff1a;中国翻译协会 近期历史回顾&#xff1a; 2024国内工商业储能市场研究报告.pdf 2023幸福企业白皮书.pdf 2024年欧亚地区移动经济报告.pdf 内容供应链变革 2023人工智能与首席营销官&#xff08;CMO&#xff09; AI科技对PC产业的影响.pdf 金融业数据应用发展报…

01本地图像导入及参数设置

左边工具栏&#xff1a;采集-》图像源&#xff0c;点击后 拉到流程窗口中 在右边有三个按钮可以添加图像和图像文件夹。 双击 图像源 可以打开 参数设置 参数说明&#xff1a; 像素格式&#xff1a;MONO8 表示图像为黑白图像&#xff0c;RGB24为彩色图像。看你想以什么图像打开…

MySql几十万条数据,同时新增或者修改

项目场景&#xff1a; 十万条甚至更多的数据新增或者修改 问题描述 现在有十万条数据甚至更多数据&#xff0c;在这些数据中&#xff0c;有部分数据存在数据库中&#xff0c;有部分数据确是新数据&#xff0c;存在的数据需要更新&#xff0c;不存在的数据需要新增 原因分析&a…