resumate / functions /writer_agent.py
gperdrizet's picture
Added mocking to test to avoid API calls where possible
a974c1c verified
'''Agent responsible for writing the resume based on user provided context'''
import ast
import json
import logging
import os
from openai import OpenAI
from configuration import (
INFERENCE_URL,
WRITER_INSTRUCTIONS,
WRITER_MODEL,
REPO_SELECTION_PROMPT,
PROJECTS_SECTION_PROMPT
)
# pylint: disable=broad-exception-caught
def write_resume(linkedin_resume: dict, github_repositories: list, job_call: dict) -> str:
"""
Generates a resume based on the provided content.
Args:
linkedin_resume (dict): Resume content extracted from linkedin profile.
github_repositories (dict): Information about the applicants GitHub repositories.
job_summary (dict): Extracted/summarized job call information.
Returns:
str: The generated resume.
"""
logger = logging.getLogger(f'{__name__}.write_resume')
logger.info("Selecting relevant GitHub repositories based on job call")
project_repos = _choose_repositories(github_repositories, job_call)
logger.info("Writing projects section of the resume")
projects = _write_projects_section(project_repos, job_call)
# Let the model select the most relevant repositories based on the job call
client = OpenAI(
base_url=INFERENCE_URL,
api_key=os.environ.get("API_KEY", "dummy-key-for-testing")
)
prompt = f'JOB CALL\n{job_call}\nLINKEDIN RESUME\n{linkedin_resume}\nPROJECTS\n{projects}'
messages = [
{
'role': 'system',
'content': WRITER_INSTRUCTIONS
},
{
'role': 'user',
'content': prompt
}
]
completion_args = {
'model': WRITER_MODEL,
'messages': messages,
}
try:
response = client.chat.completions.create(**completion_args)
except Exception as e:
response = None
logger.error('Error during job summarization API call: %s', e)
if response is not None:
response = response.choices[0].message.content
# Create data directory if it doesn't exist
data_dir = 'data'
if not os.path.exists(data_dir):
os.makedirs(data_dir)
logger.info("Created data directory: %s", data_dir)
# Save the resume to resume.md in the data directory
resume_file_path = os.path.join(data_dir, 'resume.md')
try:
with open(resume_file_path, 'w', encoding='utf-8') as f:
f.write(response)
logger.info("Resume saved to: %s", resume_file_path)
except Exception as e:
logger.error("Failed to save resume to file: %s", e)
return response
def _choose_repositories(github_repositories: list, job_call: dict) -> list:
"""
Choose relevant GitHub repositories based on the job call requirements.
Args:
github_repositories (dict): Information about the applicants GitHub repositories.
job_call (dict): Extracted/summarized job call information.
Returns:
list: Filtered list of relevant repositories.
"""
logger = logging.getLogger(f'{__name__}._choose_repositories')
# Create a new repo list without the full README text - this way we can save on input tokens
# by only sending the model the repo metadata, title, description, topics, etc.
repo_data = [
{k: v for k, v in d.items() if k != 'readme'}
for d in github_repositories
]
# Let the model select the most relevant repositories based on the job call
client = OpenAI(
base_url=INFERENCE_URL,
api_key=os.environ.get("API_KEY", "dummy-key-for-testing")
)
messages = [
{
'role': 'system',
'content': f'{REPO_SELECTION_PROMPT}'
},
{
'role': 'user',
'content': f'JOB CALL\n{json.dumps(job_call)}\n\nREPOSITORIES\n{json.dumps(repo_data)}'
}
]
completion_args = {
'model': WRITER_MODEL,
'messages': messages,
}
try:
response = client.chat.completions.create(**completion_args)
except Exception as e:
response = None
logger.error('Error during job summarization API call: %s', e)
if response is not None:
response = response.choices[0].message.content
response = ast.literal_eval(response)
# Now use the repository selection response to filter the repositories
selected_repos = [
repo for repo in github_repositories if repo['name'] in response
]
return selected_repos
def _write_projects_section(project_repos: list, job_call: dict) -> str:
"""
Write the projects section of the resume based on selected GitHub repositories.
Args:
project_repos (list): List of relevant GitHub repositories.
job_call (dict): Extracted/summarized job call information.
Returns:
str: Formatted projects section for the resume.
"""
logger = logging.getLogger(f'{__name__}._write_projects_section')
# Let the model select the most relevant repositories based on the job call
client = OpenAI(
base_url=INFERENCE_URL,
api_key=os.environ.get("API_KEY", "dummy-key-for-testing")
)
messages = [
{
'role': 'system',
'content': f'{PROJECTS_SECTION_PROMPT}'
},
{
'role': 'user',
'content': (f'JOB CALL\n{json.dumps(job_call)}\n\n' +
f'REPOSITORIES\n{json.dumps(project_repos)}')
}
]
completion_args = {
'model': WRITER_MODEL,
'messages': messages,
}
try:
response = client.chat.completions.create(**completion_args)
except Exception as e:
response = None
logger.error('Error during job summarization API call: %s', e)
if response is not None:
response = response.choices[0].message.content
return response