File size: 10,843 Bytes
9e338a3
1e5d8cf
 
41e3892
1e5d8cf
41e3892
1e5d8cf
 
f24dee8
d271190
 
 
9fd18ae
41e3892
 
 
1e5d8cf
6f936c5
41e3892
 
 
 
 
1e5d8cf
 
 
 
 
41e3892
0004adb
7c37cc7
41e3892
7c37cc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0004adb
7c37cc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41e3892
7c37cc7
 
41e3892
1e5d8cf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41e3892
1e5d8cf
f24dee8
1e5d8cf
 
 
 
 
f24dee8
 
379de84
 
41e3892
0004adb
 
41e3892
0004adb
 
 
 
41e3892
1e5d8cf
0004adb
41e3892
 
1e5d8cf
 
296ac47
 
 
 
 
 
1e5d8cf
 
7c37cc7
 
 
 
 
 
 
 
296ac47
 
 
 
 
 
 
7c37cc7
 
 
 
 
 
 
 
 
296ac47
 
 
 
 
 
7c37cc7
a4ece12
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
import streamlit as st
import os
import openai
from dotenv import load_dotenv

import os
from openai import AzureOpenAI
from azure.core.credentials import AzureKeyCredential

# Load environment variables from .env file
load_dotenv()

# Set environment variables for Azure OpenAI
ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
DEPLOYMENT_NAME = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")
API_VERSION = os.getenv("AZURE_OPENAI_API_VERION")

# Check if the necessary environment variables are loaded
if not API_KEY or not ENDPOINT or not DEPLOYMENT_NAME:
    st.error("Azure OpenAI credentials are missing. Please check your .env file.")
    st.stop()

client = AzureOpenAI(
    api_version=API_VERSION,
    azure_endpoint=ENDPOINT,
    api_key=API_KEY,
)

# Function to extract information from PD using Azure OpenAI GPT-4 model
def extract_PD_info_from_azure(text):
    prompt = f"""
    Act as an HR recruiter. Carefully evaluate the provided job description (PD) document and extract the following information into the specified structured format. Ensure that all fields are populated. If a field is not explicitly mentioned in the text, use ""N/A"" as the default value.

               - Requirements Categories to Extract:

               - Location
            
               - Country

               - City

               - Department

               - Required Years of Experience

               - Responsibilities

               - Skills

               - Experience

               - Education

               - Other Factors

               - Languages


    PD Text:
    {text}
    """
    response = client.chat.completions.create(
    messages=[
            {
                "role": "system",
                "content": "You are a helpful assistant.",
            },
            {
                "role": "user",
                "content": prompt,
            }
        ],
        max_tokens=4096,
        temperature=1.0,
        top_p=1.0,
        model=DEPLOYMENT_NAME
    )

    try:

        result = response.choices[0].message.content
        return result
    except Exception as e:
        st.error(f"Error occurred while contacting Azure OpenAI: {e}")
        return None

# Function to extract information from PD using Azure OpenAI GPT-4 model
def extract_criterions_from_azure(text):
    prompt = f"""
    Act as an HR recruiter. Based on the main criteria categories defined below, extract bullet items from the provided PD text. For each bullet item, create a Criterion Object with the following fields:
    Instructions:
        - Criterions should represent each item listed under each PD section (Skills,Education, Experience, Other Factors):
                1- For each item under PD sections mentioned above, ensure to have related criteria item created to measure it. only skip those items may not relevant or negate a state such as ""There are no extra requirements specified for this position"" .
        - PD sections with NA value, dont create Crtierion for it at all.
        - Ensure to add Criterions for Languages Proficiency based on its identified level
        - Ensure to add Criterions that has clue within the PD to measure it, if no clue in PD, do not consider it.
    
    **Important:**  
        - Output all Criterion items together under each other as follows, make sure category part formated in bold:
            1- Item 1  (Category: Skills)
            2- Item 2 (Category: Experience)  
        
       
    
     
    PD Text:
    {text}
    """
    response = client.chat.completions.create(
    messages=[
            {
                "role": "system",
                "content": "You are a helpful assistant.",
            },
            {
                "role": "user",
                "content": prompt,
            }
        ],
        max_tokens=4096,
        temperature=1.0,
        top_p=1.0,
        model=DEPLOYMENT_NAME
    )

    try:

        result = response.choices[0].message.content
        return result
    except Exception as e:
        st.error(f"Error occurred while contacting Azure OpenAI: {e}")
        return None
    
