I’m trying to display messages as they come back from API, and allow for follow up query. However my initial query is displayed (USER) but the Assistant is not. When I ask follow up question, the response from the previous question appears. Is there an issue with my logic, or my implementation or both.
app.py
import os
import openai
from flask import Flask, render_template, request, jsonify
from dotenv import load_dotenv
import time
import re
Load environment variables from .env file
load_dotenv()
app = Flask(name)
openai.api_key = os.getenv(“OPENAI_API_KEY”)
assistant_id = os.getenv(“OPENAI_ASSISTANT_ID”)
Initialize OpenAI client
client = openai.OpenAI()
Global variable to store thread ID
thread_id = None
def clean_api_text(api_text):
pattern = re.compile(r"[TextContentBlock(text=Text(annotations=, value=‘(.*?)’), type=‘text’)]“)
cleaned_text = re.sub(pattern, r’\1’, str(api_text))
cleaned_text = cleaned_text.strip(”'")
return cleaned_text
@app.route(‘/’)
def index():
return render_template(‘index.html’)
@app.route(‘/ask’, methods=[‘POST’])
def ask():
global thread_id
data = request.json
question = data.get(‘question’)
if thread_id is None:
thread = client.beta.threads.create()
thread_id = thread.id
active_runs = client.beta.threads.runs.list(thread_id=thread_id).data
if active_runs and active_runs[-1].status not in ['completed', 'failed', 'incomplete']:
return jsonify({"error": "An existing run is still active. Please wait until it completes before asking a new question."}), 400
client.beta.threads.messages.create(
thread_id=thread_id,
role="user",
content=question
)
run = client.beta.threads.runs.create(
thread_id=thread_id,
assistant_id=assistant_id
)
return jsonify({"thread_id": thread_id, "run_id": run.id})
@app.route(‘/poll_status’, methods=[‘GET’])
def poll_status():
global thread_id
thread_id = request.args.get(‘thread_id’, thread_id)
if not thread_id:
return jsonify({“status”: “No active thread”})
run = client.beta.threads.runs.list(thread_id=thread_id).data[-1]
run_status = run.status
while run_status == 'incomplete':
time.sleep(2)
run = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run.id)
run_status = run.status
messages = client.beta.threads.messages.list(thread_id=thread_id).data
response_messages = []
for msg in messages:
timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(msg.created_at))
role = "Assistant" if msg.role == 'assistant' else "User"
content = clean_api_text(msg.content)
formatted_message = f"### **{role}** ({timestamp}):<br>{content}"
response_messages.append(formatted_message)
return jsonify({"status": run.status, "messages": response_messages})
@app.route(‘/new_conversation’, methods=[‘POST’])
def new_conversation():
global thread_id
thread_id = None
return jsonify({“status”: “New conversation started”})
if name == ‘main’:
app.run(debug=True, host=‘0.0.0.0’, port=5001)
index.html
Math Tutor body { margin: 0; padding: 0; font-family: Arial, sans-serif; } .container { display: flex; flex-direction: column; height: 100vh; overflow: hidden; } .content { flex: 1; overflow-y: auto; padding: 20px; } .footer { padding: 10px; background-color: #f1f1f1; text-align: center; } .processing { display: none; color: red; } .response { white-space: pre-wrap; max-height: 300px; overflow-y: auto; background-color: #f0f8ff; padding: 10px; border-radius: 5px; } .message { margin-bottom: 10px; } .user-message { text-align: left; color: blue; } .assistant-message { text-align: right; color: green; }Welcome to Math Tutor
Ask a math question: Ask© 2024 Math Tutor
// Clear the input field and display the processing message
document.getElementById('question').value = '';
processingDiv.style.display = 'block';
const response = await fetch('/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ question })
});
const data = await response.json();
if (data.error) {
responseDiv.innerHTML = data.error;
processingDiv.style.display = 'none';
return;
}
let status = 'incomplete';
while (status === 'incomplete') {
const statusResponse = await fetch(`/poll_status?thread_id=${data.thread_id}`);
const statusData = await statusResponse.json();
status = statusData.status;
if (status !== 'incomplete') {
responseDiv.innerHTML = statusData.messages.map(msg => `<div class="message ${msg.includes('**User**') ? 'user-message' : 'assistant-message'}">${msg}</div>`).join('');
processingDiv.style.display = 'none';
newConversationButton.style.display = 'inline';
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
});
document.getElementById('new-conversation-button').addEventListener('click', async () => {
const responseDiv = document.getElementById('response');
responseDiv.innerHTML = '';
document.getElementById('new-conversation-button').style.display = 'none';
await fetch('/new_conversation', { method: 'POST' });
});
</script>
Sample Output:
User (2024-06-02 23:45:16):
What is capital of France?
Assistant (2024-06-02 23:45:04):
The answer to 2 + 2 is 4.
User (2024-06-02 23:45:00):
what is 2+2
I dont get this “”“### Assistant (2024-06-02 23:45:04):
The answer to 2 + 2 is 4.”"
Until I submit this
User (2024-06-02 23:45:16):
What is capital of France?"