import streamlit as st
import streamlit.components.v1 as components
import asyncio
import edge_tts
import os
import base64
import json
from datetime import datetime
from typing import Optional, Dict, List
import glob
# Configure page
st.set_page_config(
page_title="Research Assistant",
page_icon="🔬",
layout="wide",
initial_sidebar_state="expanded"
)
# Initialize session state
if 'current_query' not in st.session_state:
st.session_state.current_query = ''
if 'last_response' not in st.session_state:
st.session_state.last_response = ''
if 'audio_queue' not in st.session_state:
st.session_state.audio_queue = []
if 'mermaid_history' not in st.session_state:
st.session_state.mermaid_history = []
# Custom CSS
st.markdown("""
""", unsafe_allow_html=True)
def generate_mermaid_html(mermaid_code: str, height: int = 400) -> str:
"""Generate responsive Mermaid diagram HTML with click handling."""
return f"""
"""
async def generate_speech(text: str, voice: str = "en-US-AriaNeural") -> Optional[str]:
"""Generate speech using Edge TTS."""
if not text.strip():
return None
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"speech_{timestamp}.mp3"
communicate = edge_tts.Communicate(text, voice)
await communicate.save(output_file)
return output_file
def process_arxiv_search(query: str) -> Dict:
"""Process Arxiv search with your existing research code."""
# Integrate your Arxiv search code here
# This is a placeholder that simulates a response
return {
"title": "Sample Research Paper",
"abstract": "This is a sample abstract...",
"authors": ["Author 1", "Author 2"],
"url": "https://arxiv.org/abs/..."
}
def create_audio_player(file_path: str) -> str:
"""Create an HTML audio player with download button."""
with open(file_path, "rb") as audio_file:
audio_bytes = audio_file.read()
audio_b64 = base64.b64encode(audio_bytes).decode()
return f"""
"""
def handle_node_click(node_id: str):
"""Handle Mermaid diagram node clicks."""
# Convert node ID to search query
query = node_id.replace('_', ' ')
# Perform search
results = process_arxiv_search(query)
# Generate speech from results
asyncio.run(generate_speech(results['abstract']))
# Update session state
st.session_state.current_query = query
st.session_state.last_response = results
# Main Mermaid diagram definition
RESEARCH_DIAGRAM = """
graph TD
A[Literature Review] --> B[Data Analysis]
B --> C[Results]
C --> D[Conclusions]
click A callback "Research Methodology"
click B callback "Statistical Analysis"
click C callback "Research Findings"
click D callback "Research Impact"
style A fill:#f9f,stroke:#333,stroke-width:4px
style B fill:#bbf,stroke:#333,stroke-width:4px
style C fill:#bfb,stroke:#333,stroke-width:4px
style D fill:#fbb,stroke:#333,stroke-width:4px
"""
def main():
st.title("📚 Research Assistant")
# Sidebar configuration
st.sidebar.header("Configuration")
voice_option = st.sidebar.selectbox(
"Select Voice",
["en-US-AriaNeural", "en-US-GuyNeural", "en-GB-SoniaNeural"]
)
# Main layout
col1, col2 = st.columns([2, 3])
with col1:
st.subheader("Research Map")
components.html(
generate_mermaid_html(RESEARCH_DIAGRAM),
height=500,
scrolling=True
)
st.markdown("### Recent Searches")
for query in st.session_state.mermaid_history[-5:]:
st.info(query)
with col2:
st.subheader("Research Results")
# Manual search option
search_query = st.text_input("Enter search query:")
if st.button("Search"):
handle_node_click(search_query)
# Display current results
if st.session_state.last_response:
with st.container():
st.markdown("#### Latest Results")
st.json(st.session_state.last_response)
# Audio playback
audio_files = glob.glob("speech_*.mp3")
if audio_files:
latest_audio = max(audio_files, key=os.path.getctime)
st.markdown(create_audio_player(latest_audio), unsafe_allow_html=True)
# Cleanup old audio files
for file in glob.glob("speech_*.mp3")[:-5]: # Keep only last 5 files
try:
os.remove(file)
except:
pass
if __name__ == "__main__":
main()