import gradio as gr import cohere import os from docx import Document as DocxDocument from docx.shared import Pt from docx.enum.text import WD_PARAGRAPH_ALIGNMENT import pypandoc from datetime import datetime import fitz # PyMuPDF from docx import Document import zipfile # Get the API key from environment variables cohere_api_key = os.getenv('COHERE_API_KEY') if not cohere_api_key: raise ValueError("Please set the COHERE_API_KEY environment variable") # Initialize Cohere client with your API key co = cohere.Client(cohere_api_key) def extract_text_from_file(file_path): if file_path.endswith('.docx'): doc = DocxDocument(file_path) return '\n'.join([para.text for para in doc.paragraphs]) elif file_path.endswith('.pdf'): text = "" with fitz.open(file_path) as pdf_doc: for page in pdf_doc: text += page.get_text() return text else: return "" def extract_text_from_zip(zip_path): extracted_text = "" with zipfile.ZipFile(zip_path, 'r') as zip_ref: zip_ref.extractall('/tmp/certificates') for file_name in zip_ref.namelist(): file_path = os.path.join('/tmp/certificates', file_name) extracted_text += extract_text_from_file(file_path) + "\n" return extracted_text def generate_body(job_description, language, cv_text=None, certificates_text=None): model = 'command-xlarge-nightly' cv_text = f"Here is the candidate's CV:\n{cv_text}\n" if cv_text else "" certificates_text = f"Here are the candidate's certificates:\n{certificates_text}\n" if certificates_text else "" prompt = f"{cv_text}{certificates_text}Write a professional job application letter in {language} without a greeting. Only generate the body text based on this job description:\n{job_description}" response = co.generate( model=model, prompt=prompt, max_tokens=250, temperature=0.7, ) return response.generations[0].text.strip() def evaluate_match(job_description, cv_text, language): prompt = f"Evaluate how well the following resume matches the job description:\n\nJob Description:\n{job_description}\n\nResume:\n{cv_text}\n\nProvide a summary of the strengths and weaknesses, and a match score between 0 and 100, in {language}." response = co.generate( model='command-xlarge-nightly', prompt=prompt, max_tokens=150, temperature=0.7, ) return response.generations[0].text.strip() def create_application_letter(name, sender_street, sender_zip, sender_city, email, phone, job_position, employer_name, employer_street, employer_zip, employer_city, greeting_option, employer_contact_name, job_id, start_date, job_description, language, output_format, cv_file=None, certificates_file=None): cv_text = extract_text_from_file(cv_file) if cv_file else None certificates_text = extract_text_from_zip(certificates_file) if certificates_file else "" body = generate_body(job_description, language, cv_text=cv_text, certificates_text=certificates_text) doc = Document() header = doc.sections[0].header header_paragraph = header.paragraphs[0] header_paragraph.text = f"{name} | {sender_street}, {sender_zip} {sender_city} | {email} | {phone}" header_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT for run in header_paragraph.runs: run.font.size = Pt(10) doc.add_paragraph(f"{employer_name}\n{employer_contact_name if greeting_option == 'Known' else ''}\n{employer_street}\n{employer_zip} {employer_city}") current_date = datetime.now().strftime('%d.%m.%Y') paragraph = doc.add_paragraph() paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT run = paragraph.add_run(f"{employer_city}, {current_date}") run.font.size = Pt(11) doc.add_paragraph(f"Bewerbung als {job_position}\nKennnummer {job_id}\n", style='Heading 2') if language == "German": if greeting_option == "Known" and employer_contact_name: doc.add_paragraph(f"Sehr geehrter Herr {employer_contact_name},\n") else: doc.add_paragraph("Sehr geehrte Damen und Herren,\n") else: if greeting_option == "Known" and employer_contact_name: doc.add_paragraph(f"Dear {employer_contact_name},\n") else: doc.add_paragraph("Dear Sir/Madam,\n") doc.add_paragraph(body) closing_text = ( f"\nIch unterstütze Ihr Team gerne ab dem {start_date} und freue mich über die Einladung zu einem persönlichen Vorstellungsgespräch." if language == "German" else f"\nI am eager to join your team starting on {start_date} and look forward to the opportunity to discuss my application further." ) doc.add_paragraph(closing_text) doc.add_paragraph("\nMit freundlichen Grüßen,\n\n" if language == "German" else "\nSincerely,\n\n") doc.add_paragraph(f"{name}\n") for paragraph in doc.paragraphs: for run in paragraph.runs: run.font.size = Pt(11) output_filename_docx = f'{name}_application_letter.docx' doc.save(output_filename_docx) if output_format == "PDF": output_filename_pdf = f'{name}_application_letter.pdf' pypandoc.convert_file(output_filename_docx, 'pdf', outputfile=output_filename_pdf) os.remove(output_filename_docx) return output_filename_pdf else: return output_filename_docx def generate_and_download(name, sender_street, sender_zip, sender_city, email, phone, job_position, employer_name, employer_street, employer_zip, employer_city, greeting_option, employer_contact_name, job_id, start_date, job_description, language, output_format, cv_file, certificates_file, perform_evaluation): # Generate application letter output_filename = create_application_letter(name, sender_street, sender_zip, sender_city, email, phone, job_position, employer_name, employer_street, employer_zip, employer_city, greeting_option, employer_contact_name, job_id, start_date, job_description, language, output_format, cv_file=cv_file, certificates_file=certificates_file) # Perform evaluation if requested evaluation_result = "" if perform_evaluation and cv_file: cv_text = extract_text_from_file(cv_file) evaluation_result = evaluate_match(job_description, cv_text, language) return output_filename, evaluation_result description = """ # Professional Job Application Letter Generator Welcome to the ultimate tool for crafting professional job application letters with ease. This tool leverages the power of **Cohere**, a state-of-the-art language model, to automatically generate a tailored application letter body based on the job description you provide. You can optionally upload your CV in DOCX or PDF format and upload your certificates as a zip file to help generate a more personalized application letter. You can also choose to have an evaluation of how well your resume matches the job description. Simply fill in the required details, and within seconds, you'll have a beautifully formatted job application letter ready to download in either DOCX or PDF format. Start your journey to your next career opportunity with a compelling application letter generated just for you! """ with gr.Blocks() as demo: gr.Markdown(description) with gr.Row(): with gr.Column(): sender_name = gr.Textbox(label="Sender Name", placeholder="Enter your full name", value="Maximilian Müller") sender_street = gr.Textbox(label="Sender Street", placeholder="Enter your street address", value="Beispielstraße 42") sender_zip = gr.Textbox(label="Sender Postal Code", placeholder="Enter your postal code", value="10115") sender_city = gr.Textbox(label="Sender City", placeholder="Enter your city", value="Berlin") sender_email = gr.Textbox(label="Sender Email", placeholder="Enter your email", value="max.mueller@example.com") sender_phone = gr.Textbox(label="Sender Phone", placeholder="Enter your phone number", value="+49 170 1234567") certificates_file = gr.File(label="Upload Certificates (optional, as .zip)", type="filepath", file_types=[".zip"]) with gr.Column(): job_position = gr.Textbox(label="Job Position", placeholder="Enter the job position", value="Softwareentwickler") job_id = gr.Textbox(label="Job ID", placeholder="Enter the job ID", value="DEV-2024-01") start_date = gr.Textbox(label="Start Date", placeholder="Enter the start date (e.g., 15.05.2020)", value="01.09.2024") job_description = gr.Textbox(label="Job Description", placeholder="Paste the job description here", lines=11.5, value="We are seeking a dedicated Software Developer to join our team in creating innovative applications. Experience in Python and Java, as well as knowledge of agile methodologies, is required.") language = gr.Dropdown(choices=["English", "German"], label="Select Language", value="German") output_format = gr.Dropdown(choices=["DOCX", "PDF"], label="Select Output Format", value="DOCX") perform_evaluation = gr.Checkbox(label="Evaluate Resume Against Job Description (Optional)", value=False) with gr.Column(): employer_name = gr.Textbox(label="Employer Name", placeholder="Enter the employer's name", value="Tech Innovations GmbH") employer_street = gr.Textbox(label="Employer Street", placeholder="Enter the employer's street address", value="Innovationsstraße 1") employer_zip = gr.Textbox(label="Employer Postal Code", placeholder="Enter the employer's postal code", value="10115") employer_city = gr.Textbox(label="Employer City", placeholder="Enter the employer's city", value="Berlin") greeting_option = gr.Dropdown(choices=["Known", "Unknown"], label="Is the recipient's name known?", value="Known") employer_contact_name = gr.Textbox(label="Employer Contact Name", placeholder="Enter the contact person's name (if known)", value="Herr Dr. Felix Schmidt", visible=True) cv_file = gr.File(label="Upload CV (optional)", type="filepath", file_types=[".docx", ".pdf"]) generate_button = gr.Button("Generate Application Letter") output_letter = gr.File(label="Download your application letter") evaluation_output = gr.Textbox(label="Evaluation Result", placeholder="The evaluation will be displayed here...", lines=7) generate_button.click(generate_and_download, inputs=[sender_name, sender_street, sender_zip, sender_city, sender_email, sender_phone, job_position, employer_name, employer_street, employer_zip, employer_city, greeting_option, employer_contact_name, job_id, start_date, job_description, language, output_format, cv_file, certificates_file, perform_evaluation], outputs=[output_letter, evaluation_output]) demo.launch(debug=True)