Spaces:
Sleeping
Sleeping
File size: 7,661 Bytes
9ff1a7e 98fae1f 9ff1a7e 6d59c51 9ff1a7e 98fae1f 9ff1a7e 98fae1f 9ff1a7e e25b197 9ff1a7e 98fae1f 9ff1a7e 98fae1f 9ff1a7e 98fae1f 9ff1a7e 98fae1f 9ff1a7e 98fae1f |
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 |
import aiohttp
import asyncio
import nest_asyncio
import streamlit as st
import time
from pdfminer.high_level import extract_text
from docx import Document
import os
from pdf2image import convert_from_bytes
import base64
import io
import certifi
import ssl
# from dotenv import load_dotenv
import json
from prompts import (
ANALYSIS_PROMPT,
ATS_PROMPT,
OBJECTIVE_ANALYSIS_PROMPT,
SCORING_PROMPT,
DEFUALT_PREP_GUIDE,
LOW_PREP_GUIDE
)
# load_dotenv()
api_key = os.getenv('OPENAI_API_KEY')
nest_asyncio.apply()
def generate_prompts(num_images):
return {
"SCORING": SCORING_PROMPT,
"ANALYSIS": ANALYSIS_PROMPT,
"OBJECTIVE_ANALYSIS": OBJECTIVE_ANALYSIS_PROMPT,
"ATS": ATS_PROMPT.format(pages=num_images),
}
def encode_image(image):
buffered = io.BytesIO()
image.save(buffered, format="PNG")
return base64.b64encode(buffered.getvalue()).decode('utf-8')
def extract_text_from_pdf(file):
try:
# Reset file pointer to the start of the file
file.seek(0)
text = extract_text(file)
return text
except Exception as e:
print(f"An error occurred: {e}")
return None
def extract_text_from_file(file):
file_extension = os.path.splitext(file.name)[1]
if file_extension == '.pdf':
return extract_text_from_pdf(file)
elif file_extension == '.docx':
doc = Document(file)
return "\n".join([paragraph.text for paragraph in doc.paragraphs])
elif file_extension == '.txt':
return file.read().decode('utf-8')
else:
return "Unsupported file type"
async def generate_completion(message, api_key):
url = "https://api.openai.com/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
payload = {
"model": "gpt-4o",
"messages": message,
"temperature": 0.1,
"response_format": {"type": "json_object"}
}
ssl_context = ssl.create_default_context(cafile=certifi.where())
# Use certifi to specify the CA bundle for SSL certificate verification
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=ssl_context)) as session:
async with session.post(url, headers=headers, json=payload) as response:
if response.status != 200:
print(f"Error: {response.status}")
return None
response_json = await response.json()
return response_json
async def main(resume_text, job_description):
analysis_types_and_prompts = {
"SCORING": SCORING_PROMPT,
"ANALYSIS": ANALYSIS_PROMPT,
"OBJECTIVE_ANALYSIS": OBJECTIVE_ANALYSIS_PROMPT,
"ATS": ATS_PROMPT.format(pages=pdf_length)
}
tasks = []
for analysis, prompt in analysis_types_and_prompts.items():
messages = construct_message(
analysis,
prompt,
resume_text,
job_description,
base_image if analysis == "ATS" else None,
)
tasks.append(generate_completion(messages,api_key))
scoring_task = asyncio.create_task(tasks[0])
other_tasks = tasks[1:]
other_tasks_futures = [asyncio.create_task(task) for task in other_tasks]
result_scoring = await scoring_task
scoring_json = json.loads(result_scoring['choices'][0]['message']['content'])
if len(scoring_json) == 1:
return scoring_json, None # Error dictionary
other_results = await asyncio.gather(*other_tasks_futures)
responses_async = [result_scoring] + other_results
if scoring_json['Overall']['Score'] <=50:
guide_prompt = LOW_PREP_GUIDE
else:
guide_prompt = DEFUALT_PREP_GUIDE
return responses_async, guide_prompt
def construct_message(analysis, prompt, resume_text, job_description=None, base_image=None):
if analysis == "ATS":
messages = [
{"role": "system", "content": prompt},
{"role": "user",
"content": f"Here is the Job Description: {job_description}"},
{"role": "user", "content": []}
]
for image in base_image:
messages[2]["content"].append({
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{image}"
},
})
return messages
elif analysis == "OBJECTIVE_ANALYSIS":
return ([
{"role": "system", "content": prompt},
{"role": "user",
"content": f"Here is the resume text: {resume_text}"}])
else:
return ([
{"role": "system", "content": prompt},
{"role": "user",
"content": f"Here is the resume text: {resume_text} \n Here is the job description: {job_description}"}])
st.set_page_config(page_title="Resume Analyzer", layout="centered")
st.title("Resume Analyzer")
job_description_source = st.radio("Job Description Source", ("Upload File", "Paste Text"))
if job_description_source == "Upload File":
job_description_file = st.file_uploader("Upload Job Description", type=['pdf', 'docx', 'txt'])
job_description = extract_text_from_file(job_description_file) if job_description_file else None
else:
job_description = st.text_area("Paste Job Description Here")
resume_file = st.file_uploader("Upload Resume", type=['pdf', 'docx', 'txt'])
if job_description:
st.subheader("Job Description Preview")
st.text_area("Job Description", job_description, height=200)
if resume_file:
resume_text = extract_text_from_file(resume_file)
st.subheader("Resume Preview")
st.text_area("Resume", resume_text, height=200)
resume_file.seek(0)
file_bytes = resume_file.read()
images = convert_from_bytes(file_bytes)
pdf_length = len(images)
base_image = []
for image in images:
base_image.append(encode_image(image))
if st.button("Analyze Resume"):
if job_description and resume_file:
start_time = time.time()
responses_async, guide_prompt = asyncio.run(main(resume_text, job_description))
end_time = time.time()
total_time = end_time - start_time
guide_message = construct_message("GUIDE", guide_prompt, resume_text, job_description)
guide_response = asyncio.run(generate_completion(guide_message, api_key))
if isinstance(responses_async, dict) and "Error" in responses_async:
error_message = f"Improper file entered: {responses_async['Error']}"
st.write(error_message)
else:
st.subheader("Analysis Result")
st.text_area("Scoring Analysis", responses_async[0]['choices'][0]['message']['content'], height=400)
st.text_area("Gap Analysis", responses_async[1]['choices'][0]['message']['content'], height=400)
st.text_area("Objective Analysis", responses_async[2]['choices'][0]['message']['content'], height=400)
st.text_area("ATS Analysis", responses_async[3]['choices'][0]['message']['content'], height=400)
st.text_area("Interview Prep Guide", guide_response['choices'][0]['message']['content'], height=400)
st.write(f"Image prompt input tokens: {responses_async[2]['usage']['prompt_tokens']}")
# st.write(f"Time taken for OpenAI response: {response_time:.2f} seconds")
st.write(f"Total time taken for execution: {total_time:.2f} seconds")
#Testing JSON Respones:
# testing.run_tests(responses_async, guide_response)
else:
st.error("Please provide both the job description and resume.")
|