最近在研究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>