Spaces:
Sleeping
Sleeping
| def enhancer_agent(profile_data, evaluation_feedback, target_role): | |
| import streamlit as st | |
| from groq import Groq | |
| import json | |
| from config import Config | |
| try: | |
| client = Groq(api_key=Config.GROQ_API_KEY) | |
| except Exception as e: | |
| st.error(f"❌ Groq API Configuration Error: {str(e)}") | |
| st.info("Please check your Groq API key configuration.") | |
| return | |
| if 'conversation_history' not in st.session_state: | |
| st.session_state['conversation_history'] = [] | |
| if 'selected_tab' not in st.session_state: | |
| st.session_state['selected_tab'] = "Profile Overview" | |
| profile_sections = [ | |
| "Headline", | |
| "Summary/About", | |
| "Experience", # Changed from "Current Position/Experience" to "Experience" | |
| "Education", | |
| "Skills", | |
| "Certifications", | |
| "Recommendations", | |
| ] | |
| def get_section_recommendation_and_explanation(section_name, current_content): | |
| if not current_content or current_content == '-': | |
| prompt = f""" | |
| You are an AI assistant helping a user improve their LinkedIn profile for the role of {target_role}. | |
| The user currently has no content in the {section_name} section. | |
| Provide guidance on how they can effectively add this section to enhance their profile. | |
| Guidelines: | |
| - Offer general advice on what to include in the {section_name} section. | |
| - Do not fabricate any data or metrics. | |
| - Encourage the user to reflect on their own experiences and qualifications. | |
| - Keep the recommendation professional and focused. | |
| Format: | |
| Recommendation: | |
| [Provide the recommendation here] | |
| Explanation: | |
| [Provide a brief explanation here] | |
| """ | |
| else: | |
| prompt = f""" | |
| You are an AI assistant helping a user improve their LinkedIn profile for the role of {target_role}. | |
| Focus on enhancing the user's existing content in the {section_name} section to make it more professional and eye-catching. | |
| Current content: | |
| {current_content} | |
| Guidelines: | |
| - Rewrite the existing content to improve clarity, professionalism, and impact. | |
| - Do not alter or add any factual information. | |
| - Focus on changing the tone and wording, not the facts. | |
| - Do not suggest adding new roles or experiences that the user hasn't had. | |
| - Tailor the improved content to align subtly with the target role, but prioritize enhancing the current content. | |
| - Do not mention internal strategies. | |
| - Do not fabricate any data or metrics. | |
| - Keep the recommendation professional and focused. | |
| Format: | |
| Recommendation: | |
| [Provide the improved content here] | |
| Explanation: | |
| [Provide a brief explanation here] | |
| """ | |
| try: | |
| chat_completion = client.chat.completions.create( | |
| messages=[ | |
| {'role': 'user', 'content': prompt} | |
| ], | |
| model="openai/gpt-oss-120b", | |
| stream=False, | |
| temperature=0.3 | |
| ) | |
| agent_response = chat_completion.choices[0].message.content.strip() | |
| # Clean markdown formatting from GPT-OSS response | |
| agent_response = agent_response.replace('**', '').replace('*', '') | |
| except Exception as e: | |
| st.error(f"❌ Groq API Error: {str(e)}") | |
| if "organization_restricted" in str(e): | |
| st.warning("🔑 Your Groq API key has been restricted. Please:") | |
| st.info("1. Check your Groq account at https://console.groq.com/\n2. Generate a new API key\n3. Update your .env file") | |
| return "Error generating recommendation", "Unable to generate recommendation due to API error" | |
| if "Recommendation:" in agent_response and "Explanation:" in agent_response: | |
| recommendation_part = agent_response.split("Recommendation:")[1] | |
| recommendation = recommendation_part.split("Explanation:")[0].strip() | |
| explanation = recommendation_part.split("Explanation:")[1].strip() | |
| else: | |
| recommendation = agent_response | |
| explanation = "No explanation provided." | |
| return recommendation, explanation | |
| def parse_profile_data(profile_data): | |
| person = profile_data.get('person', {}) | |
| positions_data = person.get('positions', {}) | |
| certifications_data = person.get('certifications', {}) | |
| skills_data = person.get('skills', []) | |
| educations_data = person.get('schools', {}) | |
| recommendations_data = person.get('recommendations', {}) | |
| if isinstance(skills_data, list): | |
| skills_list = skills_data if skills_data else ['-'] | |
| else: | |
| skills_list = ['-'] | |
| if isinstance(positions_data, dict): | |
| positions_list = positions_data.get('positionHistory', []) | |
| else: | |
| positions_list = [] | |
| # Get ALL positions, not just current one | |
| all_positions = positions_list if positions_list else ['-'] | |
| if isinstance(certifications_data, dict): | |
| certifications_list = certifications_data.get('certificationHistory', []) | |
| certifications_list = [ | |
| cert.get('name', '-') for cert in certifications_list if isinstance(cert, dict) | |
| ] | |
| else: | |
| certifications_list = ['-'] | |
| if isinstance(educations_data, dict): | |
| educations_list = educations_data.get('educationHistory', []) | |
| # Get ALL education entries, not just the first one | |
| all_education = educations_list if educations_list else ['-'] | |
| else: | |
| all_education = ['-'] | |
| if isinstance(recommendations_data, dict): | |
| recommendations_count = recommendations_data.get('recommendationsCount', 0) | |
| else: | |
| recommendations_count = 0 | |
| summary = person.get('summary', '-') or '-' | |
| parsed_data = { | |
| 'Headline': person.get('headline', '-') or '-', | |
| 'Summary/About': summary, | |
| 'Experience': all_positions, # Changed from current_position to all_positions | |
| 'Education': all_education, # Changed from single education to all_education | |
| 'Skills': skills_list, | |
| 'Certifications': certifications_list, | |
| 'Recommendations': recommendations_count, | |
| } | |
| return parsed_data | |
| def identify_missing_elements(parsed_data): | |
| missing_elements = [] | |
| for key in profile_sections: | |
| value = parsed_data.get(key) | |
| if not value or value == '-' or (isinstance(value, list) and all(v == '-' for v in value)): | |
| missing_elements.append(key) | |
| return missing_elements | |
| parsed_profile = parse_profile_data(profile_data) | |
| missing_elements = identify_missing_elements(parsed_profile) | |
| st.title("LinkedIn Profile Enhancement Agent") | |
| st.markdown("Enhance your LinkedIn profile to stand out for the role of **{}**.".format(target_role)) | |
| tab_names = ["Profile Overview", "Profile Evaluation", "Recommendations", "Chat with Agent"] | |
| selected_tab = st.radio("Navigate to", tab_names, index=tab_names.index(st.session_state['selected_tab']), key='tabs') | |
| st.session_state['selected_tab'] = selected_tab | |
| if selected_tab == "Profile Overview": | |
| st.header("Profile Overview") | |
| st.markdown("Review your current LinkedIn profile sections.") | |
| for key in profile_sections: | |
| value = parsed_profile.get(key, '-') | |
| st.markdown(f"### {key}") # Underlined heading | |
| if not value or value == '-' or (isinstance(value, list) and not any(value)): | |
| st.markdown("_This section is currently missing or incomplete._") | |
| else: | |
| if key == "Experience" and isinstance(value, list) and value != ['-']: | |
| # Display all experience entries | |
| for i, position in enumerate(value): | |
| st.markdown(f"### Experience {i+1}") | |
| start_end_date = position.get('startEndDate', {}) | |
| start_date = start_end_date.get('start') | |
| end_date = start_end_date.get('end') | |
| if isinstance(start_date, dict): | |
| start_month = start_date.get('month', '-') | |
| start_year = start_date.get('year', '-') | |
| else: | |
| start_month = '-' | |
| start_year = '-' | |
| if isinstance(end_date, dict): | |
| end_month = end_date.get('month', '-') | |
| end_year = end_date.get('year', '-') | |
| else: | |
| end_month = 'Present' | |
| end_year = '' | |
| duration = f"{start_month}/{start_year} - {end_month}/{end_year}".strip() | |
| if duration == "-/- - Present/": | |
| duration = "Present" | |
| position_details = f"**Title:** {position.get('title', '-')}\n\n" \ | |
| f"**Company Name:** {position.get('companyName', '-')}\n\n" \ | |
| f"**Duration:** {duration}\n\n" \ | |
| f"**Description:**\n{position.get('description', '-')}" | |
| st.markdown(position_details) | |
| st.markdown("---") # Separator between experiences | |
| elif key == "Education" and isinstance(value, list) and value != ['-']: | |
| # Display all education entries | |
| for i, education in enumerate(value): | |
| st.markdown(f"### Education {i+1}") | |
| start_end_date = education.get('startEndDate', {}) | |
| start_date = start_end_date.get('start') | |
| end_date = start_end_date.get('end') | |
| if isinstance(start_date, dict): | |
| start_year = start_date.get('year', '-') | |
| else: | |
| start_year = '-' | |
| if isinstance(end_date, dict): | |
| end_year = end_date.get('year', '-') | |
| else: | |
| end_year = '-' | |
| duration = f"{start_year} - {end_year}".strip() | |
| education_details = f"**School Name:** {education.get('schoolName', '-')}\n\n" \ | |
| f"**Degree Name:** {education.get('degreeName', '-')}\n\n" \ | |
| f"**Field of Study:** {education.get('fieldOfStudy', '-')}\n\n" \ | |
| f"**Duration:** {duration}" | |
| st.markdown(education_details) | |
| st.markdown("---") # Separator between education entries | |
| elif key == "Skills" and isinstance(value, list): | |
| st.markdown("\n".join([f"- {skill}" for skill in value])) | |
| elif isinstance(value, list): | |
| st.markdown(", ".join(value)) | |
| elif isinstance(value, int): | |
| st.markdown(f"**{value} Recommendations**") | |
| else: | |
| st.markdown(value) | |
| elif selected_tab == "Profile Evaluation": | |
| st.header("Profile Evaluation") | |
| st.markdown("Here are some suggestions to improve your LinkedIn profile.") | |
| def enhance_evaluation_feedback(evaluation_feedback): | |
| prompt = f""" | |
| You are an AI assistant helping a user by improving the following evaluation feedback to make it more user-friendly and actionable. | |
| Original Evaluation Feedback: | |
| {evaluation_feedback} | |
| Guidelines: | |
| - Rephrase the feedback to be clear and helpful. | |
| - Provide actionable suggestions for improvement. | |
| - Use a friendly and encouraging tone. | |
| - Do not mention internal processes. | |
| - Do not include any disallowed content. | |
| Enhanced Evaluation Feedback: | |
| """ | |
| try: | |
| chat_completion = client.chat.completions.create( | |
| messages=[ | |
| {'role': 'user', 'content': prompt} | |
| ], | |
| model="openai/gpt-oss-120b", | |
| stream=False, | |
| temperature=0.3 | |
| ) | |
| enhanced_feedback = chat_completion.choices[0].message.content.strip() | |
| # Clean markdown formatting from GPT-OSS response | |
| enhanced_feedback = enhanced_feedback.replace('**', '').replace('*', '') | |
| return enhanced_feedback | |
| except Exception as e: | |
| st.error(f"❌ Groq API Error: {str(e)}") | |
| if "organization_restricted" in str(e): | |
| st.warning("🔑 Your Groq API key has been restricted. Please:") | |
| st.info("1. Check your Groq account at https://console.groq.com/\n2. Generate a new API key\n3. Update your .env file") | |
| return evaluation_feedback # Return original feedback if enhancement fails | |
| enhanced_evaluation = enhance_evaluation_feedback(evaluation_feedback) | |
| st.markdown(enhanced_evaluation) | |
| st.subheader("Missing Profile Sections") | |
| if missing_elements: | |
| st.markdown("Adding the following sections can greatly enhance your profile:") | |
| for element in missing_elements: | |
| st.markdown(f"- **{element}**") | |
| else: | |
| st.markdown("Great job! Your profile has all the key sections filled out.") | |
| elif selected_tab == "Recommendations": | |
| st.header("Personalized Recommendations") | |
| st.markdown(f"Enhance your profile sections to align with the role of **{target_role}**.") | |
| for key in profile_sections: | |
| current_content = parsed_profile.get(key, '-') | |
| if key == "Experience" and isinstance(current_content, list) and current_content != ['-']: | |
| # Handle multiple experience entries | |
| experience_strs = [] | |
| for position in current_content: | |
| experience_strs.append(f"Title: {position.get('title', '-')}\nCompany Name: {position.get('companyName', '-')}\nDescription: {position.get('description', '-')}") | |
| current_content_str = "\n\n".join(experience_strs) | |
| recommendation, explanation = get_section_recommendation_and_explanation(key, current_content_str) | |
| elif isinstance(current_content, list) and current_content != ['-']: | |
| current_content_str = ", ".join(current_content) | |
| recommendation, explanation = get_section_recommendation_and_explanation(key, current_content_str) | |
| elif current_content != '-' and current_content: | |
| recommendation, explanation = get_section_recommendation_and_explanation(key, current_content) | |
| else: | |
| recommendation, explanation = get_section_recommendation_and_explanation(key, '') | |
| with st.expander(f"{key} Recommendation", expanded=False): | |
| st.subheader("Recommendation") | |
| st.code(recommendation, language=None) | |
| st.subheader("Explanation") | |
| st.write(explanation) | |
| elif selected_tab == "Chat with Agent": | |
| st.header("Chat with Enhancement Agent") | |
| st.markdown("Interact with the agent to personalize your profile further or provide additional details.") | |
| def display_conversation(): | |
| for message in st.session_state['conversation_history']: | |
| if message['role'] == 'user': | |
| st.markdown(f""" | |
| <div style='text-align: left; margin: 10px 0;'> | |
| <div style='display: inline-block; padding: 10px; border-radius: 10px; background-color: #000000;'> | |
| <strong>You:</strong> {message['content']} | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| elif message['role'] == 'assistant': | |
| st.markdown(f""" | |
| <div style='text-align: left; margin: 10px 0;'> | |
| <div style='display: inline-block; padding: 10px; border-radius: 10px; background-color: #000000;'> | |
| <strong>Agent:</strong> {message['content']} | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| display_conversation() | |
| with st.form(key='chat_form', clear_on_submit=True): | |
| user_input = st.text_input("Type your message here...") | |
| submit_button = st.form_submit_button(label='Send') | |
| if submit_button: | |
| if user_input: | |
| st.session_state['conversation_history'].append({'role': 'user', 'content': user_input}) | |
| messages = st.session_state['conversation_history'].copy() | |
| profile_context = "" | |
| for key, value in parsed_profile.items(): | |
| if value != '-' and value: | |
| if key == "Experience" and isinstance(value, list) and value != ['-']: | |
| experience_details = [] | |
| for position in value: | |
| position_detail = f"Title: {position.get('title', '-')}\n" \ | |
| f"Company Name: {position.get('companyName', '-')}\n" \ | |
| f"Description: {position.get('description', '-')}" | |
| experience_details.append(position_detail) | |
| profile_context += f"\n{key}:\n" + "\n\n".join(experience_details) | |
| elif isinstance(value, list): | |
| profile_context += f"\n{key}:\n{', '.join(value)}" | |
| elif isinstance(value, int): | |
| profile_context += f"\n{key}:\n{value}" | |
| else: | |
| profile_context += f"\n{key}:\n{value}" | |
| system_prompt = f""" | |
| You are an AI assistant helping a user improve their LinkedIn profile for the role of {target_role}. | |
| Provide concise and actionable advice based on the user's messages. | |
| Avoid providing lists or unnecessary details. | |
| Offer explanations only if needed, and keep them brief. | |
| Do not mention internal strategies or methodologies. | |
| User's current profile data: | |
| {profile_context} | |
| """ | |
| messages.insert(0, {'role': 'system', 'content': system_prompt}) | |
| chat_completion = client.chat.completions.create( | |
| messages=messages, | |
| model="openai/gpt-oss-120b", | |
| stream=False, | |
| temperature=0.3 | |
| ) | |
| agent_response = chat_completion.choices[0].message.content.strip() | |
| # Clean markdown formatting from GPT-OSS response | |
| agent_response = agent_response.replace('**', '').replace('*', '') | |
| st.session_state['conversation_history'].append({'role': 'assistant', 'content': agent_response}) | |
| display_conversation() |