import os, base64 import gradio as gr # Theming (can be overridden by the host app) PRIMARY_COLOR = "#0F6CBD" # medical calm blue ACCENT_COLOR = "#C4314B" # medical alert red SUCCESS_COLOR = "#2E7D32" # positive/ok BG1 = "#F0F7FF" BG2 = "#E8F0FA" BG3 = "#DDE7F8" FONT_FAMILY = "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 'Liberation Sans', sans-serif" # App metadata (overridable) PROJECT_NAME = "Demo Project" AIO_YEAR = "2025" AIO_MODULE = "00" PROJECT_DESCRIPTION = "" META_INFO = [] # list of (label, value) def set_colors(primary: str = None, accent: str = None, bg1: str = None, bg2: str = None, bg3: str = None): """Allow host app to set theme colors dynamically.""" global PRIMARY_COLOR, ACCENT_COLOR, BG1, BG2, BG3, custom_css if primary: PRIMARY_COLOR = primary if accent: ACCENT_COLOR = accent if bg1: BG1 = bg1 if bg2: BG2 = bg2 if bg3: BG3 = bg3 # Rebuild CSS with new colors custom_css = _build_custom_css() def set_font(font_family: str): """Allow host app to set a custom font stack (e.g., 'Inter', system fallbacks).""" global FONT_FAMILY, custom_css if font_family and isinstance(font_family, str): FONT_FAMILY = font_family custom_css = _build_custom_css() def set_meta(project_name: str = None, year: str = None, module: str = None, description: str = None, meta_items: list = None): """Set project metadata used across the header and info sections.""" global PROJECT_NAME, AIO_YEAR, AIO_MODULE, PROJECT_DESCRIPTION, META_INFO if project_name is not None: PROJECT_NAME = project_name if year is not None: AIO_YEAR = year if module is not None: AIO_MODULE = module if description is not None: PROJECT_DESCRIPTION = description if meta_items is not None: META_INFO = meta_items def configure(project_name: str = None, year: str = None, module: str = None, description: str = None, colors: dict = None, font_family: str = None, meta_items: list = None): """One-call configuration for meta, theme, and font.""" if colors: set_colors( primary=colors.get("primary"), accent=colors.get("accent"), bg1=colors.get("bg1"), bg2=colors.get("bg2"), bg3=colors.get("bg3"), ) if font_family: set_font(font_family) set_meta(project_name, year, module, description, meta_items) def image_to_base64(image_path: str): # Construct the absolute path to the image current_dir = os.path.dirname(os.path.abspath(__file__)) full_image_path = os.path.join(current_dir, image_path) with open(full_image_path, "rb") as f: return base64.b64encode(f.read()).decode("utf-8") def create_header(): with gr.Row(): with gr.Column(scale=2): logo_base64 = image_to_base64("static/aivn_logo.png") gr.HTML( f"""Logo""" ) with gr.Column(scale=2): gr.HTML(f"""

{PROJECT_NAME}

AIO{AIO_YEAR}: Module {AIO_MODULE}.

""") def create_footer(): logo_base64_vlai = image_to_base64("static/vlai_logo.png") footer_html = """ """ + f""" """ return gr.HTML(footer_html) def _build_custom_css() -> str: return f""" @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); .gradio-container {{ min-height: 100vh !important; width: 100vw !important; margin: 0 !important; padding: 0px !important; background: linear-gradient(135deg, {BG1} 0%, {BG2} 50%, {BG3} 100%); background-size: 600% 600%; animation: gradientBG 7s ease infinite; }} /* Global font setup */ body, .gradio-container, .gr-block, .gr-markdown, .gr-button, .gr-input, .gr-dropdown, .gr-number, .gr-plot, .gr-dataframe, .gr-accordion, .gr-form, .gr-textbox, .gr-html, table, th, td, label, h1, h2, h3, h4, h5, h6, p, span, div {{ font-family: {FONT_FAMILY} !important; }} @keyframes gradientBG {{ 0% {{background-position: 0% 50%;}} 50% {{background-position: 100% 50%;}} 100% {{background-position: 0% 50%;}} }} /* Minimize spacing and padding */ .content-wrap {{ padding: 2px !important; margin: 0 !important; }} /* Reduce component spacing */ .gr-row {{ gap: 5px !important; margin: 2px 0 !important; }} .gr-column {{ gap: 4px !important; padding: 4px !important; }} /* Accordion optimization */ .gr-accordion {{ margin: 4px 0 !important; }} .gr-accordion .gr-accordion-content {{ padding: 2px !important; }} /* Form elements spacing */ .gr-form {{ gap: 2px !important; }} /* Button styling */ .gr-button {{ margin: 2px 0 !important; }} /* DataFrame optimization */ .gr-dataframe {{ margin: 4px 0 !important; }} /* Remove horizontal scroll from data preview */ .gr-dataframe .wrap {{ overflow-x: auto !important; max-width: 100% !important; }} /* Plot optimization */ .gr-plot {{ margin: 4px 0 !important; }} /* Reduce markdown margins */ .gr-markdown {{ margin: 2px 0 !important; }} /* Footer positioning */ .sticky-footer {{ position: fixed; bottom: 0px; left: 0; width: 100%; background: {BG1}; padding: 6px !important; box-shadow: 0 -2px 10px rgba(0,0,0,0.1); z-index: 1000; }} """ # Initialize CSS using defaults custom_css = _build_custom_css() def render_info_card(description: str = None, meta_items: list = None, icon: str = "🧠", title: str = "About this demo") -> str: desc = description if description is not None else PROJECT_DESCRIPTION items = meta_items if meta_items is not None else META_INFO meta_html = " · ".join([f"{k}: {v}" for k, v in items]) if items else "" return f"""
{icon}
{title}
{desc}
{meta_html}
""" def render_disclaimer(text: str, icon: str = "⚠️", title: str = "Educational Use Only") -> str: return f"""
{icon}
{title}
{text}
"""