import os import json import requests import streamlit as st # --- Configuration --- API_URL = "http://127.0.0.1:8000/chat" IMAGES_DIR = "images" # --- Page Setup --- st.set_page_config( page_title="Tharushika | AI Portfolio", page_icon="👋", layout="centered", initial_sidebar_state="collapsed" ) st.markdown(""" """, unsafe_allow_html=True) # --- Helper Functions --- def render_projects(data): st.markdown("### Featured Projects") if not data: st.info("No projects data received.") return cols = st.columns(2) for i, proj in enumerate(data): with cols[i % 2]: with st.container(border=True): img_path = proj.get("image_path", "") if img_path and os.path.exists(img_path): st.image(img_path, use_container_width=True) else: st.markdown(f"""
No Image
""", unsafe_allow_html=True) st.markdown(f"#### {proj.get('title', 'Untitled')}") st.caption(proj.get('type', 'Project').upper()) with st.expander("View Details"): st.write(proj.get('description', '')) st.markdown( f"**Tech Stack:** {proj.get('technologies', '')}") links = [] if proj.get('github_url'): links.append(f"[GitHub]({proj.get('github_url')})") if proj.get('demo_url'): links.append(f"[Live Demo]({proj.get('demo_url')})") if links: st.markdown("  •  ".join(links)) def render_skills(data): st.markdown("### Skills & Expertise") if not data: st.info("No skills data received.") return for category, skills in data.items(): with st.container(border=True): st.markdown(f"**{category}**") badges = "".join( [f"{s}" for s in skills]) st.markdown(badges, unsafe_allow_html=True) def render_articles(data): st.markdown("### Articles") if not data: st.info("No articles found.") return for item in data: with st.container(border=True): st.markdown(f"**{item.get('title', 'Untitled')}**") st.markdown( f"

{item.get('description', '')}

", unsafe_allow_html=True) if item.get('url'): st.markdown(f"[Read Article ›]({item['url']})") def render_videos(data): st.markdown("### Video Tutorials") if not data: st.info("No videos found.") return cols = st.columns(2) for i, item in enumerate(data): with cols[i % 2]: with st.container(border=True): thumb = item.get('thumbnail_url', "") if thumb and os.path.exists(thumb): st.image(thumb, use_container_width=True) st.markdown(f"**{item.get('title', 'Untitled')}**") st.markdown( f"

{item.get('description', '')}

", unsafe_allow_html=True) if item.get('url'): st.markdown(f"[Watch on YouTube ›]({item['url']})") def render_research(data): st.markdown("### Research") if not data: st.info("No research found.") return for item in data: with st.container(border=True): st.markdown(f"**{item.get('title', 'Untitled')}**") st.markdown( f"

{item.get('description', '')}

", unsafe_allow_html=True) if item.get('url'): st.markdown(f"[View Publication ›]({item['url']})") def render_certifications(data): st.markdown("### Certifications") if not data: st.info("No certifications found.") return for item in data: st.markdown(f"""
🎖️ {item}
""", unsafe_allow_html=True) # --- NEW: Resume Renderer --- def render_resume(data): st.markdown("### 📄 Resume / CV") col1, col2 = st.columns([1, 2]) with col1: preview_path = data.get("preview_image", "") if preview_path and os.path.exists(preview_path): st.image(preview_path, caption="Preview", use_container_width=True) else: st.markdown("""
📄
""", unsafe_allow_html=True) with col2: st.markdown(f"#### {data.get('title', 'Resume')}") st.write(data.get('description', '')) pdf_path = data.get("file_path", "") if pdf_path and os.path.exists(pdf_path): with open(pdf_path, "rb") as pdf_file: pdf_bytes = pdf_file.read() st.download_button( label="📥 Download Resume (PDF)", data=pdf_bytes, file_name="Tharushika_Abedheera_Resume.pdf", mime="application/pdf", ) else: st.error("Resume file not found.") def render_content(data): st.markdown("### Content & Research") if not data: return tab1, tab2, tab3 = st.tabs(["Articles", "Videos", "Research"]) with tab1: render_articles(data.get('articles', [])) with tab2: render_videos(data.get('videos', [])) with tab3: render_research(data.get('research', [])) # --- Centralized Chat Logic Function --- def process_chat_message(prompt): with st.spinner("Processing..."): try: response = requests.post(API_URL, json={"message": prompt}) if response.status_code == 200: api_data = response.json() st.session_state.last_exchange = { "user_query": prompt, "ai_response": api_data.get("response", ""), "tool_code": api_data.get("tool_code"), "tool_data": api_data.get("tool_data") } else: st.error(f"Backend Error: {response.status_code}") except Exception as e: st.error(f"Connection Failed: {e}") st.rerun() # --- Main Layout --- if "last_exchange" not in st.session_state: st.session_state.last_exchange = None # --- Top Section: Profile and Introduction --- if not st.session_state.last_exchange: st.markdown("
", unsafe_allow_html=True) profile_pic_path = "images/profile.png" if os.path.exists(profile_pic_path): st.image(profile_pic_path, width=160) else: st.markdown(f"""
Add profile.png
""", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.markdown("

Hey, I'm Tharushika 👋

", unsafe_allow_html=True) st.markdown("

Machine Learning Engineer

", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) if st.button("Me"): process_chat_message("Tell me about yourself") if st.button("Projects"): process_chat_message("Show me your projects") if st.button("Skills"): process_chat_message("What are your skills?") if st.button("Contact"): process_chat_message("How can I contact you?") st.markdown("
", unsafe_allow_html=True) if prompt := st.chat_input("Ask me anything..."): process_chat_message(prompt) # --- Conversation Area --- if st.session_state.last_exchange: exchange = st.session_state.last_exchange with st.chat_message("user"): st.write(exchange["user_query"]) with st.chat_message("assistant"): st.write(exchange["ai_response"]) tool_code = exchange.get("tool_code") tool_data = exchange.get("tool_data") if tool_code == "show_projects": render_projects(tool_data) elif tool_code == "show_skills": render_skills(tool_data) elif tool_code == "show_content": render_content(tool_data) elif tool_code == "show_videos": render_videos(tool_data) elif tool_code == "show_articles": render_articles(tool_data) elif tool_code == "show_research": render_research(tool_data) elif tool_code == "show_certifications": render_certifications(tool_data) elif tool_code == "show_resume": render_resume(tool_data) # <--- RESUME HANDLER ADDED if prompt := st.chat_input("Ask for more details..."): process_chat_message(prompt)