from openai import OpenAI, RateLimitError import streamlit as st import time import os import re from typing import Dict, Optional from datetime import datetime # Page configuration (moved to top to ensure it's called only once) st.set_page_config( page_title="LinkedIn Recommendation Generator", page_icon="👔", layout="wide", initial_sidebar_state="collapsed" ) # Original app CSS st.markdown(""" """, unsafe_allow_html=True) def create_star_rating(label, key, help_text=None): """Create a custom 5-star rating component""" with st.container(): st.markdown('
', unsafe_allow_html=True) col1, col2 = st.columns([3, 2]) with col1: st.markdown(f'
{label}
', unsafe_allow_html=True) if help_text: st.caption(help_text) with col2: pass rating = st.select_slider( "", options=[1, 2, 3, 4, 5], value=3, key=key, label_visibility="collapsed" ) stars = "".join(["⭐" if i < rating else "☆" for i in range(5)]) st.markdown(f"
{stars}
", unsafe_allow_html=True) return rating def generate_recommendation(ratings: Dict[str, int], employee_type: str, employee_name: str, relationship: str, time_worked: str, linkedin_url: str) -> Optional[str]: """Generate recommendation using OpenRouter API with input summary""" performance_areas = { "Technical Competence": { "Domain Knowledge": ratings['domain'], "Problem Solving": ratings['problem_solving'], "Initiative": ratings['initiative'] }, "Professional Skills": { "Adaptability": ratings['adaptability'], "Communication": ratings['communication'] }, "Interpersonal Impact": { "Team Collaboration": ratings['teamwork'], "Support & Guidance": ratings['support'] }, "Overall Performance": { "Reliability": ratings['reliability'], "Overall Contribution": ratings['overall'], "Growth Potential": ratings['potential'] } } category_scores = {} for category, metrics in performance_areas.items(): category_scores[category] = sum(metrics.values()) / len(metrics) strengths = [k for k, v in ratings.items() if v >= 4] analysis_text = "" for category, score in category_scores.items(): analysis_text += f"\n- {category}: {score:.1f}/5" recommendation_prompt = f""" You are an expert in writing professional LinkedIn recommendations. Your task is to generate a recommendation for {employee_name}. First, silently analyze the provided performance data. Do not output this analysis. - Employee: {employee_name} - Role: {employee_type} - My Relationship to them: {relationship} - Duration we worked together: {time_worked} - Performance Summary by Category:{analysis_text} - Employee's LinkedIn Profile (for context, do not mention the URL in the output): {linkedin_url or 'Not provided'} - Key Strengths (rated 4 or 5): {', '.join(strengths) if strengths else 'None specified'} Now, using that analysis, write a detailed and comprehensive LinkedIn recommendation of 200-250 words. The recommendation must: - Be complete, with no abrupt endings or incomplete sentences. - Be professional, warm, and authentic in tone. - Be free of grammatical errors, spelling mistakes, or awkward phrasing. - End with a strong, forward-looking statement about the employee's potential. Instructions for the recommendation: 1. Start by clearly stating the working relationship ({relationship}) and the duration ({time_worked}). 2. Highlight their role as a {employee_type} and their key responsibilities. 3. Weave their key strengths ({', '.join(strengths) if strengths else 'None specified'}) into a brief narrative or specific example that illustrates their positive impact (e.g., how their 'Problem Solving' skills unblocked a project or how their 'Team Collaboration' improved team morale). 4. Conclude with a clear, confident statement about their future potential and value to any organization. 5. Use vivid, descriptive language to make the recommendation personal and human. 6. Ensure the recommendation is a complete text, ending with a full sentence and a period, and meets the 200-250 word requirement. """ try: client_kwargs = { "base_url": "https://openrouter.ai/api/v1", "api_key": os.environ.get('OPENROUTER_API_KEY') } try: client = OpenAI(**client_kwargs) except TypeError as e: if "proxies" in str(e) or "unexpected keyword argument" in str(e): import openai openai.api_key = os.environ.get('OPENROUTER_API_KEY') openai.base_url = "https://openrouter.ai/api/v1" client = openai else: raise e try: final_response = client.chat.completions.create( model="openai/gpt-3.5-turbo", messages=[ {"role": "system", "content": "You are an expert in writing professional, warm, and authentic LinkedIn recommendations. Ensure the output is complete, polished, and free of errors."}, {"role": "user", "content": recommendation_prompt} ], max_tokens=400, # Increased to accommodate 200-250 words temperature=0.75 ) return final_response.choices[0].message.content.strip() except AttributeError: final_response = client.ChatCompletion.create( model="openai/gpt-3.5-turbo", messages=[ {"role": "system", "content": "You are an expert in writing professional, warm, and authentic LinkedIn recommendations. Ensure the output is complete, polished, and free of errors."}, {"role": "user", "content": recommendation_prompt} ], max_tokens=400, # Increased to accommodate 200-250 words temperature=0.75 ) return final_response['choices'][0]['message']['content'].strip() except RateLimitError: st.error("API rate limit or quota exceeded. Please check your OpenRouter account and billing details.") return None except Exception as e: st.error(f"An error occurred while generating the recommendation: {str(e)}") st.error(f"Error details: {type(e).__name__}") return None def render_header(): """Renders the main header of the application.""" st.markdown("""

