Space-Biology-Knowledge-Engine / src /streamlit_app.py
KnownAsJohn's picture
offical
758fe21
Raw
History Blame Contribute Delete
12.6 kB
import streamlit as st
import pandas as pd
import plotly.express as px
# Page configuration MUST be the first Streamlit command
st.set_page_config(
page_title="πŸš€ NASA Bioscience Explorer",
page_icon="πŸš€",
layout="wide",
initial_sidebar_state="collapsed"
)
# Now import transformers and other libraries
try:
from transformers import pipeline
import trafilatura
import textwrap
TRANSFORMERS_AVAILABLE = True
except ImportError as e:
TRANSFORMERS_AVAILABLE = False
st.error(f"⚠️ Transformers library not available: {e}")
st.info("The app will work without summarization features.")
# Load the summarizer
def load_summarizer():
if not TRANSFORMERS_AVAILABLE:
return None
try:
return pipeline("summarization", model="facebook/bart-large-cnn", device=-1)
except Exception as e:
st.error(f"Error loading summarizer: {e}")
return None
# Cached summarization function
def summarize_entire_text(text):
summarizer = load_summarizer()
if summarizer is None:
return "Summarization not available. Please check the logs for errors."
# Limit input to 8000 characters
text = text[:8000] if len(text) > 8000 else text
# Split text into chunks of 4000 characters
chunk_size = 4000
chunks = [text[i:i + chunk_size] for i in range(0, len(text), chunk_size)]
# Summarize each chunk
summaries = []
for chunk in chunks:
if chunk.strip():
try:
result = summarizer(chunk, max_length=150, min_length=40, do_sample=False)
summaries.append(result[0]['summary_text'])
except Exception as e:
st.error(f"Error summarizing chunk: {e}")
continue
# Combine summaries if there are multiple chunks
if len(summaries) > 1:
combined_summary = " ".join(summaries)
try:
final_result = summarizer(combined_summary, max_length=250, min_length=100, do_sample=False)
return final_result[0]['summary_text']
except Exception as e:
st.error(f"Error in final summarization: {e}")
return " ".join(summaries)
elif len(summaries) == 1:
return summaries[0]
else:
return "No text to summarize."
# Load data
def load_data():
try:
df = pd.read_csv('./data/SB_publication_PMC.csv')
if df.empty:
return pd.DataFrame()
except Exception as e:
st.error(f"Error loading data: {str(e)}")
return pd.DataFrame()
# Simple categorization based on title keywords
def categorize_topic(title):
title_lower = title.lower()
if any(word in title_lower for word in ['bone', 'skeletal', 'oste']):
return 'Bone Health'
elif any(word in title_lower for word in ['muscle', 'atrophy']):
return 'Muscle Physiology'
elif any(word in title_lower for word in ['immune', 'infection', 'microbiome']):
return 'Immune System'
elif any(word in title_lower for word in ['plant', 'arabidopsis', 'root']):
return 'Plant Biology'
elif any(word in title_lower for word in ['radiation', 'dna', 'genomic']):
return 'Radiation Effects'
elif any(word in title_lower for word in ['microgravity', 'gravity']):
return 'Microgravity Adaptation'
else:
return 'Other'
def detect_organism(title):
title_lower = title.lower()
if 'mouse' in title_lower or 'mice' in title_lower:
return 'Mouse'
elif 'arabidopsis' in title_lower:
return 'Arabidopsis'
elif 'drosophila' in title_lower:
return 'Drosophila'
elif 'human' in title_lower or 'astronaut' in title_lower:
return 'Human'
elif 'rat' in title_lower:
return 'Rat'
else:
return 'Various'
df['topic'] = df['Title'].apply(categorize_topic)
df['organism'] = df['Title'].apply(detect_organism)
return df
# Function to summarize paper from URL
def summarize_paper(url):
if not TRANSFORMERS_AVAILABLE:
return "Summarization feature is not available."
try:
downloaded = trafilatura.fetch_url(url)
text = trafilatura.extract(downloaded) if downloaded else None
if text:
summary = summarize_entire_text(text)
return summary
else:
return None
except Exception as e:
st.error(f"Error summarizing paper: {str(e)}")
return None
# Simple summarizer function
def summarize_from_url(url):
if not TRANSFORMERS_AVAILABLE:
return "❌ Summarization feature is not available."
try:
downloaded = trafilatura.fetch_url(url)
text = trafilatura.extract(downloaded) if downloaded else None
if text:
summary = summarize_entire_text(text)
return summary
else:
return "❌ Failed to extract text from the URL."
except Exception as e:
return f"❌ Error: {str(e)}"
# Filter publications
def filter_publications(df, search_term, selected_topics, selected_organisms):
filtered_df = df.copy()
if selected_topics and len(selected_topics) > 0:
filtered_df = filtered_df[filtered_df['topic'].isin(selected_topics)]
if selected_organisms and len(selected_organisms) > 0:
filtered_df = filtered_df[filtered_df['organism'].isin(selected_organisms)]
if search_term and search_term.strip():
search_terms = search_term.lower().split()
search_mask = pd.Series(True, index=filtered_df.index)
for term in search_terms:
term_mask = (
filtered_df['Title'].str.lower().str.contains(term, na=False) |
filtered_df['topic'].str.lower().str.contains(term, na=False) |
filtered_df['organism'].str.lower().str.contains(term, na=False)
)
search_mask &= term_mask
filtered_df = filtered_df[search_mask]
return filtered_df
# Main app
def main():
st.title("πŸš€ NASA Bioscience Explorer")
st.markdown("Explore 608 NASA life sciences publications")
# Load data
df = load_data()
if df.empty:
st.error("Failed to load data. Please check if the data file exists.")
return
# Initialize session state for summaries
if 'summaries' not in st.session_state:
st.session_state.summaries = {}
# Create header section with filters
st.markdown("### πŸ” Search and Filter Publications")
# Create three columns for filters
search_col, topic_col, organism_col = st.columns([1, 1, 1])
with search_col:
search_term = st.text_input(
"Search publications:",
placeholder="Enter keywords..."
)
with topic_col:
topic_options = df['topic'].unique().tolist()
selected_topics = st.multiselect(
"Research Topics:",
options=topic_options,
default=[]
)
with organism_col:
organism_options = df['organism'].unique().tolist()
selected_organisms = st.multiselect(
"Organisms:",
options=organism_options,
default=[]
)
st.markdown("---")
# Filter data
filtered_df = filter_publications(df, search_term, selected_topics, selected_organisms)
# Metrics
col1, col2, col3, col4 = st.columns(4)
col1.metric("Total Publications", len(df))
col2.metric("Filtered Publications", len(filtered_df))
col3.metric("Research Topics", df['topic'].nunique())
col4.metric("Organisms Studied", df['organism'].nunique())
# Create tabs
tab1, tab2 = st.tabs(["πŸ“Š Research Dashboard", "πŸ“„ Paper Summarizer"])
with tab1:
if not filtered_df.empty:
col1, col2 = st.columns(2)
with col1:
topic_counts = filtered_df['topic'].value_counts()
topic_labels = [f"{topic} ({count})" for topic, count in topic_counts.items()]
fig1 = px.pie(
values=topic_counts.values,
names=topic_labels,
title="πŸ“ˆ Research Topics Distribution"
)
fig1.update_traces(textinfo='percent+label')
st.plotly_chart(fig1, use_container_width=True)
with col2:
organism_counts = filtered_df['organism'].value_counts().reset_index()
organism_counts.columns = ['Organism', 'Count']
organism_counts['Label'] = organism_counts.apply(lambda x: f"{x['Organism']} ({x['Count']})", axis=1)
fig2 = px.bar(
data_frame=organism_counts,
x='Label',
y='Count',
title="🧬 Publications by Organism"
)
fig2.update_xaxes(tickangle=45)
fig2.update_layout(xaxis_title="")
st.plotly_chart(fig2, use_container_width=True)
st.markdown("---")
st.subheader("πŸ“š Publication Browser")
if not filtered_df.empty:
for idx, row in filtered_df.iterrows():
with st.expander(f"**{row['Title']}**"):
st.write(f"**Topic:** {row['topic']}")
st.write(f"**Organism:** {row['organism']}")
st.markdown(f"[πŸ“„ Read Paper]({row['Link']})")
summary_key = f"summary_{idx}"
if summary_key not in st.session_state:
st.session_state[summary_key] = None
if TRANSFORMERS_AVAILABLE and st.button("πŸ” Generate Summary", key=f"btn_{idx}"):
with st.spinner("Generating summary..."):
summary = summarize_paper(row['Link'])
if summary:
st.session_state[summary_key] = summary
else:
st.error("❌ Failed to extract text from this paper.")
if st.session_state[summary_key]:
st.subheader("Summary")
st.write(st.session_state[summary_key])
else:
st.warning("πŸ” No publications match the current filters.")
st.markdown("---")
st.subheader("πŸ’‘ Research Insights")
col1, col2 = st.columns(2)
with col1:
st.markdown("### 🎯 Most Studied Areas")
top_topics = df['topic'].value_counts().head(3)
for topic, count in top_topics.items():
st.write(f"- **{topic}**: {count} publications")
with col2:
st.markdown("### πŸ”¬ Research Gaps")
gaps = [
"Limited long-duration human studies",
"Combined radiation + microgravity effects",
"Psychological health in space"
]
for gap in gaps:
st.write(f"- {gap}")
with tab2:
st.markdown("### πŸ“„ Research Paper Summarizer")
if not TRANSFORMERS_AVAILABLE:
st.warning("⚠️ Summarization feature is currently unavailable. Please check the logs.")
else:
st.markdown("Enter any scientific article URL to get an AI-generated summary")
url_input = st.text_input(
"Enter Article URL:",
value="https://pmc.ncbi.nlm.nih.gov/articles/PMC10772081/",
placeholder="https://pmc.ncbi.nlm.nih.gov/articles/...",
key="url_input"
)
col1, col2 = st.columns([1, 4])
with col1:
if st.button("πŸš€ Summarize Paper", type="primary"):
if url_input:
with st.spinner("πŸ” Generating summary..."):
summary = summarize_from_url(url_input)
if summary:
with col2:
st.info(summary)
else:
with col2:
st.warning("⚠️ Please enter a URL to summarize")
if __name__ == "__main__":
main()