Spaces:
Running
Running
| import gradio as gr | |
| import time | |
| import random | |
| import re | |
| # --- Sentiment Analysis Logic (Simulating the JS Model) --- | |
| def analyze_sentiment(text): | |
| """ | |
| Simulates the sentiment analysis model (Xenova/bert-base-multilingual-uncased-sentiment) | |
| used in the JavaScript code. | |
| """ | |
| positive_keywords = ['خوب', 'عالی', 'خوشحال', 'محشر', 'دوست', 'عشق', 'موفق', 'سالم', 'خنده', '🙂', '😊', '❤️', 'good', 'great', 'love'] | |
| negative_keywords = ['بد', 'غمگین', 'ترس', 'تنفر', 'مرگ', 'درد', 'خسته', 'مشکل', '😔', '😢', '😡', 'bad', 'sad', 'hate'] | |
| score = 0.5 | |
| label = "NEUTRAL" # 3 stars | |
| text_lower = text.lower() | |
| # Simple keyword matching for demo purposes | |
| pos_count = sum(1 for word in positive_keywords if word in text_lower) | |
| neg_count = sum(1 for word in negative_keywords if word in text_lower) | |
| if pos_count > neg_count: | |
| label = "POSITIVE" # 5 stars | |
| score = random.uniform(0.7, 0.99) | |
| elif neg_count > pos_count: | |
| label = "NEGATIVE" # 1 star | |
| score = random.uniform(0.7, 0.99) | |
| else: | |
| score = random.uniform(0.4, 0.6) | |
| # Map to the star rating format used in the JS | |
| if label == "POSITIVE": | |
| star_label = "5 stars" | |
| elif label == "NEGATIVE": | |
| star_label = "1 star" | |
| else: | |
| star_label = "3 stars" | |
| return [{"label": star_label, "score": score}] | |
| def generate_ai_response(text): | |
| """Generates a response based on sentiment, mimicking the JS logic.""" | |
| result = analyze_sentiment(text) | |
| label = result[0]['label'] | |
| score = (result[0]['score'] * 100).toFixed(1) if isinstance(result[0]['score'], float) else f"{result[0]['score']*100:.1f}" | |
| if label in ["5 stars", "4 stars", "POSITIVE"]: | |
| return f"😊 خوشحالم که حالتان خوب است! (اطمینان: {score}%)" | |
| elif label in ["1 star", "2 stars", "NEGATIVE"]: | |
| return f"😔 متاسفم که اینطور احساس میکنید. امیدوارم روزتان بهتر شود. (اطمینان: {score}%)" | |
| else: | |
| return f"🤔 پیام شما دریافت شد. (اطمینان: {score}%)" | |
| # --- Application Logic --- | |
| def handle_login(username, password): | |
| """Simulates PHP login logic.""" | |
| if not username or not password: | |
| return gr.Warning("لطفاً نام کاربری و رمز عبور را وارد کنید."), None, gr.update(visible=True), gr.update(visible=False) | |
| # Simulate loading | |
| time.sleep(0.5) | |
| # In a real app, check DB here. For demo, accept any non-empty input. | |
| return ( | |
| gr.Info("ورود موفقیتآمیز بود!"), | |
| {"username": username, "role": "user"}, # User State | |
| gr.update(visible=False), # Hide Login | |
| gr.update(visible=True) # Show Chat | |
| ) | |
| def handle_register(full_name, email, username, password): | |
| """Simulates PHP registration logic.""" | |
| if not all([full_name, email, username, password]): | |
| return gr.Warning("لطفاً تمام فیلدها را پر کنید.") | |
| return gr.Info("ثبت نام با موفقیت انجام شد. لطفاً وارد شوید.") | |
| def handle_chat(message, history, user_state): | |
| """Handles message sending and AI response.""" | |
| if not message: | |
| return history, "" | |
| # Add user message | |
| history.append({"role": "user", "content": message}) | |
| # Simulate AI thinking time | |
| time.sleep(0.5) | |
| # Generate response | |
| response = generate_ai_response(message) | |
| history.append({"role": "assistant", "content": response}) | |
| return history, "" | |
| def handle_logout(): | |
| """Resets the app to login state.""" | |
| return ( | |
| None, # Clear user state | |
| [], # Clear history | |
| gr.update(visible=True), # Show Login | |
| gr.update(visible=False) # Hide Chat | |
| ) | |
| # --- Mock Data for Sidebar --- | |
| def get_online_users(): | |
| """Simulates fetching online users from database.""" | |
| users = [ | |
| {"name": "علی رضایی", "status": "online"}, | |
| {"name": "سارا محمدی", "status": "online"}, | |
| {"name": "رضا کریمی", "status": "offline"}, | |
| {"name": "مریم حسینی", "status": "online"}, | |
| {"name": "سیستم ادمین", "status": "online"}, | |
| ] | |
| return users | |
| # --- Custom CSS (Ported from your HTML) --- | |
| custom_css = """ | |
| /* | |
| * GLASSMORPHISM & MODERN UI STYLES | |
| * Adapted for Gradio Components | |
| */ | |
| :root { | |
| --glass-bg: rgba(255, 255, 255, 0.05); | |
| --glass-border: rgba(255, 255, 255, 0.1); | |
| --glass-highlight: rgba(255, 255, 255, 0.1); | |
| --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| --text-color: #ffffff; | |
| --border-radius: 16px; | |
| } | |
| /* Force RTL and Font */ | |
| body, .gradio-container { | |
| font-family: 'Vazirmatn', sans-serif !important; | |
| direction: rtl !important; | |
| text-align: right !important; | |
| } | |
| /* Main Background */ | |
| .gradio-container { | |
| background: linear-gradient(-45deg, #0f0c29, #302b63, #24243e, #4a1c40); | |
| background-size: 400% 400%; | |
| animation: gradientBG 20s ease infinite; | |
| color: var(--text-color); | |
| } | |
| @keyframes gradientBG { | |
| 0% { background-position: 0% 50%; } | |
| 50% { background-position: 100% 50%; } | |
| 100% { background-position: 0% 50%; } | |
| } | |
| /* Login Panel Styling */ | |
| .login-panel { | |
| background: var(--glass-bg); | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| border: 1px solid var(--glass-border); | |
| border-radius: 24px; | |
| padding: 40px; | |
| box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3); | |
| max-width: 450px; | |
| margin: auto; | |
| } | |
| /* Styling Tabs */ | |
| .tabs-container { | |
| background: rgba(0, 0, 0, 0.2); | |
| padding: 6px; | |
| border-radius: 50px; | |
| display: flex; | |
| margin-bottom: 25px; | |
| } | |
| .tab-btn { | |
| flex: 1; | |
| background: transparent; | |
| border: none; | |
| color: rgba(255, 255, 255, 0.6); | |
| padding: 10px; | |
| border-radius: 50px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.3s; | |
| } | |
| .tab-btn.selected { | |
| background: var(--primary-gradient); | |
| color: white; | |
| box-shadow: 0 4px 15px rgba(118, 75, 162, 0.4); | |
| } | |
| /* Chat Interface Styling */ | |
| .chat-interface { | |
| display: flex; | |
| height: 80vh; | |
| gap: 20px; | |
| background: rgba(0,0,0,0.2); | |
| border-radius: 24px; | |
| border: 1px solid var(--glass-border); | |
| padding: 20px; | |
| backdrop-filter: blur(10px); | |
| } | |
| .chat-main { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 15px; | |
| } | |
| .chat-sidebar { | |
| width: 250px; | |
| background: rgba(255, 255, 255, 0.03); | |
| border-radius: 16px; | |
| padding: 15px; | |
| border: 1px solid var(--glass-border); | |
| } | |
| /* User List Item */ | |
| .user-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| padding: 10px; | |
| border-radius: 8px; | |
| margin-bottom: 8px; | |
| background: rgba(255,255,255,0.02); | |
| } | |
| .user-status { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: #555; | |
| } | |
| .user-status.online { | |
| background: #00d2d3; | |
| box-shadow: 0 0 8px #00d2d3; | |
| } | |
| /* Chatbot Bubbles Override */ | |
| .message.user { | |
| background: var(--primary-gradient) !important; | |
| align-self: flex-end !important; | |
| border-bottom-left-radius: 4px !important; | |
| border-bottom-right-radius: 16px !important; | |
| } | |
| .message.bot { | |
| background: rgba(255, 255, 255, 0.1) !important; | |
| align-self: flex-start !important; | |
| border: 1px solid rgba(255, 255, 255, 0.1) !important; | |
| border-bottom-left-radius: 16px !important; | |
| border-bottom-right-radius: 4px !important; | |
| } | |
| /* Input Area */ | |
| .chat-input-area { | |
| display: flex; | |
| gap: 10px; | |
| background: rgba(0,0,0,0.3); | |
| padding: 10px; | |
| border-radius: 16px; | |
| border: 1px solid var(--glass-border); | |
| } | |
| /* Buttons */ | |
| .primary-btn { | |
| background: var(--primary-gradient); | |
| color: white; | |
| border: none; | |
| border-radius: 12px; | |
| padding: 12px 24px; | |
| font-weight: bold; | |
| cursor: pointer; | |
| transition: transform 0.2s; | |
| } | |
| .primary-btn:hover { | |
| transform: translateY(-2px); | |
| } | |
| .secondary-btn { | |
| background: rgba(255,255,255,0.1); | |
| color: white; | |
| border: 1px solid rgba(255,255,255,0.2); | |
| border-radius: 12px; | |
| padding: 8px 16px; | |
| cursor: pointer; | |
| } | |
| /* Hide Gradio defaults we don't need */ | |
| #component-0 { /* This targets the main container wrapper often */ | |
| padding: 20px !important; | |
| } | |
| footer { | |
| display: none !important; | |
| } | |
| """ | |
| # --- Gradio App Construction --- | |
| with gr.Blocks(css=custom_css, title="چت روم هوشمند") as demo: | |
| # Head for Fonts and Icons | |
| gr.HTML(""" | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100;300;400;500;700;900&display=swap" rel="stylesheet"> | |
| """) | |
| # Application State | |
| user_state = gr.State(value=None) # Stores user info | |
| chat_history = gr.State(value=[]) # Stores chat messages | |
| # --- LOGIN / REGISTER SECTION --- | |
| with gr.Column(elem_classes="login-panel", visible=True) as login_col: | |
| gr.HTML(""" | |
| <div style="text-align: center; margin-bottom: 30px;"> | |
| <i class="fas fa-robot" style="font-size: 3rem; background: linear-gradient(to bottom right, #fff, #a29bfe); -webkit-background-clip: text; -webkit-text-fill-color: transparent; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.2));"></i> | |
| <h1 style="font-weight: 800; font-size: 2rem; margin: 10px 0 5px;">چت روم هوشمند</h1> | |
| <p style="color: rgba(255, 255, 255, 0.7);">ورود به دنیای هوش مصنوعی</p> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="font-size: 0.8rem; color: rgba(255, 255, 255, 0.5); text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.1); padding: 4px 12px; border-radius: 20px; display: inline-block; margin-top: 10px;"> | |
| Built with anycoder | |
| </a> | |
| </div> | |
| """) | |
| with gr.Tabs(elem_classes="tabs-container") as auth_tabs: | |
| with gr.Tab("ورود", id="login_tab"): | |
| with gr.Column(): | |
| username = gr.Textbox(label="نام کاربری", placeholder="نام کاربری خود را وارد کنید", show_label=False, container=False) | |
| password = gr.Textbox(label="رمز عبور", type="password", placeholder="رمز عبور خود را وارد کنید", show_label=False, container=False) | |
| login_btn = gr.Button("ورود به سیستم", variant="primary", elem_classes="primary-btn", full_width=True) | |
| with gr.Tab("ثبت نام", id="register_tab"): | |
| with gr.Column(): | |
| reg_name = gr.Textbox(label="نام کامل", placeholder="نام و نام خانوادگی", show_label=False) | |
| reg_email = gr.Textbox(label="ایمیل", placeholder="example@mail.com", show_label=False) | |
| reg_user = gr.Textbox(label="نام کاربری", placeholder="نام کاربری دلخواه", show_label=False) | |
| reg_pass = gr.Textbox(label="رمز عبور", type="password", placeholder="رمز عبور قوی انتخاب کنید", show_label=False) | |
| register_btn = gr.Button("ثبت نام", variant="primary", elem_classes="primary-btn", full_width=True) | |
| gr.HTML(""" | |
| <div style="margin-top: 25px; padding-top: 25px; border-top: 1px solid rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.5); font-size: 0.8rem; text-align: center;"> | |
| <p><i class="fas fa-info-circle"></i> مدلهای هوش مصنوعی در مرورگر اجرا میشوند</p> | |
| </div> | |
| """) | |
| # --- CHAT INTERFACE SECTION --- | |
| with gr.Column(elem_classes="chat-interface", visible=False) as chat_col: | |
| # Sidebar: Users & Info | |
| with gr.Column(elem_classes="chat-sidebar"): | |
| gr.Markdown("## 👥 کاربران آنلاین") | |
| # Room Selector (Simulating PHP room logic) | |
| room_select = gr.Dropdown( | |
| choices=["اتاق عمومی", "گفتگوی آزاد", "پشتیبانی فنی"], | |
| value="اتاق عمومی", | |
| label="اتاق گفتگو", | |
| interactive=True | |
| ) | |
| # User List (Dynamic HTML) | |
| users_list_html = gr.HTML(value="") | |
| gr.HTML("<hr style='border-color: rgba(255,255,255,0.1); margin: 15px 0;'>") | |
| logout_btn = gr.Button("خروج از سیستم", elem_classes="secondary-btn", full_width=True, icon="fa-power-off") | |
| # Main Chat Area | |
| with gr.Column(elem_classes="chat-main"): | |
| # Header | |
| with gr.Row(): | |
| gr.HTML(""" | |
| <div style="display: flex; align-items: center; gap: 10px; color: white;"> | |
| <i class="fas fa-brain" style="font-size: 1.5rem; color: #a29bfe;"></i> | |
| <div> | |
| <h3 style="font-size: 1.1rem; margin:0;">دستیار هوشمند</h3> | |
| <span style="font-size: 0.75rem; color: #00d2d3;">آماده</span> | |
| </div> | |
| </div> | |
| """) | |
| # Chatbot | |
| chatbot = gr.Chatbot( | |
| label=None, | |
| show_label=False, | |
| bubble_full_width=False, | |
| height="auto", | |
| elem_id="chatbot-area" | |
| ) | |
| # Input Area | |
| with gr.Row(elem_classes="chat-input-area"): | |
| msg_input = gr.Textbox( | |
| placeholder="پیام خود را بنویسید...", | |
| show_label=False, | |
| scale=4, | |
| container=False, | |
| autofocus=True | |
| ) | |
| send_btn = gr.Button("ارسال", variant="primary", scale=1, elem_classes="primary-btn", icon="fa-paper-plane") | |
| # --- Event Listeners --- | |
| # 1. Login Logic | |
| login_btn.click( | |
| fn=handle_login, | |
| inputs=[username, password], | |
| outputs=[gr.Textbox(visible=False), user_state, login_col, chat_col] # Using dummy Textbox for toast output | |
| ) | |
| # 2. Register Logic | |
| register_btn.click( | |
| fn=handle_register, | |
| inputs=[reg_name, reg_email, reg_user, reg_pass], | |
| outputs=[gr.Textbox(visible=False)] | |
| ) | |
| # 3. Chat Logic | |
| submit_event = msg_input.submit( | |
| fn=handle_chat, | |
| inputs=[msg_input, chat_history, user_state], | |
| outputs=[chatbot, msg_input] | |
| ) | |
| send_btn.click( | |
| fn=handle_chat, | |
| inputs=[msg_input, chat_history, user_state], | |
| outputs=[chatbot, msg_input] | |
| ) | |
| # 4. Logout Logic | |
| logout_btn.click( | |
| fn=handle_logout, | |
| inputs=[], | |
| outputs=[user_state, chat_history, login_col, chat_col] | |
| ) | |
| # 5. Update User List (Simulated) | |
| def update_users(): | |
| users = get_online_users() | |
| html = "" | |
| for u in users: | |
| status_color = "#00d2d3" if u['status'] == 'online' else "#555" | |
| status_text = "آنلاین" if u['status'] == 'online' else "آفلاین" | |
| html += f""" | |
| <div class="user-item"> | |
| <div class="user-status {u['status']}"></div> | |
| <div style="flex:1"> | |
| <div style="font-size: 0.9rem;">{u['name']}</div> | |
| <div style="font-size: 0.7rem; color: rgba(255,255,255,0.5);">{status_text}</div> | |
| </div> | |
| </div> | |
| """ | |
| return html | |
| # Load users on startup and periodically (simulated via render trigger or just once) | |
| demo.load(update_users, outputs=users_list_html) | |
| # --- Launch Configuration --- | |
| demo.launch( | |
| theme=gr.themes.Soft( | |
| primary_hue="indigo", | |
| secondary_hue="purple", | |
| neutral_hue="slate", | |
| font=gr.themes.GoogleFont("Vazirmatn"), | |
| text_size="lg", | |
| spacing_size="lg", | |
| radius_size="md" | |
| ).set( | |
| body_background_fill="transparent", # Let our CSS handle the background | |
| block_background_fill="transparent", | |
| block_border_width="0px", | |
| button_primary_background_fill="*primary_600", | |
| button_primary_background_fill_hover="*primary_700", | |
| block_title_text_weight="600", | |
| input_background_fill="rgba(0,0,0,0.2)", | |
| input_background_fill_dark="rgba(0,0,0,0.2)", | |
| input_border_color="rgba(255,255,255,0.1)", | |
| input_border_color_dark="rgba(255,255,255,0.1)", | |
| input_radius="lg", | |
| ), | |
| footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}] | |
| ) |