firefox-chat / app.py
jbl2024's picture
Upload folder using huggingface_hub
d1967f6 verified
import gradio as gr
import json
from urllib.parse import parse_qs, urlparse
# Function to process messages with context
def process_message(message, history, context_json):
# Parse context from JSON string
try:
context = json.loads(context_json)
except:
context = {"error": "Invalid context data"}
# Here you would connect to your chatbot backend
# and provide both the message and the context
# For demo purposes, we'll just echo the message with context info
response = f"Received: {message}\n\nContext summary: Page titled '{context.get('title', 'Unknown')}'"
# Format response for Gradio Chatbot using the newer messages format
history.append({"role": "user", "content": message})
history.append({"role": "assistant", "content": response})
return history
# Create Gradio interface
with gr.Blocks(css="#chatbot {height: 400px; overflow-y: auto;}") as demo:
gr.HTML("<h2>Contextual Chatbot</h2>")
# Hidden context state - will be updated via JavaScript
context_json = gr.State('{}')
# Optional: Show context for debugging
with gr.Accordion("Page Context", open=False):
context_display = gr.JSON(value={})
update_button = gr.Button("Request Full Context")
# Main chatbot interface
chatbot = gr.Chatbot(value=[], type="messages")
msg = gr.Textbox(placeholder="Ask about this page...")
clear = gr.Button("Clear")
# Handle sending messages
msg.submit(process_message, [msg, chatbot, context_json], [chatbot])
# Clear chat history
clear.click(lambda: [], None, chatbot, queue=False)
# JavaScript to handle context
gr.HTML("""
<script>
// Debug function
function logDebug(message, data) {
console.log(`[DEBUG] ${message}`, data);
}
// Function to update the context state in Gradio
function updateContextState(contextData) {
logDebug("Updating context state with:", contextData);
// Find the hidden state element for context
const stateElements = Array.from(document.querySelectorAll('input[type="hidden"]'));
const contextStateElem = stateElements.find(el => el.name && el.name.includes('context_json'));
if (contextStateElem) {
// Update the hidden input value
contextStateElem.value = JSON.stringify(contextData);
// Create and dispatch a change event
const event = new Event('change', { bubbles: true });
contextStateElem.dispatchEvent(event);
logDebug("Context state updated", contextStateElem.value);
return true;
} else {
console.error("Could not find context state element");
return false;
}
}
// Function to update the visible JSON display
function updateJsonDisplay(contextData) {
logDebug("Updating JSON display with:", contextData);
// Find the JSON component's textarea
const jsonTextarea = document.querySelector('.json-component textarea');
if (jsonTextarea) {
jsonTextarea.value = JSON.stringify(contextData, null, 2);
// Find and click the submit button to update the value
const submitButton = jsonTextarea.closest('.json-component').querySelector('button');
if (submitButton) {
submitButton.click();
logDebug("JSON display updated");
return true;
}
}
console.error("Could not update JSON display");
return false;
}
// Function to request full context
function requestFullContext() {
logDebug("Requesting full context from parent");
window.parent.postMessage({type: 'getFullContext'}, '*');
}
// Try to get context from URL parameters
function getContextFromUrl() {
const urlParams = new URLSearchParams(window.location.search);
const contextParam = urlParams.get('context');
if (contextParam) {
try {
const parsedContext = JSON.parse(decodeURIComponent(contextParam));
logDebug("Got context from URL:", parsedContext);
return parsedContext;
} catch (e) {
console.error("Failed to parse context from URL:", e);
}
}
return null;
}
// Listen for messages from parent (extension)
window.addEventListener('message', function(event) {
logDebug("Received message from parent:", event.data);
if (event.data.type === 'fullContext') {
// We got context data from the parent
const contextData = event.data.content;
// Update both the hidden state and visible display
updateContextState(contextData);
updateJsonDisplay(contextData);
}
});
// Initialize when the page is fully loaded
document.addEventListener('DOMContentLoaded', function() {
logDebug("DOM fully loaded");
// Wait for Gradio to fully initialize
setTimeout(function() {
logDebug("Initializing context handling");
// Set up the update button
const updateButton = document.querySelector('button.update-button');
if (updateButton) {
updateButton.addEventListener('click', requestFullContext);
logDebug("Update button handler attached");
}
// First try to get context from URL
const urlContext = getContextFromUrl();
if (urlContext) {
updateContextState(urlContext);
updateJsonDisplay(urlContext);
} else {
// If no URL context, request from parent
requestFullContext();
}
}, 2000); // Wait longer for Gradio to initialize
});
</script>
""")
# Add class to update button for JavaScript selection
update_button.elem_classes = ["update-button"]
# Launch the app
if __name__ == "__main__":
demo.launch(share=True)