"""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), }