def extract_weights_from_azure(text):
    prompt = f"""
    Act as an HR recruiter. Based on the extracted criteria records from the previous step, evaluate the importance of each requirement category type based on provided criteria and assign a weight to it. The weight should reflect how critical the category is for the job, with a score from 1 to 100, ensuring that the sum of all weights does not exceed 100.

    Requirements Categories to Evaluate and Assign Weights:
    Location (keyword: Location)

    Required Years of Experience (keyword: Required_Years_of_Experience)

    Responsibilities (keyword: Responsibilities)

    Skills (keyword: Skills)

    Experience (keyword: Experience)

    Education (keyword: Education)

    Other Factors (keyword: Other_Factors)

    Languages (keyword: Language_Proficiency)


    Instructions:
    
        Dynamic Handling of Categories:
            **Include categories that have explicit criteria mentioned in the Criterions JSON Content.
            **Exclude categories that are not present in the content.
            **Adjust the weights dynamically so the sum of all assigned weights does not exceed 100.


        Weight Assignment:
            **Assign a weight (1–100) to each category based on its importance to the job.
            **Distribute weights logically, ensuring critical categories like Skills, Experience, Education, and Language Proficiency are well represented.
            **Ensure the sum of all weights, including Extra_Requirement_Three if present, totals exactly 100. 
            **If the total exceeds or is less than 100, proportionally adjust the weights of the other categories.

        Category Justification:
            **For each category, provide a detailed justification of its importance, tied to the specific requirements in the job description.
            **Explain how the requirements support the assigned weight and their direct relevance to job performance or success.

        Final Adjustment Rule:
                After assigning initial weights:
                ** Check if the total weight equals 100.
                ** If the total is less than 100, proportionally increase the weights of all present categories.
                ** If the total is more than 100, proportionally decrease the weights of all present categories.
                ** Preserve explicit weight floors (e.g., Experience greater than or equal to 15%) when adjusting.
                ** The final output must sum to exactly 100.                    
        
        Output Format:
            **The response must strictly follow below, including the Category_Description for each category.
            **Ensure that all categories in the PD criteria are represented in the weights, and no category is missing.
            **If Language_Proficiency is found in the criteria, it should have a weight assigned and be included in the output.
            **If Extra_Requirement_One is found in the criteria, it should have a weight assigned and be included in the output.
            **If Extra_Requirement_Two is found in the criteria, it should have a weight assigned and be included in the output.
            **If Extra_Requirement_Three is found in the criteria, it should have a weight assigned and be included in the output.
            
            
            Example Output:
            1- Skills (Weight: 35%): <short description about required skills for this job>
            2- Experience (Weight: 25%): <short description about required experiences for this job>
            3- Education (Weight: 25%): <short description about required education for this job>
            4- Language Proficincy (Weight: 15%): <short description about required languages for this job>

    Criterions list: 
    {text}
    
    
    """
    response = client.chat.completions.create(
    messages=[
            {
                "role": "system",
                "content": "You are a helpful assistant.",
            },
            {
                "role": "user",
                "content": prompt,
            }
        ],
        max_tokens=4096,
        temperature=1.0,
        top_p=1.0,
        model=DEPLOYMENT_NAME
    )

    try:

        result = response.choices[0].message.content
        return result
    except Exception as e:
        st.error(f"Error occurred while contacting Azure OpenAI: {e}")
        return None

# Streamlit App UI
st.title("AI Screening - Post Description Information Extraction")
st.write("Enter the PD text below, and the agent will extract relevant information such as job title, location, skills, experience, and education, Criterions, Criterion Weights.")

# Text area for entering PD content manually
pd_text = st.text_area("Enter PD Text", height=300)

if pd_text:
    # Display the entered PD text
    # st.subheader("Entered Text from PD")
    # st.text_area("PD Text", pd_text, height=300)

    # Extract relevant information using Azure OpenAI GPT-4
    extracted_info = extract_PD_info_from_azure(pd_text)

    # Display the extracted information
    if extracted_info:
        st.subheader("Extracted Information")
        with st.chat_message("assistant", avatar="πŸ€–"):
            st.markdown(
                f"<div class='chat-message assistant'>{extracted_info}</div>",
                unsafe_allow_html=True,
            )
        # st.write(extracted_info)
    else:
        st.write("Could not extract information. Please try again.")


     # Extract Criterions
    extracted_criterions = extract_criterions_from_azure(extracted_info)
    
    # Display the extracted information
    if extracted_criterions:
        st.subheader("Extracted Criterion List")
        # Immediately display the assistant's response
        with st.chat_message("assistant", avatar="πŸ€–"):
            st.markdown(
                f"<div class='chat-message assistant'>{extracted_criterions}</div>",
                unsafe_allow_html=True,
            )
        # st.write(extracted_criterions)
    else:
        st.write("Could not extract criterion information. Please try again.")
        
     # Extract Criterions
    extracted_weights = extract_weights_from_azure(extracted_criterions)
    
    # Display the extracted information
    if extracted_weights:
        st.subheader("Extracted Weights List")
        with st.chat_message("assistant", avatar="πŸ€–"):
            st.markdown(
                f"<div class='chat-message assistant'>{extracted_weights}</div>",
                unsafe_allow_html=True,
            )
        # st.write(extracted_weights)
    else:
        st.write("Could not extract weights information. Please try again.") #