import gradio as gr from huggingface_hub import InferenceClient import os MODELS = [ {"name": "Qwen 2.5 Coder 32B", "id": "Qwen/Qwen2.5-Coder-32B-Instruct"}, {"name": "Qwen 2.5 72B", "id": "Qwen/Qwen2.5-72B-Instruct"}, {"name": "Llama 3.3 70B", "id": "meta-llama/Llama-3.3-70B-Instruct"}, {"name": "Mixtral 8x7B", "id": "mistralai/Mixtral-8x7B-Instruct-v0.1"}, {"name": "DeepSeek Coder V2", "id": "deepseek-ai/DeepSeek-Coder-V2-Instruct"}, ] def stream_chat(message, history, model_name, api_key): if not api_key or api_key.strip() == "": yield "⚠️ Please enter your Hugging Face API key in the sidebar first.\n\nGet your free API key at: https://huggingface.co/settings/tokens" return model_id = next((m["id"] for m in MODELS if m["name"] == model_name), MODELS[0]["id"]) try: client = InferenceClient(token=api_key.strip()) messages = [] for h in history: if h["role"] == "user": messages.append({"role": "user", "content": h["content"]}) elif h["role"] == "assistant": messages.append({"role": "assistant", "content": h["content"]}) messages.append({"role": "user", "content": message}) response = "" for chunk in client.chat_completion( model=model_id, messages=messages, max_tokens=8192, stream=True, temperature=0.7 ): if chunk.choices[0].delta.content: response += chunk.choices[0].delta.content yield response except Exception as e: error_msg = str(e) if "401" in error_msg or "authorization" in error_msg.lower(): yield "❌ Invalid API Key. Please check your Hugging Face token.\n\nGet a new one at: https://huggingface.co/settings/tokens" elif "429" in error_msg: yield "⏳ Rate limit exceeded. Please wait a moment and try again." else: yield f"❌ Error: {error_msg}\n\nPlease try again or select a different model." CSS = """ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --bg-primary: #0A0E14; --bg-secondary: #0D1117; --bg-tertiary: #161B22; --border: #21262D; --text-primary: #E6EDF3; --text-secondary: #8B949E; --accent: #58A6FF; --accent-hover: #79C0FF; --success: #3FB950; --error: #F85149; --warning: #F0883E; } body { font-family: 'JetBrains Mono', monospace !important; background: var(--bg-primary) !important; color: var(--text-primary) !important; } .gradio-container { max-width: 100% !important; padding: 0 !important; margin: 0 !important; background: var(--bg-primary) !important; } #header { background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-tertiary) 100%); border-bottom: 2px solid var(--border); padding: 24px 48px; position: sticky; top: 0; z-index: 100; } #header h1 { font-family: 'Space Grotesk', sans-serif; font-size: 28px; font-weight: 700; letter-spacing: -0.02em; text-transform: uppercase; background: linear-gradient(135deg, var(--accent) 0%, var(--success) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin: 0; } #header .subtitle { font-size: 12px; color: var(--text-secondary); margin-top: 4px; letter-spacing: 0.1em; text-transform: uppercase; } .sidebar-section { background: var(--bg-secondary); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 20px; } .sidebar-title { font-size: 11px; font-weight: 700; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 12px; } .api-key-input input { background: var(--bg-tertiary) !important; border: 1px solid var(--border) !important; color: var(--text-primary) !important; font-family: 'JetBrains Mono', monospace !important; font-size: 12px !important; padding: 12px !important; border-radius: 8px !important; } .api-key-input input:focus { border-color: var(--accent) !important; box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1) !important; } .security-note { background: rgba(63, 185, 80, 0.1); border: 1px solid var(--success); border-radius: 8px; padding: 12px; font-size: 11px; color: var(--success); line-height: 1.6; margin-top: 12px; } .warning-note { background: rgba(240, 136, 62, 0.1); border: 1px solid var(--warning); border-radius: 8px; padding: 12px; font-size: 11px; color: var(--warning); line-height: 1.6; margin-top: 12px; } .stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 16px; } .stat-box { background: var(--bg-tertiary); border: 1px solid var(--border); border-radius: 8px; padding: 12px; text-align: center; } .stat-value { font-size: 16px; font-weight: 700; color: var(--success); margin-bottom: 4px; } .stat-label { font-size: 9px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.1em; } .chatbot-container { background: transparent !important; border: none !important; } .message { margin-bottom: 16px !important; } .user .message-row { justify-content: flex-end !important; } .bot .message-row { justify-content: flex-start !important; } .message-content { padding: 16px 20px !important; border-radius: 16px !important; font-size: 14px !important; line-height: 1.6 !important; max-width: 70% !important; } .user .message-content { background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%) !important; color: var(--bg-primary) !important; border-radius: 16px 16px 4px 16px !important; } .bot .message-content { background: var(--bg-tertiary) !important; color: var(--text-primary) !important; border: 1px solid var(--border) !important; border-radius: 16px 16px 16px 4px !important; } #message-input textarea { background: var(--bg-tertiary) !important; border: 2px solid var(--border) !important; color: var(--text-primary) !important; font-family: 'JetBrains Mono', monospace !important; font-size: 14px !important; padding: 16px !important; border-radius: 12px !important; } #message-input textarea:focus { border-color: var(--accent) !important; box-shadow: 0 0 0 4px rgba(88, 166, 255, 0.1) !important; } .btn-primary { background: linear-gradient(135deg, var(--accent) 0%, var(--success) 100%) !important; color: var(--bg-primary) !important; font-family: 'Space Grotesk', sans-serif !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: 0.05em !important; border: none !important; padding: 14px 28px !important; border-radius: 8px !important; cursor: pointer !important; } .btn-primary:hover { transform: translateY(-2px) !important; box-shadow: 0 6px 20px rgba(88, 166, 255, 0.3) !important; } .btn-secondary { background: var(--bg-tertiary) !important; color: var(--text-primary) !important; font-family: 'Space Grotesk', sans-serif !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: 0.05em !important; border: 1px solid var(--border) !important; padding: 12px 24px !important; border-radius: 8px !important; cursor: pointer !important; } .btn-secondary:hover { background: var(--bg-secondary) !important; border-color: var(--accent) !important; } label { font-family: 'Space Grotesk', sans-serif !important; color: var(--text-secondary) !important; font-size: 11px !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: 0.05em !important; } .gr-dropdown { background: var(--bg-tertiary) !important; border: 1px solid var(--border) !important; color: var(--text-primary) !important; border-radius: 8px !important; } ::selection { background: var(--accent); color: var(--bg-primary); } ::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar-track { background: var(--bg-secondary); } ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 5px; } ::-webkit-scrollbar-thumb:hover { background: var(--text-secondary); } """ with gr.Blocks(css=CSS, theme=gr.themes.Base(), title="Neural Chat") as demo: gr.HTML(""" """) with gr.Row(): with gr.Column(scale=1, min_width=320): with gr.Group(elem_classes=["sidebar-section"]): gr.HTML('') api_key_input = gr.Textbox( label="Hugging Face API Key", type="password", placeholder="hf_...", info="Your key is stored locally in your browser session", elem_classes=["api-key-input"] ) gr.HTML("""
✓ Your API key is never stored on our servers
✓ Each user uses their own key
✓ Completely secure and private
""") gr.HTML("""
📌 Get your free API key:
https://huggingface.co/settings/tokens
""") with gr.Group(elem_classes=["sidebar-section"]): gr.HTML('') model_selector = gr.Dropdown( choices=[m["name"] for m in MODELS], value=MODELS[0]["name"], label="Active Model", interactive=True, ) with gr.Group(elem_classes=["sidebar-section"]): gr.HTML('') gr.HTML("""
SECURE
32K
CONTEXT
FREE
TIER
5
MODELS
""") with gr.Group(elem_classes=["sidebar-section"]): gr.HTML('') clear_btn = gr.Button("⟳ NEW CHAT", elem_classes=["btn-secondary"], size="sm") retry_btn = gr.Button("🔄 RETRY LAST", elem_classes=["btn-secondary"], size="sm") with gr.Column(scale=3): chatbot = gr.Chatbot( value=[], height=600, show_label=False, type="messages", avatar_images=(None, "⬡"), elem_classes=["chatbot-container"] ) msg_input = gr.Textbox( placeholder="Type your message... (Shift+Enter for new line)", show_label=False, lines=3, max_lines=10, elem_id="message-input" ) with gr.Row(): send_btn = gr.Button("SEND MESSAGE", elem_classes=["btn-primary"], scale=3) stop_btn = gr.Button("⏹ STOP", elem_classes=["btn-secondary"], scale=1) gr.HTML('') gr.Examples( examples=[ "Explain quantum computing in simple terms", "Write a Python function for fibonacci sequence", "What are the SOLID principles with examples?", "Create a React component for a modal dialog", "Help me optimize this SQL query", "Explain async/await in JavaScript", ], inputs=msg_input, ) def user_msg(message, history): if not message.strip(): return "", history return "", history + [{"role": "user", "content": message}] def bot_msg(history, model, api_key): if not history or history[-1]["role"] != "user": return history user_message = history[-1]["content"] history.append({"role": "assistant", "content": ""}) for response in stream_chat(user_message, history[:-1], model, api_key): history[-1]["content"] = response yield history msg_input.submit( user_msg, [msg_input, chatbot], [msg_input, chatbot], queue=False ).then( bot_msg, [chatbot, model_selector, api_key_input], chatbot ) send_btn.click( user_msg, [msg_input, chatbot], [msg_input, chatbot], queue=False ).then( bot_msg, [chatbot, model_selector, api_key_input], chatbot ) clear_btn.click(lambda: [], None, chatbot, queue=False) def retry_last_msg(history): if not history: return history if history[-1]["role"] == "assistant": history = history[:-1] if history and history[-1]["role"] == "user": last_user_msg = history[-1] history = history[:-1] return history + [last_user_msg] return history retry_btn.click( retry_last_msg, chatbot, chatbot, queue=False ).then( bot_msg, [chatbot, model_selector, api_key_input], chatbot ) if __name__ == "__main__": demo.queue(max_size=30) demo.launch( server_name="0.0.0.0", server_port=7860, show_error=True )