Hi friends,
I’m new to Gradio, and I’m building an app with the layout of 2 columns:
- The left column is a chatbot
- The right one is like a glossary
The workflow is when a user chats with the bot, they can highlight text and click on a floating “Show” button to show the selected term in the glossary.
My trouble is when the “Show” button clicked, I want to invoke a Python function with the selected term passed in to handle some logic before returning the output to be attached to the glossary. I don’t know how to implement this properly.
The following code is what I’ve tried so far, it does capture the highlighted text, but clicking the “Show” button doesn’t do anything while I expect it should dispatch some events to simulate Gradio events, hence triggering handlers.
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=3):
chatbot = gr.Chatbot(
type="messages"
)
state = gr.State(value=[])
txt = gr.Textbox(
placeholder="Type your answer here…",
visible=True
)
demo.load(init_chat, inputs=None, outputs=[chatbot, state])
txt.submit(generate_chat_completion, inputs=[txt, state], outputs=[chatbot, state, txt])
with gr.Column(scale=1):
glossary = gr.Markdown("Glossary will appear here...")
selected_term = gr.Textbox(visible=False, elem_id="selected_term")
selected_term.submit(fn=show_term, inputs=selected_term, outputs=glossary)
js_script = """
async () => {
globalThis.setupShowButton = () => {
// Create the floating button and attach to body
if (!document.getElementById("show-btn")) {
const showBtn = document.createElement("button");
showBtn.id = "show-btn";
showBtn.textContent = "Show";
showBtn.style.display = "none";
showBtn.style.position = "absolute";
showBtn.style.zIndex = "999999";
showBtn.style.background = "#2563eb";
document.body.appendChild(showBtn);
showBtn.addEventListener("click", () => {
const term = showBtn.getAttribute("data-selection");
const textbox = document.querySelector('#selected_term');
if (textbox) {
textbox.value = term;
const inputEvent = new Event("input", { bubbles: true });
textbox.dispatchEvent(inputEvent);
const keyboardEvent = new KeyboardEvent("keydown", {
bubbles: true,
cancelable: true,
key: "Enter",
code: "Enter"
});
textbox.dispatchEvent(keyboardEvent);
showBtn.style.display = "none";
}
});
}
const showBtn = document.getElementById("show-btn");
document.addEventListener("mouseup", function () {
const selection = window.getSelection().toString().trim();
if (!selection) {
showBtn.style.display = "none";
return;
}
try {
const range = window.getSelection().getRangeAt(0);
const rect = range.getBoundingClientRect();
showBtn.style.display = "block";
showBtn.setAttribute("data-selection", selection);
} catch (err) {
console.warn("Range error:", err);
}
});
};
setTimeout(globalThis.setupShowButton, 100);
}
"""
demo.load(None, None, None, js=js_script)
return demo
Any help would be much appreciated. Thanks so much for your support!