File size: 6,262 Bytes
d1967f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
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)