File size: 10,715 Bytes
9350b9e
 
 
61125c4
 
 
 
 
 
 
 
 
9350b9e
61125c4
 
 
9350b9e
 
 
61125c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9350b9e
 
 
 
 
 
 
 
 
 
 
 
61125c4
9350b9e
 
61125c4
 
 
 
9350b9e
 
 
 
 
 
 
 
61125c4
 
 
9350b9e
 
 
98c7a78
9350b9e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61125c4
 
 
9350b9e
 
61125c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9350b9e
6b96986
 
 
61125c4
9350b9e
 
61125c4
 
 
 
 
6b96986
61125c4
6b96986
9350b9e
 
 
 
 
61125c4
9350b9e
 
 
61125c4
9350b9e
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
import openai
import gradio as gr
from PyPDF2 import PdfReader
from azure.storage.blob import BlobServiceClient
import io
from PyPDF2 import PdfReader
import json
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import os

os_connection_string = os.getenv("CONNECTION")
os_mail_password = os.getenv("MAIL_PASSWORD")

with open("sys_prompt.txt") as f:
    sys_prompt = f.read()

get_window_url_params = """
    function(job, job_params) {
        console.log(job, job_params);
        const params = new URLSearchParams(window.location.search);
        job_params = Object.fromEntries(params);
        return [job, job_params];
        }
    """

def download_and_parse_json_blob(storage_connection_string, container_name, blob_name, encoding='utf-8'):
    try:
        # Verbindung zum Blob-Dienst herstellen
        blob_service_client = BlobServiceClient.from_connection_string(storage_connection_string)

        # Container und Blob-Client erstellen
        container_client = blob_service_client.get_container_client(container_name)
        blob_client = container_client.get_blob_client(blob_name)

        # Blob herunterladen
        blob_data = blob_client.download_blob()
        blob_bytes = blob_data.readall()

        # JSON-Bytes in einen Python-Datenobjekt umwandeln
        json_text = blob_bytes.decode(encoding)
        json_data = json.loads(json_text)

        # Parameter "title" und "email" aus dem JSON-Datenobjekt extrahieren und zurückgeben
        title = json_data.get("title", "")
        email = json_data.get("email", "")

        return title, email
    except Exception as e:
        print(f"Fehler beim Herunterladen und Verarbeiten der JSON-Datei: {str(e)}")
        return None, None

def download_pdf_blob_as_text(storage_connection_string, container_name, blob_name):
    try:
        # Verbindung zum Blob-Dienst herstellen
        blob_service_client = BlobServiceClient.from_connection_string(storage_connection_string)

        # Container und Blob-Client erstellen
        container_client = blob_service_client.get_container_client(container_name)
        blob_client = container_client.get_blob_client(blob_name)

        # Blob herunterladen und als Binärdaten speichern
        blob_data = blob_client.download_blob()
        pdf_bytes = blob_data.readall()

        # PDF-Text extrahieren
        pdf_text = ""
        pdf_reader = PdfReader(io.BytesIO(pdf_bytes))
        for page_num in range(len(pdf_reader.pages)):
            page = pdf_reader.pages[page_num]
            pdf_text += page.extract_text()

        return pdf_text
    except Exception as e:
        print(f"Fehler beim Herunterladen und Konvertieren der Datei: {str(e)}")
        return None

def load_job_data(job, job_params):
    if not job:
        try:
            print("Hello there")
            print(job_params["job"])
            pdf_filename = job_params["job"]+".pdf"
            json_filename = job_params["job"]+"_jsondata.json" 
            storage_connection_string = os_connection_string
            container_name = "jobdescriptions"  # Der Name des Blob-Containers
            job = download_pdf_blob_as_text(storage_connection_string, container_name, pdf_filename)
            job_params = download_and_parse_json_blob(storage_connection_string,container_name,json_filename)
            return job, job_params, gr.Label.update("Evaluation for the job: "+job_params[0])
        except:
            gr.Error("An error occurred, the job description could not be loaded. Please contact the recruiter.")
            return job, job_params, gr.Label.update("An error occurred and the job description could not be loaded. Please contact the recruiter.", color="red") 
        # print(job)
        # print(job_params)


def add_file(file, chat, job, resume):
    if file.name.endswith(".pdf"):
        doc = PdfReader(file.name)
        text = ""
        for page in doc.pages:
            text += page.extract_text()
    else:
        with open(file.name) as f:
            text = f.read()

    if job:
        print("im cv")
        chat += [["📄 " + file.name.split("/")[-1], None]]
        resume = text
    # else:
    #     print("im job")
    #     chat += [["📄 " + file.name.split("/")[-1], "Thanks. Please upload the resume."]]
    #     job = text

    return chat, job, resume


def user(message, history):
    return "", history + [[message, None]]


def bot(history, job, resume, job_params):

    if not resume or not job:
        yield history
        return

    system = sys_prompt.format(job=job, resume=resume, n=2)
    messages = [{"role": "system", "content": system}]
    for user, assistant in history:
        if user:
            messages.append({"role": "user", "content": user})
        if assistant:
            messages.append({"role": "assistant", "content": assistant})

    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=messages,
        temperature=0.0,
        stream=True,
    )

    history[-1][1] = ""
    for chunk in response:
        if len(chunk["choices"][0]["delta"]) != 0:
            history[-1][1] = history[-1][1] + chunk["choices"][0]["delta"]["content"]
            yield history
    if history[-1][1] == "Thank you for conducting the evaluation! We will get back to you shortly.":
        print("finished")
        send_evaluation(history, job, resume, job_params)
    return

