Django HttpStreamingResponse Not Streaming
У меня возникла очень интересная проблема с Django HttpStreamingResponse. Наш сервер вызывает OpenAI Text Completion API в потоковом режиме, после получения фрагментов от OpenAI, мы инкрементально разбираем фрагменты и передаем полные JSON объекты обратно нашим клиентам. Ниже приведены некоторые фрагменты кода:
views.py
class StreamViewSet(ModelViewSet):
...
def stream(self, request):
...
json_stream = agent.get_json_objects()
return StreamingHttpResponse(json_stream, content_type="application/json")
agents.py
def stream(self):
yield from self.json_agent.get_json_stream()
json_agent.py
def get_data_stream(self):
# This calls OpenAI text completion API with stream=True
stream_response = self.get_text_completion(user_preference, stream=True)
# Create an incremental json parser
json_stream_parser = JsonStreamParser()
for chunk in stream_response:
if chunk.choices and chunk.choices[0].delta.content is not None:
json_stream_parser.feed(chunk.choices[0].delta.content)
yield from json_stream_parser.parse()
json_parser.py
class JsonStreamParser:
"""A simple JSON stream parser that can parse a stream of JSON objects.
Note it only works for an array of JSON objects, which means the input
must contain a valid JSON array, at any point of the stream, that starts with '[' and ends with ']'.
It will parse the JSON objects in the array and ignores anything outside of the array.
"""
def __init__(self):
self.buffer = ""
self.index = 0
self.open_braces = 0
self.start_index = -1
self.array_started = False
def feed(self, data):
self.buffer += data
def parse(self):
parsed = []
while self.index < len(self.buffer):
if self.buffer[self.index] == '[':
self.array_started = True
if self.buffer[self.index] == '{' and self.array_started:
# If the start_index is -1, then we have found the start of a json object
if self.start_index == -1:
self.start_index = self.index
self.open_braces += 1
elif self.buffer[self.index] == '}':
self.open_braces -= 1
# If the open_braces is 0, then we have found a complete json object
if self.open_braces == 0 and self.start_index != -1:
j_obj = self.buffer[self.start_index:self.index+1]
parsed.append(j_obj)
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# However, it will not work with
# parsed.append(json.loads(j_obj))
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Reset the start_index and the buffer
self.start_index = -1
self.buffer = self.buffer[self.index:]
self.index = 0
self.index += 1
return parsed
def flush(self):
self.buffer = ""
self.index = 0
Промежуточное ПО и приложения, которые я установил на сервер django, следующие:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
Этот код отлично работает, передавая текст нашим клиентам, пока я не добавлю json.loads()
в json_parser.py, где я хочу, чтобы он возвращал json-объект вместо текста. В чем может быть проблема, которая блокирует потоковую передачу и буферизует все данные перед отправкой в ответ?
Я пытался удалить некоторые промежуточные программы, но они, похоже, не связаны между собой. Я пробовал писать код генератора разными способами, но это не помогло.