Spaces:
Sleeping
Sleeping
File size: 6,734 Bytes
f183085 8a94320 f183085 93be3c4 f183085 93be3c4 f183085 93be3c4 f183085 9289f6a f183085 9289f6a f183085 9289f6a f183085 9289f6a f183085 9289f6a f183085 9289f6a f183085 9289f6a f183085 |
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 |
import fitz
import joblib
import numpy as np
import gradio as gr
from langchain.tools import Tool
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
import openai
import os
openai.api_key=os.getenv("OPENAI_API_KEY")
# STEP 2: Load model and vectorizer
model = joblib.load("xgb_resume_model.pkl")
vectorizer = joblib.load("tfidf_vectorizer.pkl")
# Hybrid thresholds
q_low = 0.5166
q_high = 2.8319
# Weighted keywords
weighted_keywords = {
'llm': 3.5, 'langchain': 3.5, 'openai': 3, 'data analysis': 2,
'sql': 2, 'teaching': 3, 'crm': 3, 'project management': 3.5
}
# Resume text extraction
def extract_resume_text(file):
doc = fitz.open(file.name)
return " ".join([page.get_text() for page in doc]).strip()
# Resume strength
def predict_strength(resume_text):
X = vectorizer.transform([resume_text])
prediction = model.predict(X)[0]
score = sum(weight for kw, weight in weighted_keywords.items() if kw in resume_text.lower())
norm_score = score / np.log(len(resume_text.split()) + 1)
if prediction == 'Average' and norm_score >= q_high:
prediction = 'Strong'
elif prediction == 'Average' and norm_score < q_low:
prediction = 'Weak'
return f"β
Resume Strength: {prediction}"
# Job role
def predict_role(resume_text):
roles = ["AI Engineer", "Data Scientist", "Project Manager", "Teacher", "Sales Executive"]
prompt = f"""
You are a job role classification expert. Pick one best-fit role from the list: {', '.join(roles)}.
Resume:
{resume_text}
Only respond with a single job role.
"""
response = ChatOpenAI(model="gpt-4o", openai_api_key=openai.api_key).invoke(prompt)
return f"π§© Predicted Role: {response.content.strip()}"
# Feedback logic
def gpt_resume_feedback(resume_text):
prompt = f"""
You are an expert resume reviewer. Provide structured feedback.
Resume:
{resume_text}
"""
response = openai.ChatCompletion.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
temperature=0.3
)
return response.choices[0].message.content.strip()
# STEP 3: Tools
strength_tool = Tool.from_function(predict_strength, name="Strength Tool", description="ML resume strength")
role_tool = Tool.from_function(predict_role, name="Role Tool", description="GPT role classifier")
feedback_tool = Tool.from_function(gpt_resume_feedback, name="Feedback Tool", description="GPT resume feedback")
llm = ChatOpenAI(model="gpt-4o", openai_api_key=openai.api_key)
agent_executor = initialize_agent(
tools=[strength_tool, role_tool, feedback_tool],
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
# β
STEP 4: Main routing logic (with Career Guidance Tool)
def gpt_career_guidance(resume_text="", question=""):
openai_api_key=openai.api_key
if resume_text:
prompt = f"""
You are a friendly AI career mentor. Based on the resume below, answer the user's question politely and clearly.
Use the resume to personalize your advice.
Resume:
{resume_text}
User Question:
{question}
"""
else:
prompt = f"""
You are a helpful AI career mentor. The user didn't upload a resume.
Provide a clear, friendly, and helpful response to this general career question:
User Question:
{question}
"""
try:
response = openai.ChatCompletion.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
temperature=0.5
)
return response.choices[0].message.content.strip()
except Exception as e:
return f"β Error in Career Guidance Agent: {str(e)}"
# β
Final decision logic
def agent_decision(resume_file=None, question=""):
resume_text = ""
outputs = []
if resume_file:
resume_text = extract_resume_text(resume_file)
q_lower = question.lower()
# If only resume is uploaded with no question
if resume_text and not question.strip():
return agent_executor.run(f"Analyze the resume and give both strength and role. Text: {resume_text}")
# Collect outputs from matching keywords
if resume_text and "strength" in q_lower:
outputs.append(strength_tool.run(resume_text))
if resume_text and "role" in q_lower:
outputs.append(role_tool.run(resume_text))
if resume_text and "feedback" in q_lower:
outputs.append(feedback_tool.run(resume_text))
if question.strip() and (
"strength" not in q_lower and "role" not in q_lower and "feedback" not in q_lower
):
outputs.append(gpt_career_guidance(resume_text, question))
# Join responses or show a fallback message
if outputs:
return "\n\n".join(outputs)
elif question.strip():
return gpt_career_guidance(resume_text, question)
else:
return "β οΈ Please upload a resume or ask a question."
# β
Clear button logic
def clear_fields():
return None, "", ""
with gr.Blocks(title="PathForge Agent App π§ ") as demo:
# β
Add Title (so it's visible like in your first screenshot)
gr.Markdown("<h1 style='text-align: center;'>PathForge Agent App π§ </h1>")
gr.Markdown("<p style='text-align: center;'>Upload your resume or ask a question. This smart agent will decide which tool to use!</p>")
# β
How to Use Accordion
with gr.Accordion("π οΈ How to Use This App", open=False):
gr.Markdown("""
**π Use this app in 3 simple ways:**
1. **Upload your resume** to get:
- Resume strength (Weak / Average / Strong)
- Suitable job role prediction
2. **Ask a question** (optional), such as:
- "Whatβs my resume strength?"
- "Can you give resume feedback?"
- "What role suits my profile?"
- "How to grow my career in AI?"
3. **Use both together** to get personalized guidance.
If you only ask a general career question without a resume, the app will still respond with advice!
""")
# β
Input Section
with gr.Row():
resume = gr.File(label="π Upload Resume", type="filepath", file_types=[".pdf"])
question = gr.Textbox(
label="π¬ Ask something (optional)",
placeholder="Ask about resume, role, feedback, or career growth...",
lines=3
)
# β
Submit and Clear side-by-side
with gr.Row():
submit = gr.Button("π Submit")
clear = gr.Button("π§Ή Clear", variant="secondary")
output = gr.Textbox(label="π€ Response", lines=12)
# Button logic
submit.click(fn=agent_decision, inputs=[resume, question], outputs=output)
clear.click(fn=lambda: (None, "", ""), inputs=[], outputs=[resume, question, output])
demo.launch()
if __name__ == "__main__":
demo.launch()
|