File size: 13,413 Bytes
f6dc197
 
237ec40
 
f6dc197
 
a1372cb
 
 
9b6c07d
a1372cb
 
3bdfaef
f6dc197
bc655ed
df97380
 
 
 
 
 
 
f54a323
f6dc197
 
 
f54a323
237ec40
df97380
 
 
237ec40
f6dc197
df97380
 
f6dc197
df97380
 
 
f6dc197
a1372cb
 
 
3094c8c
237ec40
 
 
48b7712
237ec40
 
 
 
 
3094c8c
237ec40
 
a1372cb
237ec40
 
 
 
 
 
1ba9479
3bdfaef
 
 
 
 
 
 
 
 
 
 
 
 
 
1ba9479
df97380
1ba9479
 
df97380
bc655ed
 
 
3bdfaef
 
 
 
 
48b7712
3bdfaef
3094c8c
bc655ed
3bdfaef
a1372cb
 
f54a323
df97380
 
 
 
 
 
 
 
 
 
bc655ed
61deb82
 
9b6c07d
 
bc655ed
61deb82
 
 
 
bc655ed
61deb82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f54a323
a1372cb
dfa8a30
 
df97380
 
dfa8a30
 
 
3094c8c
dfa8a30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df97380
 
dfa8a30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df97380
a1372cb
df97380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1372cb
f6dc197
237ec40
f6dc197
 
 
 
 
a1372cb
f6dc197
 
f54a323
f6dc197
9b6c07d
f6dc197
bc655ed
a1372cb
f54a323
f6dc197
a1372cb
9b6c07d
bc655ed
 
 
 
 
 
 
 
 
 
9b6c07d
 
bc655ed
 
 
 
 
 
 
 
 
 
 
 
9b6c07d
bc655ed
 
 
 
9b6c07d
 
61deb82
9b6c07d
 
 
f6dc197
bc655ed
 
 
 
 
 
 
 
 
 
f6dc197
f54a323
a1372cb
f54a323
a1372cb
f6dc197
 
 
 
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
import json
import os
from concurrent.futures import ThreadPoolExecutor

import gradio as gr
import requests
from langchain.chat_models import ChatOpenAI

import utils
from prompts import preprocess, recruiting_assistant, matches, intro

llm = ChatOpenAI(temperature=0.0, openai_api_key=os.environ["OPENAI"])
MAX_SKILLS = 10


def preprocess_resume(llm, resume) -> str:
    result = preprocess.preprocess_resume(llm, resume)
    resume_preprocess = result["resume_preprocess"]
    return resume_preprocess


def call_endpoint(resume_preprocessed):
    url = f"https://3jxjznzonb.execute-api.eu-west-1.amazonaws.com/dev/prediction"  # vervang met uw API-eindpunt
    headers = {
        "Content-Type": "application/json",
        "x-api-key": os.environ["API_KEY"],
    }  # pas headers indien nodig aan
    response = requests.post(
        url,
        headers=headers,
        data=json.dumps({"text": resume_preprocessed, "limit": 10}),
    )
    response_data = response.json()
    return response_data


def postprocess_vancy(vacancies, resume):
    if "prediction" in vacancies:
        prediction = vacancies["prediction"]
        if isinstance(prediction, list):
            # Convert prediction to HTML table
            html_table = "<table>"
            # Add table headers
            html_table += "<tr><th>Vacancy</th><th>Match</th></tr>"

            # Prepare a list to hold the futures
            futures = []
            matches_score_tuples = []
            # Create a ThreadPoolExecutor
            with ThreadPoolExecutor() as executor:
                for i, vacancy in enumerate(prediction):
                    # Schedule the get_skills_match function to run and store the future
                    future = executor.submit(
                        matches.get_skills_match, llm, vacancy, resume
                    )
                    futures.append((i, vacancy, future))

                # Collect the results as they become available
                for i, vacancy, future in futures:
                    skills_match = future.result()
                    skills_match_predicted = utils.get_json_list_from_result(
                        skills_match, "skills_match_predicted"
                    )
                    print("getting matched skills ...")
                    counter = 0
                    matched_skills = []
                    for element in skills_match_predicted:
                        if element["resume_index"] > 0 and element["vacancy_index"] > 0:
                            counter += 1
                            if counter > MAX_SKILLS:
                                break
                            matched_skills.append(element["content"])

                    # matched_skills = [
                    #     element["content"]
                    #     for element in skills_match_predicted
                    #     if element["resume_index"] > 0 and element["vacancy_index"] > 0
                    # ]
                    for element in matched_skills:
                        vacancy = vacancy.lower().replace(
                            element.lower(),
                            f'<span style="background-color: yellow;">{element}</span>',
                        )
                    matches_score_tuples.append(
                        (vacancy, matched_skills, len(matched_skills))
                    )
                print("sorting matches based on the score.")
                matches_score_tuples.sort(key=lambda x: x[-1], reverse=True)
                print("constructing html table.")
                for i, element in enumerate(matches_score_tuples, 1):
                    vacancy, matched_skills, score = element
                    vacancy_formatted = vacancy.replace(".,", "<br/>")
                    vacancy_formatted = f"VACATURE {i}:<br/>{vacancy_formatted}"
                    matches_html = "<br/> - ".join(matched_skills)
                    resume_matched_formatted = f"Score: {score}<br/>-{matches_html}"
                    html_table += f"<tr><td>{vacancy_formatted}</td><td>{resume_matched_formatted}</td></tr>"
            html_table += "</table>"
            return html_table

    return "niets teruggevonden, probeer nogmaals ..."


