import gradio as gr import requests import json import os from typing import Iterator # Model list MODELS = [ "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", "deepseek/deepseek-r1-0528", "deepseek/deepseek-chat-v3-0324", "openai/gpt-4.1", "openai/gpt-4.1-mini", "google/gemini-2.5-pro-preview", "microsoft/phi-4-reasoning-plus", "qwen/qwen3-30b-a3b", "meta-llama/llama-guard-4-12b", "meta-llama/llama-4-maverick", "meta-llama/llama-4-scout", "x-ai/grok-2-vision-1212" ] def get_openrouter_response(message: str, history: list, model: str, api_key: str) -> Iterator[str]: """Stream response from OpenRouter API""" if not api_key: yield "❌ Please enter your OpenRouter API key in the settings below." return # Prepare messages for API messages = [] # Add conversation history for user_msg, assistant_msg in history: messages.append({"role": "user", "content": user_msg}) if assistant_msg: messages.append({"role": "assistant", "content": assistant_msg}) # Add current message messages.append({"role": "user", "content": message}) # API request headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "HTTP-Referer": "https://huggingface.co", "X-Title": "HuggingFace OpenRouter Chat" } data = { "model": model, "messages": messages, "stream": True } try: response = requests.post( "https://openrouter.ai/api/v1/chat/completions", headers=headers, json=data, stream=True ) if response.status_code != 200: yield f"❌ Error: {response.status_code} - {response.text}" return # Stream the response full_response = "" for line in response.iter_lines(): if line: line_text = line.decode('utf-8') if line_text.startswith('data: '): if line_text.strip() == 'data: [DONE]': break try: json_data = json.loads(line_text[6:]) if 'choices' in json_data and len(json_data['choices']) > 0: delta = json_data['choices'][0].get('delta', {}) if 'content' in delta: content = delta['content'] full_response += content yield full_response except json.JSONDecodeError: continue except Exception as e: yield f"❌ Error: {str(e)}" # Custom CSS custom_css = """ /* Modern Dark Theme */ .gradio-container { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); font-family: 'Inter', 'Segoe UI', sans-serif; } /* Header Styling */ .main-header { text-align: center; padding: 2rem 0; margin-bottom: 2rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 15px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); } .main-header h1 { color: white; font-size: 2.5rem; font-weight: 700; margin: 0; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); } .main-header p { color: rgba(255, 255, 255, 0.9); font-size: 1.1rem; margin-top: 0.5rem; } /* Chat Interface */ #chatbot { /* Changed from important declarations for better compatibility */ background-color: rgba(30, 30, 50, 0.8); border-radius: 15px; border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); } #chatbot .user { background-color: rgba(102, 126, 234, 0.2); border-left: 4px solid #667eea; border-radius: 10px; padding: 10px; margin: 5px; } #chatbot .bot { background-color: rgba(118, 75, 162, 0.2); border-left: 4px solid #764ba2; border-radius: 10px; padding: 10px; margin: 5px; } /* Input Areas */ #msg-input { background-color: rgba(30, 30, 50, 0.8); border: 2px solid rgba(102, 126, 234, 0.5); border-radius: 10px; color: white; font-size: 16px; transition: all 0.3s ease; } #msg-input:focus { border-color: #667eea; box-shadow: 0 0 15px rgba(102, 126, 234, 0.3); } /* Buttons */ .submit-btn, .clear-btn, .settings-btn { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; border-radius: 10px; color: white; font-weight: 600; padding: 12px 24px; transition: all 0.3s ease; cursor: pointer; } .submit-btn:hover, .clear-btn:hover, .settings-btn:hover { transform: translateY(-2px); box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4); } /* Dropdown */ #model-dropdown { background-color: rgba(30, 30, 50, 0.9); border: 2px solid rgba(102, 126, 234, 0.5); border-radius: 10px; color: white; padding: 10px; font-size: 14px; } #model-dropdown:focus { border-color: #667eea; outline: none; } /* Settings Panel */ .settings-panel { background: rgba(30, 30, 50, 0.8); border-radius: 15px; padding: 20px; margin-top: 20px; border: 1px solid rgba(255, 255, 255, 0.1); } /* API Key Input */ #api-key-input { background-color: rgba(20, 20, 40, 0.8); border: 2px solid rgba(102, 126, 234, 0.3); border-radius: 10px; color: white; font-family: monospace; } /* Info Box */ .info-box { background: rgba(102, 126, 234, 0.1); border-left: 4px solid #667eea; border-radius: 8px; padding: 15px; margin: 10px 0; } /* Model List */ .model-info { background: rgba(30, 30, 50, 0.6); border-radius: 10px; padding: 15px; margin: 10px 0; } /* Labels */ label { color: rgba(255, 255, 255, 0.9); font-weight: 600; margin-bottom: 5px; } /* Dark theme for gradio components */ .dark { --block-background-fill: rgba(30, 30, 50, 0.8); --body-background-fill: transparent; --color-accent: #667eea; } """ # Create interface with gr.Blocks(css=custom_css, theme=gr.themes.Soft(primary_hue="violet", neutral_hue="slate").set( loader_color="#667eea", slider_color="#667eea", )) as demo: # Header gr.HTML("""

πŸš€Try my bestπŸš€

Learn by doing

""") # State for API key api_key_state = gr.State("") with gr.Row(): with gr.Column(scale=3): # Chat interface chatbot = gr.Chatbot( label="Chat", elem_id="chatbot", height=500, bubble_full_width=False ) with gr.Row(): msg = gr.Textbox( label="Type your message", placeholder="Ask me anything...", lines=2, max_lines=4, elem_id="msg-input" ) with gr.Row(): submit = gr.Button("πŸš€ Send", variant="primary", elem_classes="submit-btn") clear = gr.Button("πŸ—‘οΈ Clear", variant="secondary", elem_classes="clear-btn") with gr.Column(scale=1): # Model selection model_dropdown = gr.Dropdown( choices=MODELS, value=MODELS[0], label="πŸ€– Select Model", interactive=True, elem_id="model-dropdown" ) gr.HTML("""

Available Models:

""") # Settings with gr.Accordion("βš™οΈ Settings", open=False): api_key_input = gr.Textbox( label="OpenRouter API Key", placeholder="sk-or-v1-...", type="password", elem_id="api-key-input" ) gr.HTML("""

Get your API key from OpenRouter

""") # Event handlers def update_api_key(key): return key api_key_input.change(update_api_key, inputs=[api_key_input], outputs=[api_key_state]) def user_submit(message, history, model, api_key): return "", history + [[message, None]] def bot_response(history, model, api_key): if not history: return history user_message = history[-1][0] bot_message = "" for chunk in get_openrouter_response(user_message, history[:-1], model, api_key): bot_message = chunk history[-1][1] = bot_message yield history msg.submit( user_submit, [msg, chatbot, model_dropdown, api_key_state], [msg, chatbot] ).then( bot_response, [chatbot, model_dropdown, api_key_state], chatbot ) submit.click( user_submit, [msg, chatbot, model_dropdown, api_key_state], [msg, chatbot] ).then( bot_response, [chatbot, model_dropdown, api_key_state], chatbot ) clear.click(lambda: None, None, chatbot) # Footer gr.HTML("""

Built with AHMAD ANUGERAH using Gradio & OpenRouter

""") if __name__ == "__main__": demo.launch()