BitAI / app.py
Salt40404's picture
Update app.py
9a34660 verified
raw
history blame
3.58 kB
import gradio as gr
from huggingface_hub import InferenceClient
# Função principal da IA
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 message_chunk in client.chat_completion(
messages,
max_tokens=512,
stream=True,
temperature=0.7,
top_p=0.95,
):
token = ""
choices = message_chunk.choices
if len(choices) and choices[0].delta.content:
token = choices[0].delta.content
response += token
yield response
# HTML do ícone da BitAI
bit_icon_html = """
<svg class="bit-icon" viewBox="0 0 160 160">
<circle class="face" cx="80" cy="80" r="72"/>
<circle class="dot eye-left"/>
<circle class="dot eye-right"/>
<circle class="dot extra-dot" cx="80" cy="78" r="8"/>
</svg>
<script>
function animateEyes(node){
const wrap = node.querySelector('.bit-icon');
wrap.classList.add('thinking');
setTimeout(()=> wrap.classList.remove('thinking'), 1200);
}
// Observa novas mensagens do bot
const chatContainer = document.querySelector('.chat-interface');
if(chatContainer){
const observer = new MutationObserver(mutations => {
mutations.forEach(m => {
m.addedNodes.forEach(node => {
if(node.classList && node.classList.contains('bot')){
animateEyes(node);
// move o ícone para o topo da mensagem
node.insertAdjacentElement('afterbegin', wrap.cloneNode(true));
}
});
});
});
observer.observe(chatContainer, {childList:true, subtree:true});
}
</script>
<style>
.bit-icon{ width:30px; height:30px; margin-right:5px; vertical-align:middle;}
.face{ fill:#0b1020; }
.dot{ fill:#fff; transition: all 500ms ease; }
.eye-left { cx:56; cy:62; r:10;}
.eye-right{ cx:104; cy:62; r:10;}
.extra-dot{ opacity:0; transform:translateY(10%); transition: all 500ms ease;}
.wrap.thinking .extra-dot{ opacity:1; transform:translateY(0);}
.wrap.thinking .dot{ animation: wave 1.4s infinite ease-in-out;}
.wrap.thinking .eye-left { animation-delay:0s; }
.wrap.thinking .extra-dot{ animation-delay:0.25s;}
.wrap.thinking .eye-right{ animation-delay:0.5s;}
@keyframes wave{0%,100%{transform:translateY(0);}50%{transform:translateY(-12%);}}
</style>
"""
chatbot = gr.ChatInterface(respond, type="messages")
with gr.Blocks(css="""
body { background-color: #000; font-family: 'Arial', sans-serif; }
.gradio-container { border-radius: 20px; padding: 15px; max-width:700px; margin:20px auto; background-color:#fff; }
.chat-message { border-radius: 15px; padding:10px 15px; margin:5px 0; display:flex; align-items:flex-start;}
.chat-message.user { background-color: #dceefc; }
.chat-message.bot { background-color: #f0f0f0; justify-content:flex-start; }
""") as demo:
with gr.Sidebar():
gr.LoginButton()
chatbot.render()
gr.HTML(bit_icon_html)
if __name__ == "__main__":
demo.launch()