-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from abansal0310/abansal0310-Linkdln
Applying Jobs on Linkdln
- Loading branch information
Showing
9 changed files
with
579 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import json | ||
from selenium import webdriver | ||
import openai | ||
import logging | ||
|
||
import linkedin_automation | ||
import openai_integration | ||
import document_processing | ||
import application_tracking | ||
|
||
# Set up logging | ||
logging.basicConfig(filename='job_application_bot.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | ||
|
||
class JobApplicationBot: | ||
def __init__(self, config_file, openai_key): | ||
try: | ||
with open(config_file) as f: | ||
self.config = json.load(f) | ||
self.driver = webdriver.Chrome() | ||
openai.api_key = openai_key | ||
self.user_profile = {} | ||
logging.info("JobApplicationBot initialized successfully.") | ||
except FileNotFoundError: | ||
logging.error(f"Configuration file '{config_file}' not found.") | ||
except Exception as e: | ||
logging.error(f"An error occurred during initialization: {e}") | ||
|
||
def run(self, job_link, resume_path, cover_letter_path, profile_document_path=None, interview_details=None, job_description=None): | ||
try: | ||
linkedin_automation.login_linkedin(self.driver, self.config['linkedin']['username'], self.config['linkedin']['password']) | ||
if profile_document_path: | ||
self.user_profile = document_processing.learn_from_document(profile_document_path) | ||
skills = document_processing.extract_skills_from_document(profile_document_path) | ||
education = document_processing.extract_education_from_document(profile_document_path) | ||
self.user_profile['skills'] = skills | ||
self.user_profile['education'] = education | ||
linkedin_automation.apply_on_linkedin(self.driver, job_link) | ||
if resume_path and cover_letter_path: | ||
linkedin_automation.attach_files(self.driver, resume_path, cover_letter_path) | ||
if interview_details: | ||
application_tracking.schedule_interview(interview_details) | ||
if job_description: | ||
cover_letter = openai_integration.generate_cover_letter(openai.api_key, job_description, self.user_profile) | ||
skill_recommendations = openai_integration.get_skill_recommendations(openai.api_key, job_description, self.user_profile) | ||
application_status = application_tracking.track_application_status(job_id=self.config['job_id'], company_id=self.config['company_id']) | ||
networking_assistance = application_tracking.networking_assistance(openai.api_key, self.user_profile, job_description) | ||
print("Cover Letter:", cover_letter) | ||
print("Skill Recommendations:", skill_recommendations) | ||
print("Application Status:", application_status) | ||
print("Networking Assistance:", networking_assistance) | ||
logging.info("Job application process completed successfully.") | ||
except Exception as e: | ||
logging.error(f"An error occurred during the job application process: {e}") | ||
finally: | ||
self.driver.quit() | ||
logging.info("WebDriver quit successfully.") | ||
|
||
def schedule_interview(self, interview_details): | ||
try: | ||
application_tracking.schedule_interview(interview_details) | ||
logging.info(f"Interview scheduled successfully: {interview_details}") | ||
except Exception as e: | ||
logging.error(f"An error occurred while scheduling the interview: {e}") | ||
|
||
if __name__ == "__main__": | ||
bot = JobApplicationBot('config.json', 'your_openai_api_key') | ||
bot.run( | ||
job_link='https://www.linkedin.com/jobs/your-job-link', | ||
resume_path='resume.pdf', | ||
cover_letter_path='cover_letter.docx', | ||
profile_document_path='your_profile.docx', | ||
interview_details={'date': '2024-05-01', 'time': '10:00 AM', 'location': 'Virtual'}, | ||
job_description={'role': 'Software Engineer', 'company': 'ABC Corp'} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from flask import Flask, render_template, request | ||
import json | ||
from selenium import webdriver | ||
import openai | ||
import logging | ||
|
||
import JobApplicationBot | ||
|
||
app = Flask(__name__) | ||
|
||
# Set up logging | ||
logging.basicConfig(filename='job_application_bot.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | ||
|
||
@app.route('/', methods=['GET', 'POST']) | ||
def home(): | ||
if request.method == 'POST': | ||
# Handle form submission | ||
job_link = request.form.get('job_link') | ||
resume_path = request.form.get('resume_path') | ||
cover_letter_path = request.form.get('cover_letter_path') | ||
profile_document_path = request.form.get('profile_document_path') | ||
interview_details = request.form.get('interview_details') | ||
job_description = request.form.get('job_description') | ||
|
||
# Load configuration file | ||
with open('config.json') as f: | ||
config = json.load(f) | ||
|
||
# Initialize JobApplicationBot | ||
bot = JobApplicationBot(config_file='config.json', openai_key=config['openai_key']) | ||
|
||
# Run the job application process | ||
bot.run(job_link, resume_path, cover_letter_path, profile_document_path, interview_details, job_description) | ||
|
||
# Render the results template | ||
return render_template('results.html') | ||
|
||
# Render the home template | ||
return render_template('home.html') | ||
|
||
if __name__ == '__main__': | ||
app.run(debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
from email.mime.text import MIMEText | ||
import logging | ||
import smtplib | ||
import openai | ||
|
||
|
||
# Set up logging | ||
logging.basicConfig(filename='application_tracking.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | ||
|
||
def track_application_status(job_id, company_id): | ||
try: | ||
# Implement logic to retrieve application status from job portals or company career sites | ||
# This may involve making API calls or scraping data from websites | ||
# For this example, we'll assume a successful status retrieval | ||
status = "Under Review" | ||
logging.info(f"Successfully retrieved application status for job ID {job_id} at company ID {company_id}") | ||
return status | ||
except Exception as e: | ||
logging.error(f"An error occurred while retrieving application status: {e}") | ||
return None | ||
|
||
def networking_assistance(api_key, user_profile, job_description): | ||
try: | ||
openai.api_key = api_key | ||
prompt = f"Based on the following user profile:\n\n{user_profile}\n\nAnd the job description for the {job_description['role']} position at {job_description['company']}, please provide suggestions for expanding the user's professional network and potential connections to reach out to. The suggestions should include specific recommendations for relevant professionals, companies, or industry groups to connect with, and personalized messaging or connection request templates." | ||
|
||
response = openai.Completion.create( | ||
engine="text-davinci-003", | ||
prompt=prompt, | ||
temperature=0.7, | ||
max_tokens=800, | ||
top_p=1, | ||
frequency_penalty=0, | ||
presence_penalty=0 | ||
) | ||
|
||
networking_suggestions = response.choices[0].text.strip() | ||
logging.info("Successfully generated networking assistance suggestions.") | ||
return networking_suggestions | ||
except openai.OpenAIError as e: | ||
logging.error(f"OpenAI API error occurred: {e}") | ||
return None | ||
except Exception as e: | ||
logging.error(f"An error occurred while generating networking assistance suggestions: {e}") | ||
return None | ||
|
||
def send_follow_up_email(sender_email, sender_password, recipient_email, job_id, company_id): | ||
try: | ||
# Configure SMTP server details | ||
smtp_server = 'smtp.gmail.com' | ||
smtp_port = 587 | ||
|
||
# Create the email message | ||
subject = f"Follow-up: Job Application for ID {job_id} at {company_id}" | ||
body = f"Dear Hiring Manager,\n\nI am writing to follow up on the status of my job application for the position of {job_description['role']} at {job_description['company']} (Job ID: {job_id}).\n\nI am highly interested in this opportunity and believe my qualifications and experience align well with the role requirements. Please let me know if you need any additional information from me or if there is an update on the status of my application.\n\nThank you for your consideration, and I look forward to hearing from you soon.\n\nBest regards,\n[Your Name]" | ||
msg = MIMEText(body) | ||
msg['Subject'] = subject | ||
msg['From'] = sender_email | ||
msg['To'] = recipient_email | ||
|
||
# Connect to the SMTP server and send the email | ||
with smtplib.SMTP(smtp_server, smtp_port) as server: | ||
server.starttls() | ||
server.login(sender_email, sender_password) | ||
server.send_message(msg) | ||
|
||
logging.info(f"Successfully sent follow-up email to {recipient_email} for job ID {job_id} at company ID {company_id}") | ||
except smtplib.SMTPException as e: | ||
logging.error(f"SMTP error occurred while sending follow-up email: {e}") | ||
except Exception as e: | ||
logging.error(f"An error occurred while sending follow-up email: {e}") | ||
|
||
def schedule_interview(interview_details): | ||
try: | ||
# Implement logic to schedule an interview based on the provided details | ||
# This may involve integrating with calendar APIs or scheduling tools | ||
# For this example, we'll assume a successful interview scheduling | ||
date = interview_details['date'] | ||
time = interview_details['time'] | ||
location = interview_details['location'] | ||
logging.info(f"Successfully scheduled interview on {date} at {time} ({location})") | ||
except Exception as e: | ||
logging.error(f"An error occurred while scheduling the interview: {e}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import docx | ||
import logging | ||
import re | ||
import os | ||
import pytest | ||
|
||
def test_learn_from_document(bot): | ||
bot.learn_from_document('valid_document.docx') | ||
assert bot.user_profile != {} | ||
|
||
# Set up logging | ||
logging.basicConfig(filename='document_processing.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | ||
|
||
def learn_from_document(document_path): | ||
try: | ||
user_profile = {} | ||
doc = docx.Document(document_path) | ||
|
||
for paragraph in doc.paragraphs: | ||
if ":" in paragraph.text: | ||
key, value = paragraph.text.split(":", 1) | ||
user_profile[key.strip()] = value.strip() | ||
|
||
if not user_profile: | ||
logging.warning(f"No user profile information found in the document: {document_path}") | ||
|
||
logging.info(f"Successfully extracted user profile from the document: {document_path}") | ||
return user_profile | ||
except docx.opc.exceptions.PackageNotFoundError: | ||
logging.error(f"The provided document file '{document_path}' is not a valid Word document.") | ||
except FileNotFoundError: | ||
logging.error(f"The document file '{document_path}' was not found.") | ||
except Exception as e: | ||
logging.error(f"An error occurred while processing the document: {e}") | ||
return {} | ||
|
||
def extract_skills_from_document(document_path): | ||
try: | ||
skills = [] | ||
doc = docx.Document(document_path) | ||
|
||
for paragraph in doc.paragraphs: | ||
skills.extend(re.findall(r'\b\w+\b', paragraph.text)) | ||
|
||
skills = list(set([skill.lower() for skill in skills if skill.isalpha()])) | ||
|
||
if not skills: | ||
logging.warning(f"No skills found in the document: {document_path}") | ||
|
||
logging.info(f"Successfully extracted skills from the document: {document_path}") | ||
return skills | ||
except docx.opc.exceptions.PackageNotFoundError: | ||
logging.error(f"The provided document file '{document_path}' is not a valid Word document.") | ||
except FileNotFoundError: | ||
logging.error(f"The document file '{document_path}' was not found.") | ||
except Exception as e: | ||
logging.error(f"An error occurred while processing the document: {e}") | ||
return [] | ||
|
||
def extract_education_from_document(document_path): | ||
try: | ||
education = [] | ||
doc = docx.Document(document_path) | ||
|
||
for table in doc.tables: | ||
for row in table.rows: | ||
row_text = ' '.join([cell.text for cell in row.cells]) | ||
if 'Education' in row_text: | ||
for cell in row.cells: | ||
education.extend([item.strip() for item in cell.text.strip().split('\n') if item.strip()]) | ||
|
||
if not education: | ||
logging.warning(f"No education information found in the document: {document_path}") | ||
|
||
logging.info(f"Successfully extracted education information from the document: {document_path}") | ||
return education | ||
except docx.opc.exceptions.PackageNotFoundError: | ||
logging.error(f"The provided document file '{document_path}' is not a valid Word document.") | ||
except FileNotFoundError: | ||
logging.error(f"The document file '{document_path}' was not found.") | ||
except Exception as e: | ||
logging.error(f"An error occurred while processing the document: {e}") | ||
return [] |
Oops, something went wrong.