def search(resume):
    original_resume = resume
    resume_preprocessed = preprocess_resume(llm, resume)
    vacancies = call_endpoint(resume_preprocessed)
    vacancies_formatted = postprocess_vancy(vacancies, original_resume)
    return vacancies_formatted


def get_intro_jobseeker(vacancy, resume):
    intro_ = intro.get_intro_jobseeker(llm, vacancy, resume)
    return intro_["intro"]


def get_intro_jobissuer(vacancy, resume):
    intro_ = intro.get_intro_jobissuer(llm, vacancy, resume)
    return intro_["intro"]


def get_intro(vacancy, resume):
    jobseeker = get_intro_jobseeker(vacancy, resume)
    jobissuer = get_intro_jobissuer(vacancy, resume)
    return f"""
EMAIL KANDIDAAT:
=================

{jobseeker}

EMAIL BEDRIJF:
===============

{jobissuer}

"""


examples = [
    """
    Jan De Vries
    Magazijnier
    
    Adres: Hoofdstraat 123, 1000 Brussel
    Telefoon: +32 123 456 789
    E-mail: [email protected]
        
    Ervaren magazijnier met meer dan 7 jaar ervaring in het beheer van auto-onderdelen in grootschalige distributiecentra. Ik zoek een positie waar ik mijn expertise in voorraadbeheer, orderverwerking en teammanagement kan toepassen om de efficiëntie en productiviteit van het magazijn te verbeteren.
    
    Werkervaring
    
    Magazijnier, AutoParts Warehouse, Gent
    Januari 2017 - Heden
    
    Verantwoordelijk voor de ontvangst en verwerking van inkomende leveringen.
    Coördinatie van de dagelijkse pick- en pack-activiteiten.
    Beheer van een team van 5 medewerkers om te zorgen voor tijdige leveringen.
    Implementatie van een nieuw voorraadsysteem wat resulteerde in een vermindering van 15% in overstock.
    Assistent Magazijnier, CarParts Distributie, Antwerpen
    Juni 2014 - December 2016
    
    Geholpen bij het organiseren van het magazijn voor optimale opslag.
    Bijgehouden van voorraadniveaus en tijdig bestellingen geplaatst.
    Geholpen bij het trainen van nieuwe medewerkers.
    Opleiding
    
    Diploma Secundair Onderwijs, Technisch Onderwijs, VTI Brussel
    2010 - 2013
    
    Vaardigheden
    
    Grondige kennis van auto-onderdelen.
    Ervaren in het gebruik van voorraadbeheersystemen.
    Uitstekende organisatorische en multitasking-vaardigheden.
    Sterke communicatieve vaardigheden en teamspeler.
    Bekwaam in het gebruik van heftrucks en andere magazijnapparatuur.
    Talen
    
    Nederlands (Moedertaal)
    Engels (Vloeiend)
    Frans (Basis)
    Certificaten
    
    Heftruckcertificaat, VDAB, 2014
    """,
    """
    Johannes van der Meer
    Chef-kok
    
    Adres: Klaverstraat 45, 3000 Leiden
    Telefoon: +31 6 1234 5678
    E-mail: [email protected]
    
    Gepassioneerde en ervaren chef-kok met meer dan 12 jaar ervaring in zowel traditionele Nederlandse als internationale keukens. Bekend om het creëren van innovatieve en heerlijke gerechten met een focus op verse en lokale ingrediënten. Sterke leiderschapsvaardigheden en een bewezen vermogen om keukenteams te leiden en te trainen.
    
    WERKERVARING
    
    Executive Chef – Luxe Restaurant De Zon, Amsterdam
    Januari 2019 - Heden
    
    Verantwoordelijk voor het dagelijks beheer van de keuken.
    Ontwikkeling en implementatie van nieuwe menu's volgens seizoensgebonden beschikbaarheid.
    Training en begeleiding van een team van 15 koks en keukenpersoneel.
    Sous Chef – Brasserie Lente, Utrecht
    Juni 2013 - December 2018
    
    Assisteerde de hoofdchef bij het plannen van menu's en het organiseren van speciale evenementen.
    Beheerde voedselvoorraden en budgetten.
    Onderhield relaties met leveranciers en zorgde voor de hoogste kwaliteit ingrediënten.
    Chef de Partie – Restaurant De Oude Molen, Den Haag
    Augustus 2008 - Mei 2013
    
    Gespecialiseerd in sauzen en was verantwoordelijk voor de sauzen- en soepensectie.
    Assisteerde bij de voorbereiding van dagelijkse specials.
    Hielp bij het opleiden van junior koks.
    OPLEIDING
    
    Diploma Culinaire Kunst, Culinaire School van Amsterdam
    2005 - 2007
    
    Vakdiploma Kok, ROC Leiden
    2003 - 2005
    
    VAARDIGHEDEN
    
    Uitstekende kooktechnieken
    Menuontwikkeling
    Teamleiderschap
    Voedselveiligheid en hygiëne
    Voorraadbeheer
    Budgetbeheer
    TALEN
    
    Nederlands (Moedertaal)
    Engels (Vloeiend)
    Frans (Basis)

    """,
    """
     Naam: John Doe
     Koeltechnieker
     
     Adres: Parkstraat 123, 1000 Stadsveld
     Telefoon: +31 6 1234 5678
     E-mail: [email protected]
     Geboortedatum: 15 juli 1985
     Nationaliteit: Nederlandse
    
     Een toegewijde en bekwame koeltechnieker met 8 jaar ervaring in het ontwerpen, installeren, onderhouden en repareren van koelsystemen. Technisch onderlegd en bekend met verschillende koeltechnieken. Een probleemoplosser die snel storingen kan diagnosticeren en efficiënte oplossingen kan implementeren. Goed in teamverband en klantgericht.
    
     Werkervaring:
    
     Service Technicus bij KoelTech B.V. - januari 2018 tot heden
    
     Verantwoordelijk voor het installeren en onderhouden van commerciële en industriële koelsystemen.
     Diagnose stellen en repareren van storingen in koelapparatuur.
     Uitvoeren van preventief onderhoud om de prestaties van koelinstallaties te optimaliseren.
     Klantgerichte aanpak om vragen en problemen van klanten op te lossen.
     Assistent Koeltechnieker bij CoolAir Installaties - maart 2014 tot december 2017
    
     Betrokken bij het ontwerp en de installatie van nieuwe koelsystemen in residentiële gebouwen.
     Uitvoeren van druk- en temperatuurmetingen om de juiste werking van de systemen te waarborgen.
     Oplossen van technische problemen en het vervangen van defecte onderdelen.
     Het trainen van klanten in het juiste gebruik en onderhoud van koelapparatuur.
     Opleiding:
    
     MBO Koeltechniek - Technische School Stadsveld - 2014
     Certificaat Veilig werken met koelinstallaties - Koelacademie Nederland - 2014
     Vaardigheden:
    
     Uitgebreide kennis van verschillende koeltechnieken en -systemen.
     Sterk technisch inzicht en probleemoplossend vermogen.
     Bekend met veiligheidsvoorschriften en -procedures in de koeltechniek.
     Goede communicatieve vaardigheden om effectief te kunnen samenwerken met collega's en klanten.
     Bekwaamheid in het lezen van technische tekeningen en schema's.
     Talen:
    
     Nederlands: Moedertaal
     Engels: Goed
     Referenties:
     Beschikbaar op verzoek.
    
     Opmerking: Dit CV bevat fictieve gegevens en dient alleen ter illustratie. Gebruik het als een sjabloon en vervang de gegevens door je eigen informatie bij het maken van een CV.
     """,
]

