Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from transformers import pipeline | |
| from langdetect import detect | |
| from huggingface_hub import login | |
| import os | |
| import base64 | |
| from PIL import Image | |
| from transformers import BlipProcessor, BlipForConditionalGeneration | |
| import requests | |
| from bs4 import BeautifulSoup | |
| import cv2 | |
| from io import BytesIO | |
| import torch | |
| login(token=os.getenv("chatbot")) | |
| generator = pipeline("text-generation", model="mistralai/Mistral-7B-Instruct-v0.1") | |
| bg_to_en = pipeline("translation", model="Helsinki-NLP/opus-mt-bg-en") | |
| en_to_bg = pipeline("translation", model="Helsinki-NLP/opus-mt-en-bg") | |
| # Load BLIP for image captioning | |
| blip_processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base") | |
| blip_model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base") | |
| blip_model.to("cuda" if torch.cuda.is_available() else "cpu") | |
| def describe_image(image): | |
| inputs = blip_processor(images=image, return_tensors="pt").to(blip_model.device) | |
| out = blip_model.generate(**inputs) | |
| caption = blip_processor.decode(out[0], skip_special_tokens=True) | |
| return caption | |
| def describe_video(video_path): | |
| cap = cv2.VideoCapture(video_path) | |
| success, frame = cap.read() | |
| cap.release() | |
| if success: | |
| img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) | |
| return describe_image(img) | |
| else: | |
| return "Could not read video frame." | |
| def extract_text_from_url(url): | |
| try: | |
| response = requests.get(url, timeout=5) | |
| soup = BeautifulSoup(response.text, 'html.parser') | |
| paragraphs = soup.find_all('p') | |
| text = ' '.join([p.text for p in paragraphs]) | |
| return text[:2000] # keep it short | |
| except Exception as e: | |
| return f"Failed to fetch URL: {str(e)}" | |
| def generate_response(user_input, top_p, temperature, chat_counter, chatbot, history, image=None, video=None, url=None, request: gr.Request = None): | |
| lang = detect(user_input) | |
| print(f"Detected language: {lang}") | |
| # Translate if needed | |
| if lang == "bg": | |
| user_input_translated = bg_to_en(user_input)[0]["translation_text"] | |
| else: | |
| user_input_translated = user_input | |
| prompt = "" | |
| # Multimodal additions | |
| if image is not None: | |
| try: | |
| img_desc = describe_image(image) | |
| prompt += f"[Image Description]: {img_desc}\n" | |
| except Exception as e: | |
| prompt += f"[Image Error]: {str(e)}\n" | |
| if video is not None: | |
| try: | |
| vid_desc = describe_video(video) | |
| prompt += f"[Video Description]: {vid_desc}\n" | |
| except Exception as e: | |
| prompt += f"[Video Error]: {str(e)}\n" | |
| if url: | |
| url_content = extract_text_from_url(url) | |
| prompt += f"[URL Content]: {url_content}\n" | |
| # Append user message to prompt | |
| prompt += f"User said:\n{user_input_translated}\n\nGive simple, friendly, clear advice:\n" | |
| # Generate response | |
| response_text = generator(prompt, max_length=200, top_p=top_p, temperature=temperature, do_sample=True)[0]["generated_text"] | |
| if lang == "bg": | |
| response_text = en_to_bg(response_text)[0]["translation_text"] | |
| # Format for type="messages" | |
| history.append({"role": "user", "content": user_input}) | |
| history.append({"role": "assistant", "content": response_text}) | |
| chat_counter += 1 | |
| return history, history, chat_counter, "✅ Success", gr.update(value=''), gr.update(interactive=True) | |
| def reset_textbox(): | |
| return gr.update(value='') | |
| # ==== Enhanced Custom CSS with Masterbrand Styling ==== | |
| custom_css = f""" | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap'); | |
| * {{ | |
| font-family: 'Inter', sans-serif !important; | |
| }} | |
| .gradio-container {{ | |
| background: linear-gradient(135deg, #0a0a0a 0%, #1a0a0a 50%, #2a1a1a 100%) !important; | |
| min-height: 100vh !important; | |
| }} | |
| .main-header {{ | |
| background: linear-gradient(135deg, #0a0a0a 0%, #1a0a0a 50%, #2a1a1a 100%) !important; | |
| padding: 2rem 0 3rem 0 !important; | |
| text-align: center !important; | |
| border-bottom: 3px solid #ff0000 !important; | |
| margin-bottom: 2rem !important; | |
| position: relative !important; | |
| overflow: hidden !important; | |
| }} | |
| .main-header::before {{ | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: radial-gradient(circle at 50% 50%, rgba(255, 0, 0, 0.1) 0%, transparent 70%); | |
| pointer-events: none; | |
| }} | |
| .logo-container {{ | |
| display: flex !important; | |
| justify-content: center !important; | |
| align-items: center !important; | |
| margin-bottom: 1.5rem !important; | |
| gap: 1rem !important; | |
| }} | |
| .logo-image {{ | |
| width: 50px !important; | |
| height: 50px !important; | |
| border-radius: 15px !important; | |
| box-shadow: 0 0 30px rgba(255, 0, 0, 0.5) !important; | |
| animation: pulse-glow 2s ease-in-out infinite alternate !important; | |
| transition: transform 0.3s ease !important; | |
| }} | |
| .logo-image:hover {{ | |
| transform: scale(1.1) !important; | |
| }} | |
| .brand-text {{ | |
| background: linear-gradient(135deg, #00ff41 0%, #ffffff 50%, #ff0000 100%) !important; | |
| -webkit-background-clip: text !important; | |
| -webkit-text-fill-color: transparent !important; | |
| background-clip: text !important; | |
| font-size: 2.5rem !important; | |
| font-weight: 900 !important; | |
| letter-spacing: 2px !important; | |
| text-shadow: 0 0 20px rgba(0, 255, 65, 0.3) !important; | |
| }} | |
| .main-header h1 {{ | |
| color: #ffffff !important; | |
| font-size: 3.5rem !important; | |
| font-weight: 900 !important; | |
| text-shadow: 0 0 30px rgba(255, 0, 0, 0.5) !important; | |
| background: linear-gradient(135deg, #ffffff 0%, #ff0000 100%) !important; | |
| -webkit-background-clip: text !important; | |
| -webkit-text-fill-color: transparent !important; | |
| background-clip: text !important; | |
| margin: 0 !important; | |
| }} | |
| .main-header p {{ | |
| color: #cccccc !important; | |
| font-size: 1.3rem !important; | |
| font-weight: 500 !important; | |
| margin-top: 0.5rem !important; | |
| }} | |
| .chatbot-container {{ | |
| background: rgba(26, 26, 26, 0.95) !important; | |
| border: 2px solid #ff0000 !important; | |
| border-radius: 25px !important; | |
| box-shadow: 0 15px 40px rgba(255, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.1) !important; | |
| margin-bottom: 2rem !important; | |
| backdrop-filter: blur(10px) !important; | |
| }} | |
| .input-section {{ | |
| background: rgba(26, 26, 26, 0.8) !important; | |
| border: 2px solid #333333 !important; | |
| border-radius: 20px !important; | |
| padding: 2rem !important; | |
| margin: 1rem 0 !important; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3) !important; | |
| backdrop-filter: blur(10px) !important; | |
| transition: all 0.3s ease !important; | |
| }} | |
| .input-section:hover {{ | |
| border-color: #ff0000 !important; | |
| box-shadow: 0 15px 40px rgba(255, 0, 0, 0.2) !important; | |
| }} | |
| .input-group {{ | |
| margin-bottom: 1.5rem !important; | |
| }} | |
| .input-group:last-child {{ | |
| margin-bottom: 0 !important; | |
| }} | |
| .input-label {{ | |
| color: #ffffff !important; | |
| font-size: 1.1rem !important; | |
| font-weight: 600 !important; | |
| margin-bottom: 0.8rem !important; | |
| display: flex !important; | |
| align-items: center !important; | |
| gap: 0.5rem !important; | |
| }} | |
| .input-icon {{ | |
| font-size: 1.2rem !important; | |
| color: #ff0000 !important; | |
| }} | |
| .enhanced-textbox textarea {{ | |
| background: linear-gradient(135deg, #1a1a1a 0%, #2a2a1a 100%) !important; | |
| border: 2px solid #444444 !important; | |
| border-radius: 15px !important; | |
| color: #ffffff !important; | |
| font-size: 1.1rem !important; | |
| padding: 1.2rem !important; | |
| resize: none !important; | |
| transition: all 0.3s ease !important; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3) !important; | |
| }} | |
| .enhanced-textbox textarea:focus {{ | |
| border-color: #ff0000 !important; | |
| box-shadow: 0 0 25px rgba(255, 0, 0, 0.4), 0 5px 15px rgba(0, 0, 0, 0.3) !important; | |
| outline: none !important; | |
| transform: translateY(-2px) !important; | |
| }} | |
| .enhanced-textbox textarea::placeholder {{ | |
| color: #888888 !important; | |
| font-style: italic !important; | |
| }} | |
| .enhanced-image-input, .enhanced-video-input {{ | |
| background: rgba(42, 42, 42, 0.8) !important; | |
| border: 2px dashed #444444 !important; | |
| border-radius: 15px !important; | |
| padding: 2rem !important; | |
| text-align: center !important; | |
| transition: all 0.3s ease !important; | |
| min-height: 120px !important; | |
| display: flex !important; | |
| align-items: center !important; | |
| justify-content: center !important; | |
| }} | |
| .enhanced-image-input:hover, .enhanced-video-input:hover {{ | |
| border-color: #ff0000 !important; | |
| background: rgba(255, 0, 0, 0.05) !important; | |
| }} | |
| .enhanced-url-input input {{ | |
| background: linear-gradient(135deg, #1a1a1a 0%, #2a2a1a 100%) !important; | |
| border: 2px solid #444444 !important; | |
| border-radius: 15px !important; | |
| color: #ffffff !important; | |
| font-size: 1.1rem !important; | |
| padding: 1.2rem !important; | |
| transition: all 0.3s ease !important; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3) !important; | |
| }} | |
| .enhanced-url-input input:focus {{ | |
| border-color: #ff0000 !important; | |
| box-shadow: 0 0 25px rgba(255, 0, 0, 0.4), 0 5px 15px rgba(0, 0, 0, 0.3) !important; | |
| outline: none !important; | |
| transform: translateY(-2px) !important; | |
| }} | |
| .enhanced-url-input input::placeholder {{ | |
| color: #888888 !important; | |
| font-style: italic !important; | |
| }} | |
| .submit-button {{ | |
| background: linear-gradient(135deg, #ff0000 0%, #cc0000 100%) !important; | |
| border: none !important; | |
| border-radius: 15px !important; | |
| color: #ffffff !important; | |
| font-size: 1.2rem !important; | |
| font-weight: 700 !important; | |
| padding: 1.2rem 2.5rem !important; | |
| transition: all 0.3s ease !important; | |
| box-shadow: 0 8px 20px rgba(255, 0, 0, 0.3) !important; | |
| text-transform: uppercase !important; | |
| letter-spacing: 1px !important; | |
| width: 100% !important; | |
| margin-top: 1rem !important; | |
| }} | |
| .submit-button:hover {{ | |
| background: linear-gradient(135deg, #cc0000 0%, #aa0000 100%) !important; | |
| transform: translateY(-3px) !important; | |
| box-shadow: 0 12px 30px rgba(255, 0, 0, 0.4) !important; | |
| }} | |
| .submit-button:active {{ | |
| transform: translateY(-1px) !important; | |
| }} | |
| .accordion-container {{ | |
| background: rgba(26, 26, 26, 0.8) !important; | |
| border: 1px solid #333333 !important; | |
| border-radius: 15px !important; | |
| margin-top: 2rem !important; | |
| }} | |
| .slider-container label {{ | |
| color: #ffffff !important; | |
| font-weight: 600 !important; | |
| font-size: 1rem !important; | |
| }} | |
| .slider-container input[type="range"] {{ | |
| accent-color: #ff0000 !important; | |
| }} | |
| .status-container textarea {{ | |
| background: transparent !important; | |
| border: none !important; | |
| color: #ff0000 !important; | |
| font-weight: 600 !important; | |
| text-align: center !important; | |
| }} | |
| .footer {{ | |
| display: none !important; | |
| }} | |
| /* Enhanced chat styling */ | |
| .message.user {{ | |
| background: linear-gradient(135deg, #2a2a2a 0%, #3a3a2a 100%) !important; | |
| border-left: 4px solid #ff0000 !important; | |
| margin-left: 2rem !important; | |
| }} | |
| .message.bot {{ | |
| background: linear-gradient(135deg, #1a2a1a 0%, #2a3a2a 100%) !important; | |
| border-left: 4px solid #cc0000 !important; | |
| margin-right: 2rem !important; | |
| }} | |
| /* Responsive design */ | |
| @media (max-width: 768px) {{ | |
| .main-header h1 {{ | |
| font-size: 2.5rem !important; | |
| }} | |
| .main-header p {{ | |
| font-size: 1.1rem !important; | |
| }} | |
| .logo-image {{ | |
| width: 60px !important; | |
| height: 60px !important; | |
| }} | |
| .brand-text {{ | |
| font-size: 2rem !important; | |
| }} | |
| }} | |
| /* Animations */ | |
| @keyframes pulse-glow {{ | |
| 0% {{ | |
| box-shadow: 0 0 20px rgba(255, 0, 0, 0.3); | |
| transform: scale(1); | |
| }} | |
| 50% {{ | |
| box-shadow: 0 0 40px rgba(255, 0, 0, 0.6); | |
| transform: scale(1.02); | |
| }} | |
| 100% {{ | |
| box-shadow: 0 0 20px rgba(255, 0, 0, 0.3); | |
| transform: scale(1); | |
| }} | |
| }} | |
| @keyframes float {{ | |
| 0%, 100% {{ transform: translateY(0px); }} | |
| 50% {{ transform: translateY(-10px); }} | |
| }} | |
| .floating {{ | |
| animation: float 3s ease-in-out infinite; | |
| }} | |
| """ | |
| # ==== Enhanced Theme ==== | |
| masterbrand_theme = gr.themes.Base(primary_hue="red").set( | |
| body_background_fill="#0a0a0a", | |
| body_text_color="#ffffff", | |
| border_color_accent="#ff0000", | |
| button_primary_background_fill="#ff0000", | |
| button_primary_background_fill_hover="#cc0000", | |
| button_primary_text_color="#ffffff", | |
| block_background_fill="#1a1a1a", | |
| block_border_color="#333333" | |
| ) | |
| # ==== Enhanced UI ==== | |
| with gr.Blocks(theme=masterbrand_theme, css=custom_css, title="MasterBrand Assistant") as demo: | |
| # Enhanced header with logo | |
| logo_html = f""" | |
| <div class="main-header"> | |
| <div class="logo-container"> | |
| <img src="https://huggingface.co/spaces/Yordann/MasterBrand_ChatBot/resolve/main/logo.png" alt="MasterBrand Logo" class="logo-image floating style="height:100px;"> | |
| <div class="brand-text">MASTERBRAND</div> | |
| </div> | |
| <h1>AI ASSISTANT</h1> | |
| <p>Your Personal E-commerce Business Expert - Available in English & Bulgarian</p> | |
| <p style="font-size: 1rem; color: #ff0000; font-weight: 600; margin-top: 1rem;"> | |
| 🚀 Powered by Advanced AI • 🌍 Multilingual Support • 💼 Expert Business Guidance | |
| </p> | |
| </div> | |
| """ | |
| gr.HTML(logo_html) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| chatbot = gr.Chatbot( | |
| label="💬 Chat with MasterBrand AI", | |
| height=450, | |
| elem_classes=["chatbot-container"], | |
| type="messages", | |
| show_label=True, | |
| container=True, | |
| show_copy_button=True | |
| ) | |
| # Enhanced Input Section | |
| with gr.Column(elem_classes=["input-section"]): | |
| gr.HTML('<div class="input-label"><span class="input-icon">💬</span>Ask Your Question</div>') | |
| inputs = gr.Textbox( | |
| placeholder="Ask me anything about your e-commerce business please... 💡", | |
| label="", | |
| lines=3, | |
| elem_classes=["enhanced-textbox"], | |
| show_label=False | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.HTML('<div class="input-label"><span class="input-icon">🖼️</span>Upload Image (Optional)</div>') | |
| image_input = gr.Image( | |
| label="", | |
| type="pil", | |
| elem_classes=["enhanced-image-input"], | |
| show_label=False | |
| ) | |
| with gr.Column(): | |
| gr.HTML('<div class="input-label"><span class="input-icon">🎥</span>Upload Video (Optional)</div>') | |
| video_input = gr.Video( | |
| label="", | |
| elem_classes=["enhanced-video-input"], | |
| show_label=False | |
| ) | |
| gr.HTML('<div class="input-label"><span class="input-icon">🔗</span>Paste URL (Optional)</div>') | |
| url_input = gr.Textbox( | |
| label="", | |
| placeholder="https://example.com - Paste any URL for analysis", | |
| elem_classes=["enhanced-url-input"], | |
| show_label=False | |
| ) | |
| submit_btn = gr.Button( | |
| "🚀 Get Expert Advice", | |
| variant="primary", | |
| size="lg", | |
| elem_classes=["submit-button"] | |
| ) | |
| with gr.Row(): | |
| status_box = gr.Textbox( | |
| label="Status", | |
| interactive=False, | |
| elem_classes=["status-container"], | |
| show_label=False | |
| ) | |
| with gr.Accordion("⚙️ Advanced Settings", open=False, elem_classes=["accordion-container"]): | |
| with gr.Row(): | |
| top_p = gr.Slider( | |
| 0.1, 1.0, | |
| value=0.9, | |
| step=0.05, | |
| label="🎯 Creativity (Top-p)", | |
| elem_classes=["slider-container"], | |
| info="Higher values make responses more creative" | |
| ) | |
| temperature = gr.Slider( | |
| 0.1, 2.0, | |
| value=1.0, | |
| step=0.1, | |
| label="🌡️ Temperature", | |
| elem_classes=["slider-container"], | |
| info="Controls randomness in responses" | |
| ) | |
| # Enhanced footer | |
| gr.HTML(""" | |
| <div style="text-align: center; padding: 2rem; color: #666666; border-top: 1px solid #333333; margin-top: 3rem;"> | |
| <p style="margin: 0; font-size: 0.9rem;"> | |
| © 2025 MasterBrand AI Assistant • Built with ❤️ for E-commerce Success | |
| </p> | |
| <p style="margin: 0.5rem 0 0 0; font-size: 0.8rem; color: #888888;"> | |
| Empowering entrepreneurs worldwide with AI-driven business insights | |
| </p> | |
| </div> | |
| """ | |
| ) | |
| # State | |
| state = gr.State([]) | |
| chat_counter = gr.Number(value=0, visible=False) | |
| # Event Handlers | |
| inputs.submit(reset_textbox, [], [inputs, submit_btn], queue=False) | |
| inputs.submit( | |
| generate_response, | |
| [inputs, top_p, temperature, chat_counter, chatbot, state, image_input, video_input, url_input], | |
| [chatbot, state, chat_counter, status_box, inputs, submit_btn] | |
| ) | |
| submit_btn.click(reset_textbox, [], [inputs, submit_btn], queue=False) | |
| submit_btn.click( | |
| generate_response, | |
| [inputs, top_p, temperature, chat_counter, chatbot, state, image_input, video_input, url_input], | |
| [chatbot, state, chat_counter, status_box, inputs, submit_btn] | |
| ) | |
| # ==== Launch ==== | |
| if __name__ == "__main__": | |
| demo.queue(max_size=10).launch(server_name="0.0.0.0", server_port=7860) | |