Kiruthikaramalingam commited on
Commit
f183085
Β·
verified Β·
1 Parent(s): 027e657

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +196 -0
app.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fitz
2
+ import joblib
3
+ import numpy as np
4
+ import gradio as gr
5
+ from langchain.tools import Tool
6
+ from langchain.chat_models import ChatOpenAI
7
+ from langchain.agents import initialize_agent, AgentType
8
+ import openai
9
+
10
+
11
+ openai.api_key=os.getenv("OPENAI_API_KEY")
12
+
13
+ # STEP 2: Load model and vectorizer
14
+ model = joblib.load("xgb_resume_model.pkl")
15
+ vectorizer = joblib.load("tfidf_vectorizer.pkl")
16
+
17
+ # Hybrid thresholds
18
+ q_low = 0.5166
19
+ q_high = 2.8319
20
+
21
+ # Weighted keywords
22
+ weighted_keywords = {
23
+ 'llm': 3.5, 'langchain': 3.5, 'openai': 3, 'data analysis': 2,
24
+ 'sql': 2, 'teaching': 3, 'crm': 3, 'project management': 3.5
25
+ }
26
+
27
+ # Resume text extraction
28
+ def extract_resume_text(file):
29
+ doc = fitz.open(file.name)
30
+ return " ".join([page.get_text() for page in doc]).strip()
31
+
32
+ # Resume strength
33
+ def predict_strength(resume_text):
34
+ X = vectorizer.transform([resume_text])
35
+ prediction = model.predict(X)[0]
36
+ score = sum(weight for kw, weight in weighted_keywords.items() if kw in resume_text.lower())
37
+ norm_score = score / np.log(len(resume_text.split()) + 1)
38
+ if prediction == 'Average' and norm_score >= q_high:
39
+ prediction = 'Strong'
40
+ elif prediction == 'Average' and norm_score < q_low:
41
+ prediction = 'Weak'
42
+ return f"βœ… Resume Strength: {prediction}"
43
+
44
+ # Job role
45
+ def predict_role(resume_text):
46
+ roles = ["AI Engineer", "Data Scientist", "Project Manager", "Teacher", "Sales Executive"]
47
+ prompt = f"""
48
+ You are a job role classification expert. Pick one best-fit role from the list: {', '.join(roles)}.
49
+ Resume:
50
+ {resume_text}
51
+ Only respond with a single job role.
52
+ """
53
+ response = ChatOpenAI(model="gpt-4o", openai_api_key).invoke(prompt)
54
+ return f"🧩 Predicted Role: {response.content.strip()}"
55
+
56
+ # Feedback logic
57
+ def gpt_resume_feedback(resume_text):
58
+ prompt = f"""
59
+ You are an expert resume reviewer. Provide structured feedback.
60
+
61
+ Resume:
62
+ {resume_text}
63
+ """
64
+ response = openai.ChatCompletion.create(
65
+ model="gpt-4o",
66
+ messages=[{"role": "user", "content": prompt}],
67
+ temperature=0.3
68
+ )
69
+ return response.choices[0].message.content.strip()
70
+
71
+ # STEP 3: Tools
72
+ strength_tool = Tool.from_function(predict_strength, name="Strength Tool", description="ML resume strength")
73
+ role_tool = Tool.from_function(predict_role, name="Role Tool", description="GPT role classifier")
74
+ feedback_tool = Tool.from_function(gpt_resume_feedback, name="Feedback Tool", description="GPT resume feedback")
75
+
76
+ llm = ChatOpenAI(model="gpt-4o", openai_api_key))
77
+ agent_executor = initialize_agent(
78
+ tools=[strength_tool, role_tool, feedback_tool],
79
+ llm=llm,
80
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
81
+ verbose=True
82
+ )
83
+
84
+ # βœ… STEP 4: Main routing logic (with Career Guidance Tool)
85
+ def gpt_career_guidance(resume_text="", question=""):
86
+
87
+
88
+ if resume_text:
89
+ prompt = f"""
90
+ You are a friendly AI career mentor. Based on the resume below, answer the user's question politely and clearly.
91
+ Use the resume to personalize your advice.
92
+
93
+ Resume:
94
+ {resume_text}
95
+
96
+ User Question:
97
+ {question}
98
+ """
99
+ else:
100
+ prompt = f"""
101
+ You are a helpful AI career mentor. The user didn't upload a resume.
102
+ Provide a clear, friendly, and helpful response to this general career question:
103
+
104
+ User Question:
105
+ {question}
106
+ """
107
+ try:
108
+ response = openai.ChatCompletion.create(
109
+ model="gpt-4o",
110
+ messages=[{"role": "user", "content": prompt}],
111
+ temperature=0.5
112
+ )
113
+ return response.choices[0].message.content.strip()
114
+ except Exception as e:
115
+ return f"❌ Error in Career Guidance Agent: {str(e)}"
116
+
117
+ # βœ… Final decision logic
118
+ def agent_decision(resume_file=None, question=""):
119
+ resume_text = ""
120
+ if resume_file:
121
+ resume_text = extract_resume_text(resume_file)
122
+
123
+ q_lower = question.lower()
124
+
125
+ if resume_text and not question.strip():
126
+ return agent_executor.run(f"Analyze the resume and give both strength and role. Text: {resume_text}")
127
+
128
+ elif resume_text and "strength" in q_lower:
129
+ return strength_tool.run(resume_text)
130
+
131
+ elif resume_text and "role" in q_lower:
132
+ return role_tool.run(resume_text)
133
+
134
+ elif resume_text and "feedback" in q_lower:
135
+ return feedback_tool.run(resume_text)
136
+
137
+ elif question.strip(): # Career question with or without resume
138
+ return gpt_career_guidance(resume_text, question)
139
+
140
+ else:
141
+ return "⚠️ Please upload a resume or ask a question."
142
+
143
+ # βœ… Clear button logic
144
+ def clear_fields():
145
+ return None, "", ""
146
+
147
+ with gr.Blocks(title="PathForge Agent App 🧠") as demo:
148
+ # βœ… Add Title (so it's visible like in your first screenshot)
149
+ gr.Markdown("<h1 style='text-align: center;'>PathForge Agent App 🧠</h1>")
150
+ gr.Markdown("<p style='text-align: center;'>Upload your resume or ask a question. This smart agent will decide which tool to use!</p>")
151
+
152
+ # βœ… How to Use Accordion
153
+ with gr.Accordion("πŸ› οΈ How to Use This App", open=False):
154
+ gr.Markdown("""
155
+ **πŸ” Use this app in 3 simple ways:**
156
+
157
+ 1. **Upload your resume** to get:
158
+ - Resume strength (Weak / Average / Strong)
159
+ - Suitable job role prediction
160
+
161
+ 2. **Ask a question** (optional), such as:
162
+ - "What’s my resume strength?"
163
+ - "Can you give resume feedback?"
164
+ - "What role suits my profile?"
165
+ - "How to grow my career in AI?"
166
+
167
+ 3. **Use both together** to get personalized guidance.
168
+
169
+ If you only ask a general career question without a resume, the app will still respond with advice!
170
+ """)
171
+
172
+ # βœ… Input Section
173
+ with gr.Row():
174
+ resume = gr.File(label="πŸ“„ Upload Resume", type="filepath", file_types=[".pdf"])
175
+ question = gr.Textbox(
176
+ label="πŸ’¬ Ask something (optional)",
177
+ placeholder="Ask about resume, role, feedback, or career growth...",
178
+ lines=3
179
+ )
180
+
181
+ # βœ… Submit and Clear side-by-side
182
+ with gr.Row():
183
+ submit = gr.Button("πŸš€ Submit")
184
+ clear = gr.Button("🧹 Clear", variant="secondary")
185
+
186
+ output = gr.Textbox(label="πŸ“€ Response", lines=12)
187
+
188
+ # Button logic
189
+ submit.click(fn=agent_decision, inputs=[resume, question], outputs=output)
190
+ clear.click(fn=lambda: (None, "", ""), inputs=[], outputs=[resume, question, output])
191
+
192
+
193
+ demo.launch()
194
+
195
+ if __name__ == "__main__":
196
+ demo.launch()