SmartResume AI uses Google's Gemini AI to help users create professional, ATS-optimized resume content. Here are the main AI features:
- What it does: Single-click comprehensive resume enhancement for target role
- Input needed: Target job role + basic resume information
- AI generates: Professional summary, enhanced bullet points, improved project descriptions, and skill suggestions
- Use case: Transform basic resume into professional, ATS-optimized document
- What it does: Creates a compelling 2-3 sentence professional summary
- Input needed: Target job role, years of experience, skills, education
- AI generates: ATS-optimized summary highlighting key strengths
- Use case: When you need a strong opening statement
- What it does: Converts ALL basic job responsibilities into professional bullet points
- Input needed: Company, job title, duration, and basic responsibilities
- AI generates: 3-5 impact-driven bullet points with metrics and action verbs per job
- Use case: Transform simple job descriptions into achievement-focused content
- Note: Enhances ALL experiences, even if they already have bullet points
- What it does: Improves ALL project descriptions with professional technical language
- Input needed: Project title, technologies, basic description
- AI generates: Enhanced 2-3 line descriptions highlighting technical complexity
- Use case: Make projects stand out with clear, impactful descriptions
- What it does: Recommends relevant technical and soft skills for target role
- Input needed: Target job role, current skills
- AI generates: 5-8 industry-relevant skills tailored to the role
- Use case: Fill skill gaps and optimize for ATS keyword matching
- What it does: Analyzes entire resume and provides actionable feedback
- Input needed: Complete resume data
- AI generates: Strength rating (1-10), what's working well, improvement suggestions, ATS keywords
- Use case: Get expert feedback before sending to employers
User Input β AI Generator β Gemini API (2.5-flash/pro) β Response Processing β
Text Sanitization (remove markdown/unicode) β Session State β UI Update β PDF Export
Main Methods:
class AIGenerator:
def optimize_entire_resume(self, resume_data):
"""Comprehensive AI optimization - ONE CLICK solution"""
# Generates summary if missing
# Enhances ALL experiences with bullet points
# Improves ALL project descriptions
# Suggests additional skills
def generate_professional_summary(self, name, target_role, ...):
"""Generate compelling professional summary"""
def generate_experience_bullets(self, job_title, company, ...):
"""Create 3-5 professional bullet points"""
def enhance_project_description(self, project_title, ...):
"""Improve project description with technical language"""
def suggest_skills(self, target_role, current_skills):
"""Recommend relevant skills for role"""
def analyze_resume_quality(self, resume_data):
"""Analyze and provide feedback on resume quality"""Features:
- Multi-model fallback system (tries gemini-2.5-flash first, falls back to gemini-pro)
- Retry logic with exponential backoff for rate limiting
- Comprehensive error handling for quota limits, API errors, network issues
- Text sanitization - removes markdown formatting (**, *, _) and Unicode characters
- Session state management - prevents widget conflicts with pre-render flag system
- Batch processing - can optimize entire resume or individual sections
class GeminiClient:
def __init__(self):
# Initialize with API key from .env
self.api_key = os.getenv("GEMINI_API_KEY")
genai.configure(api_key=self.api_key)
def generate_content(self, prompt, model_name="gemini-2.5-flash"):
# Try primary model
# Fallback to gemini-pro if needed
# Handle errors gracefullyFeatures:
- Cached singleton instance (loads once, reused everywhere)
- Model fallback mechanism
- Safety settings configuration
- Temperature control for creative vs deterministic output
Contains carefully crafted prompts for each AI feature with explicit instructions:
Example - Professional Summary Prompt:
def get_summary_prompt(target_role, experience_years):
return f"""
Generate a professional resume summary for:
Role: {target_role}
Experience: {experience_years} years
Requirements:
- 2-3 sentences (50-70 words)
- Include key strengths and value proposition
- ATS-optimized keywords
- Professional tone
- Do NOT use markdown formatting (no **, *, _)
- Use plain text only
"""Key Prompt Instructions:
- All prompts explicitly forbid markdown formatting
- Request plain text output only
- Specify exact output format (bullet points, sentences, comma-separated)
- Include ATS optimization requirements
- Request quantifiable metrics where possible
def sanitize_text(text):
"""Remove markdown and Unicode characters for PDF compatibility"""
# Remove markdown formatting
text = re.sub(r'\*\*([^*]+)\*\*', r'\1', text) # **bold**
text = re.sub(r'\*([^*]+)\*', r'\1', text) # *italic*
# Replace Unicode characters
replacements = {
'\u2013': '-', # en dash
'\u2014': '--', # em dash
'\u2018': "'", # smart quotes
'\u2022': '-', # bullet
}
# Ensure Latin-1 compatibility for PDF
return sanitized_textApplied to:
- All PDF text fields (name, email, phone, etc.)
- Section titles and headers
- Bullet points and descriptions
- Links and metadata
User Journey:
- User fills in basic information (name, target role, experiences, projects)
- User clicks "β¨ Optimize Entire Resume with AI" button
- AI analyzes and enhances everything in one go
Behind the Scenes:
# Sets flag to process before widgets render
if ai_buttons['optimize_all']:
st.session_state['_optimize_all_pending'] = True
st.rerun()
# In handle_ai_generation_pre_render():
if st.session_state.get('_optimize_all_pending'):
optimizations = ai_generator.optimize_entire_resume(resume_data)
# Apply all enhancements
if 'summary' in optimizations:
st.session_state['summary'] = optimizations['summary']
if 'experience_list' in optimizations:
st.session_state['experience_list'] = optimizations['experience_list']
if 'projects_list' in optimizations:
st.session_state['projects_list'] = optimizations['projects_list']
if 'suggested_skills' in optimizations:
st.session_state['technical_skills'] += optimizations['suggested_skills']What Gets Optimized:
- β Professional summary (generated or enhanced)
- β ALL work experiences (bullet points for each)
- β ALL project descriptions (enhanced)
- β Skills (additional relevant suggestions)
Result: User goes from basic inputs to professional, ATS-optimized resume in ONE CLICK!
User Journey:
- User fills "Target Job Role" (e.g., "Software Engineer")
- User enters "Years of Experience" (e.g., 3)
- User clicks "Generate with AI" button
Behind the Scenes:
# In app.py - handle_ai_generation()
if st.session_state.generate_summary:
# Get user inputs
target_role = st.session_state.target_role
experience_years = st.session_state.experience_years
# Generate AI content
ai_generator = get_ai_generator()
summary = ai_generator.generate_ai_content(
'summary',
target_role=target_role,
experience_years=experience_years
)
# Store in session state
st.session_state.summary = summary
st.session_state.generate_summary = False
st.rerun()AI Prompt Example:
Generate a professional resume summary for a Software Engineer with 3 years of experience.
Include key technical skills, achievements, and value proposition.
Make it ATS-friendly with relevant keywords.
Keep it to 2-3 sentences.
AI Response Example:
Results-driven Software Engineer with 3 years of experience in full-stack development,
specializing in Python, React, and cloud technologies. Proven track record of delivering
scalable applications that improved system performance by 40% and reduced deployment time
by 60%. Passionate about solving complex problems with clean, maintainable code.
User Journey:
- User adds work experiences with basic responsibilities
- User clicks "Enhance All Experience" button
- AI generates professional bullet points for EVERY experience
Behind the Scenes:
# When user clicks enhance button
if ai_buttons['enhance_experience']:
enhanced_count = 0
# Process ALL experiences, not just empty ones
for idx, exp in enumerate(st.session_state.experience_list):
if exp.get('responsibilities'):
bullets = ai_generator.generate_experience_bullets(
job_title=exp['job_title'],
company=exp['company'],
duration=f"{exp['start_date']} - {exp['end_date']}",
responsibilities=exp['responsibilities']
)
# Update with new AI-generated bullets
st.session_state.experience_list[idx]['bullet_points'] = bullets
enhanced_count += 1
st.success(f"Enhanced {enhanced_count} experience entries!")Key Improvement:
- OLD: Only enhanced experiences WITHOUT bullet points
- NEW: Enhances ALL experiences that have responsibilities
- Users can re-enhance anytime to improve quality
AI Prompt Example:
Generate 3-5 professional bullet points for this work experience:
Job Title: Software Engineer
Company: ABC Tech
Responsibilities: Developed web applications, fixed bugs, worked with team
Requirements:
- Start with strong action verbs
- Include metrics/impact where possible
- Focus on achievements, not just duties
- ATS-optimized keywords
- Do NOT use markdown formatting
- Use plain text only
AI Response Example:
Developed and deployed 5+ full-stack web applications using React and Node.js, serving 10,000+ daily active users
Reduced application bug count by 45% through implementation of comprehensive unit testing and code review processes
Collaborated with cross-functional teams of 8+ members to deliver projects 20% ahead of schedule
Optimized database queries resulting in 60% improvement in page load times
User Journey:
- User adds projects with basic descriptions
- User clicks "Enhance All Projects" button
- AI improves ALL project descriptions with technical depth
Behind the Scenes:
if ai_buttons['enhance_projects']:
enhanced_count = 0
for idx, proj in enumerate(st.session_state.projects_list):
if proj.get('description'):
enhanced_desc = ai_generator.enhance_project_description(
project_title=proj['title'],
duration=proj.get('duration', ''),
technologies=proj.get('technologies', ''),
description=proj['description']
)
st.session_state.projects_list[idx]['enhanced_description'] = enhanced_desc
enhanced_count += 1Example:
Input (Basic): "Built a web app for managing tasks"
Output (AI-Enhanced): "Developed a full-stack task management web application using React and Node.js, featuring real-time collaboration, drag-and-drop interface, and RESTful API integration. Implemented JWT authentication and MongoDB for scalable data storage, serving 500+ active users."
User Journey:
- User enters target role
- User clicks "Suggest Skills" button
Behind the Scenes:
# When user clicks suggest skills
if st.session_state.suggest_skills:
target_role = st.session_state.target_role
# Generate skills
ai_generator = get_ai_generator()
skills_text = ai_generator.generate_ai_content(
'skills',
target_role=target_role
)
# Update session state
st.session_state.technical_skills = skills_text
st.session_state.suggest_skills = False
st.rerun()AI Prompt Example:
Suggest 10-15 relevant technical skills for a Data Scientist role.
Include programming languages, frameworks, tools, and technologies.
Format as comma-separated list.
AI Response Example:
Python, R, SQL, TensorFlow, PyTorch, scikit-learn, Pandas, NumPy, Matplotlib,
Jupyter Notebook, Apache Spark, Tableau, Power BI, Git, Docker
User Journey:
- User completes resume with all sections
- User clicks "Analyze Resume Quality" button
- AI provides comprehensive feedback report
Behind the Scenes:
if ai_buttons['analyze_resume']:
analysis = ai_generator.analyze_resume_quality(resume_data)
# Display analysis report
st.markdown("### π Resume Analysis Report")
st.markdown(analysis)AI Analysis Includes:
- Overall Strength Score (1-10 rating)
- What's Working Well (2-3 strong points)
- What Needs Improvement (2-3 specific actionable suggestions)
- ATS Optimization Tips (2-3 keywords/phrases to add for target role)
Example Analysis Output:
RESUME STRENGTH: 7/10
WHAT'S WORKING WELL:
β Strong technical skills section with relevant technologies
β Quantifiable achievements in work experience
β Clear project descriptions with tech stack mentioned
NEEDS IMPROVEMENT:
β Professional summary could be more specific about years of experience
β Add more metrics to project outcomes (users, performance gains)
β Include certifications section if you have any
ATS OPTIMIZATION:
+ Add keywords: "Agile methodology", "CI/CD pipeline", "cloud deployment"
+ Emphasize "full-stack development" more prominently
+ Include more action verbs: "architected", "orchestrated", "spearheaded"
if not GEMINI_API_KEY:
st.error("API key not configured. Please add GEMINI_API_KEY to .env file")
return "Please configure API key"# Retry with exponential backoff
for attempt in range(max_retries):
try:
response = model.generate_content(prompt)
return response.text
except Exception as e:
if "quota" in str(e).lower():
wait_time = (2 ** attempt) * 1 # 1s, 2s, 4s, 8s
time.sleep(wait_time)models = ["gemini-2.5-flash", "gemini-pro"]
for model_name in models:
try:
return generate_with_model(model_name, prompt)
except:
continue # Try next modelsafety_settings = {
HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
}# Problem: AI generates **bold** text, PDF doesn't support Unicode
# Solution: Two-layer approach
# Layer 1: Prevent (in prompts)
"Do NOT use any markdown formatting (no **, *, _)"
# Layer 2: Clean (in sanitization)
text = re.sub(r'\*\*([^*]+)\*\*', r'\1', text) # Remove **
text = text.replace('\u2013', '-') # Replace en-dash with hyphen# Problem: Can't modify st.session_state['summary'] after widget with key='summary' is created
# Solution: Flag-based pre-render processing
# Step 1: Set flag when button clicked
if st.button("Generate"):
st.session_state['_generate_summary_pending'] = True
st.rerun()
# Step 2: Process BEFORE widgets (in handle_ai_generation_pre_render)
if st.session_state.get('_generate_summary_pending'):
# Generate and update session state
st.session_state['summary'] = ai_generated_summary
st.session_state['_generate_summary_pending'] = False
# Step 3: Widget picks up updated value
summary = st.text_area("Summary", value=st.session_state.get('summary', ''))Why Session State? Streamlit reruns the entire script on every interaction. Session state preserves data between reruns and prevents widget conflicts.
AI Flow with Pre-Render Flag System:
# BEFORE: Direct modification (CAUSES ERROR!)
if st.button("Generate"):
st.session_state.summary = ai_result # β Error if widget exists
# AFTER: Flag-based approach (WORKS!)
# 1. User clicks button β Set flag
if st.button("Generate with AI"):
st.session_state._generate_summary_pending = True
st.rerun()
# 2. Before rendering forms β Check flags and process
def handle_ai_generation_pre_render(ai_generator):
if st.session_state.get('_generate_summary_pending'):
# Generate AI content
summary = ai_generator.generate_professional_summary(...)
# Store result BEFORE widgets are created
st.session_state['summary'] = summary
# Clear flag
st.session_state['_generate_summary_pending'] = False
# 3. Render form β Widget uses stored value (no conflict!)
summary = st.text_area("Summary",
value=st.session_state.get('summary', ''),
key="summary")Benefits:
- β No widget conflicts
- β Clean separation of AI processing and UI rendering
- β All AI operations happen before widget instantiation
- β Works for all AI features (optimize_all, generate_summary, etc.)
@st.cache_resource
def get_ai_generator():
"""Cache the AI generator instance - loads once, reused forever"""
return AIGenerator()Benefit: API client initialized only once, not on every rerun
# Instead of clicking 4 buttons individually:
# - Generate Summary
# - Enhance Experience
# - Enhance Projects
# - Suggest Skills
# Use ONE button:
optimize_all = st.button("β¨ Optimize Entire Resume")
# Processes everything in parallelBenefit: Single API session, faster processing, better UX
All text passes through sanitize_text() only once before PDF generation
- Flags are cleared immediately after processing
- No redundant AI calls on subsequent reruns
- Widget values preserved across reruns
- Async Processing: Parallel AI calls for multiple sections
- Streaming Responses: Real-time word-by-word display
- Response Caching: Cache AI responses for identical inputs
- Batch API Calls: Send multiple prompts in single request
What makes our AI system excellent:
- β ONE-CLICK OPTIMIZATION: Complete resume enhancement with single button
- β Multi-model fallback: Tries gemini-2.5-flash, falls back to gemini-pro for reliability
- β Comprehensive enhancements: Summary, ALL experiences, ALL projects, skills
- β Proper error handling: User-friendly messages, retry logic, quota management
- β ATS-optimized prompts: Explicitly designed for applicant tracking systems
- β Clean session state: Flag-based pre-render system prevents widget conflicts
- β Text sanitization: Removes markdown and Unicode for PDF compatibility
- β Quality analysis: AI feedback on resume strength and improvements
- β Cached resources: AI client loads once for performance
- β Free tier friendly: Retry logic and fallback for rate limits
Current AI capabilities:
- β¨ Complete Resume Optimization (NEW - Most Popular!)
- Professional summaries
- Experience bullet points (ALL experiences, not just empty ones)
- Project descriptions enhancement (NEW)
- Skills suggestions
- Resume quality analysis (NEW)
Recent Improvements:
- Fixed: "Already has bullet points" blocking issue
- Fixed: Session state widget conflicts
- Fixed: Unicode characters in PDF (en-dash, smart quotes)
- Fixed: Markdown formatting (bold, italic) in AI output
- Fixed: LinkedIn/Portfolio links now clickable in PDF
- Added: Complete one-click optimization
- Added: Project description enhancement
- Added: Resume quality analyzer
Technical Achievements:
- Zero widget conflicts with pre-render flag system
- Latin-1 compatible PDF generation
- Markdown-free AI responses
- Clickable hyperlinks in PDF
- Batch processing for efficiency
Future AI enhancements possible:
- Cover letter generation
- Resume keyword density analysis
- Industry-specific templates
- Multi-language support
- A/B testing suggestions (compare 2 resume versions)
- Achievement quantification helper
- Interview preparation based on resume