import os import streamlit as st import PyPDF2 from langchain_community.llms import HuggingFaceHub # Streamlit page configuration st.set_page_config(page_title="Research Position Application Generator", page_icon="🔬") # Set Hugging Face API Key os.environ["HUGGINGFACEHUB_API_TOKEN"] = st.secrets["HF_TOKEN"] # Initialize LLM llm = HuggingFaceHub( repo_id="mistralai/Mistral-7B-Instruct-v0.3", model_kwargs={"temperature": 0.5} ) def extract_text_from_pdf(uploaded_file): """ Extract text from an uploaded PDF file. Args: uploaded_file (UploadedFile): PDF file uploaded by the user Returns: str: Extracted text from the PDF """ try: pdf_reader = PyPDF2.PdfReader(uploaded_file) text = "" for page in pdf_reader.pages: text += page.extract_text() return text except Exception as e: st.error(f"Error extracting PDF text: {e}") return "" def generate_cold_email(position_details, cv_text): """ Generate a professional cold email using the LLM. Args: position_details (dict): Details about the research position cv_text (str): Text extracted from the CV/resume Returns: str: Generated cold email """ prompt = f"""Write a professional and concise cold email to Professor {position_details['professor_name']} at {position_details['university']} about the research position in {position_details['research_focus']}. The email should: 1. Demonstrate knowledge of the professor's research 2. Highlight relevant experience from the CV 3. Express genuine interest in the position 4. Be no more than 250 words CV Details: {cv_text} Research Position Details: Research Focus: {position_details['research_focus']} Professor: {position_details['professor_name']} University: {position_details['university']} """ return llm.invoke(prompt) def generate_cover_letter(position_details, cv_text): """ Generate a formal cover letter using the LLM. Args: position_details (dict): Details about the research position cv_text (str): Text extracted from the CV/resume Returns: str: Generated cover letter """ prompt = f"""Write a professional and formal cover letter for a research position with the following details: Research Focus: {position_details['research_focus']} University: {position_details['university']} The cover letter should: 1. Follow a standard business letter format 2. Clearly state the purpose of the letter 3. Highlight relevant skills and experiences from the CV 4. Demonstrate alignment with the research position 5. Be 300-400 words long 6. Include a strong closing paragraph CV Details: {cv_text} """ return llm.invoke(prompt) def main(): """ Main Streamlit app function """ st.title("🔬 Research Position Application Generator") # Sidebar for position details st.sidebar.header("Research Position Details") professor_name = st.sidebar.text_input("Professor's Name") university = st.sidebar.text_input("University") research_focus = st.sidebar.text_input("Research Focus") # CV Upload st.sidebar.header("Upload CV/Resume") uploaded_cv = st.sidebar.file_uploader("Choose a PDF file", type="pdf") # Generate button if st.sidebar.button("Generate Documents"): # Validate inputs if not (professor_name and university and research_focus and uploaded_cv): st.error("Please fill in all details and upload a CV") return # Extract CV text cv_text = extract_text_from_pdf(uploaded_cv) # Prepare position details position_details = { 'professor_name': professor_name, 'university': university, 'research_focus': research_focus } # Generate documents with st.spinner('Generating documents...'): cold_email = generate_cold_email(position_details, cv_text) cover_letter = generate_cover_letter(position_details, cv_text) # Display results st.header("Generated Documents") # Cold Email st.subheader("Cold Email") st.write(cold_email) st.download_button( label="Download Cold Email", data=cold_email, file_name="cold_email.txt", mime="text/plain" ) # Cover Letter st.subheader("Cover Letter") st.write(cover_letter) st.download_button( label="Download Cover Letter", data=cover_letter, file_name="cover_letter.txt", mime="text/plain" ) if __name__ == "__main__": main()