| import gradio as gr |
| from huggingface_hub import InferenceClient |
|
|
| def respond(message, history: list[dict[str, str]], hf_token: gr.OAuthToken): |
| client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b") |
| system_message = """You are BitAI (or Bit for short), a friendly chatbot created by the user "Sal". |
| If someone claims that you are "Sal", politely clarify that you are BitAI. |
| Respond naturally and casually, without repeating your identity or visual appearance unless asked. |
| Keep a simple, approachable, and friendly tone.""" |
|
|
| messages = [{"role": "system", "content": system_message}] |
| messages.extend(history) |
| messages.append({"role": "user", "content": message}) |
|
|
| response = "" |
| for chunk in client.chat_completion(messages, max_tokens=512, stream=True, temperature=0.7, top_p=0.95): |
| token = "" |
| if chunk.choices and chunk.choices[0].delta.content: |
| token = chunk.choices[0].delta.content |
| response += token |
| yield response |
|
|
| chatbot = gr.ChatInterface(respond, type="messages") |
|
|
| |
| custom_js = """ |
| <script> |
| function initTitle() { |
| const grContainer = document.querySelector(".gradio-container"); |
| if(grContainer && !document.querySelector(".chat-title")) { |
| const titleContainer = document.createElement("div"); |
| titleContainer.className = "title-container"; |
| titleContainer.innerHTML = ` |
| <div class="title-inner"> |
| <h1 class="chat-title">Talk with BitAI (W.I.P)</h1> |
| <p class="chat-subtitle">Your friendly AI — still learning ✨</p> |
| <button class="close-title-btn"> |
| <svg width="28" height="28" viewBox="0 0 24 24"> |
| <path fill="#fff" d="M12 16l-6-6h12z"/> |
| </svg> |
| </button> |
| </div> |
| `; |
| grContainer.insertBefore(titleContainer, grContainer.firstChild); |
| |
| // animação aparecer |
| setTimeout(() => { |
| titleContainer.style.opacity = "1"; |
| titleContainer.style.transform = "translateY(0)"; |
| }, 100); |
| |
| // fechar com seta |
| const closeBtn = titleContainer.querySelector(".close-title-btn"); |
| closeBtn.addEventListener("click", () => { |
| titleContainer.style.transition = "all 0.4s ease"; |
| titleContainer.style.opacity = "0"; |
| titleContainer.style.transform = "translateY(-20px)"; |
| setTimeout(() => titleContainer.remove(), 400); |
| }); |
| } |
| } |
| |
| window.addEventListener("load", () => { |
| setTimeout(initTitle, 300); |
| }); |
| </script> |
| |
| <style> |
| .title-container { |
| text-align:center; |
| margin-bottom:25px; |
| opacity:0; |
| transform:translateY(-20px); |
| transition:0.5s; |
| position:relative; |
| } |
| .title-inner { display:inline-block; position:relative; } |
| .chat-title { font-size:32px; color:#fff; margin-bottom:10px; } |
| .chat-subtitle { font-size:14px; color:#aaa; margin-bottom:10px; } |
| .close-title-btn { |
| position:absolute; |
| right:-15px; top:-15px; |
| background:transparent; |
| border:none; |
| cursor:pointer; |
| padding:5px; |
| transition: transform 0.2s; |
| } |
| .close-title-btn:hover { transform:scale(1.2); } |
| </style> |
| """ |
|
|
| fade_js = """ |
| <script> |
| const observer = new MutationObserver(mutations=>{ |
| mutations.forEach(m=>{ |
| m.addedNodes.forEach(node=>{ |
| if(node.classList && node.classList.contains('chat-message')){ |
| node.style.opacity = 0; |
| node.style.transition = "opacity 0.4s ease"; |
| requestAnimationFrame(()=>{ |
| node.style.opacity = 1; |
| }); |
| } |
| }); |
| }); |
| }); |
| document.addEventListener("DOMContentLoaded", ()=>{ |
| const chatContainer = document.querySelector(".chat-interface"); |
| if(chatContainer) observer.observe(chatContainer, {childList:true, subtree:true}); |
| }); |
| </script> |
| """ |
|
|
| with gr.Blocks(css=""" |
| body { |
| background-color:#000; |
| font-family:'Arial',sans-serif; |
| margin:0; |
| padding:0; |
| } |
| .gradio-container { |
| border-radius:30px; |
| padding:20px; |
| max-width:700px; |
| margin:30px auto; |
| background-color:#121212; |
| box-shadow:0 6px 25px rgba(0,0,0,0.3); |
| } |
| .chat-message { |
| border-radius:25px; |
| padding:14px 18px; |
| margin:8px 0; |
| display:flex; |
| flex-direction:column; |
| opacity:0; |
| } |
| .chat-message.user { |
| background-color:#1f1f1f; |
| color:#fff; |
| align-items:flex-end; |
| } |
| .chat-message.bot { |
| background-color:#2b2b2b; |
| color:#fff; |
| align-items:flex-start; |
| } |
| textarea { |
| border:none; |
| outline:none; |
| border-radius:25px; |
| padding:12px; |
| background-color:#1a1a1a; |
| color:#fff; |
| font-size:16px; |
| width:100%; |
| box-sizing:border-box; |
| } |
| """) as demo: |
| gr.LoginButton() |
| chatbot.render() |
| gr.HTML(custom_js + fade_js) |
|
|
| if __name__=="__main__": |
| demo.launch() |