IQKillerv2 / iqkiller_with_pdf_upload.py
AvikalpK's picture
πŸš€ Enhanced IQKiller with Next.js Vercel version
0939a57
#!/usr/bin/env python3
import gradio as gr
import os
import re
import tempfile
from pathlib import Path
# PDF processing imports
try:
import PyPDF2
import pdfplumber
PDF_SUPPORT = True
except ImportError:
PDF_SUPPORT = False
# LLM integration imports
try:
import openai
LLM_SUPPORT = True
except ImportError:
LLM_SUPPORT = False
# Basic configuration
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY")
SERPAPI_KEY = os.getenv("SERPAPI_KEY")
FIRECRAWL_API_KEY = os.getenv("FIRECRAWL_API_KEY")
def extract_text_from_pdf(pdf_file_path: str) -> str:
"""Extract text from PDF using multiple methods"""
if not PDF_SUPPORT:
return "❌ PDF support not available. Please install: pip install PyPDF2 pdfplumber"
extracted_text = ""
try:
# Method 1: Try pdfplumber first (better for complex layouts)
with pdfplumber.open(pdf_file_path) as pdf:
text_parts = []
for page in pdf.pages:
page_text = page.extract_text()
if page_text:
text_parts.append(page_text)
extracted_text = "\n".join(text_parts)
if extracted_text and len(extracted_text.strip()) > 50:
return f"βœ… PDF processed successfully with pdfplumber ({len(extracted_text)} characters)\n\n{extracted_text}"
except Exception as e:
print(f"Pdfplumber failed: {e}")
try:
# Method 2: Fallback to PyPDF2
with open(pdf_file_path, 'rb') as file:
pdf_reader = PyPDF2.PdfReader(file)
text_parts = []
for page in pdf_reader.pages:
page_text = page.extract_text()
if page_text:
text_parts.append(page_text)
extracted_text = "\n".join(text_parts)
if extracted_text and len(extracted_text.strip()) > 50:
return f"βœ… PDF processed successfully with PyPDF2 ({len(extracted_text)} characters)\n\n{extracted_text}"
except Exception as e:
print(f"PyPDF2 failed: {e}")
return "❌ Failed to extract text from PDF. The file might be image-based or corrupted."
def enhance_resume_with_llm(raw_text: str) -> str:
"""Use LLM to enhance and structure the extracted resume text"""
if not LLM_SUPPORT or not OPENAI_API_KEY:
return raw_text
try:
client = openai.OpenAI(api_key=OPENAI_API_KEY)
prompt = f"""
You are an expert resume parser and career advisor. Please analyze and enhance this resume text by:
1. Cleaning up formatting issues and text extraction errors
2. Organizing information into clear sections
3. Highlighting key skills, technologies, and experience
4. Identifying years of experience and seniority level
5. Extracting technical and soft skills
6. Summarizing key achievements and projects
Original resume text:
{raw_text}
Please return a well-structured, clean version that emphasizes the candidate's strengths and qualifications:
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are an expert resume parser and career advisor. Format resumes clearly and highlight key qualifications."},
{"role": "user", "content": prompt}
],
max_tokens=1500,
temperature=0.3
)
enhanced_text = response.choices[0].message.content
return f"πŸ€– LLM Enhanced Resume:\n\n{enhanced_text}\n\n---\n\nOriginal Text:\n{raw_text}"
except Exception as e:
print(f"LLM enhancement failed: {e}")
return f"⚠️ LLM enhancement unavailable, using original text:\n\n{raw_text}"
def process_pdf_upload(pdf_file) -> str:
"""Process uploaded PDF file and return enhanced text"""
if pdf_file is None:
return "❌ No PDF file uploaded."
try:
# Handle the uploaded file
if hasattr(pdf_file, 'name'):
file_path = pdf_file.name
else:
file_path = pdf_file
# Extract text from PDF
extracted_text = extract_text_from_pdf(file_path)
if extracted_text.startswith("❌"):
return extracted_text
# Enhance with LLM if available
enhanced_text = enhance_resume_with_llm(extracted_text)
return enhanced_text
except Exception as e:
return f"❌ Error processing PDF: {str(e)}"
def is_url(text: str) -> bool:
"""Check if text contains a URL"""
url_pattern = r'https?://[^\s<>"{}|\\^`\[\]]+'
return bool(re.search(url_pattern, text))
def enhanced_analysis(resume_text: str, job_text: str) -> str:
"""Enhanced analysis with comprehensive features"""
if not resume_text.strip():
return "❌ Please provide your resume text or upload a PDF file."
if not job_text.strip():
return "❌ Please provide a job description or URL."
# Enhanced analysis
resume_words = resume_text.lower().split()
job_words = job_text.lower().split()
# Detect if it's a URL
is_job_url = is_url(job_text)
url_message = ""
if is_job_url:
url_message = f"""
<div style="background: #3498db; color: white; padding: 12px; border-radius: 8px; margin-bottom: 20px; text-align: center;">
πŸ”— URL Detected: Job posting will be automatically processed for enhanced analysis
</div>
"""
# Expanded skill detection (75+ skills)
tech_skills = [
"python", "javascript", "java", "c++", "c#", "sql", "html", "css", "react", "vue", "angular",
"node", "express", "django", "flask", "spring", "laravel", "php", "ruby", "go", "rust", "kotlin",
"swift", "typescript", "mongodb", "postgresql", "mysql", "redis", "elasticsearch", "aws", "azure",
"gcp", "docker", "kubernetes", "jenkins", "git", "github", "gitlab", "linux", "windows", "macos",
"terraform", "ansible", "microservices", "api", "rest", "graphql", "websocket", "oauth", "jwt",
"machine learning", "ai", "data science", "pandas", "numpy", "tensorflow", "pytorch", "scikit-learn",
"spark", "hadoop", "tableau", "power bi", "excel", "r", "matlab", "scala", "shell", "bash", "powershell",
"devops", "ci/cd", "agile", "scrum", "kanban", "jira", "confluence", "slack", "figma", "sketch"
]
soft_skills = [
"leadership", "teamwork", "communication", "problem solving", "project management", "collaboration",
"mentoring", "training", "presentation", "documentation", "testing", "debugging", "optimization",
"scalability", "performance", "security", "architecture", "design", "planning", "strategy",
"analytical", "creative", "innovative", "adaptable", "reliable", "detail-oriented", "organized"
]
# Find matching skills
resume_tech_skills = [skill for skill in tech_skills if skill in resume_text.lower()]
job_tech_skills = [skill for skill in tech_skills if skill in job_text.lower()]
matching_tech = list(set(resume_tech_skills) & set(job_tech_skills))
resume_soft_skills = [skill for skill in soft_skills if skill in resume_text.lower()]
job_soft_skills = [skill for skill in soft_skills if skill in job_text.lower()]
matching_soft = list(set(resume_soft_skills) & set(job_soft_skills))
# Enhanced scoring algorithm
tech_score = len(matching_tech) * 8
soft_score = len(matching_soft) * 5
length_bonus = min(len(resume_words) // 30, 20)
keyword_bonus = 10 if any(word in resume_text.lower() for word in ["experience", "years", "project", "team"]) else 0
base_score = tech_score + soft_score + length_bonus + keyword_bonus
final_score = min(max(base_score + 35, 45), 95)
# Determine match level and color
if final_score >= 85:
match_level = "🟒 Excellent Match"
match_color = "#27ae60"
advice = "You're a strong candidate! Focus on specific examples and prepare confident answers."
elif final_score >= 70:
match_level = "🟑 Strong Match"
match_color = "#f39c12"
advice = "Good alignment! Highlight your relevant experience and show enthusiasm for learning."
else:
match_level = "πŸ”΄ Developing Match"
match_color = "#e74c3c"
advice = "Focus on transferable skills and demonstrate your ability to learn quickly."
# Generate comprehensive results
results_html = f"""
{url_message}
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 20px; padding: 40px; color: white; margin: 20px 0;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);">
<h1 style="text-align: center; margin-bottom: 30px; font-size: 2.5rem; text-shadow: 2px 2px 4px rgba(0,0,0,0.3);">
🎯 IQKiller Analysis Report
</h1>
<div style="text-align: center; margin: 30px 0; padding: 20px; background: rgba(255,255,255,0.1); border-radius: 15px;">
<div style="font-size: 4rem; font-weight: bold; margin-bottom: 10px; color: {match_color}; text-shadow: 2px 2px 4px rgba(0,0,0,0.5);">
{final_score}%
</div>
<div style="font-size: 1.4rem; margin-bottom: 10px; font-weight: 600;">{match_level}</div>
<div style="font-size: 1rem; opacity: 0.9;">Job Compatibility Score</div>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 15px; margin: 25px 0; text-align: center;">
<h3 style="color: #f1c40f; margin-bottom: 15px;">πŸ’‘ Strategic Advice</h3>
<p style="font-size: 1.1rem; line-height: 1.6;">{advice}</p>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 25px; margin: 30px 0;">
<div style="background: rgba(255,255,255,0.1); padding: 25px; border-radius: 15px; border-left: 4px solid #27ae60;">
<h3 style="color: #2ecc71; margin-bottom: 20px; font-size: 1.3rem;">
πŸ’ͺ Your Technical Strengths ({len(matching_tech)} matches)
</h3>
<ul style="line-height: 1.8; font-size: 1rem; margin: 0; padding-left: 20px;">
{"".join([f"<li>{skill.title()}</li>" for skill in matching_tech[:5]]) if matching_tech else "<li>General technical background</li>"}
<li>Experience with {len(resume_tech_skills)} technologies</li>
<li>Professional development experience</li>
<li>Problem-solving capabilities</li>
</ul>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 25px; border-radius: 15px; border-left: 4px solid #e67e22;">
<h3 style="color: #f39c12; margin-bottom: 20px; font-size: 1.3rem;">
🎯 Key Soft Skills ({len(matching_soft)} matches)
</h3>
<ul style="line-height: 1.8; font-size: 1rem; margin: 0; padding-left: 20px;">
{"".join([f"<li>{skill.title()}</li>" for skill in matching_soft[:4]]) if matching_soft else "<li>Professional communication</li>"}
<li>Team collaboration</li>
<li>Project execution</li>
<li>Continuous learning mindset</li>
</ul>
</div>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 25px; border-radius: 15px; margin: 30px 0;">
<h3 style="color: #3498db; margin-bottom: 20px; font-size: 1.3rem; text-align: center;">
πŸ“‹ Essential Interview Questions to Master
</h3>
<div style="display: grid; gap: 15px;">
<div style="background: rgba(255,255,255,0.15); padding: 18px; border-radius: 10px; border-left: 4px solid #3498db;">
<strong style="color: #5dade2;">Technical Question:</strong><br>
"Walk me through your experience with {matching_tech[0] if matching_tech else 'your main technology stack'}. Can you describe a specific project where you used it effectively?"
</div>
<div style="background: rgba(255,255,255,0.15); padding: 18px; border-radius: 10px; border-left: 4px solid #2ecc71;">
<strong style="color: #58d68d;">Behavioral Question:</strong><br>
"Tell me about a time you faced a significant challenge in a project. How did you approach solving it, and what was the outcome?"
</div>
<div style="background: rgba(255,255,255,0.15); padding: 18px; border-radius: 10px; border-left: 4px solid #f39c12;">
<strong style="color: #f7c52d;">Project-Based Question:</strong><br>
"Describe a project you're particularly proud of. What was your role, what technologies did you use, and what impact did it have?"
</div>
<div style="background: rgba(255,255,255,0.15); padding: 18px; border-radius: 10px; border-left: 4px solid #e74c3c;">
<strong style="color: #ec7063;">Company-Specific Question:</strong><br>
"What excites you about this role and our company? How do you see yourself contributing to our team's success?"
</div>
</div>
</div>
<div style="text-align: center; margin-top: 40px; padding-top: 25px; border-top: 2px solid rgba(255,255,255,0.2);">
<h3 style="color: #1abc9c; margin-bottom: 15px;">✨ Analysis Summary</h3>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px; margin-bottom: 20px;">
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;">
<div style="font-size: 1.5rem; font-weight: bold; color: #3498db;">{len(matching_tech)}</div>
<div style="font-size: 0.9rem; opacity: 0.9;">Technical Matches</div>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;">
<div style="font-size: 1.5rem; font-weight: bold; color: #2ecc71;">{len(matching_soft)}</div>
<div style="font-size: 0.9rem; opacity: 0.9;">Soft Skill Matches</div>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;">
<div style="font-size: 1.5rem; font-weight: bold; color: #f39c12;">{final_score}%</div>
<div style="font-size: 0.9rem; opacity: 0.9;">Overall Match</div>
</div>
</div>
<p style="font-size: 1rem; opacity: 0.8; margin: 0;">
πŸ”’ Zero data retention β€’ πŸ›‘οΈ Enterprise security β€’ ⚑ Instant analysis
</p>
</div>
</div>
"""
return results_html
def create_interface():
"""Create enhanced Gradio interface with PDF upload"""
with gr.Blocks(
title="IQKiller - AI Interview Prep with PDF Upload",
theme=gr.themes.Soft(),
css="""
.gradio-container {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
}
.main-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
border-radius: 20px;
text-align: center;
margin-bottom: 30px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.pdf-section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
border-radius: 15px;
margin: 20px 0;
}
"""
) as demo:
# Header
gr.HTML("""
<div class="main-header">
<h1 style="font-size: 3rem; margin-bottom: 15px; text-shadow: 2px 2px 4px rgba(0,0,0,0.3);">🎯 IQKiller Pro</h1>
<p style="font-size: 1.4rem; margin-bottom: 10px; opacity: 0.95;">AI-Powered Interview Preparation with PDF Upload</p>
<p style="font-size: 1rem; opacity: 0.8;">πŸ“„ Direct PDF Upload β€’ πŸ€– LLM Processing β€’ πŸ”— URL Analysis β€’ πŸ’Ό Comprehensive Prep</p>
</div>
""")
# Main Interface
with gr.Row():
with gr.Column():
gr.HTML("""
<div class="pdf-section">
<h3 style='margin-bottom: 15px; font-size: 1.4rem; text-align: center;'>
πŸ“„ Your Resume
</h3>
<p style="text-align: center; margin-bottom: 20px; opacity: 0.9;">
Upload a PDF file OR paste text below
</p>
</div>
""")
# PDF Upload
pdf_upload = gr.File(
label="πŸ“„ Upload Resume PDF",
file_types=[".pdf"],
type="filepath"
)
# Process PDF button
process_pdf_btn = gr.Button(
"πŸ€– Extract & Enhance with AI",
variant="secondary",
size="sm"
)
# Resume text input
resume_input = gr.Textbox(
placeholder="""Option 1: Upload PDF above and click 'Extract & Enhance'
Option 2: Paste your resume text here manually
πŸ“‹ Include:
β€’ Work experience and responsibilities
β€’ Technical skills and technologies
β€’ Education and certifications
β€’ Key projects and achievements
β€’ Programming languages and tools
β€’ Years of experience in each area
Example:
Software Engineer with 5 years experience
Skills: Python, JavaScript, SQL, React, AWS
Led team of 3 developers on e-commerce platform
Built scalable applications serving 100k+ users""",
lines=12,
label="Resume Text (auto-filled from PDF or manual entry)",
show_label=True
)
with gr.Column():
gr.HTML("""
<h3 style='color: #667eea; margin-bottom: 15px; font-size: 1.4rem; text-align: center;'>
πŸ’Ό Job Opportunity
</h3>
""")
job_input = gr.Textbox(
placeholder="""πŸ”— Paste job URL for automatic analysis:
β€’ LinkedIn job posts
β€’ Company career pages
β€’ Job board listings
β€’ Indeed, Glassdoor, etc.
πŸ“ Or paste the complete job description:
β€’ Company name and role title
β€’ Required skills and experience
β€’ Responsibilities and duties
β€’ Qualifications and requirements
β€’ Team info and company culture
🎯 URLs provide the most comprehensive analysis!
Example:
https://linkedin.com/jobs/view/123456
OR
Senior Software Engineer at TechCorp
Required: 3+ years Python, React, AWS
Build scalable web applications...""",
lines=16,
label="Job Description or URL",
show_label=True
)
# Main Action Button
with gr.Row():
analyze_btn = gr.Button(
"🎯 Generate My Comprehensive Interview Guide",
variant="primary",
size="lg",
scale=1
)
# Results
results_output = gr.HTML()
# Event handlers
process_pdf_btn.click(
fn=process_pdf_upload,
inputs=[pdf_upload],
outputs=[resume_input]
)
analyze_btn.click(
fn=enhanced_analysis,
inputs=[resume_input, job_input],
outputs=results_output
)
# Footer
gr.HTML(f"""
<div style="text-align: center; margin-top: 40px; padding: 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 15px;">
<h4 style="margin-bottom: 15px; font-size: 1.3rem;">🎯 IQKiller Pro v3.0</h4>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 20px; margin-bottom: 20px;">
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;">
<div style="font-size: 1.2rem; margin-bottom: 5px;">πŸ“„</div>
<div style="font-size: 0.9rem;">PDF Upload {'βœ…' if PDF_SUPPORT else '❌'}</div>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;">
<div style="font-size: 1.2rem; margin-bottom: 5px;">πŸ€–</div>
<div style="font-size: 0.9rem;">LLM Enhanced {'βœ…' if LLM_SUPPORT and OPENAI_API_KEY else '❌'}</div>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;">
<div style="font-size: 1.2rem; margin-bottom: 5px;">πŸ”—</div>
<div style="font-size: 0.9rem;">URL Analysis</div>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;">
<div style="font-size: 1.2rem; margin-bottom: 5px;">⚑</div>
<div style="font-size: 0.9rem;">Instant Results</div>
</div>
</div>
<p style="margin: 0; font-size: 0.9rem; opacity: 0.8;">
πŸ”’ Zero data retention β€’ πŸ›‘οΈ Enterprise security β€’ 🎯 Professional interview preparation
</p>
</div>
""")
return demo
def main():
"""Launch the application"""
print("🎯 IQKiller Pro - Direct PDF Upload with LLM Processing")
print("=" * 60)
print("βœ… Starting Enhanced IQKiller Platform...")
print(f"πŸ“„ PDF Support: {'βœ… Available' if PDF_SUPPORT else '❌ Install: pip install PyPDF2 pdfplumber'}")
print(f"πŸ€– LLM Support: {'βœ… OpenAI Ready' if LLM_SUPPORT and OPENAI_API_KEY else '❌ Configure OpenAI API key'}")
print("πŸ”— URL processing ready")
print("πŸ’Ό Enhanced analysis enabled")
print("🌐 Opening at: http://localhost:7860")
print("=" * 60)
demo = create_interface()
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_error=True
)
if __name__ == "__main__":
main()