QnoM's picture
Update app.py
f56efb4 verified
Raw History Blame Contribute Delete
4.42 kB
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"""
<div id="confirm-modal" role="dialog" aria-modal="true" aria-labelledby="confirm-title">
<div id="confirm-card">
<h3 id="confirm-title">Confirmer ?</h3>
<p>Souhaitez-vous continuer ?</p>
<div id="confirm-actions">
<button type="button"
onclick="setGradioValue('bridge-choice','non'); document.getElementById('confirm-modal').style.display='none'; document.body.style.overflow=''">Non</button>
<button type="button" class="primary"
onclick="setGradioValue('bridge-choice','oui'); document.getElementById('confirm-modal').style.display='none'; document.body.style.overflow=''">Oui</button>
</div>
</div>
</div>
"""
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()