import gradio as gr
from openai import OpenAI
import time
import html
def predict(message, history, character, api_key, progress=gr.Progress()):
client = OpenAI(api_key=api_key)
history_openai_format = []
for human, assistant in history:
history_openai_format.append({"role": "user", "content": human})
history_openai_format.append({"role": "assistant", "content": assistant})
history_openai_format.append({"role": "user", "content": message})
response = client.chat.completions.create(
model='gpt-4',
messages=history_openai_format,
temperature=1.0,
stream=True
)
partial_message = ""
for chunk in progress.tqdm(response, desc="Generating"):
if chunk.choices[0].delta.content:
partial_message += chunk.choices[0].delta.content
yield partial_message
time.sleep(0.01)
def format_history(history):
html_content = ""
for human, ai in history:
human_formatted = html.escape(human).replace('\n', '
')
html_content += f'
You: {human_formatted}
'
if ai:
ai_formatted = html.escape(ai).replace('\n', '
')
html_content += f'AI: {ai_formatted}
'
return html_content
css = """
#chat-display {
height: 600px;
overflow-y: auto;
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 10px;
}
#chat-display::-webkit-scrollbar {
width: 10px;
}
#chat-display::-webkit-scrollbar-track {
background: #f1f1f1;
}
#chat-display::-webkit-scrollbar-thumb {
background: #888;
}
#chat-display::-webkit-scrollbar-thumb:hover {
background: #555;
}
.message {
margin-bottom: 10px;
word-wrap: break-word;
overflow-wrap: break-word;
}
.user-message, .ai-message {
padding: 5px;
border-radius: 5px;
max-height: 300px;
overflow-y: auto;
}
.user-message {
background-color: #e6f3ff;
}
.ai-message {
background-color: #f0f0f0;
}
.user-message::-webkit-scrollbar, .ai-message::-webkit-scrollbar {
width: 5px;
}
.user-message::-webkit-scrollbar-thumb, .ai-message::-webkit-scrollbar-thumb {
background: #888;
}
"""
js = """
let lastScrollTop = 0;
let isNearBottom = true;
function updateScroll() {
const chatDisplay = document.getElementById('chat-display');
if (!chatDisplay) return;
const currentScrollTop = chatDisplay.scrollTop;
const scrollHeight = chatDisplay.scrollHeight;
const clientHeight = chatDisplay.clientHeight;
// Check if user was near bottom before update
isNearBottom = (currentScrollTop + clientHeight >= scrollHeight - 50);
if (isNearBottom) {
chatDisplay.scrollTop = scrollHeight;
} else {
chatDisplay.scrollTop = lastScrollTop;
}
lastScrollTop = chatDisplay.scrollTop;
}
// Set up a MutationObserver to watch for changes in the chat display
const observer = new MutationObserver(updateScroll);
const config = { childList: true, subtree: true };
// Start observing the chat display for configured mutations
document.addEventListener('DOMContentLoaded', (event) => {
const chatDisplay = document.getElementById('chat-display');
if (chatDisplay) {
observer.observe(chatDisplay, config);
// Also update scroll on manual scroll
chatDisplay.addEventListener('scroll', function() {
lastScrollTop = chatDisplay.scrollTop;
isNearBottom = (chatDisplay.scrollTop + chatDisplay.clientHeight >= chatDisplay.scrollHeight - 50);
});
}
// Add event listener for Enter key
const textbox = document.querySelector('#component-13 input'); // Update this selector if needed
if (textbox) {
textbox.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
document.querySelector('#component-13 button').click();
}
});
}
});
"""
def user(user_message, history, character, api_key):
if user_message.strip() == "":
return "", history, format_history(history)
history.append([user_message, None])
formatted_history = format_history(history)
# Start bot response generation
bot_message_generator = predict(user_message, history[:-1], character, api_key)
for chunk in bot_message_generator:
history[-1][1] = chunk
formatted_history = format_history(history)
yield "", history, formatted_history
with gr.Blocks(css=css, js=js) as demo:
gr.Markdown("My Chatbot
")
chat_history = gr.State([])
chat_display = gr.HTML(elem_id="chat-display")
with gr.Row():
msg = gr.Textbox(
label="Your message",
lines=1,
placeholder="Type your message here... (Press Enter to send)",
elem_id="user-input"
)
send_btn = gr.Button("Send")
clear = gr.Button("Clear")
dropdown = gr.Dropdown(
["Character 1", "Character 2", "Character 3", "Character 4", "Character 5", "Character 6", "Character 7", "Character 8", "Character 9", "Character 10", "Character 11", "Character 12", "Character 13"],
label="Characters",
info="Select the character that you'd like to speak to",
value="Character 1"
)
api_key = gr.Textbox(type="password", label="OpenAI API Key")
send_btn.click(user, [msg, chat_history, dropdown, api_key], [msg, chat_history, chat_display])
msg.submit(user, [msg, chat_history, dropdown, api_key], [msg, chat_history, chat_display])
clear.click(lambda: ([], []), None, [chat_history, chat_display], queue=False)
dropdown.change(lambda x: ([], []), dropdown, [chat_history, chat_display])
demo.queue()
demo.launch(max_threads=20)