|
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 |
|
from docx import Document |
|
import zipfile |
|
|
|
|
|
cohere_api_key = os.getenv('COHERE_API_KEY') |
|
if not cohere_api_key: |
|
raise ValueError("Bitte setzen Sie die Umgebungsvariable COHERE_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"Hier ist der Lebenslauf des Kandidaten:\n{cv_text}\n" if cv_text else "" |
|
certificates_text = f"Hier sind die Zertifikate des Kandidaten:\n{certificates_text}\n" if certificates_text else "" |
|
|
|
prompt = f"{cv_text}{certificates_text}Schreiben Sie ein professionelles Bewerbungsschreiben auf {language} ohne Anrede. Erstellen Sie nur den Textkörper basierend auf dieser Stellenbeschreibung:\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"Bewerten Sie, wie gut der folgende Lebenslauf zur Stellenbeschreibung passt:\n\nStellenbeschreibung:\n{job_description}\n\nLebenslauf:\n{cv_text}\n\nGeben Sie eine Zusammenfassung der Stärken und Schwächen sowie eine Übereinstimmungsbewertung zwischen 0 und 100 ab, auf {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}_Bewerbungsschreiben.docx' |
|
doc.save(output_filename_docx) |
|
|
|
if output_format == "PDF": |
|
output_filename_pdf = f'{name}_Bewerbungsschreiben.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): |
|
|
|
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) |
|
|
|
|
|
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 = """ |
|
# Professioneller Bewerbungsschreiben-Generator |
|
|
|
Willkommen beim ultimativen Tool zum Erstellen professioneller Bewerbungsschreiben mit Leichtigkeit. Dieses Tool nutzt die Kraft von **Cohere**, einem hochmodernen Sprachmodell, um automatisch einen maßgeschneiderten Bewerbungstext basierend auf der von Ihnen bereitgestellten Stellenbeschreibung zu erstellen. |
|
|
|
Sie können optional Ihren Lebenslauf im DOCX- oder PDF-Format hochladen und Ihre Zertifikate als ZIP-Datei, um ein persönlicheres Bewerbungsschreiben zu erstellen. Sie können auch wählen, ob Sie eine Bewertung darüber erhalten möchten, wie gut Ihr Lebenslauf zur Stellenbeschreibung passt. Füllen Sie einfach die erforderlichen Felder aus und in wenigen Sekunden erhalten Sie ein wunderschön formatiertes Bewerbungsschreiben, das Sie entweder im DOCX- oder PDF-Format herunterladen können. |
|
|
|
Starten Sie Ihren Weg zu Ihrer nächsten Karrierechance mit einem überzeugenden Bewerbungsschreiben, das speziell für Sie erstellt wurde! |
|
""" |
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown(description) |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
sender_name = gr.Textbox(label="Absendername", placeholder="Geben Sie Ihren vollständigen Namen ein", value="Maximilian Müller") |
|
sender_street = gr.Textbox(label="Straße des Absenders", placeholder="Geben Sie Ihre Straßenadresse ein", value="Beispielstraße 42") |
|
sender_zip = gr.Textbox(label="PLZ des Absenders", placeholder="Geben Sie Ihre Postleitzahl ein", value="10115") |
|
sender_city = gr.Textbox(label="Stadt des Absenders", placeholder="Geben Sie Ihre Stadt ein", value="Berlin") |
|
sender_email = gr.Textbox(label="E-Mail des Absenders", placeholder="Geben Sie Ihre E-Mail-Adresse ein", value="[email protected]") |
|
sender_phone = gr.Textbox(label="Telefon des Absenders", placeholder="Geben Sie Ihre Telefonnummer ein", value="+49 170 1234567") |
|
certificates_file = gr.File(label="Zertifikate hochladen (optional, als .zip)", type="filepath", file_types=[".zip"]) |
|
|
|
with gr.Column(): |
|
job_position = gr.Textbox(label="Stellenbezeichnung", placeholder="Geben Sie die Stellenbezeichnung ein", value="Softwareentwickler") |
|
job_id = gr.Textbox(label="Job-ID", placeholder="Geben Sie die Job-ID ein", value="DEV-2024-01") |
|
start_date = gr.Textbox(label="Startdatum", placeholder="Geben Sie das Startdatum ein (z.B. 15.05.2020)", value="01.09.2024") |
|
job_description = gr.Textbox(label="Stellenbeschreibung", placeholder="Fügen Sie hier die Stellenbeschreibung ein", lines=11.5, value="Wir suchen einen engagierten Softwareentwickler, der unser Team bei der Erstellung innovativer Anwendungen unterstützt. Erfahrungen mit Python und Java sowie Kenntnisse agiler Methoden sind erforderlich.") |
|
language = gr.Dropdown(choices=["Englisch", "Deutsch"], label="Sprache auswählen", value="Deutsch") |
|
output_format = gr.Dropdown(choices=["DOCX", "PDF"], label="Ausgabeformat auswählen", value="DOCX") |
|
perform_evaluation = gr.Checkbox(label="Lebenslauf im Vergleich zur Stellenbeschreibung bewerten (optional)", value=False) |
|
|
|
with gr.Column(): |
|
employer_name = gr.Textbox(label="Arbeitgebername", placeholder="Geben Sie den Namen des Arbeitgebers ein", value="Tech Innovations GmbH") |
|
employer_street = gr.Textbox(label="Straße des Arbeitgebers", placeholder="Geben Sie die Straßenadresse des Arbeitgebers ein", value="Innovationsstraße 1") |
|
employer_zip = gr.Textbox(label="PLZ des Arbeitgebers", placeholder="Geben Sie die Postleitzahl des Arbeitgebers ein", value="10115") |
|
employer_city = gr.Textbox(label="Stadt des Arbeitgebers", placeholder="Geben Sie die Stadt des Arbeitgebers ein", value="Berlin") |
|
greeting_option = gr.Dropdown(choices=["Bekannt", "Unbekannt"], label="Ist der Name des Empfängers bekannt?", value="Bekannt") |
|
employer_contact_name = gr.Textbox(label="Name des Ansprechpartners beim Arbeitgeber", placeholder="Geben Sie den Namen des Ansprechpartners ein (falls bekannt)", value="Herr Dr. Felix Schmidt", visible=True) |
|
cv_file = gr.File(label="Lebenslauf hochladen (optional)", type="filepath", file_types=[".docx", ".pdf"]) |
|
|
|
generate_button = gr.Button("Bewerbungsschreiben erstellen") |
|
output_letter = gr.File(label="Laden Sie Ihr Bewerbungsschreiben herunter") |
|
evaluation_output = gr.Textbox(label="Bewertungsergebnis", placeholder="Die Bewertung wird hier angezeigt...", 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) |
|
|