I am experiencing an issue while streaming responses from the OpenAI Chat_completion API through my Quartz backend to my React frontend. Specifically, the chunks of data processed from the backend are repeating or missing when displayed in the chatbox UI.
Error:
Some chunks are repeating in the frontend chatbox even after receiving all the chunks from backend
Many chunks are missing when displayed in the chatbox UI even after receiving all the chunks from backend
Steps to Reproduce:
Call the OpenAI Chat_completion API from the Quartz backend.
Stream the response chunks to the React frontend.
Process and display the chunks in a chatbox component in the React UI.
Observed Behavior:
Some of the chunks are repeating after printing a few chunks in the frontend.
Many chunks are missing in the final response displayed in the UI.
The Problem: Some of the chunks are missing while printing in the UI
The problem shown in UI
The repeation of chunks in the UI
Thanks for the help!!! Really appreciate any help.
Here is Backend code snippet:
@gpt_run.route('/aiapp', methods=['POST'])
async def interactive_function():
data = await request.get_json()
question = data['query']
async def generate():
response_text = ""
async for chunk in model.ask(question):
if chunk:
response_text += chunk
yield f"{json.dumps({'chunk': chunk})}n"
chat.append({'question': question, 'answer': response_text})
chat_key = "chat_" + str(int(time.time()))
chat_ref.set({chat_key: chat})
print(response_text)
return Response(generate(), content_type='application/json')
Query sent from the front End: “Hey”
This is the payload response to the Front End:
{"chunk": "Hello"}
{"chunk": "!"}
{"chunk": " How"}
{"chunk": " can"}
{"chunk": " I"}
{"chunk": " assist"}
{"chunk": " you"}
{"chunk": " today"}
{"chunk": "?"}
{"chunk": "Hello"}
{"chunk": ","}
{"chunk": " how"}
{"chunk": " can"}
{"chunk": " I"}
{"chunk": " assist"}
{"chunk": " you"}
{"chunk": " today"}
{"chunk": "?"}
{"chunk": " If"}
{"chunk": " you"}
{"chunk": " have"}
{"chunk": " any"}
{"chunk": " questions"}
{"chunk": " or"}
{"chunk": " need"}
{"chunk": " help"}
{"chunk": " with"}
{"chunk": " anything"}
{"chunk": ","}
{"chunk": " feel"}
{"chunk": " free"}
{"chunk": " to"}
{"chunk": " ask"}
{"chunk": "."}
Main.js(React FrontEnd):
async function handleSubmit(e) {
e.preventDefault();
if (!waitingForResponse && input.trim()) {
setWaitingForResponse(true);
setIsLoading(true);
const newMessage = { user: "user", message: input };
setMessageList(prev => [...prev, newMessage]);
setInput("");
// Fetch data and process chunks
const response = await fetch("http://localhost:8000/gptRun/aiapp", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: input }),
});
const reader = response.body.getReader();
let receivedChunks = '';
let partialChunk = '';
let processedChunks = new Set(); // Use a Set to store processed chunks
// Create an initial bot message
const botMessage = { user: "bot", message: '' };
setMessageList(prev => [...prev, botMessage]);
try {
let done = false;
do {
const { value, done: readerDone } = await reader.read();
done = readerDone;
if (done) break;
receivedChunks += new TextDecoder().decode(value, { stream: true });
let splitPos;
while ((splitPos = receivedChunks.indexOf('n')) >= 0) {
let chunk = receivedChunks.substring(0, splitPos);
receivedChunks = receivedChunks.substring(splitPos + 1);
// Combine complete chunk with partial chunk (if any)
if (partialChunk) {
chunk = partialChunk + chunk;
partialChunk = ''; // Clear partialChunk for next iteration
}
try {
const parsedChunk = JSON.parse(chunk);
if (parsedChunk.chunk && !processedChunks.has(parsedChunk.chunk)) {
// Add the new chunk to the processedChunks set
processedChunks.add(parsedChunk.chunk);
console.log("Processing chunk: ", parsedChunk.chunk);
// Append the chunk to the bot's message in real-time
setMessageList(prev => {
const updatedMessages = [...prev];
const lastMessage = updatedMessages[updatedMessages.length - 1];
// Check if the chunk is already appended to the last bot message
if (lastMessage.user === "bot" && !lastMessage.message.includes(parsedChunk.chunk)) {
console.log("Appending chunk to bot's message: ", parsedChunk.chunk);
lastMessage.message += parsedChunk.chunk;
}
return updatedMessages;
});
// Debug: Log the updated messages list
console.log("Updated messages list: ", JSON.stringify(messageList, null, 2));
}
} catch (error) {
console.error("Error parsing chunk: ", error);
partialChunk = chunk; // If there's an error, assume the chunk is incomplete and save it as partialChunk
}
}
// Save any remaining incomplete chunk
if (receivedChunks.length > 0) {
partialChunk += receivedChunks;
receivedChunks = '';
}
// Wait for a brief moment before processing the next chunk
await new Promise(resolve => setTimeout(resolve, 100)); // Adjust the delay as needed
} while (!done);
// Clear the processed chunks after they have been fully handled
processedChunks.clear();
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setWaitingForResponse(false);
setIsLoading(false);
}
}
}
Anik De is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.