最近在研究ChatGPT的时候,想通过openai提供的接口使国内用户也可以无限制访问,于是打算基于django开发一款应用。页面的渲染也得想ChatGPT一样采用流式响应,django中StreamingHttpResponse是支持流式响应的一种方式。
django 代码
python
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 chunk
response = StreamingHttpResponse(get_streaming_content(chat_response), content_type='application/octet-stream')
return response
settings.py
python
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请求前端处理流没有哦
附上前端处理响应并实时渲染的代码
html
<!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>