Files
resumeformatter/backend/app/services/ai_service.py
Laxmi Khilnani cda50356b4
Some checks failed
Profile Linker Docker Build / Build and push Docker image (push) Failing after 3s
feat: Complete Smart Resume Formatter with R2 and Gemini AI integration
- Integrated Cloudflare R2 for template storage and converted file management
- Added Google Gemini AI for resume parsing and HTML generation
- Created backend API endpoints for templates, conversion, and history
- Refactored frontend to use real API instead of mock data
- Fixed Docker networking issues (IPv6/IPv4) for R2 connectivity
- Added resumeService.ts for frontend API integration
- Updated Vite configuration for proper asset serving in Docker
- Successfully tested with 13 templates from R2 bucket
2025-10-14 21:43:41 +05:30

136 lines
4.9 KiB
Python

"""
Gemini AI Service
Handles resume text extraction and HTML generation
"""
import google.generativeai as genai
from typing import Optional
import base64
from app.core.config import settings
class AIService:
"""Service for interacting with Google Gemini AI"""
def __init__(self):
"""Initialize Gemini AI with API key"""
if not settings.GEMINI_API_KEY:
raise ValueError("GEMINI_API_KEY not configured")
genai.configure(api_key=settings.GEMINI_API_KEY)
self.model = genai.GenerativeModel('gemini-2.0-flash-exp')
async def extract_text_from_resume(
self,
file_content: bytes,
mime_type: str
) -> Optional[str]:
"""
Extract text from resume file using Gemini Vision
Args:
file_content: File content as bytes
mime_type: MIME type of the file (application/pdf or application/vnd.openxmlformats-officedocument.wordprocessingml.document)
Returns: Extracted text or None if failed
"""
try:
# Convert bytes to base64
base64_data = base64.b64encode(file_content).decode('utf-8')
prompt = """Extract all text from this resume document.
Preserve the original structure, including sections, headings, bullet points, and line breaks, as plain text.
Focus on maintaining the hierarchical structure of the content."""
response = self.model.generate_content([
{
'mime_type': mime_type,
'data': base64_data
},
prompt
])
return response.text
except Exception as e:
print(f"Error extracting text from resume: {e}")
return None
async def generate_html_from_template(
self,
resume_text: str,
template_html: str
) -> Optional[str]:
"""
Generate formatted HTML by merging resume content with template
Args:
resume_text: Extracted resume text
template_html: HTML template content
Returns: Generated HTML or None if failed
"""
try:
prompt = self._build_generation_prompt(resume_text, template_html)
response = self.model.generate_content(prompt)
# Clean up the response (remove code blocks if present)
html_content = response.text.strip()
if html_content.startswith('```html'):
html_content = html_content[7:] # Remove ```html
if html_content.endswith('```'):
html_content = html_content[:-3] # Remove ```
return html_content.strip()
except Exception as e:
print(f"Error generating HTML: {e}")
return None
def _build_generation_prompt(self, resume_text: str, template_html: str) -> str:
"""Build the prompt for HTML generation"""
instructions = """### 🎯 EXACT TEMPLATE PRESERVATION INSTRUCTIONS:
**🚨 RULE #1: COPY TEMPLATE EXACTLY - NO STRUCTURAL CHANGES! 🚨**
**🚨 RULE #2: ONLY REPLACE PLACEHOLDER TEXT - NOTHING ELSE! 🚨**
**YOU ARE A FIND-AND-REPLACE TOOL - NOT A DESIGNER!**
**SIMPLE 3-STEP PROCESS:**
1. **COPY**: Take the entire HTML template (every character from <!DOCTYPE to </html>).
2. **FIND**: Locate placeholder text in the template (like "{{name}}", "John Doe", "Software Engineer", "2020-2023", etc.).
3. **REPLACE**: Replace ONLY that placeholder text with the user's corresponding information.
**WHAT TO REPLACE:**
- Names, contact info
- Job titles, companies, dates, descriptions
- Education details
- Skills lists
**WHAT TO NEVER CHANGE:**
- HTML tags (div, p, h1, etc.), CSS classes, IDs, or any inline styles.
- The overall HTML structure, layout, nesting, alignment, spacing, colors, and fonts.
**FOR EXTRA USER CONTENT:**
If the user's resume has sections not present in the template (e.g., 'Projects', 'Certifications'):
- Find a similar section in the template (e.g., 'Experience').
- Copy that section's HTML structure.
- Add it at a logical place (usually at the end) with the user's content.
- Reuse the same CSS classes and styling patterns to maintain consistency.
**CRITICAL:** Ensure ALL information from the user's resume is included in the final HTML. Do not omit any details.
"""
return f"""You are an expert HTML resume generator. Your task is to take the user's resume content and perfectly merge it into the provided company HTML template by acting as a precise find-and-replace tool.
**User's Resume Content:**
---
{resume_text}
---
**Company HTML Template:**
---
{template_html}
---
{instructions}
Now, generate the final, complete HTML file. Your entire output must be only the HTML code, starting with `<!DOCTYPE html>` and ending with `</html>`. Do not include any explanations or surrounding text."""
# Singleton instance
ai_service = AIService()