def send_evaluation(history, job, resume, job_params):

    # Chatverlauf in einen Textstring umwandeln
    chat_text = ""
    for entry in history:
        if entry[0]:
            chat_text += "Applicant: " + entry[0] + "\n"
        if entry[1]:
            chat_text += "Chatbot: " + entry[1] + "\n"

    # Einstellungen für den SMTP-Server
    smtp_server = "smtp.gmail.com"
    smtp_port = 587
    smtp_username = "[email protected]"
    smtp_password = os_mail_password

    # Sender- und Empfänger-E-Mail-Adressen
    sender_email = "[email protected]"
    receiver_email = job_params[1]

    ai_summary = "TEST Summary"
    prompt = "You are a professional recruiter who has been given a CV and a job description and has created 10 questions based on that. The eventual applicant has entered his answers to the questions. Now you have to evaluate on the basis of the answers if the applicant fits the job in principle. This is the case when about 70percent of all questions have been answered satisfactorily and positively. Keep in mind that an answer must always be fact-based, so if, for example, the question asks for examples, the potential applicant must also give such examples. Please also provide details of which questions were answered positively and why."
    res = openai.ChatCompletion.create(
            model="gpt-4",
            temperature=0.2,
            messages=[
                {
                    "role": "system",
                    "content": prompt,
                },
                {"role": "system", "content": "Job description: "+job+"; Resume: "+resume},
                {"role": "system", "content": "Chathistory: "+chat_text},
            ],
    )   
    ai_summary = res.choices[0]["message"]["content"]
    # E-Mail-Nachricht erstellen
    subject = "Evaluation for the job: "+job_params[0] 
    message = f"""
Dear Recruiter,

Please find attached the complete chat history for this evaluation and resume.

The evaluation AI-supported summarized:

{ai_summary}

Sincerely,
Your Evaluation Tool
"""

    msg = MIMEMultipart()
    msg['From'] = sender_email
    msg['To'] = receiver_email
    msg['Subject'] = subject
    msg.attach(MIMEText(message, 'plain'))

    # Chatverlauf in eine Textdatei schreiben
    chat_file_path = "chat_history.txt"
    with open(chat_file_path, 'w', encoding='utf-8') as chat_file:
        chat_file.write(chat_text)

    # Chatverlauf als Anhang hinzufügen
    with open(chat_file_path, 'r', encoding='utf-8') as chat_file:
        chat_attachment = MIMEText(chat_file.read(), _subtype='plain')
        chat_attachment.add_header('Content-Disposition', 'attachment', filename='chat_history.txt')
        msg.attach(chat_attachment)

    # Resume-Bytes in eine TXT-Datei schreiben und als Anhang hinzufügen
    resume_file = io.BytesIO()
    resume_file.write(resume.encode('utf-8'))
    resume_file.seek(0)
    resume_attachment = MIMEText(resume_file.read().decode('utf-8'), _subtype='plain')
    resume_attachment.add_header('Content-Disposition', 'attachment', filename='resume.txt')
    msg.attach(resume_attachment)

    # SMTP-Verbindung herstellen und E-Mail senden
    try:
        server = smtplib.SMTP(smtp_server, smtp_port)
        server.starttls()
        server.login(smtp_username, smtp_password)
        text = msg.as_string()
        server.sendmail(sender_email, receiver_email, text)
        server.quit()
        print("E-Mail wurde erfolgreich gesendet.")
    except Exception as e:
        print("Fehler beim Senden der E-Mail:", str(e))

css = "footer {visibility: hidden} #component-0{height: 90vh !important} #chatbot{height: 85vh !important}}"

with gr.Blocks(css=css) as app:
    job_params = gr.JSON({}, visible=False, label="URL Params")
    job = gr.State("")
    resume = gr.State("")
    gr.Markdown(
        f"<div style='display: flex; justify-content: space-between;align-items: center;margin-bottom: 1rem' ><h1>CV Evaluation</h1><img width='150' src='https://www.workgenius.com/wp-content/uploads/2023/03/WorkGenius_navy-1.svg' alt='WorkGeniusLogo' /></div>"
    )
    input_test = gr.Label("An error occurred and the job description could not be loaded. Please contact the recruiter.", show_label=False)
    app.load(load_job_data,[job, job_params], [job, job_params, input_test], _js=get_window_url_params)
    chat = gr.Chatbot(
        [[None, "Please upload your resume to begin the evaluation process. After uploading, approximately 10 questions will be asked to determine if the position is a good fit for you. The entire process takes about 10 to 15 minutes."]], height=600, elem_id="chatbot"
    )
    with gr.Row():
        clr = gr.Button("Clear", scale=0)
        msg = gr.Textbox(lines=1, show_label=False, scale=1)
        file = gr.UploadButton("Browse", file_types=[".pdf", ".txt"], scale=0)
    msg.submit(user, [msg, chat], [msg, chat], queue=False).then(
        bot, [chat, job, resume, job_params], chat
    )
    file.upload(
        add_file, [file, chat, job, resume], [chat, job, resume], queue=False
    ).then(bot, [chat, job, resume, job_params], chat)
    clr.click(lambda: None, None, chat, queue=False)

app.queue()
app.launch()