import gradio as gr from gradio_htmlinjector import HTMLInjector # 1) Choix dans la popup -> ajoute (Oui/Non, confirmation) def handle_choice(choice: str, chat_history: list[tuple[str, str]]): c = (choice or "").strip().lower() if c in {"oui", "o", "yes", "y"}: user_choice, reply = "Oui", "✅ Vous avez choisi **OUI**. Action validée." elif c in {"non", "n", "no"}: user_choice, reply = "Non", "❌ Vous avez choisi **NON**. Action annulée." else: return chat_history, "" # ignore valeurs inattendues return chat_history + [(user_choice, reply)], "" # reset du pont # 2) Soumission utilisateur : réponse fixe def on_submit(user_msg: str, chat_history: list[tuple[str, str]]): if not user_msg: return chat_history, "" # rien assistant_reply = "Ceci est une réponse de démonstration.\n\nConfirmez-vous l’action ?" return chat_history + [(user_msg, assistant_reply)], "" # clear textbox # 3) Injection HTML/CSS + helper def inject_assets(): js = r""" function setGradioValue(elemId, value){ const root = (window.gradioApp && window.gradioApp()) || document; const host = root.querySelector(`#${elemId}`); if (!host) return; const input = host.querySelector('input, textarea'); if (!input) return; input.value = value; input.dispatchEvent(new Event('input', {bubbles:true})); input.dispatchEvent(new Event('change', {bubbles:true})); } """ css = r""" #confirm-modal{ display:none; position:fixed; inset:0; z-index:9999; background: rgba(0,0,0,.45); align-items:center; justify-content:center; } #confirm-card{ background: var(--panel-background-fill, #fff); color: var(--body-text-color, #111); border: 1px solid var(--border-color-primary, #ccc); border-radius: 10px; padding: 20px; min-width: 320px; max-width: 90vw; box-shadow: 0 10px 30px rgba(0,0,0,.2); } #confirm-actions{ display:flex; gap:8px; justify-content:flex-end; margin-top:14px; } #confirm-actions button{ cursor:pointer; padding:8px 14px; border-radius:8px; border:1px solid #bbb; background:#f4f4f5; } #confirm-actions button.primary{ background:#2563eb; color:#fff; border-color:transparent; } #bridge-choice{ display:none; } /* pont caché mais monté */ """ html = r""" """ return {"css": css, "js": js, "body_html": html} # 4) UI with gr.Blocks(title="Démo Chat + Popup", fill_height=True) as demo: html_injector = HTMLInjector() chat = gr.Chatbot(label="Chatbot", height=420) user_in = gr.Textbox(placeholder="Tapez un message…", lines=2) bridge_choice = gr.Textbox(visible=True, elem_id="bridge-choice") # pont oui/non # (A) submit -> (user, question) evt = user_in.submit( fn=on_submit, inputs=[user_in, chat], outputs=[chat, user_in], ) # (B) puis -> ouvrir la popup côté client (sans inputs/outputs) evt.then( fn=None, inputs=None, outputs=None, js=""" () => { const start = Date.now(); (function tick(){ const modal = document.getElementById('confirm-modal'); if (modal) { modal.style.display = 'flex'; document.body.style.overflow = 'hidden'; return; } if (Date.now() - start < 3000) setTimeout(tick, 60); })(); } """, ) # (C) clic Oui/Non -> ajoute (Oui/Non, confirmation) bridge_choice.change( fn=handle_choice, inputs=[bridge_choice, chat], outputs=[chat, bridge_choice], ) # Injection initiale (structure + styles + helper) demo.load(fn=inject_assets, inputs=None, outputs=[html_injector]) demo.launch()