LinkedIn Recommendation Generator

Build impactful recommendations for LinkedIn - Made By github.com/ninjacode911

""", unsafe_allow_html=True) def render_input_form() -> Dict: """Renders the input form and returns a dictionary of user inputs.""" st.markdown('

📋 Basic Information

', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: employee_name = st.text_input( "Employee Name", key="employee_name", placeholder="e.g., John Smith" ) relationship = st.selectbox( "Your relationship with this person", ["", "Direct Manager", "Senior Manager", "Team Lead", "Colleague", "Project Manager", "Department Head", "HR Manager"], key="relationship" ) with col2: employee_type = st.selectbox( "Employee Role/Department", ["", "Software Developer", "AI Engineer", "Marketing Specialist", "Sales Representative", "Project Manager", "Data Analyst", "UI/UX Designer", "Customer Support", "Business Analyst", "Product Manager", "DevOps Engineer", "Content Creator", "HR Specialist", "Other"], key="employee_type" ) time_worked = st.selectbox( "How long have you worked together?", ["", "Less than 6 months", "6 months - 1 year", "1-2 years", "2-3 years", "3-5 years", "More than 5 years"], key="time_worked" ) linkedin_url = st.text_input( "Enter LinkedIn Profile URL", key="linkedin_url", placeholder="e.g., https://www.linkedin.com/in/username" ) st.markdown('

⭐ Performance Evaluation

', unsafe_allow_html=True) st.markdown("*Rate each aspect on a scale of 1-5 stars*") ratings = {} st.markdown("
Core Competencies
", unsafe_allow_html=True) ratings['domain'] = create_star_rating( "How would you rate the employee's knowledge and expertise in their specific field or role?", "domain" ) ratings['problem_solving'] = create_star_rating( "How effectively does the employee address challenges and find solutions?", "problem_solving" ) ratings['initiative'] = create_star_rating( "How proactive is the employee in taking initiative and contributing to company objectives?", "initiative" ) st.markdown("
Professional Skills
", unsafe_allow_html=True) ratings['adaptability'] = create_star_rating( "How well does the employee handle change or take on new responsibilities?", "adaptability" ) ratings['communication'] = create_star_rating( "How clearly and professionally does the employee communicate ideas or information?", "communication" ) st.markdown("
Interpersonal Skills
", unsafe_allow_html=True) ratings['teamwork'] = create_star_rating( "How well does the employee work with colleagues or teams to achieve goals?", "teamwork" ) ratings['support'] = create_star_rating( "How well does the employee support or guide others in the work environment?", "support" ) st.markdown("
Performance & Potential
", unsafe_allow_html=True) ratings['reliability'] = create_star_rating( "How consistently does the employee demonstrate dedication and reliability?", "reliability" ) ratings['overall'] = create_star_rating( "How would you rate the employee's overall contribution to their role and the team?", "overall" ) ratings['potential'] = create_star_rating( "How would you rate the employee's potential for further growth or advancement within the organization?", "potential" ) return { "employee_name": employee_name, "relationship": relationship, "employee_type": employee_type, "time_worked": time_worked, "linkedin_url": linkedin_url, "ratings": ratings } def render_results_section(ratings: Dict[str, int]): """Renders the recommendation, action buttons, and analytics.""" if st.session_state.recommendation_generated: st.markdown(f"""

