Spaces:
Sleeping
Sleeping
| """ | |
| CyberGuide Gradio Web App | |
| Modern dark-themed UI with cybersecurity terminal aesthetic | |
| """ | |
| import os | |
| import gradio as gr | |
| from model import chat_streaming, get_model | |
| # CSS for dark theme with green terminal aesthetic | |
| CUSTOM_CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Inter:wght@400;500;600&display=swap'); | |
| * { | |
| font-family: 'Inter', sans-serif; | |
| } | |
| /* Root dark theme */ | |
| :root { | |
| --primary-green: #00ff41; | |
| --dark-bg: #0d1117; | |
| --darker-bg: #010409; | |
| --card-bg: #161b22; | |
| --border-color: #30363d; | |
| --text-light: #c9d1d9; | |
| --text-muted: #8b949e; | |
| } | |
| body, .gradio-container { | |
| background-color: var(--dark-bg) !important; | |
| color: var(--text-light) !important; | |
| } | |
| /* Main container */ | |
| .gradio-container { | |
| max-width: 1400px; | |
| } | |
| /* Header */ | |
| .gradio-container > .prose { | |
| background: linear-gradient(135deg, var(--darker-bg) 0%, var(--card-bg) 100%); | |
| border-bottom: 2px solid var(--primary-green); | |
| padding: 20px !important; | |
| border-radius: 0; | |
| } | |
| .gradio-container > .prose h1 { | |
| color: var(--primary-green) !important; | |
| text-shadow: 0 0 10px rgba(0, 255, 65, 0.3); | |
| font-weight: 600; | |
| margin: 0 !important; | |
| font-size: 28px !important; | |
| } | |
| /* Main layout - row */ | |
| .row { | |
| gap: 20px; | |
| } | |
| /* Sidebar Container */ | |
| .sidebar-container { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 15px; | |
| background-color: var(--card-bg); | |
| padding: 20px; | |
| border-radius: 8px; | |
| border: 1px solid var(--border-color); | |
| height: fit-content; | |
| } | |
| .sidebar-container > label { | |
| color: var(--primary-green) !important; | |
| font-weight: 600; | |
| font-size: 14px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| } | |
| /* Quick question buttons */ | |
| .quick-btn { | |
| background: linear-gradient(135deg, rgba(0, 255, 65, 0.1) 0%, rgba(0, 255, 65, 0.05) 100%); | |
| border: 1px solid var(--primary-green) !important; | |
| color: var(--primary-green) !important; | |
| font-weight: 500; | |
| padding: 12px 16px !important; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| font-size: 13px; | |
| text-align: left; | |
| font-family: 'JetBrains Mono', monospace; | |
| } | |
| .quick-btn:hover { | |
| background: linear-gradient(135deg, rgba(0, 255, 65, 0.2) 0%, rgba(0, 255, 65, 0.1) 100%); | |
| box-shadow: 0 0 15px rgba(0, 255, 65, 0.4); | |
| transform: translateX(4px); | |
| } | |
| /* Chat area */ | |
| .chat-container { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 15px; | |
| } | |
| /* Chatbot styling */ | |
| .gr-chatbot { | |
| background-color: var(--darker-bg) !important; | |
| border: 1px solid var(--border-color) !important; | |
| border-radius: 8px !important; | |
| } | |
| .gr-chatbot .message.bot { | |
| background-color: var(--card-bg) !important; | |
| border-left: 3px solid var(--primary-green); | |
| border-radius: 6px; | |
| } | |
| .gr-chatbot .message.bot .md-box { | |
| color: var(--text-light) !important; | |
| } | |
| .gr-chatbot .message.user { | |
| background: linear-gradient(135deg, rgba(0, 255, 65, 0.1) 0%, rgba(0, 255, 65, 0.05) 100%); | |
| border-left: 3px solid var(--primary-green); | |
| } | |
| .gr-chatbot .message.user .md-box { | |
| color: var(--text-light) !important; | |
| } | |
| /* Code blocks in chat */ | |
| .gr-chatbot code { | |
| background-color: rgba(0, 255, 65, 0.1) !important; | |
| color: var(--primary-green) !important; | |
| border-left: 2px solid var(--primary-green) !important; | |
| font-family: 'JetBrains Mono', monospace !important; | |
| } | |
| .gr-chatbot pre { | |
| background: var(--darker-bg) !important; | |
| border: 1px solid var(--border-color) !important; | |
| border-left: 3px solid var(--primary-green) !important; | |
| } | |
| /* Textbox for input */ | |
| .gr-textbox textarea, .gr-textbox input { | |
| background-color: var(--card-bg) !important; | |
| border: 1px solid var(--border-color) !important; | |
| color: var(--text-light) !important; | |
| border-radius: 6px !important; | |
| font-family: 'JetBrains Mono', monospace !important; | |
| } | |
| .gr-textbox textarea::placeholder { | |
| color: var(--text-muted) !important; | |
| } | |
| .gr-textbox textarea:focus, | |
| .gr-textbox input:focus { | |
| border-color: var(--primary-green) !important; | |
| box-shadow: 0 0 0 2px rgba(0, 255, 65, 0.2) !important; | |
| } | |
| /* Sliders */ | |
| .gr-slider { | |
| background-color: var(--card-bg); | |
| border-radius: 8px; | |
| } | |
| .gr-slider input { | |
| accent-color: var(--primary-green) !important; | |
| } | |
| .gr-slider label { | |
| color: var(--text-light) !important; | |
| } | |
| /* Buttons */ | |
| .gr-button { | |
| background: linear-gradient(135deg, var(--primary-green) 0%, #00dd36 100%); | |
| border: none !important; | |
| color: var(--darker-bg) !important; | |
| font-weight: 600; | |
| border-radius: 6px !important; | |
| transition: all 0.3s ease; | |
| padding: 12px 24px !important; | |
| } | |
| .gr-button:hover { | |
| box-shadow: 0 0 20px rgba(0, 255, 65, 0.5); | |
| transform: translateY(-2px); | |
| } | |
| .gr-button:active { | |
| transform: translateY(0); | |
| } | |
| /* Copy button styling */ | |
| .copy-btn { | |
| background: rgba(0, 255, 65, 0.2) !important; | |
| border: 1px solid var(--primary-green) !important; | |
| color: var(--primary-green) !important; | |
| font-size: 12px !important; | |
| padding: 6px 12px !important; | |
| border-radius: 4px !important; | |
| } | |
| .copy-btn:hover { | |
| background: rgba(0, 255, 65, 0.3) !important; | |
| } | |
| /* Parameter section */ | |
| .parameters { | |
| background-color: var(--card-bg); | |
| padding: 15px; | |
| border-radius: 8px; | |
| border: 1px solid var(--border-color); | |
| } | |
| .parameters > label { | |
| color: var(--text-light) !important; | |
| font-weight: 600; | |
| font-size: 14px; | |
| } | |
| /* Footer */ | |
| .footer { | |
| background: linear-gradient(135deg, #1a0000 0%, rgba(255, 0, 0, 0.05) 100%); | |
| border-top: 2px solid #ff4444; | |
| padding: 15px; | |
| border-radius: 6px; | |
| margin-top: 20px; | |
| text-align: center; | |
| } | |
| .footer p { | |
| color: #ff6666 !important; | |
| margin: 0 !important; | |
| font-size: 12px; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| } | |
| /* Markdown styling */ | |
| .prose { | |
| color: var(--text-light) !important; | |
| } | |
| .prose h1, .prose h2, .prose h3 { | |
| color: var(--primary-green) !important; | |
| } | |
| /* Scrollbar styling */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| height: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: var(--card-bg); | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--primary-green); | |
| border-radius: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #00dd36; | |
| } | |
| /* Responsive */ | |
| @media (max-width: 768px) { | |
| .row { | |
| flex-direction: column; | |
| } | |
| .sidebar-container { | |
| max-width: 100%; | |
| } | |
| } | |
| """ | |
| QUICK_QUESTIONS = [ | |
| "🔍 How do I use nmap for network scanning?", | |
| "🎯 Explain SQL injection vulnerability", | |
| "🛡️ How to analyze suspicious network traffic?", | |
| "🔐 Steps for privilege escalation testing", | |
| "🐛 Debug this bash script", | |
| "📊 How to write a Metasploit module?", | |
| "🔑 SSL/TLS certificate analysis process", | |
| "⚔️ Lateral movement techniques in pen testing", | |
| ] | |
| def process_message(msg_text, chat_history, temperature, max_tokens, compute_mode): | |
| """Process user message and stream response""" | |
| chat_history = chat_history or [] | |
| chat_history.append({"role": "user", "content": msg_text}) | |
| chat_history.append({"role": "assistant", "content": ""}) | |
| yield chat_history | |
| response = "" | |
| for chunk in chat_streaming( | |
| msg_text, | |
| temperature, | |
| max_tokens, | |
| device_preference=compute_mode, | |
| ): | |
| response += chunk | |
| chat_history[-1]["content"] = response | |
| yield chat_history | |
| def add_quick_question(question, chat_history, temperature, max_tokens, compute_mode): | |
| """Handle quick question button clicks""" | |
| yield from process_message( | |
| question, | |
| chat_history, | |
| temperature, | |
| max_tokens, | |
| compute_mode, | |
| ) | |
| def create_app(): | |
| """Create and configure the Gradio app""" | |
| with gr.Blocks( | |
| css=CUSTOM_CSS, | |
| theme=gr.themes.Soft(primary_hue="green"), | |
| title="CyberGuide - AI Security Assistant", | |
| ) as app: | |
| # Header | |
| gr.Markdown( | |
| "# 🚨 CyberGuide - AI Security Assistant\n" | |
| "*Your intelligent companion for cybersecurity analysis and penetration testing*" | |
| ) | |
| with gr.Row(): | |
| # Sidebar | |
| with gr.Column(scale=1, min_width=280): | |
| gr.Markdown( | |
| "### Quick Questions\n" | |
| "Click a button to start a conversation" | |
| ) | |
| with gr.Column(): | |
| quick_btns = [] | |
| for question in QUICK_QUESTIONS: | |
| btn = gr.Button( | |
| value=question, | |
| elem_classes="quick-btn", | |
| size="sm", | |
| ) | |
| quick_btns.append((btn, question)) | |
| # Parameters section | |
| gr.Markdown("### Settings") | |
| temperature_slider = gr.Slider( | |
| minimum=0.0, | |
| maximum=1.0, | |
| value=0.7, | |
| step=0.05, | |
| label="Temperature", | |
| info="Higher = more creative", | |
| ) | |
| max_tokens_slider = gr.Slider( | |
| minimum=128, | |
| maximum=2048, | |
| value=512, | |
| step=128, | |
| label="Max Tokens", | |
| info="Response length limit", | |
| ) | |
| compute_mode_radio = gr.Radio( | |
| choices=["auto", "gpu", "cpu"], | |
| value="auto", | |
| label="Compute Mode", | |
| info="Select auto, GPU, or CPU. Model reloads when mode changes.", | |
| ) | |
| # Main chat area | |
| with gr.Column(scale=3): | |
| chatbot = gr.Chatbot( | |
| type="messages", | |
| label="Chat", | |
| height=600, | |
| show_label=False, | |
| elem_classes="chat-container", | |
| avatar_images=( | |
| "https://i.imgur.com/rplKIZs.png", # User avatar | |
| "https://i.imgur.com/N8gJmq4.png", # AI avatar | |
| ), | |
| ) | |
| # Input area | |
| with gr.Row(): | |
| msg = gr.Textbox( | |
| label="Your message", | |
| placeholder="Ask CyberGuide about security topics...", | |
| lines=3, | |
| max_lines=5, | |
| scale=4, | |
| show_label=False, | |
| ) | |
| submit_btn = gr.Button( | |
| "Send", | |
| scale=1, | |
| size="lg", | |
| ) | |
| # Footer warning | |
| gr.HTML( | |
| '<div class="footer">' | |
| "<p>⚠️ AUTHORIZED USE ONLY ⚠️</p>" | |
| "<p>This tool is for authorized security testing only. " | |
| "Unauthorized access or attack on systems is illegal.</p>" | |
| "</div>" | |
| ) | |
| # Event handlers | |
| submit_btn.click( | |
| fn=process_message, | |
| inputs=[ | |
| msg, | |
| chatbot, | |
| temperature_slider, | |
| max_tokens_slider, | |
| compute_mode_radio, | |
| ], | |
| outputs=[chatbot], | |
| queue=True, | |
| api_name=False, | |
| ).then( | |
| lambda: gr.Textbox(value=""), | |
| outputs=[msg], | |
| api_name=False, | |
| ) | |
| msg.submit( | |
| fn=process_message, | |
| inputs=[ | |
| msg, | |
| chatbot, | |
| temperature_slider, | |
| max_tokens_slider, | |
| compute_mode_radio, | |
| ], | |
| outputs=[chatbot], | |
| queue=True, | |
| api_name=False, | |
| ).then( | |
| lambda: gr.Textbox(value=""), | |
| outputs=[msg], | |
| api_name=False, | |
| ) | |
| # Quick question buttons | |
| for btn, question in quick_btns: | |
| question_state = gr.State(question) | |
| btn.click( | |
| fn=add_quick_question, | |
| inputs=[ | |
| question_state, | |
| chatbot, | |
| temperature_slider, | |
| max_tokens_slider, | |
| compute_mode_radio, | |
| ], | |
| outputs=[chatbot], | |
| queue=True, | |
| api_name=False, | |
| ) | |
| return app | |
| if __name__ == "__main__": | |
| print("Initializing CyberGuide...") | |
| app = create_app() | |
| app.queue(max_size=20, default_concurrency_limit=1) | |
| is_hf_space = bool(os.getenv("SPACE_ID")) | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=int(os.getenv("PORT", "7860")), | |
| share=not is_hf_space, | |
| show_api=False, | |
| show_error=True, | |
| ) | |