Spaces:
No application file
No application file
| #!/usr/bin/env python3 | |
| """ | |
| Enhanced Interview Guide Generator - InterviewGuideGPT Format | |
| Generates polished, role-specific interview guides following exact structure requirements | |
| """ | |
| import re | |
| import json | |
| from typing import Dict, List, Any | |
| from dataclasses import dataclass | |
| class GuideData: | |
| """Structured data for interview guide generation""" | |
| role_title: str | |
| company: str | |
| match_score: float | |
| user_overview: str | |
| user_skills: List[str] | |
| role_skills: List[str] | |
| team_context: str | |
| interview_rounds: int | |
| process_notes: List[str] | |
| key_projects: List[str] = None | |
| candidate_strengths: List[str] = None | |
| skill_gaps: List[str] = None | |
| class InterviewGuideGPT: | |
| """Elite career-coach AI for generating polished interview guides""" | |
| def __init__(self): | |
| self.tech_skills = [ | |
| "Python", "JavaScript", "Java", "SQL", "React", "Node.js", | |
| "AWS", "Docker", "Git", "Machine Learning", "Data Science", | |
| "Analytics", "R", "Tableau", "Pandas", "NumPy", "TensorFlow", | |
| "Kubernetes", "MongoDB", "PostgreSQL", "Redis", "Apache Spark", | |
| "Scala", "Hadoop", "Spark", "Kafka", "Elasticsearch" | |
| ] | |
| self.company_insights = { | |
| "spotify": "Spotify prizes data-driven creativity in music.", | |
| "google": "Google values innovation and technical excellence at scale.", | |
| "amazon": "Amazon focuses on customer obsession and operational excellence.", | |
| "microsoft": "Microsoft emphasizes collaboration and empowering others.", | |
| "meta": "Meta drives connection and community through technology.", | |
| "apple": "Apple pursues perfection in user experience and design.", | |
| "netflix": "Netflix champions freedom, responsibility, and context over control." | |
| } | |
| def analyze_resume_and_job(self, resume_text: str, job_text: str) -> GuideData: | |
| """Analyze resume and job to extract structured data""" | |
| # Extract user data | |
| user_skills = self._extract_skills(resume_text) | |
| user_overview = self._extract_user_overview(resume_text) | |
| # Extract job data | |
| role_title, company = self._extract_role_and_company(job_text) | |
| role_skills = self._extract_skills(job_text) | |
| team_context = self._extract_team_context(job_text) | |
| # Calculate match score | |
| match_score = self._calculate_match_score(user_skills, role_skills, resume_text, job_text) | |
| # Generate process info | |
| interview_rounds = self._estimate_interview_rounds(company, role_title) | |
| process_notes = self._generate_process_notes(company, role_title) | |
| # Extract additional data | |
| key_projects = self._extract_key_projects(resume_text) | |
| candidate_strengths = self._extract_strengths(resume_text, user_skills) | |
| skill_gaps = list(set(role_skills) - set(user_skills)) | |
| return GuideData( | |
| role_title=role_title, | |
| company=company, | |
| match_score=match_score, | |
| user_overview=user_overview, | |
| user_skills=user_skills, | |
| role_skills=role_skills, | |
| team_context=team_context, | |
| interview_rounds=interview_rounds, | |
| process_notes=process_notes, | |
| key_projects=key_projects, | |
| candidate_strengths=candidate_strengths, | |
| skill_gaps=skill_gaps | |
| ) | |
| def _extract_skills(self, text: str) -> List[str]: | |
| """Extract technical skills from text""" | |
| skills = [] | |
| text_lower = text.lower() | |
| for skill in self.tech_skills: | |
| if skill.lower() in text_lower: | |
| skills.append(skill) | |
| # Add soft skills | |
| soft_skills = ["Leadership", "Communication", "Project Management", "Team Work", "Problem Solving"] | |
| for skill in soft_skills: | |
| if skill.lower() in text_lower or any(word in text_lower for word in skill.lower().split()): | |
| skills.append(skill) | |
| return list(set(skills)) | |
| def _extract_user_overview(self, resume_text: str) -> str: | |
| """Extract user overview from resume""" | |
| # Look for experience years | |
| experience_match = re.search(r'(\d+)[\s\+]*years?\s+(?:of\s+)?experience', resume_text, re.IGNORECASE) | |
| years = experience_match.group(1) if experience_match else "several" | |
| # Look for degree/education | |
| education_patterns = [ | |
| r'(bachelor|master|phd|doctorate|degree)', | |
| r'(computer science|data science|engineering|mathematics|statistics)' | |
| ] | |
| education = "degree" | |
| for pattern in education_patterns: | |
| match = re.search(pattern, resume_text, re.IGNORECASE) | |
| if match: | |
| education = match.group(1) | |
| break | |
| return f"Professional with {years} years of experience and {education} background" | |
| def _extract_role_and_company(self, job_text: str) -> tuple: | |
| """Extract role title and company from job text""" | |
| # Extract company | |
| company_patterns = [ | |
| r'at\s+([A-Z][a-zA-Z\s&\.]+?)(?:\s|$|,|\n)', | |
| r'([A-Z][a-zA-Z\s&\.]+?)\s+is\s+(?:hiring|looking)', | |
| r'join\s+([A-Z][a-zA-Z\s&\.]+?)(?:\s|$|,|\n)', | |
| ] | |
| company = "Company" | |
| for pattern in company_patterns: | |
| match = re.search(pattern, job_text, re.IGNORECASE) | |
| if match: | |
| company = match.group(1).strip() | |
| break | |
| # Extract role | |
| role_patterns = [ | |
| r'(senior\s+)?(data\s+scientist|software\s+engineer|product\s+manager|analyst|developer)', | |
| r'position[:\s]+(senior\s+)?([a-zA-Z\s]+)', | |
| r'role[:\s]+(senior\s+)?([a-zA-Z\s]+)', | |
| ] | |
| role = "Role" | |
| for pattern in role_patterns: | |
| match = re.search(pattern, job_text, re.IGNORECASE) | |
| if match: | |
| groups = match.groups() | |
| if len(groups) >= 2: | |
| senior_part = groups[0] or "" | |
| role_part = groups[1] or groups[-1] | |
| role = (senior_part + role_part).strip().title() | |
| break | |
| return role, company | |
| def _extract_team_context(self, job_text: str) -> str: | |
| """Extract team context from job description""" | |
| context_keywords = [ | |
| "team", "collaborate", "cross-functional", "stakeholder", | |
| "partner", "work with", "engineering", "product", "data" | |
| ] | |
| sentences = job_text.split('.') | |
| for sentence in sentences: | |
| if any(keyword in sentence.lower() for keyword in context_keywords): | |
| return sentence.strip() | |
| return "Collaborative team environment focused on innovation and results" | |
| def _calculate_match_score(self, user_skills: List[str], role_skills: List[str], resume_text: str, job_text: str) -> float: | |
| """Calculate match score between user and role""" | |
| if not role_skills: | |
| return 0.75 | |
| # Skill overlap | |
| skill_overlap = len(set(user_skills) & set(role_skills)) | |
| skill_score = skill_overlap / len(role_skills) if role_skills else 0.5 | |
| # Experience factor | |
| experience_match = re.search(r'(\d+)[\s\+]*years?\s+(?:of\s+)?experience', resume_text, re.IGNORECASE) | |
| experience_years = int(experience_match.group(1)) if experience_match else 3 | |
| experience_score = min(experience_years * 0.15, 1.0) | |
| # Education factor | |
| education_score = 0.2 if any(word in resume_text.lower() for word in ['degree', 'bachelor', 'master']) else 0.1 | |
| # Role relevance | |
| role_keywords = ['engineer', 'scientist', 'analyst', 'manager', 'developer'] | |
| role_relevance = 0.2 if any(keyword in resume_text.lower() for keyword in role_keywords) else 0.1 | |
| final_score = (skill_score * 0.5 + experience_score * 0.3 + education_score * 0.1 + role_relevance * 0.1) | |
| return min(max(final_score, 0.4), 0.97) | |
| def _estimate_interview_rounds(self, company: str, role: str) -> int: | |
| """Estimate number of interview rounds""" | |
| if any(term in company.lower() for term in ['startup', 'small']): | |
| return 3 | |
| elif any(term in company.lower() for term in ['google', 'amazon', 'microsoft', 'apple', 'meta']): | |
| return 5 | |
| else: | |
| return 4 | |
| def _generate_process_notes(self, company: str, role: str) -> List[str]: | |
| """Generate interview process notes""" | |
| base_process = [ | |
| "Phone/Video Screen", | |
| "Technical Assessment", | |
| "Behavioral Interview", | |
| "Final Round" | |
| ] | |
| if any(term in role.lower() for term in ['senior', 'lead', 'principal']): | |
| base_process.insert(-1, "Leadership Interview") | |
| return base_process | |
| def _extract_key_projects(self, resume_text: str) -> List[str]: | |
| """Extract key projects from resume""" | |
| project_indicators = [ | |
| r'built\s+([^\.]+)', | |
| r'developed\s+([^\.]+)', | |
| r'created\s+([^\.]+)', | |
| r'led\s+([^\.]+)', | |
| r'implemented\s+([^\.]+)' | |
| ] | |
| projects = [] | |
| for pattern in project_indicators: | |
| matches = re.findall(pattern, resume_text, re.IGNORECASE) | |
| projects.extend([match.strip() for match in matches[:2]]) # Limit to 2 per pattern | |
| return projects[:6] # Max 6 projects | |
| def _extract_strengths(self, resume_text: str, skills: List[str]) -> List[str]: | |
| """Extract candidate strengths""" | |
| strengths = [] | |
| # Add top skills as strengths | |
| strengths.extend(skills[:3]) | |
| # Add experience-based strengths | |
| if re.search(r'(\d+)[\s\+]*years', resume_text, re.IGNORECASE): | |
| strengths.append("Extensive experience") | |
| if any(word in resume_text.lower() for word in ['led', 'managed', 'supervised']): | |
| strengths.append("Leadership experience") | |
| if any(word in resume_text.lower() for word in ['scaled', 'optimized', 'improved']): | |
| strengths.append("Performance optimization") | |
| return strengths[:6] | |
| def generate_interview_guide(self, guide_data: GuideData) -> str: | |
| """Generate interview guide following exact InterviewGuideGPT format""" | |
| # Calculate derived helpers | |
| match_bucket, emoji = self._get_match_bucket(guide_data.match_score) | |
| percent = round(guide_data.match_score * 100, 1) | |
| user_skills_set = set(guide_data.user_skills) | |
| role_skills_set = set(guide_data.role_skills) | |
| strong = len(user_skills_set & role_skills_set) | |
| partial = len(user_skills_set) - strong | |
| gaps = len(role_skills_set) - strong | |
| # Get company insight | |
| company_insight = self._get_company_insight(guide_data.company) | |
| # Generate sections | |
| intro = self._generate_introduction(guide_data) | |
| tech_questions = self._generate_technical_questions(guide_data) | |
| behavioral_questions = self._generate_behavioral_questions(guide_data) | |
| culture_questions = self._generate_culture_questions(guide_data) | |
| talking_points = self._generate_talking_points(guide_data) | |
| smart_questions = self._generate_smart_questions(guide_data) | |
| # Format the complete guide | |
| guide = f"""# Personalized Interview Guide: {guide_data.role_title} at {guide_data.company} | |
| **Match Score: {emoji} {match_bucket} Match ({percent}%)** | |
| --- | |
| ## Introduction | |
| {intro} | |
| ## π Skills Match Analysis | |
| **Overall Assessment:** Strong technical foundation with {strong} direct skill matches and proven experience in {guide_data.user_overview.split()[-2]} {guide_data.user_overview.split()[-1]}. | |
| ```text | |
| Skills Breakdown | |
| Strong Matches {'β' * min(20, strong * 2)} {strong} | |
| Partial Matches {partial} | |
| Skill Gaps {gaps} | |
| ``` | |
| β **Your Strengths:** {', '.join(guide_data.user_skills[:6])} | |
| ## π― Interview Process at {guide_data.company} | |
| 1. **Typical rounds:** {guide_data.interview_rounds} | |
| 2. **Stages:** {', '.join(guide_data.process_notes)} | |
| 3. **Timeline:** 3-4 weeks (typical) | |
| 4. **Company insight:** {company_insight} | |
| ## π§ Technical & Problem-Solving Questions | |
| {tech_questions} | |
| ## π€ Behavioral & Experience Questions | |
| {behavioral_questions} | |
| ## π’ Company & Culture Questions | |
| {culture_questions} | |
| ## π Preparation Strategy | |
| **Immediate priorities:** Review core technical concepts β’ Prepare STAR examples β’ Research company background | |
| **Study schedule:** Technical 60% β’ Behavioral 25% β’ Company 15% | |
| **Time allocation:** 5β7 hours over 3β5 days | |
| ## π¬ Key Talking Points | |
| {talking_points} | |
| ## β Smart Questions to Ask | |
| {smart_questions} | |
| ## ποΈ Day-of-Interview Checklist | |
| β Morning review of key concepts | |
| β Confirm logistics and timing | |
| β Mental preparation and confidence building | |
| β Arrive 10 minutes early | |
| ## β Success Metrics | |
| β Demonstrated {len(guide_data.user_skills)} core strengths | |
| β Asked β₯4 thoughtful questions | |
| β Showed enthusiasm & growth mindset | |
| ## π Conclusion | |
| You're an excellent fitβbe confident. Good luck! π | |
| --- | |
| *Generated with IQKiller v2.0 β no data retained.*""" | |
| return guide | |
| def _get_match_bucket(self, score: float) -> tuple: | |
| """Get match bucket and emoji""" | |
| if score >= 0.90: | |
| return "Excellent", "π’" | |
| elif score >= 0.80: | |
| return "Strong", "π‘" | |
| else: | |
| return "Developing", "π΄" | |
| def _get_company_insight(self, company: str) -> str: | |
| """Get company-specific insight""" | |
| company_lower = company.lower() | |
| for key, insight in self.company_insights.items(): | |
| if key in company_lower: | |
| return insight | |
| return f"{company} values innovation and excellence in their field." | |
| def _generate_introduction(self, guide_data: GuideData) -> str: | |
| """Generate introduction section""" | |
| return f"This {guide_data.role_title} position at {guide_data.company} represents an excellent opportunity for someone with your background. Your {guide_data.user_overview} aligns well with {guide_data.team_context.lower()}. With your technical skills and experience, you're well-positioned to contribute meaningfully to their mission." | |
| def _generate_technical_questions(self, guide_data: GuideData) -> str: | |
| """Generate exactly 3 technical questions""" | |
| questions = [] | |
| # Question 1: System design | |
| q1 = f"""**1. How would you design a system to handle {guide_data.role_title.lower()} requirements at scale?** | |
| *Why they ask:* Tests your system design skills and understanding of scalability challenges. | |
| *How to answer:* Start with requirements gathering, discuss architecture, data flow, and scaling considerations. | |
| *Key points:* System architecture understanding, scalability considerations, technology trade-offs""" | |
| # Question 2: Technical depth | |
| main_skill = guide_data.user_skills[0] if guide_data.user_skills else "your main technology" | |
| q2 = f"""**2. Given your experience with {main_skill}, how would you approach solving a complex data problem?** | |
| *Why they ask:* Assesses your problem-solving approach and technical depth in {main_skill}. | |
| *How to answer:* Break down the problem, discuss methodology, mention specific tools and techniques. | |
| *Key points:* Deep knowledge of {main_skill}, problem decomposition skills, practical application""" | |
| # Question 3: Role-specific | |
| q3 = f"""**3. Describe how you would optimize performance in a {guide_data.role_title.lower()} context.** | |
| *Why they ask:* Evaluates your understanding of performance optimization specific to this role. | |
| *How to answer:* Discuss monitoring, bottleneck identification, and optimization strategies. | |
| *Key points:* Performance metrics understanding, optimization techniques, real-world experience""" | |
| return f"{q1}\n\n{q2}\n\n{q3}" | |
| def _generate_behavioral_questions(self, guide_data: GuideData) -> str: | |
| """Generate exactly 3 behavioral questions""" | |
| q1 = """**1. Tell me about a time when you had to learn a new technology quickly for a project.** | |
| *STAR Framework:* Situation - Task - Action - Result | |
| *Focus on:* Learning agility, problem-solving approach, impact of quick learning""" | |
| q2 = """**2. Describe a situation where you had to work with a difficult team member or stakeholder.** | |
| *STAR Framework:* Situation - Task - Action - Result | |
| *Focus on:* Communication skills, conflict resolution, collaboration approach""" | |
| q3 = """**3. Give me an example of a project where you had to make trade-offs between competing priorities.** | |
| *STAR Framework:* Situation - Task - Action - Result | |
| *Focus on:* Decision-making process, stakeholder management, outcome evaluation""" | |
| return f"{q1}\n\n{q2}\n\n{q3}" | |
| def _generate_culture_questions(self, guide_data: GuideData) -> str: | |
| """Generate exactly 3 culture questions""" | |
| q1 = f"""**1. Why are you interested in working at {guide_data.company} specifically?** | |
| *Purpose:* Tests genuine interest and company research. | |
| *Approach:* Connect company mission to your values and career goals.""" | |
| q2 = f"""**2. How do you stay current with industry trends and continue learning in your field?** | |
| *Purpose:* Assesses growth mindset and continuous learning. | |
| *Approach:* Share specific resources, communities, and learning practices.""" | |
| q3 = f"""**3. Describe your ideal work environment and team dynamics.** | |
| *Purpose:* Evaluates cultural fit and team compatibility. | |
| *Approach:* Align your preferences with {guide_data.company}'s known culture.""" | |
| return f"{q1}\n\n{q2}\n\n{q3}" | |
| def _generate_talking_points(self, guide_data: GuideData) -> str: | |
| """Generate key talking points""" | |
| points = [] | |
| # Add background | |
| points.append(f"β {guide_data.user_overview}") | |
| # Add key projects | |
| if guide_data.key_projects: | |
| points.append(f"β {len(guide_data.key_projects)} key projects including {', '.join(guide_data.key_projects[:2])}") | |
| # Add skills highlights | |
| top_skills = guide_data.user_skills[:3] | |
| points.append(f"β Technical expertise: {' + '.join(top_skills)} highlights") | |
| return '\n'.join(points) | |
| def _generate_smart_questions(self, guide_data: GuideData) -> str: | |
| """Generate smart questions to ask""" | |
| questions = [ | |
| "β What does success look like in the first 90 days?", | |
| "β What's the biggest technical challenge facing the team?", | |
| f"β How does {guide_data.company} support professional development and career growth?", | |
| f"β What do you enjoy most about working at {guide_data.company}?", | |
| "β How do you measure the impact of this role on company objectives?", | |
| f"β What opportunities exist for innovation within the {guide_data.role_title} position?" | |
| ] | |
| return '\n'.join(questions) | |
| # Main function to generate guide from resume and job text | |
| def generate_interviewgpt_guide(resume_text: str, job_text: str) -> str: | |
| """Generate interview guide using InterviewGuideGPT format""" | |
| generator = InterviewGuideGPT() | |
| guide_data = generator.analyze_resume_and_job(resume_text, job_text) | |
| return generator.generate_interview_guide(guide_data) | |
| # Legacy compatibility | |
| class ComprehensiveAnalyzer: | |
| """Legacy wrapper for backward compatibility""" | |
| def __init__(self): | |
| self.generator = InterviewGuideGPT() | |
| def generate_comprehensive_guide(self, resume_text: str, job_input: str): | |
| """Legacy method for backward compatibility""" | |
| guide_data = self.generator.analyze_resume_and_job(resume_text, job_input) | |
| return MockGuide(self.generator.generate_interview_guide(guide_data)) | |
| class MockGuide: | |
| """Mock guide object for legacy compatibility""" | |
| def __init__(self, content): | |
| self.content = content | |
| def format_interview_guide_html(guide) -> str: | |
| """Convert markdown guide to HTML for display""" | |
| import re | |
| html_content = guide.content | |
| # Convert markdown headers to HTML | |
| html_content = re.sub(r'^# (.*)', r'<h1 style="color: white; text-align: center; margin-bottom: 20px;">\1</h1>', html_content, flags=re.MULTILINE) | |
| html_content = re.sub(r'^## (.*)', r'<h2 style="color: white; margin: 30px 0 20px 0;">\1</h2>', html_content, flags=re.MULTILINE) | |
| # Convert markdown bold to HTML | |
| html_content = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', html_content) | |
| # Convert markdown code blocks | |
| html_content = re.sub(r'```text\n(.*?)\n```', r'<pre style="background: rgba(0,0,0,0.3); padding: 15px; border-radius: 8px; color: white; font-family: monospace;">\1</pre>', html_content, flags=re.DOTALL) | |
| # Convert lists | |
| html_content = re.sub(r'^β (.*)', r'<li style="color: rgba(255,255,255,0.9); margin: 5px 0;">\1</li>', html_content, flags=re.MULTILINE) | |
| html_content = re.sub(r'^β (.*)', r'<p style="color: var(--apple-green); margin: 15px 0;"><strong>β \1</strong></p>', html_content, flags=re.MULTILINE) | |
| # Convert line breaks to HTML | |
| html_content = html_content.replace('\n\n', '</p><p style="color: rgba(255,255,255,0.9); line-height: 1.6; margin: 15px 0;">') | |
| html_content = html_content.replace('\n', '<br>') | |
| # Wrap in container | |
| html_content = f''' | |
| <div class="result-card slide-in" style="max-width: 1200px; margin: 0 auto; background: var(--glass-bg); border-radius: 16px; padding: 30px; backdrop-filter: blur(15px); box-shadow: var(--shadow-soft);"> | |
| <p style="color: rgba(255,255,255,0.9); line-height: 1.6; margin: 15px 0;"> | |
| {html_content} | |
| </p> | |
| </div> | |
| ''' | |
| return html_content |