Spaces:
Sleeping
Sleeping
Upload 6 files
Browse files- PwsResumeClassifier.py +56 -20
- app.py +94 -134
- app_funtions.py +150 -0
PwsResumeClassifier.py
CHANGED
@@ -25,6 +25,8 @@ class PwsResumeClassifier:
|
|
25 |
paragraph) the reason why the resume was deemed as a good match and why it got the ranking it did.'''
|
26 |
|
27 |
def __init__(self, organization_id, project_id, api_key):
|
|
|
|
|
28 |
self.client = OpenAI(
|
29 |
organization=organization_id,
|
30 |
project=project_id,
|
@@ -37,7 +39,6 @@ class PwsResumeClassifier:
|
|
37 |
instructions=self.instructions,
|
38 |
model='gpt-4-turbo',
|
39 |
tools=[{"type": "file_search"}],
|
40 |
-
temperature=0.1
|
41 |
)
|
42 |
|
43 |
self.assistant_id = self.assistant.id
|
@@ -49,18 +50,18 @@ class PwsResumeClassifier:
|
|
49 |
file_name in
|
50 |
file_names]
|
51 |
|
52 |
-
vector_store = self.client.beta.vector_stores.create(
|
53 |
name="Resumes",
|
54 |
)
|
55 |
|
56 |
file_batch = self.client.beta.vector_stores.file_batches.upload_and_poll(
|
57 |
-
vector_store_id=vector_store.id,
|
58 |
files=file_streams
|
59 |
)
|
60 |
|
61 |
self.assistant = self.client.beta.assistants.update(
|
62 |
assistant_id=self.assistant_id,
|
63 |
-
tool_resources={"file_search": {"vector_store_ids": [vector_store.id]}},
|
64 |
)
|
65 |
|
66 |
def get_best_resumes(self, job_description) -> str:
|
@@ -80,28 +81,63 @@ class PwsResumeClassifier:
|
|
80 |
|
81 |
regex_patter = r"【.*?】"
|
82 |
message_content = re.sub(regex_patter, '', message_content)
|
83 |
-
return message_content
|
84 |
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
|
90 |
-
|
91 |
-
break
|
92 |
|
93 |
-
|
94 |
-
|
|
|
95 |
role="user",
|
96 |
-
content=
|
97 |
)
|
98 |
|
99 |
run = self.client.beta.threads.runs.create_and_poll(
|
100 |
-
thread_id=
|
|
|
101 |
)
|
102 |
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
paragraph) the reason why the resume was deemed as a good match and why it got the ranking it did.'''
|
26 |
|
27 |
def __init__(self, organization_id, project_id, api_key):
|
28 |
+
self.thread_chatbot = None
|
29 |
+
self.assistant_chatbot = None
|
30 |
self.client = OpenAI(
|
31 |
organization=organization_id,
|
32 |
project=project_id,
|
|
|
39 |
instructions=self.instructions,
|
40 |
model='gpt-4-turbo',
|
41 |
tools=[{"type": "file_search"}],
|
|
|
42 |
)
|
43 |
|
44 |
self.assistant_id = self.assistant.id
|
|
|
50 |
file_name in
|
51 |
file_names]
|
52 |
|
53 |
+
self.vector_store = self.client.beta.vector_stores.create(
|
54 |
name="Resumes",
|
55 |
)
|
56 |
|
57 |
file_batch = self.client.beta.vector_stores.file_batches.upload_and_poll(
|
58 |
+
vector_store_id=self.vector_store.id,
|
59 |
files=file_streams
|
60 |
)
|
61 |
|
62 |
self.assistant = self.client.beta.assistants.update(
|
63 |
assistant_id=self.assistant_id,
|
64 |
+
tool_resources={"file_search": {"vector_store_ids": [self.vector_store.id]}},
|
65 |
)
|
66 |
|
67 |
def get_best_resumes(self, job_description) -> str:
|
|
|
81 |
|
82 |
regex_patter = r"【.*?】"
|
83 |
message_content = re.sub(regex_patter, '', message_content)
|
|
|
84 |
|
85 |
+
description_chatbot = r'''You are an assistant that answers questions regarding a set of resumes and a job
|
86 |
+
posting.'''
|
87 |
+
|
88 |
+
instructions_chatbot = r'''You are provided multiple resumes of applicants applying to a job posting. The job
|
89 |
+
description of the posting is: ''' + job_description + '''. The criteria
|
90 |
+
for the judging the best matching resume are the following:\n\n
|
91 |
+
|
92 |
+
1. How well the applicant's years of experiences matches the years of experience requirement
|
93 |
+
in the job posting.\n
|
94 |
+
2. How well the applicant's educational degree(s) match the degree requirements in the job posting.\n
|
95 |
+
3. How well the applicant's skills compare to the skills desired in the job posting.\n
|
96 |
+
4. How well the applicant's previous work experiences have relation to the job posting.\n\n
|
97 |
+
|
98 |
+
Not all of the criteria above may be relevant to the job posting, but use as many criteria as possible.\n\n. You
|
99 |
+
will provide answers to the user's prompts based on the resumes provides, job description, and criteria outlined above.'''
|
100 |
+
|
101 |
+
self.assistant_chatbot = self.client.beta.assistants.create(
|
102 |
+
name="Resume chatbot",
|
103 |
+
description=description_chatbot,
|
104 |
+
instructions=instructions_chatbot,
|
105 |
+
model="gpt-4o",
|
106 |
+
tools=[{"type": "file_search"}],
|
107 |
+
tool_resources={"file_search": {"vector_store_ids": [self.vector_store.id]}}
|
108 |
+
)
|
109 |
+
self.thread_chatbot = self.client.beta.threads.create()
|
110 |
+
|
111 |
+
return message_content
|
112 |
|
113 |
+
def query_assistant(self, user_input):
|
|
|
114 |
|
115 |
+
try:
|
116 |
+
messages = self.client.beta.threads.messages.create(
|
117 |
+
thread_id=self.thread_chatbot.id,
|
118 |
role="user",
|
119 |
+
content=user_input
|
120 |
)
|
121 |
|
122 |
run = self.client.beta.threads.runs.create_and_poll(
|
123 |
+
thread_id=self.thread_chatbot.id,
|
124 |
+
assistant_id=self.assistant_chatbot.id,
|
125 |
)
|
126 |
|
127 |
+
if run.status == 'completed':
|
128 |
+
messages = self.client.beta.threads.messages.list(
|
129 |
+
thread_id=self.thread_chatbot.id
|
130 |
+
)
|
131 |
+
|
132 |
+
messages = self.client.beta.threads.messages.list(
|
133 |
+
thread_id=self.thread_chatbot.id
|
134 |
+
)
|
135 |
+
|
136 |
+
response_text = messages.data[0].content[0].text.value
|
137 |
+
regex_patter = r"【.*?】"
|
138 |
+
response_text = re.sub(regex_patter, '', response_text)
|
139 |
+
return response_text
|
140 |
+
|
141 |
+
except Exception as e:
|
142 |
+
print(e)
|
143 |
+
return 'My apologies. We could not fulfill your request due to an error.'
|
app.py
CHANGED
@@ -1,135 +1,95 @@
|
|
1 |
-
|
2 |
-
import os
|
3 |
-
import shutil
|
4 |
-
import glob
|
5 |
-
import gradio as gr
|
6 |
-
from pathlib import Path
|
7 |
-
from datetime import datetime
|
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 |
-
def
|
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 |
-
@gr.render(triggers=[upload_resume.upload, delete_resume.click, log_in.click])
|
97 |
-
def file_exp():
|
98 |
-
resume_file_explorer = gr.FileExplorer(
|
99 |
-
root_dir=os.path.abspath("Resumes"),
|
100 |
-
label='Resumes',
|
101 |
-
interactive=True,
|
102 |
-
elem_id='explorer',
|
103 |
-
)
|
104 |
-
|
105 |
-
upload_resume.upload(fn=add_resume, inputs=upload_resume)
|
106 |
-
delete_resume.click(fn=remove_resumes, inputs=resume_file_explorer)
|
107 |
-
with gr.Tab('OpenAI'):
|
108 |
-
with gr.Row():
|
109 |
-
job_select = gr.Dropdown(label='Select Job', choices=job_names + ['Custom'], allow_custom_value=True)
|
110 |
-
with gr.Row(visible=False) as job_details:
|
111 |
-
with gr.Column():
|
112 |
-
job_name_input = gr.Textbox(label='Job Name', lines=1, interactive=True)
|
113 |
-
job_description_input = gr.Textbox(label='Job Description', lines=5, interactive=True)
|
114 |
-
get_resumes = gr.Button('Find best resume')
|
115 |
-
with gr.Row(visible=True) as gpt_response:
|
116 |
-
best_resumes = gr.Markdown()
|
117 |
-
|
118 |
-
job_select.select(fn=job_selected, inputs=job_select,
|
119 |
-
outputs=[job_name_input, job_description_input, job_details, best_resumes])
|
120 |
-
get_resumes.click(send_to_openai, inputs=[job_name_input, job_description_input],
|
121 |
-
outputs=[best_resumes, gpt_response])
|
122 |
-
|
123 |
-
|
124 |
-
if __name__ == '__main__':
|
125 |
-
# Remove all current resumes from the Resumes folder
|
126 |
-
files = glob.glob(os.path.abspath('Resumes') + "/*")
|
127 |
-
for f in files:
|
128 |
-
os.remove(f)
|
129 |
-
|
130 |
-
# Copy all the defaults resumes to the resume folder
|
131 |
-
files = glob.glob(os.path.abspath('Default Resumes') + "/*")
|
132 |
-
for f in files:
|
133 |
-
shutil.copy(f, os.path.abspath('Resumes'))
|
134 |
-
|
135 |
demo.launch()
|
|
|
1 |
+
import app_funtions as appfun
|
2 |
+
import os
|
3 |
+
import shutil
|
4 |
+
import glob
|
5 |
+
import gradio as gr
|
6 |
+
from pathlib import Path
|
7 |
+
from datetime import datetime
|
8 |
+
|
9 |
+
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
10 |
+
|
11 |
+
gr.Markdown("""<h1><center>Resume Processing</center></h1>""")
|
12 |
+
password_row = gr.Row()
|
13 |
+
password_text_row = gr.Row(visible=False)
|
14 |
+
content_row = gr.Row(visible=False)
|
15 |
+
confirmation_row = gr.Row(visible=False)
|
16 |
+
|
17 |
+
MIL_Password = gr.Textbox(type='password', label="Enter the Password", visible=True)
|
18 |
+
log_in = gr.Button("Log In", visible=True)
|
19 |
+
log_in.click(fn=appfun.check_password, inputs=MIL_Password,
|
20 |
+
outputs=[MIL_Password, log_in, password_text_row, content_row])
|
21 |
+
|
22 |
+
with password_text_row:
|
23 |
+
gr.Markdown("""<h3><center>Incorrect Password. Access Denied.</center></h3>""")
|
24 |
+
|
25 |
+
with content_row:
|
26 |
+
with gr.Tab('Resume Input'):
|
27 |
+
gr.Markdown("""<h3><center>Resumes Input</center></h3>""")
|
28 |
+
gr.Markdown("""<p><center>Upload or delete any resumes you would like to have the AI use:</center></p>""")
|
29 |
+
with gr.Row():
|
30 |
+
with gr.Column():
|
31 |
+
upload_resume = gr.UploadButton('Upload Resume', file_count="multiple")
|
32 |
+
with gr.Column():
|
33 |
+
delete_resume = gr.Button('Delete')
|
34 |
+
|
35 |
+
with gr.Row():
|
36 |
+
|
37 |
+
@gr.render(triggers=[upload_resume.upload, delete_resume.click, log_in.click])
|
38 |
+
def file_exp():
|
39 |
+
resume_file_explorer = gr.FileExplorer(
|
40 |
+
root_dir=os.path.abspath("Resumes"),
|
41 |
+
label='Resumes',
|
42 |
+
interactive=True,
|
43 |
+
elem_id='explorer',
|
44 |
+
)
|
45 |
+
upload_resume.upload(fn=appfun.add_resume, inputs=upload_resume)
|
46 |
+
delete_resume.click(fn=appfun.remove_resumes, inputs=resume_file_explorer)
|
47 |
+
with gr.Tab('Job Input'):
|
48 |
+
gr.Markdown("""<h3><center>Job Input</center></h3>""")
|
49 |
+
gr.Markdown("""<p><center>Upload a document you would like to extract job description from. Supported file types are: .pdf,
|
50 |
+
.docx, .pptx, .txt.</center></p>""")
|
51 |
+
upload_file = gr.File()
|
52 |
+
extract_button = gr.Button('Extract')
|
53 |
+
extract_completion_message = gr.Markdown("""<p><center></center></p>""")
|
54 |
+
with gr.Tab('Rank Resumes'):
|
55 |
+
gr.Markdown("""<h3><center>Rank Resumes</center></h3>""")
|
56 |
+
gr.Markdown("""<p><center>Choose the job posting of which you would like to get the top 3 resumes for.</center></p>""")
|
57 |
+
job_select = gr.Dropdown(label='Select Job', choices=appfun.job_names + ['Custom'], allow_custom_value=True)
|
58 |
+
with gr.Row(visible=False) as job_details:
|
59 |
+
with gr.Column():
|
60 |
+
job_name_input = gr.Textbox(label='Job Name', lines=1, interactive=True)
|
61 |
+
job_description_input = gr.Textbox(label='Job Description', lines=5, interactive=True)
|
62 |
+
get_resumes = gr.Button('Rank Resumes')
|
63 |
+
with gr.Row(visible=True) as gpt_response:
|
64 |
+
best_resumes = gr.Markdown()
|
65 |
+
with gr.Tab("Chatbot"):
|
66 |
+
chatbot = gr.Chatbot(avatar_images=("user.jpeg", "gpt.jpg"), height=750)
|
67 |
+
state = gr.State()
|
68 |
+
chatbot_textbox = gr.Textbox(label="Input", info="", lines=1,
|
69 |
+
placeholder="Please process resumes", scale=1,
|
70 |
+
interactive=False)
|
71 |
+
chatbot_submit = gr.Button("SEND", interactive=False, scale=1)
|
72 |
+
chatbot_submit.click(appfun.my_chatbot, inputs=[chatbot_textbox, state],
|
73 |
+
outputs=[chatbot, state, chatbot_textbox])
|
74 |
+
|
75 |
+
|
76 |
+
|
77 |
+
job_select.select(fn=appfun.job_selected, inputs=job_select,
|
78 |
+
outputs=[job_name_input, job_description_input, job_details, best_resumes])
|
79 |
+
get_resumes.click(appfun.send_to_openai, inputs=[job_name_input, job_description_input],
|
80 |
+
outputs=[best_resumes, gpt_response, chatbot_textbox, chatbot_submit])
|
81 |
+
extract_button.click(fn=appfun.extract_jobs, inputs=upload_file, outputs=[extract_completion_message, job_select])
|
82 |
+
|
83 |
+
|
84 |
+
if __name__ == '__main__':
|
85 |
+
# Remove all current resumes from the Resumes folder
|
86 |
+
files = glob.glob(os.path.abspath('Resumes') + "/*")
|
87 |
+
for f in files:
|
88 |
+
os.remove(f)
|
89 |
+
|
90 |
+
# Copy all the defaults resumes to the resume folder
|
91 |
+
files = glob.glob(os.path.abspath('Default Resumes') + "/*")
|
92 |
+
for f in files:
|
93 |
+
shutil.copy(f, os.path.abspath('Resumes'))
|
94 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
demo.launch()
|
app_funtions.py
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
|
3 |
+
from PwsResumeClassifier import PwsResumeClassifier as pws
|
4 |
+
from openai import OpenAI
|
5 |
+
import app_funtions as appfun
|
6 |
+
import os
|
7 |
+
import shutil
|
8 |
+
import glob
|
9 |
+
import gradio as gr
|
10 |
+
import json
|
11 |
+
from pathlib import Path
|
12 |
+
|
13 |
+
os.environ['PROJECT'] = 'proj_ct77YbVBWyY3cNDoGA4Xkpzk'
|
14 |
+
os.environ['OPENAIORG'] = 'org-Qc0wKzpN6ewg8NpSc9s7cTtS'
|
15 |
+
os.environ['MILPASSWORD'] = 'MILRESUME'
|
16 |
+
os.environ['APIKEY'] = 'sk-proj-24nTWywXfoK0f4fEd2jdT3BlbkFJLaAZTDMkNcY8HP20Asf2'
|
17 |
+
|
18 |
+
job_names = []
|
19 |
+
job_descriptions = []
|
20 |
+
|
21 |
+
client_pws = pws(organization_id=os.getenv('OPENAIORG'), project_id=os.getenv('PROJECT'), api_key=os.getenv('APIKEY'))
|
22 |
+
|
23 |
+
client = OpenAI(
|
24 |
+
organization=os.getenv('OPENAIORG'),
|
25 |
+
project=os.getenv('PROJECT'),
|
26 |
+
api_key=os.getenv('APIKEY')
|
27 |
+
)
|
28 |
+
|
29 |
+
def check_password(password):
|
30 |
+
if password == os.getenv('MILPASSWORD'):
|
31 |
+
|
32 |
+
return [gr.Textbox(visible=False), gr.Button(visible=False), gr.Row.update(visible=False), gr.Row.update(visible=True)]
|
33 |
+
else:
|
34 |
+
return [gr.Textbox(visible=True), gr.Button(visible=True), gr.Row.update(visible=True), gr.Row.update(visible=False)]
|
35 |
+
|
36 |
+
|
37 |
+
def add_resume(resume_list):
|
38 |
+
for resume in resume_list:
|
39 |
+
shutil.copy2(os.path.abspath(resume), os.path.abspath('Resumes'))
|
40 |
+
|
41 |
+
|
42 |
+
def remove_resumes(file_explorer):
|
43 |
+
for file in file_explorer:
|
44 |
+
os.remove(file)
|
45 |
+
|
46 |
+
|
47 |
+
def job_selected(selected_name):
|
48 |
+
print(job_names)
|
49 |
+
if selected_name in job_names:
|
50 |
+
return [selected_name, job_descriptions[job_names.index(selected_name)], gr.Row.update(visible=True),
|
51 |
+
gr.Markdown()]
|
52 |
+
elif selected_name == 'Custom':
|
53 |
+
return ['', '', gr.Row.update(visible=True), gr.Markdown()]
|
54 |
+
else:
|
55 |
+
return ['', '', gr.Row.update(visible=False), gr.Markdown()]
|
56 |
+
|
57 |
+
|
58 |
+
def send_to_openai(name, description):
|
59 |
+
|
60 |
+
try:
|
61 |
+
print('Sending to AI')
|
62 |
+
client_pws.set_vector_store(os.path.abspath('Resumes'))
|
63 |
+
resumes_output = client_pws.get_best_resumes('Job Name: ' + name + '. Job Description: ' + description)
|
64 |
+
response = gr.Markdown('<p>' + resumes_output + '</p>')
|
65 |
+
return [response, gr.Row.update(visible=True),
|
66 |
+
gr.Textbox(label="Input", info="", lines=1, placeholder="Ask the chatbot.", interactive=True, scale=1),
|
67 |
+
gr.Button("SEND", interactive=True, scale=1)]
|
68 |
+
except Exception as e:
|
69 |
+
response = gr.Markdown('<p>An error occurred. Please try again.</p>')
|
70 |
+
return [response, gr.Row.update(visible=True),
|
71 |
+
gr.Textbox(label="Input", info="", lines=1, placeholder="Please process resumes", interactive=False, scale=1),
|
72 |
+
gr.Button("SEND", interactive=False, scale=1)]
|
73 |
+
|
74 |
+
|
75 |
+
def extract_jobs(filepath):
|
76 |
+
try:
|
77 |
+
description = r"""You are a document information extraction assistant that extract job names and job description
|
78 |
+
precisely and accurately from a provided file."""
|
79 |
+
|
80 |
+
instructions = r"""You will be provided a document that contains information about one or more job positions.
|
81 |
+
You will extract all of these job positions and return them in a JSON Array. Each item in the JSON Array will
|
82 |
+
have a field "job_name" for the name of the job position and "job_description" for the description and
|
83 |
+
requirements of the job position. Your response
|
84 |
+
should only be a JSON Array with all items."""
|
85 |
+
|
86 |
+
file_streams = [open(filepath, "rb")]
|
87 |
+
vector_store = client.beta.vector_stores.create(
|
88 |
+
name="Job Description File",
|
89 |
+
)
|
90 |
+
|
91 |
+
file_batch = client.beta.vector_stores.file_batches.upload_and_poll(
|
92 |
+
vector_store_id=vector_store.id,
|
93 |
+
files=file_streams
|
94 |
+
)
|
95 |
+
|
96 |
+
assistant = client.beta.assistants.create(
|
97 |
+
name="Job Description Extract Assistant",
|
98 |
+
description=description,
|
99 |
+
instructions=instructions,
|
100 |
+
model="gpt-4o",
|
101 |
+
tools=[{"type": "file_search"}],
|
102 |
+
tool_resources={"file_search": {"vector_store_ids": [vector_store.id]}},
|
103 |
+
temperature=0
|
104 |
+
)
|
105 |
+
thread = client.beta.threads.create()
|
106 |
+
|
107 |
+
messages = client.beta.threads.messages.create(
|
108 |
+
thread_id=thread.id,
|
109 |
+
role="user",
|
110 |
+
content="Please extract all job descriptions"
|
111 |
+
)
|
112 |
+
|
113 |
+
run = client.beta.threads.runs.create_and_poll(
|
114 |
+
thread_id=thread.id,
|
115 |
+
assistant_id=assistant.id,
|
116 |
+
)
|
117 |
+
|
118 |
+
if run.status == 'completed':
|
119 |
+
messages = client.beta.threads.messages.list(
|
120 |
+
thread_id=thread.id
|
121 |
+
)
|
122 |
+
|
123 |
+
messages = client.beta.threads.messages.list(
|
124 |
+
thread_id=thread.id
|
125 |
+
)
|
126 |
+
print(messages.data[0].content[0].text.value)
|
127 |
+
json_array = messages.data[0].content[0].text.value
|
128 |
+
json_array = re.sub(r"^```json", "", json_array)
|
129 |
+
json_array = re.sub(r"```$", "", json_array)
|
130 |
+
json_array = re.sub(r"【.*?】", "", json_array)
|
131 |
+
print(json_array)
|
132 |
+
print(json.loads(json_array))
|
133 |
+
|
134 |
+
for job in json.loads(json_array):
|
135 |
+
job_names.append(job['job_name'])
|
136 |
+
job_descriptions.append(job['job_description'])
|
137 |
+
return [gr.Markdown("""<p><center>Extraction completed successfully</center></p>"""),
|
138 |
+
gr.Dropdown(label='Select Job', choices=job_names + ['Custom'], allow_custom_value=True)]
|
139 |
+
except Exception as e:
|
140 |
+
return [gr.Markdown("""<p><center>Parsing failed. Error message: """ + repr(e) + """</center></p>"""),
|
141 |
+
gr.Dropdown(label='Select Job', choices=appfun.job_names + ['Custom'], allow_custom_value=True)]
|
142 |
+
|
143 |
+
|
144 |
+
def my_chatbot(user_input, history):
|
145 |
+
text = ""
|
146 |
+
history = history or []
|
147 |
+
output = client_pws.query_assistant(user_input)
|
148 |
+
history.append((user_input, output))
|
149 |
+
|
150 |
+
return history, history, text
|