📝 Your LinkedIn Recommendation

{st.session_state.generated_text}
""", unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: if st.button("📋 Show Text for Copying"): st.code(st.session_state.generated_text, language="text") st.info("You can now manually copy the text above.") with col2: if st.button("🔄 Generate New Version"): st.session_state.recommendation_generated = False st.rerun() if st.session_state.saved_linkedin_url: st.markdown(f"""
Click on the Employee's LinkedIn Profile: {st.session_state.saved_linkedin_url}
""", unsafe_allow_html=True) st.markdown("""

📖 How to Post on LinkedIn

  1. Copy the recommendation text above
  2. Click on the person's LinkedIn profile
  3. Click "More" → "Recommend"
  4. Paste the generated recommendation
  5. Review and send!
""", unsafe_allow_html=True) st.markdown('

📊 Rating Summary

', unsafe_allow_html=True) col1, col2, col3, col4 = st.columns(4) avg_rating = sum(ratings.values()) / len(ratings) highest_rating = max(ratings.values()) lowest_rating = min(ratings.values()) with col1: st.metric("Average Rating", f"{avg_rating:.1f}/5", f"{avg_rating/5*100:.0f}%") with col2: st.metric("Highest Rating", f"{highest_rating}/5") with col3: st.metric("Lowest Rating", f"{lowest_rating}/5") with col4: st.metric("Word Count", len(st.session_state.generated_text.split())) def main(): """Main function to run the Streamlit application.""" # Check for API key api_key = os.environ.get('OPENROUTER_API_KEY') if not api_key: try: if hasattr(st, 'secrets') and 'OPENROUTER_API_KEY' in st.secrets: api_key = st.secrets['OPENROUTER_API_KEY'] os.environ['OPENROUTER_API_KEY'] = api_key except Exception: pass if not api_key: st.error("🔑 OpenRouter API key not found. Please add it to your Hugging Face Space secrets in the 'Settings' tab.") st.info("Debug: Check that your OPENROUTER_API_KEY is properly set in the Hugging Face Space settings under 'Repository secrets'.") st.stop() render_header() # Initialize session state if 'recommendation_generated' not in st.session_state: st.session_state.recommendation_generated = False if 'generated_text' not in st.session_state: st.session_state.generated_text = "" if 'saved_linkedin_url' not in st.session_state: st.session_state.saved_linkedin_url = "" form_data = render_input_form() col1, col2, col3 = st.columns([1, 2, 1]) with col2: if st.button("🚀 Generate LinkedIn Recommendation", type="primary"): required_fields = ["employee_name", "employee_type", "relationship", "time_worked"] if not all(form_data[field] for field in required_fields): st.error("Please fill in all required fields in the 'Basic Information' section.") else: with st.spinner("🤖 Analyzing performance data and crafting your recommendation..."): progress_bar = st.progress(0, text="Analyzing...") time.sleep(0.5) progress_bar.progress(50, text="Generating text...") recommendation = generate_recommendation(**form_data) # Validate recommendation if recommendation: word_count = len(recommendation.split()) # Check if recommendation is within 150-300 words and ends with a period if word_count < 150 or not recommendation.strip().endswith('.'): st.error("The generated recommendation is incomplete or too short. Please try again.") st.session_state.recommendation_generated = False progress_bar.empty() time.sleep(0.5) st.rerun() else: st.session_state.recommendation_generated = True st.session_state.generated_text = recommendation st.session_state.saved_linkedin_url = form_data["linkedin_url"] st.success("✅ Recommendation generated successfully!") progress_bar.progress(100, text="Done!") time.sleep(0.5) progress_bar.empty() st.rerun() else: progress_bar.empty() render_results_section(form_data["ratings"]) if __name__ == "__main__": main()