From 628fd55201f5c3ce55df8c6141639add73c0ea1e Mon Sep 17 00:00:00 2001 From: Joseph Adediji Date: Wed, 28 Aug 2024 22:20:24 +0100 Subject: [PATCH 1/4] docs: update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f649bbc..82b17e8 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ LinkedIn_AIHawk steps in as a game-changing solution to these challenges. It's n ## Installation +**Please watch this video to set up your LinkedIn_AIHawk: [How to set up LinkedIn_AIHawk](https://youtu.be/gdW9wogHEUM) - https://youtu.be/gdW9wogHEUM** + 1. **Download and Install Python:** Ensure you have the last Python version installed. If not, download and install it from Python's official website. For detailed instructions, refer to the tutorials: From d004ea06d5a0db1415377edd8b350bc4d7926d5e Mon Sep 17 00:00:00 2001 From: Joseph Adediji Date: Wed, 28 Aug 2024 22:21:26 +0100 Subject: [PATCH 2/4] Adjust the LLM temperature to reduce hallucinations --- src/gpt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gpt.py b/src/gpt.py index 5794cca..371c0c2 100644 --- a/src/gpt.py +++ b/src/gpt.py @@ -115,7 +115,7 @@ class LoggerChatModel: class GPTAnswerer: def __init__(self, openai_api_key): self.llm_cheap = LoggerChatModel( - ChatOpenAI(model_name="gpt-4o-mini", openai_api_key=openai_api_key, temperature=0.8) + ChatOpenAI(model_name="gpt-4o-mini", openai_api_key=openai_api_key, temperature=0.4) ) @property def job_description(self): From 1f7004696117aef9af9717ab9bbe2d1f857bcef9 Mon Sep 17 00:00:00 2001 From: 1 Date: Sat, 31 Aug 2024 17:18:18 +0300 Subject: [PATCH 3/4] Readme upd to ease troubleshooting and fixing --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3258335..15fe7b8 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ LinkedIn_AIHawk steps in as a game-changing solution to these challenges. It's n ## Installation **Please watch this video to set up your LinkedIn_AIHawk: [How to set up LinkedIn_AIHawk](https://youtu.be/gdW9wogHEUM) - https://youtu.be/gdW9wogHEUM** - +0. **Confirmed succesfull runs OSs & Python**: Python 3.10, 3.11.9(64b), 3.12.5(64b) . Windows 10, Ubuntu 22 1. **Download and Install Python:** Ensure you have the last Python version installed. If not, download and install it from Python's official website. For detailed instructions, refer to the tutorials: @@ -507,11 +507,16 @@ TODO ): ## Troubleshooting +- **Carefully read logs and output :** Most of the errors are verbosely reflected just watch the output and try to find the root couse. +- **If nothing works by unknown reason:** Use tested OS. Reboot and/or update OS. Use new clean venv. Try update Python to the tested version. - **ChromeDriver Issues:** Ensure ChromeDriver is compatible with your installed Chrome version. - **Missing Files:** Verify that all necessary files are present in the data folder. -- **Invalid YAML:** Check your YAML files for syntax errors. - - If you encounter any issues, you can open an issue on [GitHub](https://github.com/feder-cr/linkedIn_auto_jobs_applier_with_AI/issues). I'll be more than happy to assist you! +- **Invalid YAML:** Check your YAML files for syntax errors . Try to use external YAML validators e.g. https://www.yamllint.com/ +- **OpenAI endpoint isues**: Try to check possible limits\blocking at their side + +If you encounter any issues, you can open an issue on [GitHub](https://github.com/feder-cr/linkedIn_auto_jobs_applier_with_AI/issues). + Please add valuable details to the subject and to the description. If you need new feature then please reflect this. + I'll be more than happy to assist you! ## Conclusion From 6d72788f807be86635d21acb5afd96469ff24294 Mon Sep 17 00:00:00 2001 From: feder-cr <85809106+feder-cr@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:35:28 +0200 Subject: [PATCH 4/4] cover letter fixed --- .gitignore | 1 + src/linkedIn_easy_applier.py | 36 +++++++++--------------------------- src/linkedIn_job_manager.py | 12 ------------ 3 files changed, 10 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 4e73720..6d06188 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ generated_cv* .vscode chrome_profile answers.json +data* \ No newline at end of file diff --git a/src/linkedIn_easy_applier.py b/src/linkedIn_easy_applier.py index 8c95d8c..c9b9625 100644 --- a/src/linkedIn_easy_applier.py +++ b/src/linkedIn_easy_applier.py @@ -30,7 +30,6 @@ class LinkedInEasyApplier: self.resume_generator_manager = resume_generator_manager self.all_data = self._load_questions_from_json() - def _load_questions_from_json(self) -> List[dict]: output_file = 'answers.json' try: @@ -49,7 +48,6 @@ class LinkedInEasyApplier: tb_str = traceback.format_exc() raise Exception(f"Error loading questions data from JSON file: \nTraceback:\n{tb_str}") - def job_apply(self, job: Any): self.driver.get(job.link) time.sleep(random.uniform(3, 5)) @@ -91,7 +89,6 @@ class LinkedInEasyApplier: attempt += 1 raise Exception("No clickable 'Easy Apply' button found") - def _get_job_description(self) -> str: try: see_more_button = self.driver.find_element(By.XPATH, '//button[@aria-label="Click to see more description"]') @@ -107,7 +104,6 @@ class LinkedInEasyApplier: tb_str = traceback.format_exc() raise Exception(f"Error getting Job description: \nTraceback:\n{tb_str}") - def _get_job_recruiter(self): try: hiring_team_section = WebDriverWait(self.driver, 10).until( @@ -253,16 +249,12 @@ class LinkedInEasyApplier: if radios: question_text = section.text.lower() options = [radio.text.lower() for radio in radios] - existing_answer = None for item in self.all_data: if self._sanitize_text(question_text) in item['question'] and item['type'] == 'radio': existing_answer = item - break - if existing_answer: - self._select_radio(radios, existing_answer['answer']) - return True - + self._select_radio(radios, existing_answer['answer']) + return True answer = self.gpt_answerer.answer_question_from_options(question_text, options) self._save_questions_to_json({'type': 'radio', 'question': question_text, 'answer': answer}) self._select_radio(radios, answer) @@ -283,12 +275,10 @@ class LinkedInEasyApplier: answer = self.gpt_answerer.answer_question_textual_wide_range(question_text) existing_answer = None for item in self.all_data: - if item['question'] == self._sanitize_text(question_text) and item['type'] == question_type: + if 'cover' not in item['question'] and item['question'] == self._sanitize_text(question_text) and item['type'] == question_type: existing_answer = item - break - if existing_answer: - self._enter_text(text_field, existing_answer['answer']) - return True + self._enter_text(text_field, existing_answer['answer']) + return True self._save_questions_to_json({'type': question_type, 'question': question_text, 'answer': answer}) self._enter_text(text_field, answer) return True @@ -302,15 +292,12 @@ class LinkedInEasyApplier: answer_date = self.gpt_answerer.answer_question_date() answer_text = answer_date.strftime("%Y-%m-%d") - existing_answer = None for item in self.all_data: if self._sanitize_text(question_text) in item['question'] and item['type'] == 'date': existing_answer = item - break - if existing_answer: - self._enter_text(date_field, existing_answer['answer']) - return True + self._enter_text(date_field, existing_answer['answer']) + return True self._save_questions_to_json({'type': 'date', 'question': question_text, 'answer': answer_text}) self._enter_text(date_field, answer_text) @@ -325,16 +312,12 @@ class LinkedInEasyApplier: if dropdown: select = Select(dropdown) options = [option.text for option in select.options] - existing_answer = None for item in self.all_data: if self._sanitize_text(question_text) in item['question'] and item['type'] == 'dropdown': existing_answer = item - break - if existing_answer: - self._select_dropdown_option(dropdown, existing_answer['answer']) - return True - + self._select_dropdown_option(dropdown, existing_answer['answer']) + return True answer = self.gpt_answerer.answer_question_from_options(question_text, options) self._save_questions_to_json({'type': 'dropdown', 'question': question_text, 'answer': answer}) self._select_dropdown_option(dropdown, answer) @@ -385,7 +368,6 @@ class LinkedInEasyApplier: tb_str = traceback.format_exc() raise Exception(f"Error saving questions data to JSON file: \nTraceback:\n{tb_str}") - def _sanitize_text(self, text: str) -> str: sanitized_text = text.lower() sanitized_text = sanitized_text.strip() diff --git a/src/linkedIn_job_manager.py b/src/linkedIn_job_manager.py index d368d71..7a87ae5 100644 --- a/src/linkedIn_job_manager.py +++ b/src/linkedIn_job_manager.py @@ -53,18 +53,6 @@ class LinkedInJobManager: def set_resume_generator_manager(self, resume_generator_manager): self.resume_generator_manager = resume_generator_manager - """ def old_question(self): - self.set_old_answers = {} - file_path = 'data_folder/output/old_Questions.csv' - if os.path.exists(file_path): - with open(file_path, 'r', newline='', encoding='utf-8', errors='ignore') as file: - csv_reader = csv.reader(file, delimiter=',', quotechar='"') - for row in csv_reader: - if len(row) == 3: - answer_type, question_text, answer = row - self.set_old_answers[(answer_type.lower(), question_text.lower())] = answer""" - - def start_applying(self): self.easy_applier_component = LinkedInEasyApplier(self.driver, self.resume_path, self.set_old_answers, self.gpt_answerer, self.resume_generator_manager) searches = list(product(self.positions, self.locations))