demo = gr.Blocks(theme=gr.themes.Soft())

with demo:
    with gr.Group():
        with gr.Box():
            with gr.Row(elem_id="prompt-container").style(
                mobile_collapse=False, equal_height=True
            ):
                with gr.Column():
                    text_cv = gr.Textbox(
                        lines=7,
                        label="1. Voer een CV in en krijg relevante vacatures terug.",
                    )
                    b1 = gr.Button("Zoek Vacatures", variant='primary', size="sm")
                    html_search_result = gr.HTML(
                        label="Top vacatures gevonden in de database",
                    )
                    b1.click(search, inputs=text_cv, outputs=html_search_result)

                    gr.Markdown(
                        """
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    """
                    )

                    text_vacature = gr.Textbox(
                        label="2. Selecteer een geschikte vacature voor deze CV, plak deze in het tekstveld hieronder en krijg een relevante intro.",
                        lines=7,
                    )
                    b2 = gr.Button("Schrijf Intro", variant='primary', size="sm")

                    gr.Markdown(
                        """
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    """
                    )

                    text_intro = gr.Textbox(
                        label="3. Introductie E-mail",
                        lines=7,
                    )
                    b2.click(
                        get_intro,
                        inputs=[text_vacature, text_cv],
                        outputs=[text_intro],
                    )

                    gr.Markdown(
                        """
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    """
                    )

                    gr.Examples(
                        examples=examples,
                        fn=search,
                        inputs=text_cv,
                        outputs=html_search_result,
                        cache_examples=False,
                    )

demo.launch()