File size: 9,142 Bytes
4fd18a2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
"""Cover letter tool for generating personalized cover letters - letter.generate endpoint."""
from typing import Dict, Any
from ..services import LLMService, ProfileService
class CoverLetterTool:
"""Tool for generating personalized cover letters."""
def __init__(self):
self.llm_service = LLMService()
self.profile_service = ProfileService()
def generate(
self, user_id: str, job_description: str, tone: str = "professional"
) -> Dict[str, Any]:
"""
Generate a personalized cover letter using LLM.
This is the main letter.generate endpoint that calls an LLM to create
a short, personalized cover letter in any tone.
Args:
user_id: User identifier to access profile for personalization
job_description: The job posting description to tailor the letter to
tone: Tone of the cover letter
Options: "professional", "casual", "enthusiastic", "formal"
Default: "professional"
Returns:
Dict with generated cover letter and metadata:
{
"success": True,
"cover_letter": "Dear Hiring Manager,\n\nI am writing to express...",
"tone_used": "professional",
"word_count": 245,
"character_count": 1456,
"estimated_reading_time": "1 minute"
}
"""
try:
# Get user profile
profile = self.profile_service.get_profile(user_id)
if not profile:
return {
"success": False,
"message": "User profile not found. Please create a profile first.",
}
# Validate tone
valid_tones = ["professional", "casual", "enthusiastic", "formal"]
if tone not in valid_tones:
return {
"success": False,
"message": f"Invalid tone. Must be one of: {', '.join(valid_tones)}",
}
# Validate job description
if not job_description or len(job_description.strip()) < 50:
return {
"success": False,
"message": "Job description must be at least 50 characters long",
}
# Generate cover letter
result = self.llm_service.generate_cover_letter(
profile, job_description, tone
)
# Add additional metadata if successful
if result.get("success") and result.get("cover_letter"):
word_count = result.get("word_count", 0)
result["estimated_reading_time"] = self._estimate_reading_time(
word_count
)
result["tips"] = self._get_cover_letter_tips(tone)
return result
except Exception as e:
return {
"success": False,
"message": f"Error generating cover letter: {str(e)}",
}
def generate_multiple_tones(
self, user_id: str, job_description: str, tones: list[str] = None
) -> Dict[str, Any]:
"""
Generate cover letters in multiple tones for comparison.
Args:
user_id: User identifier
job_description: Job posting description
tones: List of tones to generate (default: ["professional", "enthusiastic"])
Returns:
Dict with multiple cover letters in different tones
"""
if tones is None:
tones = ["professional", "enthusiastic"]
results = {}
errors = []
for tone in tones:
result = self.generate(user_id, job_description, tone)
if result.get("success"):
results[tone] = result
else:
errors.append(f"{tone}: {result.get('message', 'Unknown error')}")
if results:
return {
"success": True,
"cover_letters": results,
"tones_generated": list(results.keys()),
"errors": errors if errors else None,
}
else:
return {
"success": False,
"message": "Failed to generate any cover letters",
"errors": errors,
}
def customize_for_company(
self,
user_id: str,
job_description: str,
company_info: str,
tone: str = "professional",
) -> Dict[str, Any]:
"""
Generate a cover letter with additional company-specific customization.
Args:
user_id: User identifier
job_description: Job posting description
company_info: Additional information about the company
tone: Tone for the cover letter
Returns:
Dict with customized cover letter
"""
try:
# Enhance job description with company info
enhanced_description = (
f"{job_description}\n\nCompany Information:\n{company_info}"
)
# Generate the cover letter
result = self.generate(user_id, enhanced_description, tone)
if result.get("success"):
result["customization"] = "Company-specific information included"
return result
except Exception as e:
return {
"success": False,
"message": f"Error generating customized cover letter: {str(e)}",
}
def _estimate_reading_time(self, word_count: int) -> str:
"""Estimate reading time based on word count (average 200 words per minute)."""
if word_count == 0:
return "0 minutes"
minutes = max(1, round(word_count / 200))
if minutes == 1:
return "1 minute"
else:
return f"{minutes} minutes"
def _get_cover_letter_tips(self, tone: str) -> list[str]:
"""Get tone-specific tips for cover letters."""
tips_by_tone = {
"professional": [
"Keep it concise and focused on achievements",
"Use formal language and proper business format",
"Highlight quantifiable results when possible",
],
"casual": [
"Show personality while remaining respectful",
"Use conversational language but avoid slang",
"Focus on cultural fit and team collaboration",
],
"enthusiastic": [
"Express genuine excitement for the role",
"Use energetic language and positive adjectives",
"Show passion for the company's mission",
],
"formal": [
"Follow strict business letter format",
"Use traditional and respectful language",
"Emphasize credentials and qualifications",
],
}
return tips_by_tone.get(
tone, ["Tailor the letter to the specific job and company"]
)
def get_cover_letter_template(self, tone: str = "professional") -> Dict[str, Any]:
"""
Get a basic cover letter template for the specified tone.
Args:
tone: Desired tone for the template
Returns:
Dict with template structure and guidelines
"""
templates = {
"professional": {
"structure": [
"Header with your contact information",
"Date and employer contact information",
"Professional greeting",
"Opening paragraph: Position and brief introduction",
"Body paragraph 1: Relevant experience and skills",
"Body paragraph 2: Achievements and value proposition",
"Closing paragraph: Next steps and gratitude",
"Professional closing",
],
"sample_opening": "I am writing to express my strong interest in the [Position Title] role at [Company Name].",
"sample_closing": "I would welcome the opportunity to discuss how my experience can contribute to your team's success.",
},
"enthusiastic": {
"structure": [
"Energetic opening that shows excitement",
"Passionate description of relevant experience",
"Connection to company mission and values",
"Enthusiastic closing with call to action",
],
"sample_opening": "I am thrilled to apply for the [Position Title] position at [Company Name]!",
"sample_closing": "I can't wait to bring my passion and skills to your amazing team!",
},
}
return {
"success": True,
"tone": tone,
"template": templates.get(tone, templates["professional"]),
"tips": self._get_cover_letter_tips(tone),
}
|