|
|
import execution.euron_streamlit as st |
|
|
from src.helper import download_hugging_face_embeddings |
|
|
from langchain_pinecone import PineconeVectorStore |
|
|
from langchain.chains import create_retrieval_chain |
|
|
from langchain.chains.combine_documents import create_stuff_documents_chain |
|
|
from langchain_core.prompts import ChatPromptTemplate |
|
|
from src.prompt import * |
|
|
from src.euron_chat import EuronChatModel |
|
|
from dotenv import load_dotenv |
|
|
import os |
|
|
|
|
|
|
|
|
load_dotenv() |
|
|
pinecone_api_key = os.getenv("PINECONE_API_KEY") |
|
|
euron_api_key = os.getenv("EURON_API_KEY") |
|
|
|
|
|
if not pinecone_api_key or not euron_api_key: |
|
|
st.error("Missing keys in environment") |
|
|
st.stop() |
|
|
|
|
|
|
|
|
st.markdown(""" |
|
|
<style> |
|
|
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&display=swap'); |
|
|
|
|
|
/* Global font */ |
|
|
* { |
|
|
font-family: 'Fira Code', monospace !important; |
|
|
} |
|
|
|
|
|
/* Sidebar background & padding */ |
|
|
[data-testid="stSidebar"] { |
|
|
background-color: #f0f2f6 !important; /* Light ash */ |
|
|
border-radius: 0 20px 20px 0; |
|
|
padding: 25px 15px; |
|
|
} |
|
|
|
|
|
/* Sidebar title */ |
|
|
[data-testid="stSidebar"] .css-1d391kg { |
|
|
color: #1f2937 !important; |
|
|
font-size: 2rem; |
|
|
font-weight: 700; |
|
|
text-align: center; |
|
|
margin-bottom: 25px; |
|
|
} |
|
|
|
|
|
/* Sidebar radio buttons as styled buttons */ |
|
|
[data-testid="stSidebar"] .stRadio > div { |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
gap: 12px; |
|
|
} |
|
|
[data-testid="stSidebar"] .stRadio label { |
|
|
background-color: rgba(31,41,55,0.1) !important; /* subtle gray */ |
|
|
color: #1f2937 !important; |
|
|
padding: 12px 18px; |
|
|
border-radius: 12px; |
|
|
transition: all 0.3s ease; |
|
|
cursor: pointer; |
|
|
font-size: 1.1rem; |
|
|
font-weight: 500; |
|
|
} |
|
|
[data-testid="stSidebar"] .stRadio label:hover { |
|
|
background-color: rgba(31,41,55,0.2) !important; |
|
|
transform: translateX(5px); |
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.2); |
|
|
} |
|
|
[data-testid="stSidebar"] .stRadio input:checked + label { |
|
|
background-color: #4B5563 !important; /* Darker for selected */ |
|
|
color: #ffffff !important; |
|
|
} |
|
|
|
|
|
/* Sidebar image */ |
|
|
[data-testid="stSidebar"] img { |
|
|
border-radius: 15px; |
|
|
margin-bottom: 20px; |
|
|
} |
|
|
|
|
|
/* Sidebar divider */ |
|
|
[data-testid="stSidebar"] hr { |
|
|
border: 1px solid rgba(0,0,0,0.2) !important; |
|
|
margin: 20px 0; |
|
|
} |
|
|
|
|
|
/* Sidebar caption */ |
|
|
[data-testid="stSidebar"] .css-1x8i1po { |
|
|
text-align: center; |
|
|
font-size: 0.9rem; |
|
|
color: #4b5563 !important; |
|
|
margin-top: 15px; |
|
|
} |
|
|
</style> |
|
|
""", unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
with st.sidebar: |
|
|
|
|
|
st.image("static/icon.png", width=120) |
|
|
st.markdown("---") |
|
|
menu = st.radio("Go to", ["About Me", "Chatbot"], label_visibility="hidden") |
|
|
st.markdown("---") |
|
|
st.caption("Β© 2025 Shanin Hossain") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if "rag_chain" not in st.session_state: |
|
|
st.session_state.rag_chain = None |
|
|
st.session_state.embeddings = None |
|
|
st.session_state.retriever = None |
|
|
if "messages" not in st.session_state: |
|
|
st.session_state.messages = [] |
|
|
|
|
|
def initialize_rag(): |
|
|
try: |
|
|
if st.session_state.rag_chain is None: |
|
|
st.session_state.embeddings = download_hugging_face_embeddings() |
|
|
index_name = "portfolio" |
|
|
docsearch = PineconeVectorStore.from_existing_index( |
|
|
index_name=index_name, |
|
|
embedding=st.session_state.embeddings |
|
|
) |
|
|
st.session_state.retriever = docsearch.as_retriever( |
|
|
search_type="similarity", search_kwargs={"k": 3} |
|
|
) |
|
|
chatModel = EuronChatModel() |
|
|
prompt = ChatPromptTemplate.from_messages( |
|
|
[ |
|
|
("system", system_prompt), |
|
|
("human", "{input}"), |
|
|
] |
|
|
) |
|
|
question_answer_chain = create_stuff_documents_chain(chatModel, prompt) |
|
|
st.session_state.rag_chain = create_retrieval_chain( |
|
|
st.session_state.retriever, question_answer_chain |
|
|
) |
|
|
except Exception as e: |
|
|
st.error(f"Error initializing RAG: {str(e)}") |
|
|
st.stop() |
|
|
|
|
|
|
|
|
|
|
|
if menu == "About Me": |
|
|
st.write("Hey there π") |
|
|
st.title("π¨ I'm Shanin Hossain") |
|
|
st.markdown(""" |
|
|
I'm an AI Engineer & Research Assistant passionate about: |
|
|
- Machine Learning, Deep Learning, and Generative AI |
|
|
- Computer Vision & Natural Language Processing |
|
|
- Healthcare Informatics and Medical Imaging |
|
|
|
|
|
π I have worked on multiple AI projects, including OCR, Retrieval-Augmented Generation (RAG), and hybrid graph networks. |
|
|
""") |
|
|
st.success("π Navigate to **Chatbot** in the sidebar to chat with me!") |
|
|
st.header("My Projects", divider="gray") |
|
|
|
|
|
|
|
|
projects = [ |
|
|
{ |
|
|
"name": "Brain Glioma Grading System", |
|
|
"description": "Developed a hybrid graph neural network to grade glioma tumors from medical imaging data.", |
|
|
"tech_stack": ["PyTorch Geometric", "Graph Neural Networks", "Medical Imaging", "Python"] |
|
|
}, |
|
|
{ |
|
|
"name": "OCR Automation", |
|
|
"description": "Built an OCR pipeline for document image understanding and text extraction.", |
|
|
"tech_stack": ["YOLOv8", "OpenCV", "Tesseract OCR", "FastAPI"] |
|
|
}, |
|
|
{ |
|
|
"name": "Portfolio Chatbot", |
|
|
"description": "Created a RAG-powered chatbot integrated with Pinecone & custom embeddings for Q&A over portfolio data.", |
|
|
"tech_stack": ["Streamlit", "LangChain", "Pinecone", "Hugging Face"] |
|
|
}, |
|
|
] |
|
|
|
|
|
|
|
|
for project in projects: |
|
|
with st.container(): |
|
|
st.subheader(project["name"]) |
|
|
st.write(project["description"]) |
|
|
|
|
|
|
|
|
badges_html = " ".join([ |
|
|
f"<span class='badge'>{tech}</span>" for tech in project["tech_stack"] |
|
|
]) |
|
|
|
|
|
st.markdown( |
|
|
f"<div style=''>{badges_html}</div>", |
|
|
unsafe_allow_html=True |
|
|
) |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
|
|
|
st.markdown(""" |
|
|
<style> |
|
|
.badge { |
|
|
display: inline-block; |
|
|
padding: 6px 12px; |
|
|
font-size: 0.70rem; |
|
|
font-weight: 600; |
|
|
color: white; |
|
|
border-radius: 12px; |
|
|
} |
|
|
|
|
|
/* Randomized color palette */ |
|
|
.badge:nth-child(5n+1) { background-color: #2563EB; } /* Blue */ |
|
|
.badge:nth-child(5n+2) { background-color: #059669; } /* Green */ |
|
|
.badge:nth-child(5n+3) { background-color: #D97706; } /* Orange */ |
|
|
.badge:nth-child(5n+4) { background-color: #9333EA; } /* Purple */ |
|
|
.badge:nth-child(5n+5) { background-color: #DC2626; } /* Red */ |
|
|
</style> |
|
|
""", unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
st.header("Publications", divider="gray") |
|
|
|
|
|
|
|
|
publications = [ |
|
|
{ |
|
|
"title": "Automated Detection of Age-Related Macular Degeneration (AMD) Using Deep Learning", |
|
|
"venue": "Journal of Medical Imaging & Health Informatics, 2023", |
|
|
"description": "Published a deep learning-based pipeline to detect age-related macular degeneration from retinal images.", |
|
|
"link": "https://doi.org/xxxxxx" |
|
|
}, |
|
|
{ |
|
|
"title": "Using Hyperdimensional Computing to Extract Features for the Detection of Type 2 Diabetes", |
|
|
"venue": "Conference on Health Informatics, 2024 (Under Review)", |
|
|
"description": "Explored hyperdimensional computing techniques to improve detection of Type 2 Diabetes from clinical data.", |
|
|
"link": "" |
|
|
} |
|
|
] |
|
|
|
|
|
|
|
|
for pub in publications: |
|
|
with st.container(): |
|
|
st.subheader(pub["title"]) |
|
|
st.caption(pub["venue"]) |
|
|
st.write(pub["description"]) |
|
|
|
|
|
if pub["link"]: |
|
|
st.markdown(f"[π View Publication]({pub['link']})") |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif menu == "Chatbot": |
|
|
st.title("π€ Shanin Chatbot") |
|
|
st.write("Ask me anything about my portfolio!") |
|
|
|
|
|
|
|
|
for msg in st.session_state.messages: |
|
|
with st.chat_message(msg["role"]): |
|
|
st.write(msg["content"]) |
|
|
|
|
|
|
|
|
if prompt := st.chat_input("Type your question..."): |
|
|
|
|
|
st.session_state.messages.append({"role": "user", "content": prompt}) |
|
|
with st.chat_message("user"): |
|
|
st.write(prompt) |
|
|
|
|
|
|
|
|
if st.session_state.rag_chain is None: |
|
|
with st.spinner("Initializing RAG pipeline..."): |
|
|
initialize_rag() |
|
|
|
|
|
try: |
|
|
with st.spinner("Generating response..."): |
|
|
response = st.session_state.rag_chain.invoke({"input": prompt}) |
|
|
answer = response["answer"] |
|
|
|
|
|
|
|
|
st.session_state.messages.append({"role": "assistant", "content": answer}) |
|
|
with st.chat_message("assistant"): |
|
|
st.write(answer) |
|
|
|
|
|
except Exception as e: |
|
|
st.error(f"Error processing request: {str(e)}") |
|
|
|