Django中使用流式响应,自己也能实现ChatGPT的效果
最近在研究ChatGPT的时候,想通过openai提供的接口使国内用户也可以无限制访问,于是打算基于django开发一款应用。页面的渲染也得想ChatGPT一样采用流式响应,django中StreamingHttpResponse是支持流式响应的一种方式。
django 代码
class ChatView(APIView):def get(self, request, *args, **kwargs):prompt= request.GET.get('prompt', '')chat_response = openai.ChatCompletion.create(model="gpt-3.5-turbo",stream=True,messages=[{'role': 'user','content': prompt,}])def get_streaming_content(chat_response):for chunk in chat_response:yield chunkresponse = StreamingHttpResponse(get_streaming_content(chat_response), content_type='application/octet-stream')return response
settings.py
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [os.path.join(BASE_DIR,'templates')],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]
遇到的问题
在本地通过python manage runserver
启动项目后,通过浏览器访问(一开始是GET请求)是能明显看到效果的,但是当使用Nginx+uwsgi部署之后,发现流式响应失效了,于是研究了一下写下这篇文章备忘。
解决方案
首先Nginx和uwsgi的通信方式不能使用socket方式,必须使用http方式,还得修改部分Nginx配置
nginx部分配置
location / {proxy_pass http://127.0.0.1:8080;proxy_buffering off; # 重点是这个配置
}
uwsgi部分配置
[uwsgi]
; 不能使用socket方式通信
;socket = /tmp/uwsgi_%(site_name).sock
; 使用http方式通信
http = 0.0.0.0:8080
GET请求直接在浏览器打开才有此问题,POST请求前端处理流没有哦
附上前端处理响应并实时渲染的代码
<!DOCTYPE html>
<html>
<head><title>Demo</title><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body><div class="container mt-5"><div class="row"><div class="col-md-6 offset-md-3"><div class="form-group"><label for="inputText">输入内容:</label><textarea class="form-control" id="inputText" placeholder="在这里输入内容"></textarea></div><button type="button" id="submitBtn" class="btn btn-primary">提交</button></div></div><div class="row mt-3"><div class="col-md-6 offset-md-3"><div id="responseContainer" class="border p-3"></div></div></div>
</div><script>$(document).ready(function () {$('#submitBtn').click(function () {var inputText = $('#inputText').val();function displayData(data) {var outputDiv = document.getElementById('responseContainer');outputDiv.innerText += data;}fetch('/api/chatgpt/chat/', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({'input': inputText}),}).then(function (response) {// 确保响应状态码正常if (!response.ok) {throw new Error('Response failed');}// 使用响应的ReadableStream来处理数据var reader = response.body.getReader();function read() {return reader.read().then(function (result) {// 处理读取到的数据if (!result.done) {var value = result.value;// 在这里处理接收到的数据,例如更新页面上的内容var decoder = new TextDecoder('utf-8')var chunk = decoder.decode(value)displayData(chunk)// 继续读取下一块数据return read();}});}return read();}).catch(function (error) {// 处理错误});});});
</script>
</body>
</html>