Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| from .components import ( | |
| create_header, | |
| create_chatbot, | |
| create_input_row, | |
| create_clear_button, | |
| create_top_header, | |
| create_login_form, | |
| ) | |
| from .handlers import ( | |
| setup_handlers, | |
| handle_login, | |
| handle_register, | |
| handle_logout, | |
| handle_load_history | |
| ) | |
| from utils.helpers import convert_chatbot_messages_to_list | |
| from auth.db import init_db | |
| import modelscope_studio.components.antdx as antdx | |
| import modelscope_studio.components.base as ms | |
| import modelscope_studio.components.antd as antd | |
| init_db() | |
| theme = gr.themes.Soft() | |
| def create_auth(session, chat_column, chatbot): | |
| with gr.Column() as auth_block: | |
| with gr.Row(): | |
| with gr.Column(scale=8): | |
| create_header() | |
| with gr.Column(scale=2): | |
| top_row, welcome_text, login_btn, logout_btn = create_top_header() | |
| login_form, username, password, login_submit, register_btn, back_btn, status = create_login_form() | |
| # Sự kiện: bấm nút đăng nhập → hiện form, ẩn khu vực chat | |
| login_btn.click( | |
| lambda: ( | |
| gr.update(visible=False), # Ẩn nút đăng nhập | |
| gr.update(visible=True), # Hiện form đăng nhập | |
| gr.update(visible=False), # Ẩn khu vực | |
| gr.update(value="", visible=False) # Ẩn message | |
| ), | |
| None, | |
| [login_btn, login_form, chat_column, welcome_text] | |
| ) | |
| # Sự kiện: bấm nút đăng xuất → xóa session, ẩn lời chào | |
| def logout_handler(): | |
| msg = handle_logout(session) | |
| return ( | |
| msg, | |
| gr.update(visible=True), # Hiện nút đăng nhập | |
| gr.update(visible=False), # Ẩn nút đăng xuất | |
| gr.update(value="", visible=True), # Hiện message | |
| gr.update(visible=True), # Hiện khu vực chat | |
| gr.update(value=[]) # Reset chatbot | |
| ) | |
| logout_btn.click( | |
| logout_handler, | |
| None, | |
| [status, login_btn, logout_btn, welcome_text, chat_column, chatbot] | |
| ) | |
| # Sự kiện: bấm nút trở lại → ẩn lời chào | |
| def return_handler(): | |
| return ( | |
| "", | |
| gr.update(visible=True), # Hiện nút đăng nhập | |
| gr.update(visible=False), # Ẩn login form | |
| gr.update(visible=True), # Hiện khu vực chat | |
| gr.update(value="", visible=True) # Hiện message | |
| ) | |
| back_btn.click( | |
| return_handler, | |
| None, | |
| [status, login_btn, login_form, chat_column, welcome_text] | |
| ) | |
| # Sự kiện: xác thực đăng nhập | |
| def login_submit_handler(u, p): | |
| success, msg, username = handle_login(u, p, session) | |
| if success: | |
| welcome = f"👋 Xin chào, {username.title()}!" | |
| history = handle_load_history(username) | |
| return ( | |
| msg, | |
| gr.update(visible=True), # Hiện chat_column | |
| gr.update(visible=False), # Ẩn form đăng nhập | |
| gr.update(visible=True), # Hiện nút đăng xuất | |
| gr.update(visible=False), # Ẩn nút đăng nhập | |
| gr.update(value=welcome, visible=True), # Hiện lời chào | |
| gr.update(value=history) | |
| ) | |
| else: | |
| return ( | |
| msg, | |
| gr.update(visible=False), | |
| gr.update(visible=True), | |
| gr.update(visible=False), | |
| gr.update(visible=False), | |
| gr.update(value="", visible=True), | |
| gr.update(value=[]) | |
| ) | |
| login_submit.click( | |
| login_submit_handler, | |
| inputs=[username, password], | |
| outputs=[status, chat_column, login_form, | |
| logout_btn, login_btn, welcome_text, chatbot] | |
| ) | |
| # Sự kiện: đăng ký tài khoản | |
| def register_handler(u, p): | |
| success, msg = handle_register(u, p, session) | |
| return msg | |
| register_btn.click( | |
| register_handler, | |
| inputs=[username, password], | |
| outputs=[status] | |
| ) | |
| return { | |
| "auth_block": auth_block, | |
| "top_row": top_row, | |
| "login_form": login_form, | |
| "welcome_text": welcome_text, | |
| "login_btn": login_btn, | |
| "logout_btn": logout_btn, | |
| "username": username, | |
| "password": password, | |
| "login_submit": login_submit, | |
| "register_btn": register_btn, | |
| "status": status | |
| } | |
| def create_chat_column(session): | |
| """Tạo giao diện chatbot""" | |
| with gr.Column(visible=True) as chat_column: | |
| with gr.Column(elem_classes=["tab-container"]): | |
| username = session.value.get("user") | |
| # Chatbot with clear badge overlay | |
| with gr.Group(elem_classes=["chatbot-wrapper"]): | |
| chatbot = create_chatbot() | |
| clear_btn = create_clear_button() | |
| # File display (1 line above input) | |
| file_display = gr.Markdown( | |
| "", elem_classes=["file-display-compact"], visible=False) | |
| # Input row with textbox and submit button | |
| row, message, submit_btn = create_input_row() | |
| # Audio input component for speech-to-text | |
| audio_input = gr.Audio( | |
| sources=["microphone"], | |
| type="filepath", | |
| label="🎤 Nhập bằng giọng nói", | |
| waveform_options=gr.WaveformOptions( | |
| show_recording_waveform=False, | |
| ), | |
| ) | |
| clear_btn = create_clear_button() | |
| setup_handlers(message, chatbot, submit_btn, | |
| clear_btn, session, audio_input=audio_input) | |
| return chat_column, chatbot | |
| def build_layout(): | |
| """Build the Gradio UI layout for the healthcare AI assistant with modelscope_studio components.""" | |
| with gr.Blocks( | |
| theme=theme, | |
| css=""" | |
| .tab-title { font-size: 1.2rem; font-weight: 600; } | |
| .tab-subtitle { font-size: 0.9rem; color: #555; margin-top: 0.3rem; } | |
| .tab-container { border-radius: 10px; } | |
| .general-tab { background-color: #e6f7ff; border: 1px solid #91caff; } | |
| .nutrition-tab { background-color: #f6ffed; border: 1px solid #b7eb8f; } | |
| .exercise-tab { background-color: #fff7e6; border: 1px solid #ffd591; } | |
| .mental-tab { background-color: #f9f0ff; border: 1px solid #d3adf7; } | |
| .featured-tip { | |
| background-color: rgba(255, 255, 255, 0.7); | |
| padding: 10px; | |
| border-radius: 8px; | |
| margin-bottom: 15px; | |
| border-left: 4px solid #4b8bf4; | |
| } | |
| .tab-selected { border-bottom: 3px solid #1890ff !important; font-weight: bold; } | |
| .tab-header { margin-bottom: 12px; } | |
| .tab-container button::after { bottom: -20px; } | |
| .action-buttons { | |
| display: flex; | |
| gap: 10px; | |
| } | |
| .build-layout-container { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .auth-block { | |
| order: 1; | |
| } | |
| .chat-block { | |
| order: 2; | |
| } | |
| .login-form-container { | |
| max-width: 70%; | |
| margin: auto; | |
| } | |
| .login-input label span { | |
| background-color: unset | |
| } | |
| .login-buttons { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-top: 15px; | |
| } | |
| .login-btn, .register-btn { | |
| width: 48%; | |
| padding: 10px; | |
| font-weight: bold; | |
| border-radius: 8px; | |
| } | |
| .login-status textarea { | |
| margin-top: 15px; | |
| background-color: #fffbe6; | |
| border-left: 4px solid #faad14; | |
| border-radius: 8px; | |
| padding: 10px; | |
| font-size: 0.95rem; | |
| color: #333; | |
| } | |
| .file-display-compact { | |
| font-size: 0.85rem; | |
| color: #666; | |
| padding: 4px 8px; | |
| background-color: #f5f5f5; | |
| border-radius: 4px; | |
| margin: 0 0 8px 0; | |
| } | |
| .input-container { | |
| position: relative; | |
| } | |
| .message-input textarea { | |
| padding-right: 45px !important; | |
| } | |
| .small-button { | |
| max-width: 200px; | |
| } | |
| /* Speech input styling */ | |
| #speech-input-panel { | |
| background-color: #f0f7ff; | |
| border: 2px solid #1890ff; | |
| border-radius: 8px; | |
| padding: 15px; | |
| margin-top: 10px; | |
| } | |
| .speech-audio-input { | |
| border: 2px dashed #1890ff; | |
| border-radius: 8px; | |
| padding: 10px; | |
| } | |
| .speech-status { | |
| background-color: #e6f7ff; | |
| border-left: 4px solid #1890ff; | |
| } | |
| .speech-transcription { | |
| background-color: #fafafa; | |
| border: 1px solid #d9d9d9; | |
| border-radius: 4px; | |
| } | |
| /* Chatbot wrapper with badge overlay */ | |
| .chatbot-wrapper { | |
| position: relative !important; | |
| background: transparent !important; | |
| border: none !important; | |
| padding: 0 !important; | |
| } | |
| .clear-badge { | |
| position: absolute !important; | |
| top: 8px !important; | |
| right: 8px !important; | |
| z-index: 10 !important; | |
| font-size: 0.75rem !important; | |
| padding: 4px 8px !important; | |
| min-width: auto !important; | |
| height: auto !important; | |
| background-color: rgba(239, 68, 68, 0.9) !important; | |
| border: none !important; | |
| border-radius: 4px !important; | |
| color: white !important; | |
| cursor: pointer !important; | |
| } | |
| .clear-badge:hover { | |
| background-color: rgba(220, 38, 38, 1) !important; | |
| } | |
| /* Input block with inline button */ | |
| .input-block { | |
| background-color: #27272A; | |
| border-radius: 8px; | |
| padding: 12px; | |
| } | |
| .input-block > div { | |
| background: transparent !important; | |
| } | |
| .input-label { | |
| font-size: 0.75rem !important; | |
| color: #a1a1aa !important; | |
| margin-bottom: 5px !important; | |
| background-color: #27272A !important; | |
| } | |
| .input-label p { | |
| margin: 0 !important; | |
| font-size: 0.75rem !important; | |
| } | |
| .input-row { | |
| gap: 0 !important; | |
| align-items: center !important;; | |
| } | |
| .input-row button { | |
| min-width: 60px !important; | |
| height: 40px !important; | |
| margin: 0 !important; | |
| border-radius: 0 6px 6px 0 !important; | |
| font-size: 1rem; | |
| } | |
| .message-input { | |
| height: 40px !important; | |
| background: transparent !important; | |
| } | |
| .message-input textarea { | |
| height: 40px !important; | |
| min-height: 40px !important; | |
| max-height: 40px !important; | |
| border-radius: 6px 0 0 6px !important; | |
| box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3) !important; | |
| background-color: #1a1a1c !important; | |
| border: none !important; | |
| color: #ffffff !important; | |
| padding: 10px 12px !important; | |
| } | |
| .message-input textarea::placeholder { | |
| color: #a1a1aa !important; | |
| } | |
| /* Hide Gradio processing time display */ | |
| .progress-text { | |
| display: none !important; | |
| } | |
| footer { | |
| display: none !important; | |
| } | |
| """ | |
| ) as demo, ms.Application(), antdx.XProvider(): | |
| session = gr.State({"user": None, "history": []}) | |
| with antd.Flex(vertical=True, gap="middle"): | |
| chat_column, chatbot = create_chat_column(session) | |
| chat_column.elem_classes = ["chat-block"] | |
| auth_ui = create_auth(session, chat_column, chatbot) | |
| auth_ui["auth_block"].elem_classes = ["auth-block"] | |
| return demo | |