anupajose commited on
Commit
067e9a7
·
verified ·
1 Parent(s): bb1aa0c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +224 -0
app.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ from langchain_community.document_loaders import PyPDFLoader
4
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
5
+ from langchain_community.vectorstores import FAISS
6
+ from langchain_community.embeddings import HuggingFaceEmbeddings
7
+ from groq import Groq
8
+ from dotenv import load_dotenv
9
+ from faster_whisper import WhisperModel
10
+ from elevenlabs.client import ElevenLabs
11
+ from elevenlabs import play
12
+ import tempfile
13
+
14
+ # Load environment variables
15
+ load_dotenv()
16
+
17
+ # Initialize APIs
18
+ GROQ_API_KEY = "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"
19
+ ELEVENLABS_API_KEY = "ap2_69e1e821-6ea7-4fa0-88dc-ba54f2ac246c"
20
+
21
+ # Initialize clients
22
+ groq_client = Groq(api_key=GROQ_API_KEY)
23
+ elevenlabs_client = ElevenLabs(api_key=ELEVENLABS_API_KEY)
24
+
25
+ # Initialize Whisper model
26
+ whisper_model = WhisperModel("small", device="cpu", compute_type="int8")
27
+
28
+ def summarize_resume(resume_text):
29
+ """Generate a concise summary of key resume points"""
30
+ prompt = f"""Create a concise summary of this resume highlighting:
31
+ 1. Professional title/role
32
+ 2. Years of experience
33
+ 3. Core skills/competencies
34
+ 4. Education background
35
+ 5. Notable achievements
36
+
37
+ Resume:
38
+ {resume_text[:3000]}... [truncated]"""
39
+
40
+ response = groq_client.chat.completions.create(
41
+ messages=[{"role": "user", "content": prompt}],
42
+ model="llama3-70b-8192",
43
+ temperature=0.3,
44
+ )
45
+ return response.choices[0].message.content
46
+
47
+ def calculate_ats_score(resume_text):
48
+ """Calculate ATS score based on resume content"""
49
+ prompt = f"""Analyze this resume and calculate an ATS score (0-100) considering:
50
+ 1. Keyword optimization (20 pts)
51
+ 2. Section organization (20 pts)
52
+ 3. Experience quality (20 pts)
53
+ 4. Education completeness (20 pts)
54
+ 5. Readability (20 pts)
55
+
56
+ Return ONLY the numerical score and nothing else.
57
+
58
+ Resume:
59
+ {resume_text[:3000]}... [truncated]"""
60
+
61
+ response = groq_client.chat.completions.create(
62
+ messages=[{"role": "user", "content": prompt}],
63
+ model="llama3-70b-8192",
64
+ temperature=0,
65
+ )
66
+ try:
67
+ return int(response.choices[0].message.content.strip())
68
+ except:
69
+ return 50 # Default if parsing fails
70
+
71
+ def process_resume(file):
72
+ """Process uploaded resume PDF"""
73
+ try:
74
+ # Load and process PDF
75
+ loader = PyPDFLoader(file.name)
76
+ docs = RecursiveCharacterTextSplitter(
77
+ chunk_size=1000,
78
+ chunk_overlap=200,
79
+ separators=["\n\n", "\n", " ", ""]
80
+ ).split_documents(loader.load())
81
+
82
+ # Create vector store
83
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
84
+ FAISS.from_documents(docs, embeddings).save_local("resume_index")
85
+
86
+ # Generate outputs
87
+ full_text = "\n".join([doc.page_content for doc in docs])
88
+ gr.Info("✅ Resume processed successfully!")
89
+ return summarize_resume(full_text), f"ATS Score: {calculate_ats_score(full_text)}/100"
90
+
91
+ except Exception as e:
92
+ gr.Warning(f"❌ Error: {str(e)}")
93
+ return f"Error: {str(e)}", "ATS Score: N/A"
94
+
95
+ def transcribe_audio(audio_path):
96
+ """Convert speech to text using Whisper"""
97
+ segments, _ = whisper_model.transcribe(audio_path)
98
+ return " ".join([segment.text for segment in segments])
99
+
100
+ def generate_question(resume_text):
101
+ """Generate general interview questions based on resume"""
102
+ prompt = f"""Generate one general interview question focusing on:
103
+ - Teamwork experiences
104
+ - Challenges overcome
105
+ - Learning experiences
106
+ - Career motivations
107
+ - Problem-solving examples
108
+
109
+ Make it conversational and open-ended.
110
+
111
+ Resume Excerpt:
112
+ {resume_text[:2000]}... [truncated]"""
113
+
114
+ response = groq_client.chat.completions.create(
115
+ messages=[{"role": "user", "content": prompt}],
116
+ model="llama3-70b-8192",
117
+ temperature=0.7,
118
+ )
119
+ return response.choices[0].message.content
120
+
121
+ def evaluate_response(question, response_text):
122
+ """Evaluate interview response"""
123
+ prompt = f"""Evaluate this interview response on:
124
+ 1. Clarity (1-5)
125
+ 2. Confidence (1-5)
126
+ 3. Relevance (1-5)
127
+ 4. Suggested improvements
128
+
129
+ Question: {question}
130
+ Response: {response_text}"""
131
+
132
+ evaluation = groq_client.chat.completions.create(
133
+ messages=[{"role": "user", "content": prompt}],
134
+ model="llama3-70b-8192",
135
+ temperature=0.2,
136
+ )
137
+ return evaluation.choices[0].message.content
138
+
139
+ def speak_feedback(text):
140
+ """Convert text feedback to speech"""
141
+ try:
142
+ if not text.strip():
143
+ raise ValueError("Empty feedback text")
144
+
145
+ audio = elevenlabs_client.generate(
146
+ text=text,
147
+ voice="Rachel",
148
+ model="eleven_monolingual_v2"
149
+ )
150
+
151
+ # Create a temporary file
152
+ with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as tmp:
153
+ for chunk in audio:
154
+ if chunk:
155
+ tmp.write(chunk)
156
+ tmp_path = tmp.name
157
+
158
+ return tmp_path
159
+ except Exception as e:
160
+ gr.Warning(f"TTS Error: {str(e)}")
161
+ return None
162
+
163
+ # Gradio Interface
164
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
165
+ gr.Markdown("## Ready Set Hire")
166
+ gr.Markdown("Upload your resume and practice general interview questions with AI feedback")
167
+
168
+ with gr.Tab("📄 Resume Analysis"):
169
+ with gr.Row():
170
+ with gr.Column():
171
+ resume_upload = gr.File(
172
+ label="Upload Resume (PDF)",
173
+ file_types=[".pdf"],
174
+ elem_id="resume-upload"
175
+ )
176
+ process_btn = gr.Button("Analyze Resume", variant="primary")
177
+ with gr.Column():
178
+ resume_summary = gr.Textbox(label="Resume Summary", lines=10)
179
+ ats_score = gr.Textbox(
180
+ label="ATS Compatibility Score",
181
+ interactive=False,
182
+ elem_classes=["ats-score"]
183
+ )
184
+ process_btn.click(
185
+ fn=process_resume,
186
+ inputs=resume_upload,
187
+ outputs=[resume_summary, ats_score]
188
+ )
189
+
190
+ with gr.Tab("🎤 Mock Interview"):
191
+ with gr.Row():
192
+ with gr.Column():
193
+ audio_input = gr.Audio(sources=["microphone"], type="filepath")
194
+ transcribe_btn = gr.Button("Transcribe Response", variant="primary")
195
+ question_box = gr.Textbox(label="Current Question")
196
+ generate_btn = gr.Button("Generate New Question")
197
+ with gr.Column():
198
+ transcription = gr.Textbox(label="Your Response")
199
+ evaluation = gr.Textbox(label="Feedback", lines=8)
200
+ feedback_audio = gr.Audio(label="Feedback Audio", visible=False)
201
+
202
+ # Event handlers
203
+ transcribe_btn.click(
204
+ fn=transcribe_audio,
205
+ inputs=audio_input,
206
+ outputs=transcription
207
+ )
208
+
209
+ generate_btn.click(
210
+ fn=generate_question,
211
+ inputs=resume_summary,
212
+ outputs=question_box
213
+ )
214
+
215
+ gr.on(
216
+ triggers=[transcription.change],
217
+ fn=evaluate_response,
218
+ inputs=[question_box, transcription],
219
+ outputs=evaluation
220
+ )
221
+
222
+
223
+ if __name__ == "__main__":
224
+ demo.launch()