parent
6540bbbb40
commit
b554357be9
9 changed files with 77 additions and 127 deletions
48
src/gpt.py
48
src/gpt.py
|
|
@ -6,7 +6,8 @@ import time
|
|||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Union
|
||||
from typing import Dict, List
|
||||
from typing import Union
|
||||
|
||||
import httpx
|
||||
from Levenshtein import distance
|
||||
|
|
@ -37,7 +38,7 @@ class OpenAIModel(AIModel):
|
|||
def invoke(self, prompt: str) -> str:
|
||||
print("invoke in openai")
|
||||
response = self.model.invoke(prompt)
|
||||
return response.content
|
||||
return response
|
||||
|
||||
|
||||
class ClaudeModel(AIModel):
|
||||
|
|
@ -48,7 +49,7 @@ class ClaudeModel(AIModel):
|
|||
|
||||
def invoke(self, prompt: str) -> str:
|
||||
response = self.model.invoke(prompt)
|
||||
return response.content
|
||||
return response
|
||||
|
||||
|
||||
class OllamaModel(AIModel):
|
||||
|
|
@ -58,14 +59,14 @@ class OllamaModel(AIModel):
|
|||
|
||||
def invoke(self, prompt: str) -> str:
|
||||
response = self.model.invoke(prompt)
|
||||
return response.content
|
||||
return response
|
||||
|
||||
|
||||
class AIAdapter:
|
||||
def __init__(self, config: dict, api_key: str):
|
||||
self.model = self._create_model(config, api_key)
|
||||
|
||||
def _create_model(self, config: dict, api_key: str) -> Union[OpenAIModel, OllamaModel, ClaudeModel]:
|
||||
def _create_model(self, config: dict, api_key: str) -> AIModel:
|
||||
llm_model_type = config['llm_model_type']
|
||||
llm_model = config['llm_model']
|
||||
llm_api_url = config['llm_api_url']
|
||||
|
|
@ -78,7 +79,7 @@ class AIAdapter:
|
|||
elif llm_model_type == "ollama":
|
||||
return OllamaModel(api_key, llm_model, llm_api_url)
|
||||
else:
|
||||
raise ValueError(f"Unsupported model type: {llm_model_type}")
|
||||
raise ValueError(f"Unsupported model type: {model_type}")
|
||||
|
||||
def invoke(self, prompt: str) -> str:
|
||||
return self.model.invoke(prompt)
|
||||
|
|
@ -108,34 +109,25 @@ class LLMLogger:
|
|||
logger.debug("Prompts are of type StringPromptValue")
|
||||
prompts = prompts.text
|
||||
logger.debug("Prompts converted to text: %s", prompts)
|
||||
elif isinstance(prompts, dict):
|
||||
logger.debug("Prompts are of type dict")
|
||||
elif isinstance(prompts, Dict):
|
||||
logger.debug("Prompts are of type Dict")
|
||||
try:
|
||||
if "messages" in prompts:
|
||||
logger.debug("Prompts contain 'messages' key")
|
||||
prompts = {
|
||||
f"prompt_{i + 1}": prompt["content"]
|
||||
for i, prompt in enumerate(prompts["messages"])
|
||||
}
|
||||
logger.debug("Prompts converted to dictionary: %s", prompts)
|
||||
else:
|
||||
logger.debug("Prompts dictionary does not contain 'messages' key")
|
||||
prompts = {
|
||||
f"prompt_{i + 1}": prompt.content
|
||||
for i, prompt in enumerate(prompts.messages)
|
||||
}
|
||||
logger.debug("Prompts converted to dictionary: %s", prompts)
|
||||
except Exception as e:
|
||||
logger.error("Error converting prompts to dictionary: %s", str(e))
|
||||
raise
|
||||
else:
|
||||
logger.debug("Prompts are of unknown type, attempting default conversion")
|
||||
try:
|
||||
if hasattr(prompts, "messages"):
|
||||
logger.debug("Prompts have 'messages' attribute")
|
||||
prompts = {
|
||||
f"prompt_{i + 1}": prompt.content
|
||||
for i, prompt in enumerate(prompts.messages)
|
||||
}
|
||||
logger.debug("Prompts converted to dictionary using default method: %s", prompts)
|
||||
else:
|
||||
logger.error("Prompts do not have 'messages' attribute, and default conversion failed")
|
||||
raise ValueError("Prompts structure is not supported.")
|
||||
prompts = {
|
||||
f"prompt_{i + 1}": prompt.content
|
||||
for i, prompt in enumerate(prompts.messages)
|
||||
}
|
||||
logger.debug("Prompts converted to dictionary using default method: %s", prompts)
|
||||
except Exception as e:
|
||||
logger.error("Error converting prompts using default method: %s", str(e))
|
||||
raise
|
||||
|
|
@ -299,7 +291,7 @@ class GPTAnswerer:
|
|||
|
||||
def __init__(self, config, llm_api_key):
|
||||
self.ai_adapter = AIAdapter(config, llm_api_key)
|
||||
self.llm_cheap = LoggerChatModel(self.ai_adapter.model)
|
||||
self.llm_cheap = LoggerChatModel(self.ai_adapter)
|
||||
|
||||
@property
|
||||
def job_description(self):
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ import random
|
|||
import re
|
||||
import time
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Any, Tuple, Set
|
||||
from typing import List, Optional, Any, Tuple
|
||||
|
||||
from httpx import HTTPStatusError
|
||||
from reportlab.lib.pagesizes import A4
|
||||
|
|
@ -24,13 +23,11 @@ from src.utils import logger
|
|||
|
||||
|
||||
class LinkedInEasyApplier:
|
||||
def __init__(self, driver: Any, resume_dir: Optional[str], set_old_answers: Set[Tuple[str, str, str]],
|
||||
def __init__(self, driver: Any, resume_dir: Optional[str], set_old_answers: List[Tuple[str, str, str]],
|
||||
gpt_answerer: Any, resume_generator_manager):
|
||||
logger.debug("Initializing LinkedInEasyApplier")
|
||||
if resume_dir is None or not os.path.exists(resume_dir):
|
||||
resume_dir = None
|
||||
else:
|
||||
resume_dir = Path(resume_dir)
|
||||
self.driver = driver
|
||||
self.resume_path = resume_dir
|
||||
self.set_old_answers = set_old_answers
|
||||
|
|
@ -541,19 +538,17 @@ class LinkedInEasyApplier:
|
|||
|
||||
lines = split_text_by_width(cover_letter_text, "Helvetica", 12, max_width)
|
||||
|
||||
line_height = 14
|
||||
max_lines_per_page = int(available_height // line_height)
|
||||
|
||||
for line in lines:
|
||||
text_height = text_object.getY()
|
||||
if text_height > bottom_margin:
|
||||
text_object.textLine(line)
|
||||
else:
|
||||
|
||||
if text_height - line_height < bottom_margin:
|
||||
c.drawText(text_object)
|
||||
c.showPage()
|
||||
text_object = c.beginText(50, page_height - 50)
|
||||
text_object.setFont("Helvetica", 12)
|
||||
|
||||
text_object.textLine(line)
|
||||
text_object.textLine(line)
|
||||
|
||||
c.drawText(text_object)
|
||||
c.save()
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ class LinkedInJobManager:
|
|||
def set_parameters(self, parameters):
|
||||
logger.debug("Setting parameters for LinkedInJobManager")
|
||||
self.company_blacklist = parameters.get('company_blacklist', []) or []
|
||||
self.title_blacklist = parameters.get('title_blacklist', []) or []
|
||||
self.title_blacklist = parameters.get('titleBlacklist', []) or []
|
||||
self.positions = parameters.get('positions', [])
|
||||
self.locations = parameters.get('locations', [])
|
||||
self.apply_once_at_company = parameters.get('apply_once_at_company', False)
|
||||
self.apply_once_at_company = parameters.get('applyOnceAtCompany', False)
|
||||
self.base_search_url = self.get_base_search_url(parameters)
|
||||
self.seen_jobs = []
|
||||
|
||||
|
|
@ -272,7 +272,7 @@ class LinkedInJobManager:
|
|||
logger.debug(f"Applicants text found: {applicants_text}")
|
||||
|
||||
# Extract numeric digits from the text (e.g., "70 applicants" -> "70")
|
||||
applicants_count = ''.join([char for char in str(applicants_text) if char.isdigit()])
|
||||
applicants_count = ''.join(filter(str.isdigit, applicants_text))
|
||||
logger.debug(f"Extracted applicants count: {applicants_count}")
|
||||
|
||||
if applicants_count:
|
||||
|
|
@ -370,7 +370,7 @@ class LinkedInJobManager:
|
|||
url_parts = []
|
||||
if parameters['remote']:
|
||||
url_parts.append("f_CF=f_WRA")
|
||||
experience_levels = [str(i + 1) for i, (level, v) in enumerate(parameters.get('experience_level', {}).items()) if
|
||||
experience_levels = [str(i + 1) for i, (level, v) in enumerate(parameters.get('experienceLevel', {}).items()) if
|
||||
v]
|
||||
if experience_levels:
|
||||
url_parts.append(f"f_E={','.join(experience_levels)}")
|
||||
|
|
@ -429,6 +429,7 @@ class LinkedInJobManager:
|
|||
link_seen = link in self.seen_jobs
|
||||
is_blacklisted = title_blacklisted or company_blacklisted or link_seen
|
||||
logger.debug("Job blacklisted status: %s", is_blacklisted)
|
||||
return is_blacklisted
|
||||
|
||||
return title_blacklisted or company_blacklisted or link_seen
|
||||
|
||||
|
|
|
|||
|
|
@ -179,8 +179,3 @@ def printyellow(text):
|
|||
reset = "\033[0m"
|
||||
logger.debug("Printing text in yellow: %s", text)
|
||||
print(f"{yellow}{text}{reset}")
|
||||
|
||||
|
||||
def stringWidth(text, font, font_size):
|
||||
bbox = font.getbbox(text)
|
||||
return bbox[2] - bbox[0]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue