import gradio as gr import base64 import os import json # --- Helper Functions --- def load_json(filename): """Load JSON data from content folder""" try: with open(f"content/{filename}.json", "r", encoding="utf-8") as f: return json.load(f) except Exception as e: print(f"Error loading {filename}.json: {e}") return {} def file_to_data_uri(filepath, mime_type="application/pdf"): """Convert file to data URI""" try: with open(filepath, "rb") as f: data = f.read() b64 = base64.b64encode(data).decode("utf-8") return f"data:{mime_type};base64,{b64}" except Exception as e: print(f"Error converting file to data URI: {e}") return None def image_to_data_uri(filepath, mime_type="image/jpeg"): """Convert image to data URI""" try: with open(filepath, "rb") as f: data = f.read() b64 = base64.b64encode(data).decode("utf-8") return f"data:{mime_type};base64,{b64}" except Exception as e: print(f"Error converting image to data URI: {e}") return None # --- Navigation Functions --- def show_data_analytics(): return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False) def show_machine_learning(): return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False) def show_computer_vision(): return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True) def go_home(): return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False) def toggle_resume(is_visible): """Toggle the visibility of the resume section.""" new_state = not is_visible new_label = "Hide Resume" if new_state else "View Resume" return new_state, gr.update(visible=new_state), gr.update(value=new_label) # --- Icons (SVG) --- data_analytics_icon = """""" machine_learning_icon = """""" computer_vision_icon = """""" home_icon = """""" linkedin_icon = """""" github_icon = """""" mail_icon = """""" link_icon = """""" document_icon = """""" # Dictionary for icon access icons = { "data_analytics_icon": data_analytics_icon, "machine_learning_icon": machine_learning_icon, "computer_vision_icon": computer_vision_icon, "home_icon": home_icon, "linkedin_icon": linkedin_icon, "github_icon": github_icon, "mail_icon": mail_icon, "link_icon": link_icon, "document_icon": document_icon } # --- Helper functions for generating HTML --- def generate_profile_html(): """Generate HTML for the profile section""" try: profile_img_uri = image_to_data_uri(profile_data.get("photo", "data/My_photo.jpeg")) # Skills HTML skills_html = "" for skill in profile_data.get("skills", []): skills_html += f'
{skill}
\n' # Social links HTML social_links_html = "" for link in profile_data.get("social_links", []): icon = icons.get(link.get("icon", ""), "") id_attr = f' id="{link["id"]}"' if "id" in link else "" social_links_html += f''' { icon } ''' return f'''
{profile_data.get(
{profile_data.get("name", "")}

{profile_data.get("title", "")}

{profile_data.get("about", "")}
{skills_html}
''' except Exception as e: # Fallback if error occurs print(f"Error generating profile HTML: {e}") return f'''
Profile
{profile_data.get("name", "Name")}

{profile_data.get("title", "Title")}

{profile_data.get("about", "About text")}
{', '.join(profile_data.get("skills", ["Skills"]))}
''' def generate_resume_html(): """Generate HTML for the collapsible resume section""" return '''
''' def generate_cards_html(): """Generate HTML for the specialization cards""" cards_html = "" for card in sections_data.get("cards", []): icon = icons.get(card.get("icon", ""), "") cards_html += f'''
{icon} {card.get("title", "")}
{card.get("description", "")}
''' return cards_html def generate_contact_html(): """Generate HTML for the contact section""" contact = profile_data.get("contact", {}) footer = profile_data.get("footer", {}) return f'''

{contact.get("heading", "Contact Me")}

{contact.get("text", "")}

{contact.get("button_text", "Contact")}
''' def generate_skills_html(skills_data, section_class): """Generate HTML for skills in a section""" skills_html = "" for skill_category in skills_data: items_html = "" for item in skill_category.get("items", []): items_html += f"
  • {item}
  • \n" skills_html += f'''

    {skill_category.get("category", "")}

    ''' return skills_html def generate_projects_html(projects_data, section_class): """Generate HTML for projects in a section""" projects_html = "" for project in projects_data: projects_html += f'''
    {project.get("title", "")} {icons.get("link_icon", "")} View Project
    {project.get("description", "")} Tech Stack: {project.get("tech_stack", "")}
    ''' return projects_html def generate_section_html(section_data, section_class): """Generate HTML for a complete section""" skills_html = generate_skills_html(section_data.get("skills", []), section_class) projects_html = generate_projects_html(section_data.get("projects", []), section_class) return f'''

    {section_data.get("heading", "")}

    {section_data.get("intro", "")}

    Skills

    {skills_html}

    Projects

    {projects_html} ''' # --- CSS --- portfolio_css = """ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=Montserrat:wght@700;800&display=swap'); :root { --primary-da: #8a2be2; --secondary-da: #2575fc; --primary-ml: #00b4db; --secondary-ml: #0083b0; --primary-cv: #ff4d7e; --secondary-cv: #fd3e58; --dark-bg: #0f1118; --card-bg: #1a1d29; --text-primary: #ffffff; --text-secondary: #e0e0e0; --text-muted: #a0a0a0; --shadow-sm: 0 4px 6px rgba(0, 0, 0, 0.1); --shadow-md: 0 8px 16px rgba(0, 0, 0, 0.2); --shadow-lg: 0 12px 24px rgba(0, 0, 0, 0.2); --border-radius-sm: 8px; --border-radius-md: 12px; --border-radius-lg: 20px; --transition-fast: 0.2s ease; --transition-med: 0.3s ease; --transition-slow: 0.5s ease; } body { font-family: 'Poppins', sans-serif; background: var(--dark-bg); background-image: radial-gradient(circle at 25% 25%, rgba(53, 53, 113, 0.05) 0%, transparent 50%), radial-gradient(circle at 75% 75%, rgba(113, 53, 53, 0.05) 0%, transparent 50%); color: var(--text-primary); margin: 0; padding: 0; overflow-x: hidden; line-height: 1.6; letter-spacing: 0.5px; font-weight: 400; } .gr-container { max-width: 1200px; margin: 0 auto; padding: 20px; } /* Scrollbar styling */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.05); border-radius: 4px; } ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.3); } /* Landing section */ .landing-section { text-align: center; margin-bottom: 60px; padding: 40px 20px; position: relative; } .landing-section:before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 500px; background: linear-gradient(180deg, rgba(0,0,0,0.7) 0%, transparent 100%); z-index: -1; } .landing-section h1, .landing-section h2 { color: var(--text-primary) !important; margin-top: 0; } .landing-section h1 { font-family: 'Montserrat', sans-serif; font-size: 3.2rem; font-weight: 800; margin-bottom: 0.5rem; background: linear-gradient(90deg, var(--primary-da), var(--primary-ml), var(--primary-cv)); -webkit-background-clip: text; background-clip: text; color: transparent !important; letter-spacing: -0.5px; } .landing-section h2 { font-size: 2rem; font-weight: 600; margin-bottom: 1.5rem; } .profile-container { margin: 30px auto; display: flex; align-items: center; justify-content: center; flex-direction: column; } .profile-pic { width: 180px; height: 180px; border-radius: 50%; object-fit: cover; border: 4px solid rgba(255, 255, 255, 0.2); box-shadow: var(--shadow-md); margin-bottom: 20px; position: relative; background: linear-gradient(45deg, var(--primary-da), var(--primary-ml), var(--primary-cv)); padding: 4px; } .profile-pic img { border-radius: 50%; width: 100%; height: 100%; object-fit: cover; } .name-text { font-size: 2.6rem; font-weight: 700; margin-top: 10px; margin-bottom: 10px; } @keyframes float { 0% { transform: translateY(0px) } 50% { transform: translateY(-10px) } 100% { transform: translateY(0px) } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .about-text { max-width: 800px; margin: 0 auto 40px; font-size: 1.25rem; line-height: 1.6; color: var(--text-secondary); } .skills-container { margin-top: 20px; display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-bottom: 40px; } .skill-pill { background: rgba(255, 255, 255, 0.1); padding: 8px 16px; border-radius: 30px; font-size: 0.9rem; font-weight: 500; color: var(--text-secondary); } .social-links { display: flex; justify-content: center; gap: 20px; margin: 30px 0; } .social-button { background: rgba(255, 255, 255, 0.1); border: none; border-radius: 50%; width: 50px; height: 50px; display: flex; align-items: center; justify-content: center; transition: all var(--transition-med); color: var(--text-primary); font-size: 1.2rem; box-shadow: var(--shadow-sm); } .social-button:hover { transform: translateY(-5px); background: rgba(255, 255, 255, 0.2); box-shadow: var(--shadow-md); } .social-linkedin:hover { background: #0077b5; } .social-github:hover { background: #333; } .social-email:hover { background: #ea4335; } .social-button svg { width: 24px; height: 24px; } /* Card styling */ .cards-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px; margin: 40px 0; } .card-container { position: relative; /* Important for button positioning */ margin-bottom: 20px; height: 100%; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .card-container.da:before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 6px; background: linear-gradient(90deg, var(--primary-da), var(--secondary-da)); z-index: 5; border-radius: var(--border-radius-md) var(--border-radius-md) 0 0; } .card-container.ml:before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 6px; background: linear-gradient(90deg, var(--primary-ml), var(--secondary-ml)); z-index: 5; transition: all var(--transition-med); border-radius: var(--border-radius-md) var(--border-radius-md) 0 0; } .card-container.cv:before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 6px; background: linear-gradient(90deg, var(--primary-cv), var(--secondary-cv)); z-index: 5; border-radius: var(--border-radius-md) var(--border-radius-md) 0 0; } .card-content { padding: 30px; min-height: 200px; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 26px; font-weight: 700; position: relative; z-index: 2; transition: all var(--transition-med); } .card-content svg { width: 60px; height: 60px; margin-bottom: 20px; opacity: 0.9; transition: all var(--transition-med); } .card-inner { transition: transform var(--transition-med), box-shadow var(--transition-med), background-color var(--transition-med); text-align: center; border-radius: var(--border-radius-md); background: var(--card-bg); overflow: hidden; box-shadow: var(--shadow-md); height: 100%; cursor: pointer; /* Indicates the card is clickable */ position: relative; /* Ensure child elements are positioned relative to the card */ } .card-inner:hover { transform: translateY(-10px) scale(1.05); /* Adds a slight zoom effect */ box-shadow: var(--shadow-lg); /* Increases shadow for emphasis */ background: rgba(255, 255, 255, 0.1); /* Subtle background change */ border: 2px solid var(--primary-da); /* Optional: Add a border to emphasize hover */ } .card-inner:hover .card-content svg { transform: scale(1.1); /* Slightly enlarges the icon */ opacity: 1; } .card-inner:hover .card-description { color: var(--text-primary); /* Optional: changes text color for emphasis */ } /* Add a subtle glow effect */ .card-inner:hover:before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; border-radius: var(--border-radius-md); box-shadow: 0 0 15px rgba(255, 255, 255, 0.3); z-index: -1; } .card-description { padding: 0 20px 20px; color: var(--text-secondary); font-size: 1.1rem; line-height: 1.5; } /* Card button styling - crucial for making cards clickable */ .card-button { position: absolute !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; opacity: 0 !important; z-index: 10 !important; cursor: pointer !important; margin: 0 !important; padding: 0 !important; border: none !important; transform: scale(1.05) !important; transition: transform 0.2s ease !important; background: none !important; } .click-to-view { margin-top: 15px; padding: 8px 15px; border-radius: 20px; display: inline-block; font-weight: 600; font-size: 0.9rem; transition: all var(--transition-med); background: rgba(255, 255, 255, 0.1); box-shadow: var(--shadow-sm); margin-left: auto; margin-right: auto; color: var(--text-primary); text-align: center; } /* Add glow effect */ .click-to-view:hover { transform: translateY(-2px); box-shadow: 0 0 15px rgba(255, 255, 255, 0.5), var(--shadow-md); background: rgba(255, 255, 255, 0.2); color: var(--text-primary); filter: brightness(1.2); } /* Add animation for subtle pulsing effect */ @keyframes glow-pulse { 0% { box-shadow: 0 0 5px rgba(255, 255, 255, 0.2); } 50% { box-shadow: 0 0 15px rgba(255, 255, 255, 0.4); } 100% { box-shadow: 0 0 5px rgba(255, 255, 255, 0.2); } } .click-to-view { animation: glow-pulse 3s infinite; } .card-description p { margin-bottom: 15px; margin-top: 0; } .card-description { display: flex; flex-direction: column; align-items: center; justify-content: space-between; height: 100%; padding: 0 20px 20px; color: var(--text-secondary); font-size: 1.1rem; line-height: 1.5; } /* Different colors for each card type */ .da-click { color: var(--primary-da); border: 1px solid var(--primary-da); } .ml-click { color: var(--primary-ml); border: 1px solid var(--primary-ml); } .cv-click { color: var(--primary-cv); border: 1px solid var(--primary-cv); } /* Hover effects */ .click-to-view:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); background: rgba(255, 255, 255, 0.15); } .card-inner:hover .click-to-view { transform: translateY(-2px); box-shadow: var(--shadow-md); } .card-inner:hover .da-click { background-color: rgba(138, 43, 226, 0.1); } .card-inner:hover .ml-click { background-color: rgba(0, 180, 219, 0.1); } .card-inner:hover .cv-click { background-color: rgba(255, 77, 126, 0.1); } .experience-timeline { margin: 80px 0 60px; padding: 20px; position: relative; } .experience-timeline h2 { text-align: center; margin-bottom: 60px; position: relative; display: inline-block; left: 50%; transform: translateX(-50%); font-family: 'Montserrat', sans-serif; font-size: 2.5rem; font-weight: 700; background: linear-gradient(90deg, var(--primary-da), var(--primary-ml), var(--primary-cv)); -webkit-background-clip: text; background-clip: text; color: transparent; } .experience-timeline h2:after { content: ''; position: absolute; bottom: -10px; left: 0; width: 100%; height: 3px; border-radius: 3px; background: linear-gradient(90deg, var(--primary-da), var(--primary-ml), var(--primary-cv)); } /* Horizontal Timeline Styling */ .timeline-container { display: flex; justify-content: space-between; align-items: flex-start; position: relative; margin: 40px auto; max-width: 100%; overflow-x: auto; padding: 20px 0; } .timeline-track { position: absolute; top: 50%; left: 0; right: 0; height: 4px; background: linear-gradient(to right, var(--primary-da), var(--primary-ml), var(--primary-cv)); border-radius: 2px; z-index: 1; } .timeline-node { position: relative; display: flex; flex-direction: column; align-items: center; width: 150px; margin: 0 20px; z-index: 2; } .timeline-dot { width: 20px; height: 20px; background: var(--primary-da); border-radius: 50%; box-shadow: 0 0 10px rgba(255, 255, 255, 0.5); margin-bottom: 10px; transition: transform 0.3s ease; } .timeline-year { font-size: 1rem; font-weight: 600; margin-bottom: 10px; color: var(--text-primary); } .timeline-content { background: var(--card-bg); border-radius: var(--border-radius-md); box-shadow: var(--shadow-sm); padding: 15px; text-align: center; width: 100%; transition: transform 0.3s ease, box-shadow 0.3s ease; } .timeline-node:hover .timeline-dot { transform: scale(1.3); } .timeline-node:hover .timeline-content { transform: translateY(-10px); box-shadow: var(--shadow-md); } /* Responsive adjustments for smaller screens */ @media (max-width: 768px) { .timeline-container { flex-direction: column; align-items: center; } .timeline-track { display: none; } .timeline-node { margin: 20px 0; } } /* Section styling */ .section-container { padding: 60px 20px; position: relative; } .section-container:before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 300px; background: radial-gradient(ellipse at top, rgba(255,255,255,0.05) 0%, transparent 70%); z-index: 0; } .da-section h1.section-heading { color: var(--primary-da); position: relative; display: inline-block; } .ml-section h1.section-heading { color: var(--primary-ml); position: relative; display: inline-block; } .cv-section h1.section-heading { color: var(--primary-cv); position: relative; display: inline-block; } .section-heading:after { content: ''; position: absolute; bottom: -10px; left: 0; width: 100%; height: 3px; border-radius: 3px; } .da-section .section-heading:after { background: var(--primary-da); } .ml-section .section-heading:after { background: var(--primary-ml); } .cv-section .section-heading:after { background: var(--primary-cv); } /* Subheadings color-coded */ .section-subheading.da { color: var(--primary-da); } .section-subheading.ml { color: var(--primary-ml); } .section-subheading.cv { color: var(--primary-cv); } /* Back buttons */ .back-button { border: none; border-radius: var(--border-radius-lg); padding: 10px 20px; font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: transform var(--transition-fast), box-shadow var(--transition-fast); margin-bottom: 30px; display: flex; align-items: center; gap: 8px; } .back-button:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); } .back-button-da { background: linear-gradient(45deg, var(--primary-da), var(--secondary-da)); color: #fff; } .back-button-ml { background: linear-gradient(45deg, var(--primary-ml), var(--secondary-ml)); color: #fff; } .back-button-cv { background: linear-gradient(45deg, var(--primary-cv), var(--secondary-cv)); color: #fff; } .back-button svg { width: 20px; height: 20px; } /* Contact form */ .contact-container { background: var(--card-bg); border-radius: var(--border-radius-md); padding: 30px; max-width: 600px; margin: 0 auto; box-shadow: var(--shadow-md); } .hire-me-button { background: linear-gradient(45deg, var(--primary-da), var(--primary-cv)); color: white; border: none; border-radius: var(--border-radius-lg); padding: 12px 25px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all var(--transition-med); box-shadow: var(--shadow-sm); display: inline-block; text-decoration: none; } .hire-me-button:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); filter: brightness(1.1); } /* Project cards */ .project-card { background: var(--card-bg); border-radius: var(--border-radius-md); padding: 25px; margin-bottom: 20px; box-shadow: var(--shadow-sm); transition: all var(--transition-med); border-left: 4px solid transparent; } .da-section .project-card { border-left-color: var(--primary-da); } .ml-section .project-card { border-left-color: var(--primary-ml); } .cv-section .project-card { border-left-color: var(--primary-cv); } .project-card:hover { transform: translateX(5px); box-shadow: var(--shadow-md); } .project-title { font-size: 1.3rem; font-weight: 600; margin-bottom: 10px; display: flex; align-items: center; justify-content: space-between; } .project-title-text { flex: 1; } .project-link { color: var(--text-secondary); transition: all var(--transition-med); text-decoration: none; display: inline-flex; align-items: center; margin-left: 10px; } .project-link svg { width: 16px; height: 16px; } .da-section .project-title-text { color: var(--primary-da); } .ml-section .project-title-text { color: var(--primary-ml); } .cv-section .project-title-text { color: var(--primary-cv); } .da-section .project-link:hover { color: var(--primary-da); } .ml-section .project-link:hover { color: var(--primary-ml); } .cv-section .project-link:hover { color: var(--primary-cv); } .project-description { color: var(--text-secondary); line-height: 1.5; } .tech-stack { display: block; margin-top: 10px; font-style: italic; color: var(--text-muted); } /* Skills list */ .skills-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 15px; margin-top: 20px; margin-bottom: 40px; /* Added margin to create space between skills and projects */ } .skill-category { background: rgba(255, 255, 255, 0.05); border-radius: var(--border-radius-sm); padding: 15px; transition: all var(--transition-med); } .skill-category:hover { background: rgba(255, 255, 255, 0.08); transform: translateY(-3px); } .skill-category h4 { margin-top: 0; margin-bottom: 10px; font-size: 1.1rem; } .da-section .skill-category h4 { color: var(--primary-da); } .ml-section .skill-category h4 { color: var(--primary-ml); } .cv-section .skill-category h4 { color: var(--primary-cv); } .skill-category ul { margin: 0; padding-left: 20px; color: var(--text-secondary); } .skill-category li { margin-bottom: 5px; } /* Section intro text */ .section-intro { max-width: 800px; margin-bottom: 30px; line-height: 1.6; color: var(--text-secondary); font-size: 1.1rem; } /* Footer */ .footer { text-align: center; padding: 40px 20px; margin-top: 60px; color: var(--text-muted); font-size: 0.9rem; } /* Animations for scroll */ .animate-on-scroll { opacity: 0; transform: translateY(20px); transition: opacity 0.6s ease, transform 0.6s ease; } .animate-on-scroll.show { animation: fadeInUp 0.6s ease forwards; } @keyframes fadeInUp { 0% { opacity: 0; transform: translateY(20px); } 100% { opacity: 1; transform: translateY(0); } } /* Loading states */ .loading-spinner { border: 4px solid rgba(255, 255, 255, 0.2); border-top: 4px solid var(--primary-da); border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* Glassmorphism effects */ .glass-container { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: var(--border-radius-md); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } /* Subtle background patterns */ body { background-image: url('https://www.transparenttextures.com/patterns/noise.png'); } /* Gradient refinements */ button { background: linear-gradient(45deg, var(--primary-da), var(--primary-ml)); } /* Shadow depth variations */ .card-container:hover { box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } /* ARIA attributes */ button { aria-label: "Interactive button"; } /* Keyboard navigation */ button:focus { outline: 2px solid var(--primary-da); outline-offset: 2px; } /* Mobile-first refinements */ @media (max-width: 768px) { .cards-grid { grid-template-columns: 1fr; } } /* Touch-friendly targets */ button { padding: 12px 20px; } /* Responsive typography */ h1 { font-size: calc(2rem + 1vw); } /* Parallax scrolling effects */ .section-container:before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 300px; background: linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent); transform: translateY(-50%); will-change: transform; transition: transform 0.3s ease; } body.onscroll .section-container:before { transform: translateY(0); } /* Mouse-follow glow effect */ .interactive:hover { box-shadow: 0 0 15px rgba(255, 255, 255, 0.5); } /* Staggered animation sequences */ @keyframes staggeredFadeIn { 0% { opacity: 0; transform: translateY(20px); } 100% { opacity: 1; transform: translateY(0); } } .list-item { opacity: 0; animation: staggeredFadeIn 0.6s ease forwards; } .list-item:nth-child(1) { animation-delay: 0.2s; } .list-item:nth-child(2) { animation-delay: 0.4s; } .list-item:nth-child(3) { animation-delay: 0.6s; } /* Interactive particles background */ .particles-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: url('https://www.transparenttextures.com/patterns/cubes.png'); opacity: 0.1; } /* Smooth page section transitions */ html { scroll-behavior: smooth; } /* Custom cursor styles */ body { cursor: url('https://example.com/custom-cursor.png'), auto; } button:hover { cursor: pointer; } /* Resume Section */ .resume-section { margin: 40px auto; padding: 20px; text-align: center; max-width: 800px; box-shadow: var(--shadow-md); } .resume-toggle-button { background: linear-gradient(45deg, var(--primary-da), var(--primary-cv)); color: white; border: none; border-radius: var(--border-radius-lg); padding: 10px 20px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all var(--transition-med); box-shadow: var(--shadow-sm); width: auto; /* Adjust width to fit the text */ min-width: 150px; /* Optional: Set a minimum width for consistency */ } .resume-toggle-button:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); filter: brightness(1.1); } .resume-content { margin-top: 20px; text-align: center; } .resume-download-button { display: inline-block; margin: 20px 0; padding: 10px 20px; font-size: 1rem; font-weight: 600; color: white; background: linear-gradient(45deg, var(--primary-da), var(--primary-cv)); border: none; border-radius: var(--border-radius-lg); text-decoration: none; transition: all var(--transition-med); box-shadow: var(--shadow-sm); } .resume-download-button:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); filter: brightness(1.1); } .resume-preview { margin-top: 20px; border: 1px solid rgba(255, 255, 255, 0.2); border-radius: var(--border-radius-md); overflow: hidden; box-shadow: var(--shadow-sm); } .resume-iframe { width: 100%; height: 500px; border: none; } /* Performance optimizations */ img { loading: lazy; } /* Micro-interactions */ button:hover { transform: translateY(-3px); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); transition: transform 0.3s ease, box-shadow 0.3s ease; } button:active { transform: scale(0.95); transition: transform 0.1s ease; } /* Scroll to Top Button */ .scroll-to-top { position: fixed; bottom: 20px; right: 20px; background: linear-gradient(45deg, var(--primary-da), var(--primary-cv)); color: white; border: none; border-radius: 50%; width: 50px; height: 50px; font-size: 1.5rem; font-weight: bold; cursor: pointer; box-shadow: var(--shadow-md); display: none; /* Initially hidden */ align-items: center; justify-content: center; transition: all var(--transition-med); z-index: 1000; } .scroll-to-top:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); filter: brightness(1.1); } """ # Load all content from JSON files try: profile_data = load_json("profile") sections_data = load_json("sections") data_analytics_data = load_json("data_analytics") machine_learning_data = load_json("machine_learning") computer_vision_data = load_json("computer_vision") except Exception as e: print(f"Error loading content: {e}") # Default values in case of error profile_data = {} sections_data = {"cards": []} data_analytics_data = {} machine_learning_data = {} computer_vision_data = {} # --- Portfolio Layout --- with gr.Blocks(title=f"{profile_data.get('name', 'Portfolio')}", css=portfolio_css) as demo: # Create sections # Data Analytics Section (initially hidden) with gr.Row(visible=False, elem_classes="section-container da-section") as da_section: with gr.Column(): # Back button back_from_da = gr.Button("← Back to Home", elem_classes="back-button back-button-da") gr.HTML(generate_section_html(data_analytics_data, "da")) # Machine Learning Section (initially hidden) with gr.Row(visible=False, elem_classes="section-container ml-section") as ml_section: with gr.Column(): # Back button back_from_ml = gr.Button("← Back to Home", elem_classes="back-button back-button-ml") gr.HTML(generate_section_html(machine_learning_data, "ml")) # Computer Vision Section (initially hidden) with gr.Row(visible=False, elem_classes="section-container cv-section") as cv_section: with gr.Column(): # Back button back_from_cv = gr.Button("← Back to Home", elem_classes="back-button back-button-cv") gr.HTML(generate_section_html(computer_vision_data, "cv")) with gr.Row(visible=True, elem_classes="landing-section") as landing_section: with gr.Column(): # Profile section with picture gr.HTML(generate_profile_html()) # Resume Section (Hugging Face-compatible implementation) resume_state = gr.State(value=False) with gr.Group(visible=False) as resume_container: gr.File(value="data/resume.pdf", label="Resume", interactive=False) resume_toggle_btn = gr.Button("View Resume") resume_toggle_btn.click(fn=toggle_resume, inputs=[resume_state], outputs=[resume_state, resume_container, resume_toggle_btn]) # Specializations heading gr.HTML("

    My Specializations

    ") # Cards Grid with proper structure with gr.Row(elem_classes="cards-grid"): with gr.Column(): # Data Analytics Card gr.HTML('
    ') da_button = gr.Button("Data Analytics", elem_classes="card-button") gr.HTML(f'''
    {icons.get(sections_data.get("cards", [])[0].get("icon", ""), "")} {sections_data.get("cards", [])[0].get("title", "Data Analytics")}
    {sections_data.get("cards", [])[0].get("description", "")}
    Click to view
    ''') with gr.Column(): # Machine Learning Card gr.HTML('
    ') ml_button = gr.Button("Machine Learning", elem_classes="card-button") gr.HTML(f'''
    {icons.get(sections_data.get("cards", [])[1].get("icon", ""), "")} {sections_data.get("cards", [])[1].get("title", "Machine Learning")}
    {sections_data.get("cards", [])[1].get("description", "")}
    Click to view
    ''') with gr.Column(): # Computer Vision Card gr.HTML('
    ') cv_button = gr.Button("Computer Vision", elem_classes="card-button") gr.HTML(f'''
    {icons.get(sections_data.get("cards", [])[2].get("icon", ""), "")} {sections_data.get("cards", [])[2].get("title", "Computer Vision")}
    {sections_data.get("cards", [])[2].get("description", "")}
    Click to view
    ''') gr.HTML(f'''

    My Journey

    2018-2021
    Bachelor's in Commerce (89%)

    SRM University Chennai

    Graduated with honors focusing on Business and Finance.

    2021-2023
    Junior Software Engineer at Cognizant

    Chennai India

    Developed and maintained enterprise-grade Java applications for the Insurance domain

    2023-2024
    Post-Graduation in AI/ML (97%)

    George Brown college,Canada

    Advanced studies in AI/ML and data science.

    2025
    Seeking ML Engineer/Data Scientist Role

    Ready for opportunities in ML and Data Science in Canada.

    ''') gr.HTML(""" """) # Contact section gr.HTML(generate_contact_html()) # Add a Gradio File component to serve the resume file gr.File(value="data/resume.pdf", label="Resume", interactive=False, visible=False) # Set up click events for navigation da_button.click(show_data_analytics, inputs=None, outputs=[landing_section, da_section, ml_section, cv_section]) ml_button.click(show_machine_learning, inputs=None, outputs=[landing_section, da_section, ml_section, cv_section]) cv_button.click(show_computer_vision, inputs=None, outputs=[landing_section, da_section, ml_section, cv_section]) back_from_da.click(go_home, inputs=None, outputs=[landing_section, da_section, ml_section, cv_section]) back_from_ml.click(go_home, inputs=None, outputs=[landing_section, da_section, ml_section, cv_section]) back_from_cv.click(go_home, inputs=None, outputs=[landing_section, da_section, ml_section, cv_section]) # Scroll to Top Button gr.HTML(""" """) # Launch the app if __name__ == "__main__": demo.launch()