import gradio as gr import torch from transformers import pipeline import base64 import os def get_logo_html(): if os.path.exists("logo.png"): with open("logo.png", "rb") as f: b64 = base64.b64encode(f.read()).decode("utf-8") img = f'' else: img = "" return f"""
{img}
BrainGPT
NEURAL ENGINE ONLINE - POWERED BY QWEN2
""" CSS = """ @import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;600;700&family=Share+Tech+Mono&display=swap'); *, *::before, *::after { box-sizing: border-box; } body, .gradio-container { background: #0a0a0a !important; font-family: 'Rajdhani', sans-serif !important; color: #e8e0d0 !important; } .braingpt-header { display: flex; align-items: center; gap: 18px; padding: 18px 24px 10px 24px; border-bottom: 1px solid #2a1a00; background: linear-gradient(180deg, #110900 0%, #0a0a0a 100%); margin-bottom: 8px; } .braingpt-title { font-family: 'Rajdhani', sans-serif; font-size: 2rem; font-weight: 700; letter-spacing: 3px; background: linear-gradient(90deg, #ff6a00, #ffb347, #ff6a00); background-size: 200%; -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; animation: shimmer 3s linear infinite; text-transform: uppercase; } .braingpt-sub { font-family: 'Share Tech Mono', monospace; font-size: 0.72rem; color: #664422; letter-spacing: 2px; margin-top: 2px; } @keyframes shimmer { 0% { background-position: 0% } 100% { background-position: 200% } } .chatbot { background: #0d0d0d !important; border: 1px solid #1f1208 !important; border-radius: 12px !important; font-family: 'Rajdhani', sans-serif !important; font-size: 1.05rem !important; } .message.user { background: linear-gradient(135deg, #1a0d00, #2a1500) !important; border: 1px solid #3d1f00 !important; border-radius: 12px 12px 2px 12px !important; color: #ffcc88 !important; font-weight: 600 !important; } .message.bot { background: linear-gradient(135deg, #0f0f0f, #161208) !important; border: 1px solid #2b1f00 !important; border-radius: 12px 12px 12px 2px !important; color: #e8d8b8 !important; } .thinking-bar { display: none; align-items: center; gap: 10px; padding: 8px 16px; margin: 4px 0 8px 0; background: linear-gradient(90deg, #1a0d00, #0d0d0d); border-left: 3px solid #ff6a00; border-radius: 0 8px 8px 0; font-family: 'Share Tech Mono', monospace; font-size: 0.8rem; color: #ff8c33; letter-spacing: 1px; } .thinking-bar.active { display: flex; } .thinking-dots span { display: inline-block; width: 6px; height: 6px; background: #ff6a00; border-radius: 50%; margin: 0 2px; animation: bounce-dot 1.2s infinite; } .thinking-dots span:nth-child(2) { animation-delay: 0.2s; } .thinking-dots span:nth-child(3) { animation-delay: 0.4s; } @keyframes bounce-dot { 0%, 80%, 100% { transform: translateY(0); opacity: 0.4; } 40% { transform: translateY(-6px); opacity: 1; } } #msg-input textarea { background: #111 !important; border: 1px solid #2b1800 !important; border-radius: 10px !important; color: #ffcc88 !important; font-family: 'Rajdhani', sans-serif !important; font-size: 1rem !important; caret-color: #ff6a00 !important; resize: none !important; padding: 12px 14px !important; transition: border-color 0.2s; } #msg-input textarea:focus { border-color: #ff6a00 !important; box-shadow: 0 0 12px #ff6a0033 !important; outline: none !important; } #send-btn, #clear-btn { font-family: 'Rajdhani', sans-serif !important; font-weight: 700 !important; letter-spacing: 1.5px !important; border-radius: 10px !important; border: none !important; cursor: pointer !important; transition: all 0.18s ease !important; text-transform: uppercase !important; font-size: 0.9rem !important; padding: 12px 22px !important; } #send-btn { background: linear-gradient(135deg, #ff6a00, #cc4400) !important; color: #fff !important; box-shadow: 0 0 16px #ff6a0044 !important; min-width: 110px !important; } #send-btn:hover { background: linear-gradient(135deg, #ff8c33, #ff5500) !important; box-shadow: 0 0 28px #ff6a0077 !important; transform: translateY(-1px) !important; } #send-btn.thinking { background: linear-gradient(135deg, #2a1500, #1a0d00) !important; color: #ff8c33 !important; pointer-events: none !important; } #clear-btn { background: #161208 !important; color: #664422 !important; border: 1px solid #2b1800 !important; } #clear-btn:hover { background: #1f1208 !important; color: #ff8c33 !important; border-color: #ff6a00 !important; } .examples-table td { background: #111 !important; border: 1px solid #1f1200 !important; color: #cc7733 !important; font-family: 'Rajdhani', sans-serif !important; border-radius: 6px !important; cursor: pointer !important; transition: background 0.15s, color 0.15s !important; } .examples-table td:hover { background: #1f1000 !important; color: #ff8c33 !important; border-color: #ff6a00 !important; } ::-webkit-scrollbar { width: 5px; } ::-webkit-scrollbar-track { background: #0a0a0a; } ::-webkit-scrollbar-thumb { background: #2b1800; border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: #ff6a00; } """ JS = """ () => { function setup() { const sendBtn = document.getElementById('send-btn'); const bar = document.getElementById('thinking-bar'); if (!sendBtn || !bar) return; new MutationObserver(() => { const loading = document.querySelector('.generating') !== null || document.querySelector('.eta-bar') !== null; if (loading) { sendBtn.classList.add('thinking'); const s = sendBtn.querySelector('span'); if (s) s.innerText = 'Thinking...'; bar.classList.add('active'); } else { sendBtn.classList.remove('thinking'); const s = sendBtn.querySelector('span'); if (s) s.innerText = 'Enviar'; bar.classList.remove('active'); } }).observe(document.body, { childList: true, subtree: true }); } setTimeout(setup, 1500); } """ pipe = pipeline( "text-generation", model="Qwen/Qwen2-1.5B-Instruct", torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32, device_map="auto", ) def chat(message, history): if not message or not message.strip(): return "" try: if len(message) > 1000: message = message[:1000] + "... [texto cortado]" system_msg = ( "Voce e BrainGPT, uma inteligencia artificial poderosa, direta e precisa. " "Responda sempre em portugues de forma clara e concisa. " "Nunca invente factos. Se nao souber, diga claramente." ) msgs = [{"role": "system", "content": system_msg}] for u, b in history[-6:]: if u: msgs.append({"role": "user", "content": u}) if b: msgs.append({"role": "assistant", "content": b}) msgs.append({"role": "user", "content": message}) prompt = pipe.tokenizer.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True) if len(prompt) > 3500: return "Conversa muito longa. Clica em Limpar e recomeça." result = pipe( prompt, max_new_tokens=280, do_sample=True, temperature=0.7, top_p=0.9, pad_token_id=pipe.tokenizer.eos_token_id, truncation=True, ) resposta = result[0]["generated_text"].split("<|im_start|>assistant\n")[-1].strip() resposta = resposta.replace("<|im_end|>", "").strip() return resposta if resposta else "Resposta vazia. Tenta reformular." except torch.cuda.OutOfMemoryError: return "Memoria GPU esgotada. Clica em Limpar e tenta novamente." except Exception as e: return f"Erro: {str(e)[:150]}" def user_submit(message, history): if not message.strip(): return "", history return "", history + [[message, None]] def bot_respond(history): if not history or history[-1][1] is not None: return history history[-1][1] = chat(history[-1][0], history[:-1]) return history with gr.Blocks(title="BrainGPT") as demo: gr.HTML(get_logo_html()) gr.HTML("""
THINKING...
""") chatbot = gr.Chatbot(label="", height=480, bubble_full_width=False) with gr.Row(): msg = gr.Textbox( placeholder="Escreve a tua mensagem...", show_label=False, lines=1, max_lines=5, elem_id="msg-input", scale=8, ) send_btn = gr.Button("Enviar", elem_id="send-btn", variant="primary", scale=2) clear_btn = gr.Button("Limpar", elem_id="clear-btn", variant="secondary", scale=1) gr.Examples( examples=["Quem es tu?", "Explica IA em 3 frases", "Como funciona o Bitcoin?", "5 dicas de produtividade"], inputs=msg, label="Exemplos", ) msg.submit(user_submit, [msg, chatbot], [msg, chatbot], queue=False).then(bot_respond, chatbot, chatbot) send_btn.click(user_submit, [msg, chatbot], [msg, chatbot], queue=False).then(bot_respond, chatbot, chatbot) clear_btn.click(lambda: ([], ""), outputs=[chatbot, msg], queue=False) demo.queue(max_size=5).launch(css=CSS, js=JS)