| import os
|
| import logging
|
| from typing import Optional
|
| import openai
|
| import re
|
| from dotenv import load_dotenv
|
| import traceback
|
|
|
|
|
| project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| dotenv_path = os.path.join(project_root, '.env')
|
| if not load_dotenv(dotenv_path=dotenv_path) and not os.getenv("OPENAI_API"):
|
| print("Warning: .env file not found or OPENAI_API key not set directly as environment variable.")
|
| print(f"Attempted .env path: {dotenv_path}")
|
|
|
|
|
|
|
| logging.basicConfig(level=logging.INFO)
|
| logger = logging.getLogger(__name__)
|
|
|
| class CoverLetterGenerator:
|
| def __init__(self, model_name: str = "gpt-3.5-turbo"):
|
| """
|
| Initialize the CoverLetterGenerator.
|
| Ensure OPENAI_API environment variable is set.
|
| """
|
| self.api_key = os.getenv("OPENAI_API")
|
| if not self.api_key:
|
| logger.error("OPENAI_API environment variable not found.")
|
| raise ValueError("OPENAI_API key is not set.")
|
|
|
|
|
| openai.api_key = self.api_key
|
|
|
|
|
|
|
| self.model_name = model_name
|
| logger.info(f"CoverLetterGenerator initialized with model {model_name}.")
|
|
|
| def generate_cover_letter(
|
| self,
|
| job_description: str,
|
| cv_text: str,
|
| temperature: float = 0.7,
|
| max_tokens: int = 800
|
| ) -> Optional[str]:
|
| try:
|
| if not job_description or not cv_text:
|
| logger.error("Job description and CV text must not be empty.")
|
| return None
|
|
|
| prompt = f"""
|
| You are an expert job application assistant. Your task is to draft a concise and professional 3-paragraph cover letter.
|
| The letter should be tailored specifically to the job description provided, using relevant information from the candidate's CV.
|
| Address the letter "Dear Hiring Manager," and conclude with "Sincerely, [Your Name]".
|
| Maintain a formal tone throughout. Focus on highlighting how the candidate's skills and experience directly align with the job requirements.
|
|
|
| --- START OF CANDIDATE CV ---
|
| {cv_text}
|
| --- END OF CANDIDATE CV ---
|
|
|
| --- START OF JOB DESCRIPTION ---
|
| {job_description}
|
| --- END OF JOB DESCRIPTION ---
|
|
|
| Based on the CV and Job Description, please generate the cover letter now:
|
| Cover Letter:
|
| """
|
|
|
| logger.info(f"Sending prompt to OpenAI model {self.model_name} for cover letter generation...")
|
|
|
|
|
| response = openai.ChatCompletion.create(
|
| model=self.model_name,
|
| messages=[{"role": "user", "content": prompt}],
|
| temperature=temperature,
|
| max_tokens=max_tokens,
|
| top_p=0.95,
|
| n=1
|
| )
|
| generated_text = response["choices"][0]["message"]["content"].strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| sanitized_text = re.sub(r'[^\x00-\x7F]+', '', generated_text)
|
| sanitized_text = re.sub(r'(\r\n|\r|\n){3,}', '\n\n', sanitized_text)
|
| sanitized_text = re.sub(r'[ \t]{2,}', ' ', sanitized_text)
|
|
|
| logger.info("Cover letter generated successfully.")
|
| return sanitized_text
|
|
|
| except openai.APIError as e:
|
| logger.error(f"OpenAI API Error generating cover letter: {e}")
|
|
|
| return f"Error from OpenAI: {e}"
|
| except Exception as e:
|
| logger.error(f"Unexpected error generating cover letter: {str(e)}")
|
| traceback.print_exc()
|
| return None
|
|
|
|
|
| def main_test():
|
| logger.info("Starting CoverLetterGenerator test...")
|
| try:
|
|
|
| if not os.getenv("OPENAI_API"):
|
| print("Skipping test: OPENAI_API key not set. Please set it in your .env file.")
|
| return
|
|
|
| generator = CoverLetterGenerator()
|
|
|
| sample_job_desc = """
|
| We are seeking a motivated Software Engineer to join our dynamic team.
|
| Responsibilities include developing and maintaining web applications, collaborating with cross-functional teams,
|
| and contributing to all phases of the development lifecycle.
|
| Required skills: Proficiency in Python, experience with Django or Flask, familiarity with RESTful APIs,
|
| and strong problem-solving abilities. BSc in Computer Science or related field.
|
| """
|
|
|
| sample_cv_text = """
|
| Lauris Piziks
|
| Software Developer
|
| Highly skilled and results-oriented Software Developer with 3 years of experience in Python development,
|
| specializing in building scalable web applications using Flask and Django.
|
| Proven ability to design and implement RESTful APIs and integrate third-party services.
|
| Adept at problem-solving and working in agile environments.
|
| Education: BSc in Software Engineering.
|
| Technical Skills: Python, Flask, Django, PostgreSQL, Docker, Git, JavaScript, HTML, CSS.
|
| """
|
|
|
| print("\nGenerating cover letter for sample job and CV...")
|
| letter = generator.generate_cover_letter(sample_job_desc, sample_cv_text)
|
|
|
| if letter:
|
| print("\n--- Generated Cover Letter ---")
|
| print(letter)
|
| print("----------------------------")
|
| else:
|
| print("\n❌ Cover letter generation failed during test.")
|
|
|
| except ValueError as ve:
|
| print(f"Test Initialization Error: {ve}")
|
| except Exception as e:
|
| logger.error(f"Error in CoverLetterGenerator main_test: {str(e)}")
|
| traceback.print_exc()
|
|
|
| if __name__ == "__main__":
|
| main_test()
|
|
|