Streaming Chat Completion in Flask

By

Profile image

Adeniyi Aderounmu

3 min read
Post Image

In this blog post, we will explore how to use OpenAI's GPT-3.5 Turbo API to stream chat completions in a Flask application. We will create an endpoint /api/stream that accepts a POST request and returns a streamed response with a Content-Type of text/plain. Additionally, we will also provide an example of how to integrate the frontend part with the API. Let's dive into the code!

Backend Implementation

First, let's take a look at the backend implementation using Flask:

@app.route('/api/stream', methods=['POST'])
def stream():
    def generate():
        openai.api_key = "sk-key"  # Replace with your OpenAI API key

        # Define the initial message for the chat completion
        messages = [
            {'role': 'user', 'content': 'Count to 10, with a comma between each number and no newlines. E.g., 1, 2, 3, ...'}
        ]

        response = openai.ChatCompletion.create(
            model='gpt-3.5-turbo',
            messages=messages,
            temperature=0,
            stream=True
        )

        try:
            for chunk in response:
                # Extract the content from the chat completion response
                content = chunk["choices"][0].get("delta", {}).get("content", "")
                if content:
                    yield content
        except Exception as err:
            Response("An error occurred", status=400, content_type='text/plain')

    # Return the streamed response with a Content-Type of text/plain
    return Response(generate(), content_type='text/plain')

In the above code, we define a Flask route /api/stream that accepts a POST request. Inside the route function, we define a generator function generate() that streams the response from the GPT-3.5 Turbo API. We set stream=True in the openai.ChatCompletion.create() method to enable streaming.

The initial message for the chat completion is defined in the messages list, which contains a single message from the user asking to count to 10 with commas between each number. The temperature parameter is set to 0, which means the completions will be deterministic and not random.

We loop through the chunks of the streamed response from the API using a for loop, and extract the content of each chunk using the choices field in the response. We concatenate the content to the text variable to accumulate the completed text.

Finally, we return the generated text as a streamed response with a Content-Type of text/plain using Flask's Response class.

Note: Don't forget to replace the openai.api_key with your actual OpenAI API key for authentication.

Frontend Integration

Now, let's take a look at how you can integrate the frontend part with the backend API. Here's an example implementation using JavaScript:

try {
  const response = await fetch('/api/stream', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Auth': 'jwt',
    },
    body: JSON.stringify({ message: '' }),
  })

  const reader = response.body.getReader()
  while (true) {
    const { done, value } = await reader.read()
    if (done) break
    this.stream += new TextDecoder().decode(value)
  }
} catch (error) {
  console.error(error)
}

In the above frontend code, we use fetch() to send a POST request to the /api/stream endpoint in the Flask backend. We set the Content-Type header to "application/json" to indicate that we are sending JSON data in the request body. We also include an authentication token in the X-Auth header, assuming you are using an authentication system that provides a token.

The body of the request is an empty JSON object { message: ""}. You can customize this message according to your application's requirements.

Once we receive the response from the backend, we create a ReadableStream reader using response.body.getReader() to read the streamed response in chunks. We use a while loop to continuously read the chunks until the done property of the response is true, indicating that the response is complete.

Inside the loop, we decode the value of each chunk using new TextDecoder().decode(value) and append it to the appropriate variable or element in the frontend. In this example, we append the decoded text to this.stream to accumulate the completed text.

Finally, if any error occurs during the request or response handling, we log it to the console for debugging purposes.

Conclusion

In this blog post, we explored how to implement streaming chat completions with OpenAI's GPT-3.5 Turbo API in a Flask application. We created a backend endpoint that returns a streamed response with a Content-Type of text/plain, and integrated it with the frontend using JavaScript's fetch() and ReadableStream. By leveraging the power of streaming, we can efficiently handle large responses from the API and display real-time updates in the frontend. You can now incorporate chat completions in your applications to generate dynamic and interactive responses. Happy coding!