我们希望做一个流式输出的后端,然后让前端去捕获这个流式输出,并且在聊天界面中流式输出。
首先构造流式输出引擎。
# 构造流式输出引擎
query_engine = index.as_query_engine(streaming=True, similarity_top_k=3,llm=llm)
然后生成response_stream,这个response_stream里面有一个生成器,叫做response_gen。我们可以像列表一样去迭代这个生成器,然后取出生成的文本。
response_stream = query_engine.query("请写一篇1000字的文章论述法学专业就业前景")
for text in response_stream.response_gen:print(text,end="")
这样我们就可以在Jupyter的界面看到流式输出了。
我们也可以做一个后端,可以用FastAPI来做。这是一个新的python web框架,性能很强悍。
我们先来安装一下这个框架:
在Jupyter的格子中输入以下内容。
%pip install fastapi
%pip install uvicorn
框架都很小,很快就安装好。
下面我们来改造一下,用fastapi做成http接口。
新建一个Jupyter notebook的格子,填入以下代码:
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
app = FastAPI()
app.add_middleware(CORSMiddleware,allow_origins=["*"])
@app.get('/stream_chat')
async def stream_chat(param:str = "你好"):async def generate(): # 我们假设query_engine已经构建完成response_stream = query_engine.query(param) for text in response_stream.response_gen:yield textreturn StreamingResponse(generate(), media_type='text/event-stream')
if __name__ == '__main__':config = uvicorn.Config(app, host='0.0.0.0', port=5000)server = uvicorn.Server(config)await server.serve()
可以看到,这里的关键的关键在于yield语句的使用以及用一个generate函数构建Response。
然后在前端我们就可以愉快地接收了。
当然也可以新建一个python文件,填入以下代码:
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
app = FastAPI()
app.add_middleware(CORSMiddleware,allow_origins=["*"])
@app.get('/stream_chat')
async def stream_chat(param:str = "你好"):def generate(): # 我们假设query_engine已经构建完成response_stream = query_engine.query(param) for text in response_stream.response_gen:yield textreturn StreamingResponse(generate(), media_type='text/event-stream')
if __name__ == '__main__':uvicorn.run(app, host='0.0.0.0', port=5000)
可以看到在jupyter的格子中运行的代码与在py文件中运行的代码的区别仅仅在于if __name__ == '__main__':
之后的代码。这是因为Jupyter是一个交互式的环境,它会在每个单元格中运行代码,而不是在一个独立的程序中运行。因此,当我们在Jupyter中运行一个程序时,它会在一个新的进程中运行,而不是在当前进程中运行。这就是为什么我们在Jupyter中运行的代码需要在if __name__ == '__main__':
之后的代码中用uvicorn.Server启动服务器。而在py文件中运行的代码则不需要。
我们甚至可以直接在浏览器地址栏里输入:
http://127.0.0.1:5000/stream_chat?param=你是谁?
然后浏览器页面就会出现流式输出。
我们也可以把它封装到一个js函数中
async function fetchStream(param) { const url = `http://127.0.0.1:5000/stream_chat?param=${encodeURIComponent(param)}`;const response = await fetch(url); const reader = response.body.getReader(); while (true) { const { value, done } = await reader.read(); if (done) { // 如果没有更多的数据可读,退出循环 statusvue.isTalking=false; break; } // 处理接收到的数据 const text = new TextDecoder("utf-8").decode(value); console.log(text)}
}
然后我们就可以在想要用到地地方调用这个fetchStream函数了。这个函数需要一个参数,是字符串形式的。