Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -58,7 +58,7 @@ def upload_blob(pdf_name, json_data, pdf_data_jobdescription,pdf_data_cvs, pre_g
|
|
58 |
|
59 |
cv_nr_for_id = i+1
|
60 |
cv_session_state_string = "cv-"+str(cv_nr_for_id)
|
61 |
-
session_state_name = st.session_state["final_candidates"][i].metadata["name"]
|
62 |
names.append(session_state_name)
|
63 |
cv_id = pdf_name + "-cv-nr-" + str(cv_nr_for_id)+str(calendar.timegm(time.gmtime()))
|
64 |
upload_db_item(session_state_name, json.loads(json_data), pdf_name, cv_id)
|
@@ -171,26 +171,68 @@ st.markdown(
|
|
171 |
|
172 |
with open("sys_prompt_frontend.txt") as f:
|
173 |
sys_prompt = f.read()
|
|
|
|
|
174 |
|
175 |
def adjust_numbering(lst):
|
176 |
return [f"{i + 1}. {item.split('. ', 1)[1]}" for i, item in enumerate(lst)]
|
177 |
|
178 |
def generate_candidate_mail(candidate, chat_link)-> str:
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
We have added the job description to the mail attachment.
|
195 |
If you are interested in the position, please click on the following link, answer a few questions from our chatbot for about 10-15 minutes and we will get back to you.
|
196 |
|
@@ -204,21 +246,24 @@ WorkGenius
|
|
204 |
|
205 |
def generate_job_bullets(job)->str:
|
206 |
prompt = "You are a professional recruiter whose task is to summarize the provided job description in the most important 5 key points. The key points should have a maximum of 8 words. The only thing you should return are the bullet points."
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
|
|
|
|
|
|
222 |
|
223 |
def check_keywords_in_content(database_path, table_name, input_id, keywords):
|
224 |
# Verbindung zur Datenbank herstellen
|
@@ -248,6 +293,100 @@ def check_keywords_in_content(database_path, table_name, input_id, keywords):
|
|
248 |
|
249 |
return contains_keywords
|
250 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
if "similarity_search_string" not in st.session_state:
|
252 |
st.session_state["similarity_search_string"] = None
|
253 |
if "job_string" not in st.session_state:
|
@@ -260,6 +399,12 @@ if "final_question_string" not in st.session_state:
|
|
260 |
st.session_state["final_question_string"] = []
|
261 |
if "ai_questions" not in st.session_state:
|
262 |
st.session_state["ai_questions"] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
if "db" not in st.session_state:
|
264 |
embedder = OpenAIEmbeddings(deployment="text-embedding-ada-002", chunk_size=1)
|
265 |
embedding_function = embedder.embed_query
|
@@ -288,6 +433,43 @@ with col_clear:
|
|
288 |
if st.button("Clear", use_container_width=True):
|
289 |
streamlit_js_eval(js_expressions="parent.window.location.reload()")
|
290 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
st.write("Switch from a similarity search (default) to a hybrid search (activated)")
|
292 |
st.toggle("Switch Search", key="search_type")
|
293 |
|
@@ -304,74 +486,23 @@ text_area_params = st.text_area(label="Add additional search parameters, which a
|
|
304 |
|
305 |
submit = st.button("Search candidates",disabled= True if st.session_state["final_candidates"] else False)
|
306 |
|
307 |
-
def load_candidates():
|
308 |
-
with st.spinner("Load the candidates, this may take a moment..."):
|
309 |
-
filter_string = ""
|
310 |
-
query_string = "The following keywords must be included: " + text_area_params + " " + st.session_state["job_string"]
|
311 |
-
checked_candidates = []
|
312 |
-
db_path = 'cvdb.db'
|
313 |
-
table_name = 'files'
|
314 |
-
candidates_per_search = 100
|
315 |
-
target_candidates_count = 10
|
316 |
-
current_offset = 0
|
317 |
-
|
318 |
-
if st.session_state["screened"]:
|
319 |
-
filter_string = "amount_screenings gt 0 "
|
320 |
-
if st.session_state["handed"]:
|
321 |
-
if len(filter_string) > 0:
|
322 |
-
filter_string += "and amount_handoffs gt 0 "
|
323 |
-
else:
|
324 |
-
filter_string += "amount_handoffs gt 0 "
|
325 |
-
if st.session_state["placed"]:
|
326 |
-
if len(filter_string) > 0:
|
327 |
-
filter_string += "and amount_placed gt 0"
|
328 |
-
else:
|
329 |
-
filter_string += "amount_placed gt 0"
|
330 |
-
print(filter_string)
|
331 |
-
while len(checked_candidates) < target_candidates_count:
|
332 |
-
# Führe eine similarity search durch und erhalte 100 Kandidaten
|
333 |
-
if st.session_state["search_type"]:
|
334 |
-
print("hybrid")
|
335 |
-
raw_candidates = st.session_state["db"].hybrid_search(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
336 |
-
else:
|
337 |
-
print("similarity")
|
338 |
-
raw_candidates = st.session_state["db"].similarity_search(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
339 |
-
|
340 |
-
for candidate in raw_candidates[current_offset:]:
|
341 |
-
candidates_id = candidate.metadata["source"].split("/")[-1]
|
342 |
-
keyword_bool = check_keywords_in_content(db_path, table_name, candidates_id, text_area_params.split(','))
|
343 |
-
|
344 |
-
if keyword_bool:
|
345 |
-
checked_candidates.append(candidate)
|
346 |
-
|
347 |
-
# Überprüfe, ob die Zielanzahl erreicht wurde und breche die Schleife ab, wenn ja
|
348 |
-
if len(checked_candidates) >= target_candidates_count:
|
349 |
-
break
|
350 |
-
|
351 |
-
current_offset += candidates_per_search
|
352 |
-
if current_offset == 600:
|
353 |
-
break
|
354 |
-
# Setze die Ergebnisse in der Session State Variable
|
355 |
-
st.session_state["docs_res"] = checked_candidates
|
356 |
-
if len(checked_candidates) == 0:
|
357 |
-
st.error("No candidates can be found with these keywords. Please adjust the keywords and try again.", icon="🚨")
|
358 |
|
359 |
if not st.session_state["job"] and submit:
|
360 |
st.error("Please upload a job description to search for candidates")
|
361 |
if st.session_state["docs_res"] and submit:
|
362 |
-
load_candidates()
|
363 |
-
if (st.session_state["
|
364 |
-
if not st.session_state["job_string"]:
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
if not st.session_state["docs_res"]:
|
374 |
-
load_candidates()
|
375 |
if not st.session_state["final_candidates"]:
|
376 |
for i,doc in enumerate(st.session_state["docs_res"]):
|
377 |
# print(doc)
|
@@ -383,21 +514,34 @@ if (st.session_state["job"] and submit) or st.session_state["docs_res"]:
|
|
383 |
st.rerun()
|
384 |
with cols_final[0]:
|
385 |
# st.subheader(doc.metadata["source"])
|
386 |
-
with st.expander(doc.metadata["name"]):
|
387 |
-
st.write(doc.page_content)
|
388 |
-
if st.
|
389 |
-
|
390 |
-
|
391 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
392 |
else:
|
393 |
print("Now Questions")
|
394 |
st.subheader("Your Candidates:")
|
395 |
-
st.write(", ".join(candidate.metadata["name"] for candidate in st.session_state["final_candidates"]))
|
396 |
# for i,candidate in enumerate(st.session_state["final_candidates"]):
|
397 |
# st.write(candidate.metadata["source"])
|
398 |
-
cv_strings = "; Next CV: ".join(candidate.page_content for candidate in st.session_state["final_candidates"])
|
399 |
# print(len(cv_strings))
|
400 |
-
system = sys_prompt.format(job=st.session_state["job_string"], resume=st.session_state["final_candidates"][0], n=15)
|
401 |
if not st.session_state["ai_questions"]:
|
402 |
try:
|
403 |
# st.write("The questions are generated. This may take a short moment...")
|
@@ -517,7 +661,7 @@ Your Candidate-Search-Tool
|
|
517 |
for candidate in st.session_state["final_candidates"]:
|
518 |
styles = getSampleStyleSheet()
|
519 |
pdf = SimpleDocTemplate(temp_pdf_file)
|
520 |
-
flowables = [Paragraph(candidate.page_content, styles['Normal'])]
|
521 |
pdf.build(flowables)
|
522 |
with open(temp_pdf_file, 'rb') as pdf_file:
|
523 |
bytes_data = pdf_file.read()
|
@@ -527,9 +671,9 @@ Your Candidate-Search-Tool
|
|
527 |
mail_txt_string = ""
|
528 |
for i, candidate in enumerate(st.session_state["final_candidates"]):
|
529 |
if i > 0:
|
530 |
-
mail_txt_string += "\n\nMail to the "+str(i+1)+". candidate: "+candidate.metadata["name"]+" "+candidate.metadata["candidateId"]+" \n\n"
|
531 |
else:
|
532 |
-
mail_txt_string += "Mail to the "+str(i+1)+". candidate: "+candidate.metadata["name"]+" "+candidate.metadata["candidateId"]+" \n\n"
|
533 |
mail_txt_string += generate_candidate_mail(candidate,candidate_links[i])
|
534 |
# Summary in eine TXT Datei schreiben
|
535 |
mail_txt_path = "mailattachment.txt"
|
@@ -565,6 +709,4 @@ Your Candidate-Search-Tool
|
|
565 |
st.success('The dispatch and the upload of the data was successful')
|
566 |
except Exception as e:
|
567 |
st.error("Unfortunately the SMS dispatch did not work. Please reload the page and try again or contact the administrator. ", icon="🚨")
|
568 |
-
print("Fehler beim Senden der SMS:", str(e))
|
569 |
-
|
570 |
-
|
|
|
58 |
|
59 |
cv_nr_for_id = i+1
|
60 |
cv_session_state_string = "cv-"+str(cv_nr_for_id)
|
61 |
+
session_state_name = st.session_state["final_candidates"][i][0].metadata["name"]
|
62 |
names.append(session_state_name)
|
63 |
cv_id = pdf_name + "-cv-nr-" + str(cv_nr_for_id)+str(calendar.timegm(time.gmtime()))
|
64 |
upload_db_item(session_state_name, json.loads(json_data), pdf_name, cv_id)
|
|
|
171 |
|
172 |
with open("sys_prompt_frontend.txt") as f:
|
173 |
sys_prompt = f.read()
|
174 |
+
with open("sys_prompt_job_optimization.txt") as j:
|
175 |
+
sys_prompt_optimization = j.read()
|
176 |
|
177 |
def adjust_numbering(lst):
|
178 |
return [f"{i + 1}. {item.split('. ', 1)[1]}" for i, item in enumerate(lst)]
|
179 |
|
180 |
def generate_candidate_mail(candidate, chat_link)-> str:
|
181 |
+
candidate_first_name = candidate[0].metadata["name"].split(" ")[0]
|
182 |
+
prompt = f"You are a professional recruiter who has selected a suitable candidate on the basis of a job description. Your task is to write two to three sentences about the applicant and explain why we think they are suitable for the job. The text will then be used in an e-mail to the applicant, so please address it to them. Please start the e-mail with 'Dear {candidate_first_name}'. I'll write the end of the mail myself."
|
183 |
+
try:
|
184 |
+
res = openai.ChatCompletion.create(
|
185 |
+
engine="gpt-4",
|
186 |
+
temperature=0.2,
|
187 |
+
messages=[
|
188 |
+
{
|
189 |
+
"role": "system",
|
190 |
+
"content": prompt,
|
191 |
+
},
|
192 |
+
{"role": "system", "content": "Job description: "+st.session_state["job_string"]+"; Resume: "+candidate[0].page_content}
|
193 |
+
],
|
194 |
+
)
|
195 |
+
# print(res.choices[0]["message"]["content"])
|
196 |
+
except Exception as e:
|
197 |
+
# Iterativ die Anfrage wiederholen und 200 Chars von hinten vom Resume weglassen
|
198 |
+
max_retries = 5
|
199 |
+
retries = 0
|
200 |
+
while retries < max_retries:
|
201 |
+
try:
|
202 |
+
# Reduziere die Länge des Resume um 200 Chars von hinten
|
203 |
+
candidate[0].page_content = candidate[0].page_content[:-200]
|
204 |
+
|
205 |
+
# Neue Anfrage senden
|
206 |
+
res = openai.ChatCompletion.create(
|
207 |
+
engine="gpt-4",
|
208 |
+
temperature=0.2,
|
209 |
+
messages=[
|
210 |
+
{
|
211 |
+
"role": "system",
|
212 |
+
"content": prompt,
|
213 |
+
},
|
214 |
+
{"role": "system", "content": "Job description: " + st.session_state["job_string"] + "; Resume: " + candidate[0].page_content}
|
215 |
+
],
|
216 |
+
)
|
217 |
+
# print(res.choices[0]["message"]["content"])
|
218 |
+
|
219 |
+
# Wenn die Anfrage erfolgreich ist, den Schleifen-Iterator beenden
|
220 |
+
break
|
221 |
|
222 |
+
except Exception as e:
|
223 |
+
# Bei erneuter Ausnahme die Schleife fortsetzen
|
224 |
+
retries += 1
|
225 |
+
if retries == max_retries:
|
226 |
+
# Falls die maximale Anzahl von Wiederholungen erreicht ist, handle die Ausnahme entsprechend
|
227 |
+
print("Max retries reached. Unable to get a valid response.")
|
228 |
+
return "The CV was too long to generate a Mail"
|
229 |
+
# Hier kannst du zusätzlichen Code für den Fall implementieren, dass die maximale Anzahl von Wiederholungen erreicht wurde.
|
230 |
+
|
231 |
+
# Optional: Füge eine Wartezeit zwischen den Anfragen hinzu, um API-Beschränkungen zu respektieren
|
232 |
+
time.sleep(1)
|
233 |
+
|
234 |
+
output_string = f"""{res.choices[0]["message"]["content"]}
|
235 |
+
|
236 |
We have added the job description to the mail attachment.
|
237 |
If you are interested in the position, please click on the following link, answer a few questions from our chatbot for about 10-15 minutes and we will get back to you.
|
238 |
|
|
|
246 |
|
247 |
def generate_job_bullets(job)->str:
|
248 |
prompt = "You are a professional recruiter whose task is to summarize the provided job description in the most important 5 key points. The key points should have a maximum of 8 words. The only thing you should return are the bullet points."
|
249 |
+
try:
|
250 |
+
res = openai.ChatCompletion.create(
|
251 |
+
engine="gpt-4",
|
252 |
+
temperature=0.2,
|
253 |
+
messages=[
|
254 |
+
{
|
255 |
+
"role": "system",
|
256 |
+
"content": prompt,
|
257 |
+
},
|
258 |
+
{"role": "system", "content": "Job description: "+job}
|
259 |
+
],
|
260 |
+
)
|
261 |
+
# print(res.choices[0]["message"]["content"])
|
262 |
+
output_string = f"""{res.choices[0]["message"]["content"]}"""
|
263 |
+
# print(output_string)
|
264 |
+
return output_string
|
265 |
+
except Exception as e:
|
266 |
+
print(f"Fehler beim generieren der Bullets: {str(e)}")
|
267 |
|
268 |
def check_keywords_in_content(database_path, table_name, input_id, keywords):
|
269 |
# Verbindung zur Datenbank herstellen
|
|
|
293 |
|
294 |
return contains_keywords
|
295 |
|
296 |
+
def load_candidates(fillup):
|
297 |
+
with st.spinner("Load the candidates, this may take a moment..."):
|
298 |
+
# print(st.session_state["job_string"])
|
299 |
+
filter_string = ""
|
300 |
+
query_string = "The following keywords must be included: " + text_area_params + " " + st.session_state["job_string"]
|
301 |
+
checked_candidates = []
|
302 |
+
db_path = 'cvdb.db'
|
303 |
+
table_name = 'files'
|
304 |
+
candidates_per_search = 100
|
305 |
+
target_candidates_count = 10
|
306 |
+
current_offset = 0
|
307 |
+
|
308 |
+
if st.session_state["screened"]:
|
309 |
+
filter_string = "amount_screenings gt 0 "
|
310 |
+
if st.session_state["handed"]:
|
311 |
+
if len(filter_string) > 0:
|
312 |
+
filter_string += "and amount_handoffs gt 0 "
|
313 |
+
else:
|
314 |
+
filter_string += "amount_handoffs gt 0 "
|
315 |
+
if st.session_state["placed"]:
|
316 |
+
if len(filter_string) > 0:
|
317 |
+
filter_string += "and amount_placed gt 0"
|
318 |
+
else:
|
319 |
+
filter_string += "amount_placed gt 0"
|
320 |
+
# print(filter_string)
|
321 |
+
if not fillup:
|
322 |
+
while len(checked_candidates) < target_candidates_count:
|
323 |
+
# Führe eine similarity search durch und erhalte 100 Kandidaten
|
324 |
+
if st.session_state["search_type"]:
|
325 |
+
print("hybrid")
|
326 |
+
# raw_candidates = st.session_state["db"].hybrid_search(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
327 |
+
raw_candidates = st.session_state["db"].hybrid_search_with_score(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
328 |
+
else:
|
329 |
+
print("similarity")
|
330 |
+
# raw_candidates = st.session_state["db"].similarity_search(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
331 |
+
raw_candidates = st.session_state["db"].similarity_search_with_relevance_scores(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
332 |
+
|
333 |
+
for candidate in raw_candidates[current_offset:]:
|
334 |
+
candidates_id = candidate[0].metadata["source"].split("/")[-1]
|
335 |
+
keyword_bool = check_keywords_in_content(db_path, table_name, candidates_id, text_area_params.split(','))
|
336 |
+
|
337 |
+
if keyword_bool:
|
338 |
+
checked_candidates.append(candidate)
|
339 |
+
|
340 |
+
# Überprüfe, ob die Zielanzahl erreicht wurde und breche die Schleife ab, wenn ja
|
341 |
+
if len(checked_candidates) >= target_candidates_count:
|
342 |
+
break
|
343 |
+
|
344 |
+
current_offset += candidates_per_search
|
345 |
+
if current_offset == 600:
|
346 |
+
break
|
347 |
+
# Setze die Ergebnisse in der Session State Variable
|
348 |
+
st.session_state["docs_res"] = checked_candidates
|
349 |
+
st.session_state["candidate_offset"] = current_offset
|
350 |
+
if len(checked_candidates) == 0:
|
351 |
+
st.error("No candidates can be found with these keywords. Please adjust the keywords and try again.", icon="🚨")
|
352 |
+
else:
|
353 |
+
# Setze die Zielanzahl auf 10
|
354 |
+
target_candidates_count = 10
|
355 |
+
|
356 |
+
current_offset = st.session_state["candidate_offset"]
|
357 |
+
|
358 |
+
# Solange die Anzahl der überprüften Kandidaten kleiner als die Zielanzahl ist
|
359 |
+
while len(st.session_state["docs_res"]) < target_candidates_count:
|
360 |
+
# Führe eine similarity search durch und erhalte 100 Kandidaten
|
361 |
+
if st.session_state["search_type"]:
|
362 |
+
print("hybrid")
|
363 |
+
# raw_candidates = st.session_state["db"].hybrid_search(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
364 |
+
raw_candidates = st.session_state["db"].hybrid_search_with_score(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
365 |
+
else:
|
366 |
+
print("similarity")
|
367 |
+
# raw_candidates = st.session_state["db"].similarity_search(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
368 |
+
raw_candidates = st.session_state["db"].similarity_search_with_relevance_scores(query_string, k=candidates_per_search+current_offset, filters=filter_string)
|
369 |
+
temp_offset_add = 0
|
370 |
+
for candidate in raw_candidates[current_offset:]:
|
371 |
+
candidates_id = candidate[0].metadata["source"].split("/")[-1]
|
372 |
+
keyword_bool = check_keywords_in_content(db_path, table_name, candidates_id, text_area_params.split(','))
|
373 |
+
|
374 |
+
if keyword_bool:
|
375 |
+
st.session_state["docs_res"].append(candidate)
|
376 |
+
temp_offset_add += 1
|
377 |
+
# Überprüfe, ob die Zielanzahl erreicht wurde und breche die Schleife ab, wenn ja
|
378 |
+
if len(st.session_state["docs_res"]) >= target_candidates_count:
|
379 |
+
st.session_state["candidate_offset"] = current_offset+temp_offset_add
|
380 |
+
break
|
381 |
+
|
382 |
+
current_offset += candidates_per_search
|
383 |
+
if current_offset == 900:
|
384 |
+
break
|
385 |
+
|
386 |
+
# Wenn die Liste immer noch leer ist, zeige eine Fehlermeldung an
|
387 |
+
if len(st.session_state["docs_res"]) == 0:
|
388 |
+
st.warning("No more candidates can be found.", icon="🔥")
|
389 |
+
|
390 |
if "similarity_search_string" not in st.session_state:
|
391 |
st.session_state["similarity_search_string"] = None
|
392 |
if "job_string" not in st.session_state:
|
|
|
399 |
st.session_state["final_question_string"] = []
|
400 |
if "ai_questions" not in st.session_state:
|
401 |
st.session_state["ai_questions"] = None
|
402 |
+
if "raw_job" not in st.session_state:
|
403 |
+
st.session_state["raw_job"] = None
|
404 |
+
if "optimized_job" not in st.session_state:
|
405 |
+
st.session_state["optimized_job"] = None
|
406 |
+
if "candidate_offset" not in st.session_state:
|
407 |
+
st.session_state["candidate_offset"] = 0
|
408 |
if "db" not in st.session_state:
|
409 |
embedder = OpenAIEmbeddings(deployment="text-embedding-ada-002", chunk_size=1)
|
410 |
embedding_function = embedder.embed_query
|
|
|
433 |
if st.button("Clear", use_container_width=True):
|
434 |
streamlit_js_eval(js_expressions="parent.window.location.reload()")
|
435 |
|
436 |
+
if st.session_state["job"]:
|
437 |
+
if not st.session_state["job_string"]:
|
438 |
+
if not st.session_state["optimized_job"]:
|
439 |
+
with st.spinner("Optimizing the job description. This may take a moment..."):
|
440 |
+
pdf_data_jobdescription = st.session_state["job"].read()
|
441 |
+
pdf_data_jobdescription_string = ""
|
442 |
+
pdf_reader_job = PdfReader(io.BytesIO(pdf_data_jobdescription))
|
443 |
+
for page_num in range(len(pdf_reader_job.pages)):
|
444 |
+
page = pdf_reader_job.pages[page_num]
|
445 |
+
pdf_data_jobdescription_string += page.extract_text()
|
446 |
+
# st.session_state["pdf_data_jobdescription"] = pdf_data_jobdescription activate and add sessio state if data is needed
|
447 |
+
system_prompt_job = sys_prompt_optimization.format(job=pdf_data_jobdescription_string)
|
448 |
+
try:
|
449 |
+
res = openai.ChatCompletion.create(
|
450 |
+
engine="gpt-4",
|
451 |
+
temperature=0.2,
|
452 |
+
messages=[
|
453 |
+
{
|
454 |
+
"role": "system",
|
455 |
+
"content": system_prompt_job,
|
456 |
+
},
|
457 |
+
],
|
458 |
+
)
|
459 |
+
# print(res.choices[0]["message"]["content"])
|
460 |
+
output_string = f"""{res.choices[0]["message"]["content"]}"""
|
461 |
+
st.session_state["optimized_job"] = output_string
|
462 |
+
st.rerun()
|
463 |
+
except Exception as e:
|
464 |
+
print(f"Fehler beim generieren der optimierten JD: {str(e)}")
|
465 |
+
st.error("An error has occurred. Please reload the page or contact the admin.", icon="🚨")
|
466 |
+
# st.session_state["job_string"] = pdf_data_jobdescription_string
|
467 |
+
# print(output_string)
|
468 |
+
st.text_area("This is the AI-generated optimized job description. If necessary, change something to your liking:", value=st.session_state["optimized_job"], height=700, key="optimized_job_edited")
|
469 |
+
if st.button("Accept the job description"):
|
470 |
+
st.session_state["job_string"] = st.session_state["optimized_job_edited"]
|
471 |
+
st.rerun()
|
472 |
+
|
473 |
st.write("Switch from a similarity search (default) to a hybrid search (activated)")
|
474 |
st.toggle("Switch Search", key="search_type")
|
475 |
|
|
|
486 |
|
487 |
submit = st.button("Search candidates",disabled= True if st.session_state["final_candidates"] else False)
|
488 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
489 |
|
490 |
if not st.session_state["job"] and submit:
|
491 |
st.error("Please upload a job description to search for candidates")
|
492 |
if st.session_state["docs_res"] and submit:
|
493 |
+
load_candidates(False)
|
494 |
+
if (st.session_state["job_string"] and submit) or st.session_state["docs_res"]:
|
495 |
+
# if not st.session_state["job_string"]:
|
496 |
+
# pdf_data_jobdescription = st.session_state["job"].read()
|
497 |
+
# pdf_data_jobdescription_string = ""
|
498 |
+
# pdf_reader_job = PdfReader(io.BytesIO(pdf_data_jobdescription))
|
499 |
+
# for page_num in range(len(pdf_reader_job.pages)):
|
500 |
+
# page = pdf_reader_job.pages[page_num]
|
501 |
+
# pdf_data_jobdescription_string += page.extract_text()
|
502 |
+
# # st.session_state["pdf_data_jobdescription"] = pdf_data_jobdescription activate and add sessio state if data is needed
|
503 |
+
# st.session_state["job_string"] = pdf_data_jobdescription_string
|
504 |
if not st.session_state["docs_res"]:
|
505 |
+
load_candidates(False)
|
506 |
if not st.session_state["final_candidates"]:
|
507 |
for i,doc in enumerate(st.session_state["docs_res"]):
|
508 |
# print(doc)
|
|
|
514 |
st.rerun()
|
515 |
with cols_final[0]:
|
516 |
# st.subheader(doc.metadata["source"])
|
517 |
+
with st.expander(doc[0].metadata["name"]+" with a search score of: "+str(round(doc[1] * 100, 3))+"%"):
|
518 |
+
st.write(doc[0].page_content)
|
519 |
+
if len(st.session_state["docs_res"])>=10:
|
520 |
+
if st.button("Accept candidates", key="accept_candidates_btn"):
|
521 |
+
print("hello")
|
522 |
+
st.session_state["final_candidates"] = st.session_state["docs_res"].copy()
|
523 |
+
st.rerun()
|
524 |
+
else:
|
525 |
+
col_accept, col_empty ,col_load_new = st.columns([2, 3, 2])
|
526 |
+
with col_accept:
|
527 |
+
if st.button("Accept candidates", key="accept_candidates_btn"):
|
528 |
+
print("hello")
|
529 |
+
st.session_state["final_candidates"] = st.session_state["docs_res"].copy()
|
530 |
+
st.rerun()
|
531 |
+
with col_load_new:
|
532 |
+
if st.button("Load new candidates", key="load_new_candidates"):
|
533 |
+
print("loading new candidates")
|
534 |
+
load_candidates(True)
|
535 |
+
st.rerun()
|
536 |
else:
|
537 |
print("Now Questions")
|
538 |
st.subheader("Your Candidates:")
|
539 |
+
st.write(", ".join(candidate[0].metadata["name"] for candidate in st.session_state["final_candidates"]))
|
540 |
# for i,candidate in enumerate(st.session_state["final_candidates"]):
|
541 |
# st.write(candidate.metadata["source"])
|
542 |
+
cv_strings = "; Next CV: ".join(candidate[0].page_content for candidate in st.session_state["final_candidates"])
|
543 |
# print(len(cv_strings))
|
544 |
+
system = sys_prompt.format(job=st.session_state["job_string"], resume=st.session_state["final_candidates"][0][0].page_content, n=15)
|
545 |
if not st.session_state["ai_questions"]:
|
546 |
try:
|
547 |
# st.write("The questions are generated. This may take a short moment...")
|
|
|
661 |
for candidate in st.session_state["final_candidates"]:
|
662 |
styles = getSampleStyleSheet()
|
663 |
pdf = SimpleDocTemplate(temp_pdf_file)
|
664 |
+
flowables = [Paragraph(candidate[0].page_content, styles['Normal'])]
|
665 |
pdf.build(flowables)
|
666 |
with open(temp_pdf_file, 'rb') as pdf_file:
|
667 |
bytes_data = pdf_file.read()
|
|
|
671 |
mail_txt_string = ""
|
672 |
for i, candidate in enumerate(st.session_state["final_candidates"]):
|
673 |
if i > 0:
|
674 |
+
mail_txt_string += "\n\nMail to the "+str(i+1)+". candidate: "+candidate[0].metadata["name"]+" "+candidate[0].metadata["candidateId"]+" \n\n"
|
675 |
else:
|
676 |
+
mail_txt_string += "Mail to the "+str(i+1)+". candidate: "+candidate[0].metadata["name"]+" "+candidate[0].metadata["candidateId"]+" \n\n"
|
677 |
mail_txt_string += generate_candidate_mail(candidate,candidate_links[i])
|
678 |
# Summary in eine TXT Datei schreiben
|
679 |
mail_txt_path = "mailattachment.txt"
|
|
|
709 |
st.success('The dispatch and the upload of the data was successful')
|
710 |
except Exception as e:
|
711 |
st.error("Unfortunately the SMS dispatch did not work. Please reload the page and try again or contact the administrator. ", icon="🚨")
|
712 |
+
print("Fehler beim Senden der SMS:", str(e))
|
|
|
|