ZainabFatimaa commited on
Commit
4b8ca84
·
verified ·
1 Parent(s): 6d287aa

Update src/app.py

Browse files
Files changed (1) hide show
  1. src/app.py +246 -188
src/app.py CHANGED
@@ -187,6 +187,7 @@ class ImprovedNLPProcessor:
187
  (token.isalpha() or token in resume_keywords)):
188
  filtered_tokens.append(token)
189
 
 
190
  return ' '.join(filtered_tokens[:max_terms])
191
 
192
  class ImprovedChatMemory:
@@ -202,6 +203,7 @@ class ImprovedChatMemory:
202
  }
203
  st.session_state.improved_chat_history.append(conversation)
204
 
 
205
  if len(st.session_state.improved_chat_history) > 6:
206
  st.session_state.improved_chat_history = st.session_state.improved_chat_history[-6:]
207
 
@@ -210,131 +212,295 @@ class ImprovedChatMemory:
210
  if not st.session_state.improved_chat_history:
211
  return ""
212
 
 
213
  last_conv = st.session_state.improved_chat_history[-1]
214
- last_topic = last_conv['user'][:30]
215
  return f"Previously discussed: {last_topic}"
216
 
217
  class ImprovedCPUChatbot:
218
  def __init__(self):
 
 
 
 
219
  self.nlp_processor = ImprovedNLPProcessor()
220
  self.memory = ImprovedChatMemory()
221
  self.is_loaded = False
222
 
223
- # Comprehensive template responses for better coverage
224
  self.template_responses = {
225
  'experience': "To improve your experience section: Use bullet points with action verbs, quantify achievements with numbers, focus on results rather than duties, and tailor content to match job requirements.",
226
  'ats': "Make your resume ATS-friendly by: Using standard section headings, including relevant keywords naturally, avoiding images and complex formatting, using common fonts like Arial, and saving as PDF.",
227
  'skills': "Enhance your skills section by: Organizing technical and soft skills separately, matching skills to job descriptions, providing proficiency levels, and including both hard and soft skills relevant to your target role.",
228
  'keywords': "Add relevant keywords by: Studying job descriptions in your field, using industry-specific terms, including both acronyms and full terms, and incorporating them naturally throughout your resume.",
229
- 'format': "Improve resume formatting with: Clear section headings, consistent bullet points, readable fonts, appropriate white space, and a clean, professional layout that's easy to scan.",
230
- 'summary': "Write an effective summary by: Starting with your professional title, highlighting 2-3 key achievements, mentioning relevant skills, and keeping it to 3-4 lines maximum.",
231
- 'education': "Optimize your education section by: Listing degree, institution, and graduation year, including relevant coursework for entry-level positions, mentioning GPA if above 3.5, and adding academic achievements.",
232
- 'projects': "Showcase projects effectively by: Describing the problem solved, technologies used, your specific role, quantifiable results or impact, and linking to live demos or repositories when possible.",
233
- 'cover_letter': "Create compelling cover letters by: Addressing specific job requirements, showing knowledge of the company, highlighting relevant achievements, and ending with a strong call to action.",
234
- 'interview': "Prepare for interviews by: Researching the company and role, practicing STAR method responses, preparing questions to ask, and reviewing your resume thoroughly to discuss any point confidently."
235
  }
236
 
237
- def initialize(self):
238
- """Initialize the chatbot - lightweight version without model loading"""
 
239
  try:
240
- # Simulate brief initialization
241
- import time
242
- time.sleep(0.5) # Brief delay to show initialization
243
- self.is_loaded = True
244
- return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  except Exception as e:
246
- st.error(f"Failed to initialize: {str(e)}")
247
- return False
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  def get_template_response(self, user_input: str) -> str:
250
- """Enhanced template response matching"""
251
  user_lower = user_input.lower()
252
 
253
- # More comprehensive keyword matching
254
- response_mapping = [
255
- (['experience', 'work history', 'job history', 'employment', 'career'], 'experience'),
256
- (['ats', 'applicant tracking', 'ats-friendly', 'system'], 'ats'),
257
- (['skills', 'technical skills', 'abilities', 'competencies'], 'skills'),
258
- (['keywords', 'keyword', 'terms', 'buzzwords'], 'keywords'),
259
- (['format', 'formatting', 'layout', 'design', 'structure'], 'format'),
260
- (['summary', 'objective', 'profile', 'about', 'intro'], 'summary'),
261
- (['education', 'degree', 'university', 'college', 'school'], 'education'),
262
- (['projects', 'portfolio', 'work samples', 'personal projects'], 'projects'),
263
- (['cover letter', 'covering letter', 'application letter'], 'cover_letter'),
264
- (['interview', 'interviews', 'interviewing', 'job interview'], 'interview')
265
- ]
266
-
267
- for keywords, response_key in response_mapping:
268
- if any(keyword in user_lower for keyword in keywords):
269
- return self.template_responses[response_key]
270
-
271
- # General improvement queries
272
- if any(phrase in user_lower for phrase in ['improve my resume', 'better resume', 'hire me', 'get hired', 'land job']):
273
  return "To improve your resume for HR success: Use a clear, professional format with standard headings. Tailor your content to match job descriptions. Quantify achievements with numbers. Include relevant keywords naturally. Keep it to 1-2 pages. Use bullet points with action verbs. Proofread carefully for errors."
 
 
274
 
275
- if any(phrase in user_lower for phrase in ['hr', 'hiring manager', 'recruiter', 'employer']):
276
- return "To appeal to HR professionals: Use standard section headings they recognize. Include relevant keywords for ATS systems. Show clear career progression. Make it scannable with bullet points. Demonstrate measurable value and impact you can bring to their organization."
 
 
 
 
 
 
277
 
278
- if any(word in user_lower for word in ['help', 'advice', 'tips', 'suggestions']):
279
- return "Key resume best practices: Customize for each job application. Use metrics to show impact. Include both technical and soft skills. Write compelling summaries. Use reverse chronological order. Keep formatting clean and professional. Focus on achievements, not just duties."
280
 
281
- return None
 
 
 
 
 
 
 
282
 
283
  def generate_response(self, user_input: str, resume_context: str = "") -> str:
284
- """Generate response using templates and contextual advice"""
285
  if not self.is_loaded:
286
- return "Please initialize the AI assistant first by clicking 'Initialize AI'."
287
 
288
- # Try template response first
289
  template_response = self.get_template_response(user_input)
290
  if template_response:
291
  self.memory.add_conversation(user_input, template_response)
292
  return template_response
293
 
294
- # If no template match, provide contextual advice
295
- contextual_response = self.get_contextual_advice(user_input, resume_context)
296
- self.memory.add_conversation(user_input, contextual_response)
297
- return contextual_response
 
298
 
299
- def get_contextual_advice(self, user_input: str, resume_context: str) -> str:
300
- """Provide advice based on resume context and user input"""
301
  user_lower = user_input.lower()
302
 
303
- # Analyze resume context if available
304
- if resume_context:
305
- word_count = len(resume_context.split())
306
- has_contact = '@' in resume_context or any(char.isdigit() for char in resume_context[:200])
307
- has_bullets = any(marker in resume_context for marker in ['•', '*', '-', '→'])
308
-
309
- context_advice = []
310
-
311
- if word_count < 200:
312
- context_advice.append("Your resume appears brief - consider expanding with more detailed achievements and responsibilities.")
313
- elif word_count > 800:
314
- context_advice.append("Your resume might be too lengthy - focus on the most relevant and impactful information.")
315
-
316
- if not has_contact:
317
- context_advice.append("Ensure your contact information (email and phone) is clearly visible at the top.")
318
-
319
- if not has_bullets:
320
- context_advice.append("Use bullet points to improve readability and make your achievements easier to scan.")
321
-
322
- if context_advice:
323
- return "Based on your resume: " + " ".join(context_advice)
324
-
325
- # Default comprehensive advice based on query type
326
  if any(phrase in user_lower for phrase in ['improve', 'better', 'enhance', 'optimize']):
327
- return """To improve your resume effectiveness: 1) Tailor content to match specific job descriptions. 2) Use quantifiable achievements with numbers and percentages. 3) Start bullet points with strong action verbs like 'Led', 'Implemented', 'Increased'. 4) Keep it concise but comprehensive (1-2 pages). 5) Use clean, professional formatting with consistent styling. 6) Include both technical and soft skills relevant to your field. 7) Proofread thoroughly for grammar and spelling errors."""
328
 
 
 
 
 
 
329
  elif any(phrase in user_lower for phrase in ['job', 'career', 'position', 'role', 'work']):
330
- return """For successful job applications: 1) Research each company and role thoroughly. 2) Customize your resume for every application. 3) Highlight experiences most relevant to the specific position. 4) Use industry-specific terminology and keywords. 5) Show clear alignment between your background and their requirements. 6) Demonstrate both technical competencies and interpersonal skills. 7) Follow up professionally after applications."""
331
 
332
- elif any(word in user_lower for word in ['why', 'what', 'how', 'when', 'where']):
333
- return """Resume fundamentals: Focus on achievements over duties, use specific numbers when possible, maintain consistent formatting, tailor content for each application, include relevant keywords naturally, keep information current and accurate, and ensure easy readability with clear section headings."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
 
 
 
 
335
  else:
336
- return """Key resume principles: Use professional formatting with clear headings. Lead with your strongest qualifications. Include relevant keywords naturally throughout. Quantify achievements with specific metrics. Keep descriptions concise but impactful. Ensure error-free writing and consistent style. Focus on the value you can bring to potential employers."""
 
 
337
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  @st.cache_resource
339
  def download_nltk_data():
340
  try:
@@ -700,114 +866,6 @@ class ResumeAnalyzer:
700
  buffer.seek(0)
701
  return buffer
702
 
703
- def create_improved_chat_interface(resume_context: str = ""):
704
- """Create improved chat interface with better UI"""
705
-
706
- st.markdown('<h3 class="section-header">AI Resume Assistant</h3>', unsafe_allow_html=True)
707
-
708
- # Initialize chatbot
709
- if 'improved_chatbot' not in st.session_state:
710
- st.session_state.improved_chatbot = ImprovedCPUChatbot()
711
-
712
- chatbot = st.session_state.improved_chatbot
713
-
714
- # Model status and initialization
715
- col1, col2 = st.columns([3, 1])
716
-
717
- with col1:
718
- if chatbot.is_loaded:
719
- display_alert_box("AI Assistant is ready to help with your resume questions", "success")
720
- else:
721
- display_alert_box("Click 'Initialize AI' to start the assistant", "info")
722
-
723
- with col2:
724
- if st.button("Initialize AI", type="primary", use_container_width=True):
725
- with st.spinner("Initializing AI model..."):
726
- if chatbot.initialize():
727
- st.success("AI model loaded successfully!")
728
- st.rerun()
729
- else:
730
- st.error("Failed to initialize AI model")
731
-
732
- if chatbot.is_loaded:
733
- # Quick questions section
734
- st.markdown('<h4 class="section-header">Quick Questions</h4>', unsafe_allow_html=True)
735
-
736
- quick_questions = [
737
- ("Experience Section Help", "How can I improve my experience section?"),
738
- ("ATS Optimization", "How do I make my resume ATS-friendly?"),
739
- ("Keywords & Skills", "What keywords should I include?"),
740
- ("Format & Layout", "How should I format my resume?")
741
- ]
742
-
743
- cols = st.columns(2)
744
- for i, (title, question) in enumerate(quick_questions):
745
- with cols[i % 2]:
746
- if st.button(title, use_container_width=True):
747
- st.session_state.quick_question = question
748
-
749
- # Chat input section
750
- st.markdown('<h4 class="section-header">Ask a Question</h4>', unsafe_allow_html=True)
751
-
752
- user_question = st.text_input(
753
- "Type your resume question here:",
754
- value=st.session_state.get('quick_question', ''),
755
- placeholder="How can I improve my resume for better results?",
756
- key="improved_chat_input"
757
- )
758
-
759
- # Action buttons
760
- col1, col2, col3 = st.columns([1, 1, 2])
761
- with col1:
762
- send_clicked = st.button("Send Question", type="primary", use_container_width=True)
763
- with col2:
764
- if st.button("Clear Chat", use_container_width=True):
765
- st.session_state.improved_chat_history = []
766
- if 'quick_question' in st.session_state:
767
- del st.session_state.quick_question
768
- st.rerun()
769
-
770
- # Generate response
771
- if send_clicked and user_question.strip():
772
- with st.spinner("Generating personalized advice..."):
773
- response = chatbot.generate_response(user_question, resume_context)
774
- if 'quick_question' in st.session_state:
775
- del st.session_state.quick_question
776
- st.rerun()
777
-
778
- # Display conversation history
779
- if st.session_state.improved_chat_history:
780
- st.markdown('<h4 class="section-header">Conversation History</h4>', unsafe_allow_html=True)
781
-
782
- for conv in reversed(st.session_state.improved_chat_history[-3:]):
783
- with st.container():
784
- st.markdown(f"**Question:** {conv['user']}")
785
- st.markdown(f"**Answer:** {conv['bot']}")
786
- st.caption(f"Asked at: {conv['timestamp']}")
787
- st.divider()
788
-
789
- else:
790
- # Information about the AI assistant
791
- st.markdown('<h4 class="section-header">About the AI Assistant</h4>', unsafe_allow_html=True)
792
-
793
- with st.expander("Features and Capabilities", expanded=True):
794
- st.markdown("""
795
- **The AI Resume Assistant provides:**
796
-
797
- **Instant Expert Advice** - Get immediate answers to common resume questions
798
-
799
- **Personalized Recommendations** - Tailored advice based on your specific resume content
800
-
801
- **Quick Response Options** - Pre-built answers for the most frequently asked questions
802
-
803
- **Conversation Memory** - The assistant remembers your previous questions in the current session
804
-
805
- **Model Information:**
806
- - Uses DistilGPT2 with optimized parameters for resume advice
807
- - Runs locally on CPU for privacy and speed
808
- - Enhanced with expert knowledge templates for common scenarios
809
- """)
810
-
811
  def main():
812
  st.set_page_config(
813
  page_title="Professional Resume Analyzer",
 
187
  (token.isalpha() or token in resume_keywords)):
188
  filtered_tokens.append(token)
189
 
190
+ # Return only the most relevant terms
191
  return ' '.join(filtered_tokens[:max_terms])
192
 
193
  class ImprovedChatMemory:
 
203
  }
204
  st.session_state.improved_chat_history.append(conversation)
205
 
206
+ # Keep only last 6 conversations
207
  if len(st.session_state.improved_chat_history) > 6:
208
  st.session_state.improved_chat_history = st.session_state.improved_chat_history[-6:]
209
 
 
212
  if not st.session_state.improved_chat_history:
213
  return ""
214
 
215
+ # Only use the last conversation for context
216
  last_conv = st.session_state.improved_chat_history[-1]
217
+ last_topic = last_conv['user'][:30] # First 30 chars only
218
  return f"Previously discussed: {last_topic}"
219
 
220
  class ImprovedCPUChatbot:
221
  def __init__(self):
222
+ self.model_name = "distilgpt2"
223
+ self.model = None
224
+ self.tokenizer = None
225
+ self.pipeline = None
226
  self.nlp_processor = ImprovedNLPProcessor()
227
  self.memory = ImprovedChatMemory()
228
  self.is_loaded = False
229
 
230
+ # Predefined responses for common resume questions
231
  self.template_responses = {
232
  'experience': "To improve your experience section: Use bullet points with action verbs, quantify achievements with numbers, focus on results rather than duties, and tailor content to match job requirements.",
233
  'ats': "Make your resume ATS-friendly by: Using standard section headings, including relevant keywords naturally, avoiding images and complex formatting, using common fonts like Arial, and saving as PDF.",
234
  'skills': "Enhance your skills section by: Organizing technical and soft skills separately, matching skills to job descriptions, providing proficiency levels, and including both hard and soft skills relevant to your target role.",
235
  'keywords': "Add relevant keywords by: Studying job descriptions in your field, using industry-specific terms, including both acronyms and full terms, and incorporating them naturally throughout your resume.",
236
+ 'format': "Improve resume formatting with: Clear section headings, consistent bullet points, readable fonts, appropriate white space, and a clean, professional layout that's easy to scan."
 
 
 
 
 
237
  }
238
 
239
+ @st.cache_resource
240
+ def load_model(_self):
241
+ """Load the model with better configuration"""
242
  try:
243
+ with st.spinner("Loading AI model (first time may take 2-3 minutes)..."):
244
+ tokenizer = AutoTokenizer.from_pretrained(_self.model_name)
245
+ tokenizer.pad_token = tokenizer.eos_token
246
+
247
+ model = AutoModelForCausalLM.from_pretrained(
248
+ _self.model_name,
249
+ torch_dtype=torch.float32,
250
+ low_cpu_mem_usage=True
251
+ )
252
+
253
+ # Create pipeline with better parameters
254
+ text_generator = pipeline(
255
+ "text-generation",
256
+ model=model,
257
+ tokenizer=tokenizer,
258
+ device=-1, # CPU only
259
+ max_new_tokens=50, # Reduced for better quality
260
+ do_sample=True,
261
+ temperature=0.8,
262
+ top_p=0.85,
263
+ top_k=50,
264
+ repetition_penalty=1.2, # Reduce repetition
265
+ pad_token_id=tokenizer.eos_token_id,
266
+ no_repeat_ngram_size=3 # Prevent 3-gram repetition
267
+ )
268
+
269
+ return model, tokenizer, text_generator
270
  except Exception as e:
271
+ st.error(f"Failed to load model: {str(e)}")
272
+ return None, None, None
273
+
274
+ def initialize(self):
275
+ """Initialize the chatbot"""
276
+ if not self.is_loaded:
277
+ result = self.load_model()
278
+ if result[0] is not None:
279
+ self.model, self.tokenizer, self.pipeline = result
280
+ self.is_loaded = True
281
+ st.success("AI model loaded successfully!")
282
+ return True
283
+ else:
284
+ return False
285
+ return True
286
 
287
  def get_template_response(self, user_input: str) -> str:
288
+ """Check if we can use a template response for common questions"""
289
  user_lower = user_input.lower()
290
 
291
+ # Check for common patterns
292
+ if any(word in user_lower for word in ['experience', 'work history', 'job history']):
293
+ return self.template_responses['experience']
294
+ elif any(word in user_lower for word in ['ats', 'applicant tracking', 'ats-friendly']):
295
+ return self.template_responses['ats']
296
+ elif any(word in user_lower for word in ['skills', 'technical skills', 'abilities']):
297
+ return self.template_responses['skills']
298
+ elif any(word in user_lower for word in ['keywords', 'keyword', 'terms']):
299
+ return self.template_responses['keywords']
300
+ elif any(word in user_lower for word in ['format', 'formatting', 'layout', 'design']):
301
+ return self.template_responses['format']
302
+ # Add general improvement patterns
303
+ elif any(phrase in user_lower for phrase in ['improve my resume', 'better resume', 'hire me', 'get hired', 'land job']):
 
 
 
 
 
 
 
304
  return "To improve your resume for HR success: Use a clear, professional format with standard headings. Tailor your content to match job descriptions. Quantify achievements with numbers. Include relevant keywords naturally. Keep it to 1-2 pages. Use bullet points with action verbs. Proofread carefully for errors."
305
+ elif any(word in user_lower for word in ['help', 'advice', 'tips', 'suggestions']):
306
+ return "Key resume tips: Match your resume to each job application. Use metrics to show your impact. Include both technical and soft skills. Write a compelling summary. Use reverse chronological order. Keep formatting clean and simple."
307
 
308
+ return None
309
+
310
+ def create_simple_prompt(self, user_input: str, resume_context: str = "") -> str:
311
+ """Create a very simple, clear prompt"""
312
+ # Try template response first
313
+ template_response = self.get_template_response(user_input)
314
+ if template_response:
315
+ return template_response
316
 
317
+ # Extract key terms
318
+ key_terms = self.nlp_processor.extract_key_terms(user_input)
319
 
320
+ # Create simple prompt
321
+ if resume_context:
322
+ context_snippet = resume_context[:100].replace('\n', ' ')
323
+ prompt = f"Resume help: {context_snippet}\nQuestion: {user_input}\nAdvice:"
324
+ else:
325
+ prompt = f"Resume question: {user_input}\nHelpful advice:"
326
+
327
+ return prompt
328
 
329
  def generate_response(self, user_input: str, resume_context: str = "") -> str:
330
+ """Generate response with better quality control and timeout handling"""
331
  if not self.is_loaded:
332
+ return "Please initialize the AI model first by clicking 'Initialize AI'."
333
 
334
+ # Check for template response first (this should catch most questions)
335
  template_response = self.get_template_response(user_input)
336
  if template_response:
337
  self.memory.add_conversation(user_input, template_response)
338
  return template_response
339
 
340
+ # For non-template questions, provide a general helpful response instead of using the model
341
+ # This avoids the generation loops and stuck behavior
342
+ general_response = self.get_comprehensive_advice(user_input)
343
+ self.memory.add_conversation(user_input, general_response)
344
+ return general_response
345
 
346
+ def get_comprehensive_advice(self, user_input: str) -> str:
347
+ """Provide comprehensive advice based on user input patterns"""
348
  user_lower = user_input.lower()
349
 
350
+ # Comprehensive resume improvement advice
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  if any(phrase in user_lower for phrase in ['improve', 'better', 'enhance', 'optimize']):
352
+ return """To improve your resume effectiveness: 1) Tailor it to each job by matching keywords from the job description. 2) Use quantifiable achievements (increased sales by 25%, managed team of 10). 3) Start bullet points with strong action verbs. 4) Keep it concise - ideally 1-2 pages. 5) Use a clean, professional format with consistent styling. 6) Include relevant technical and soft skills. 7) Proofread carefully for any errors."""
353
 
354
+ # HR/hiring focused advice
355
+ elif any(phrase in user_lower for phrase in ['hr', 'hire', 'hiring', 'recruiter', 'employer']):
356
+ return """To make your resume appealing to HR and hiring managers: 1) Use standard section headings they expect (Experience, Education, Skills). 2) Include relevant keywords to pass ATS screening. 3) Show clear career progression and achievements. 4) Make it easy to scan with bullet points and white space. 5) Demonstrate value you can bring to their organization. 6) Include measurable results and impacts."""
357
+
358
+ # Job search and career advice
359
  elif any(phrase in user_lower for phrase in ['job', 'career', 'position', 'role', 'work']):
360
+ return """For job search success: 1) Customize your resume for each application. 2) Research the company and role requirements. 3) Highlight relevant experience and skills prominently. 4) Use industry-specific terminology. 5) Show how your background aligns with their needs. 6) Include both technical competencies and soft skills."""
361
 
362
+ # General help
363
+ else:
364
+ return """Key resume best practices: Use a professional format with clear headings. Lead with your strongest qualifications. Include relevant keywords naturally. Quantify achievements with specific numbers. Keep descriptions concise but impactful. Ensure error-free writing and consistent formatting. Focus on what value you bring to employers."""
365
+
366
+ def get_general_advice(self, user_input: str) -> str:
367
+ """Fallback advice for when model fails"""
368
+ user_lower = user_input.lower()
369
+ if 'experience' in user_lower:
370
+ return "Focus on achievements with numbers, use action verbs, and show results."
371
+ elif 'skill' in user_lower:
372
+ return "List skills that match the job description and organize them by category."
373
+ elif 'ats' in user_lower:
374
+ return "Use standard headings, include keywords, and avoid complex formatting."
375
+ else:
376
+ return "Make sure your resume is clear, relevant to the job, and easy to read."
377
+
378
+ def clean_response_thoroughly(self, response: str, user_input: str) -> str:
379
+ """Thoroughly clean the generated response"""
380
+ if not response or len(response.strip()) < 5:
381
+ return self.get_general_advice(user_input)
382
+
383
+ # Remove common problematic patterns
384
+ response = re.sub(r'\|[^|]*\|', '', response) # Remove pipe-separated content
385
+ response = re.sub(r'Advice:\s*', '', response) # Remove "Advice:" repetition
386
+ response = re.sub(r'\s+', ' ', response) # Replace multiple spaces
387
+ response = re.sub(r'[.]{2,}', '.', response) # Replace multiple periods
388
+
389
+ # Split into sentences and filter
390
+ sentences = [s.strip() for s in response.split('.') if s.strip()]
391
+ good_sentences = []
392
+
393
+ seen_content = set()
394
+ for sentence in sentences[:2]: # Max 2 sentences
395
+ if (len(sentence) > 15 and
396
+ sentence.lower() not in seen_content and
397
+ not sentence.lower().startswith(('you are', 'i am', 'as a', 'how do')) and
398
+ 'advice' not in sentence.lower()):
399
+
400
+ good_sentences.append(sentence)
401
+ seen_content.add(sentence.lower())
402
 
403
+ if good_sentences:
404
+ response = '. '.join(good_sentences)
405
+ if not response.endswith('.'):
406
+ response += '.'
407
  else:
408
+ response = self.get_general_advice(user_input)
409
+
410
+ return response.strip()
411
 
412
+ def create_improved_chat_interface(resume_context: str = ""):
413
+ """Create improved chat interface"""
414
+
415
+ st.header("AI Resume Assistant")
416
+
417
+ # Initialize chatbot
418
+ if 'improved_chatbot' not in st.session_state:
419
+ st.session_state.improved_chatbot = ImprovedCPUChatbot()
420
+
421
+ chatbot = st.session_state.improved_chatbot
422
+
423
+ # Model initialization
424
+ col1, col2 = st.columns([3, 1])
425
+
426
+ with col1:
427
+ st.info("Using DistilGPT2 with improved response quality")
428
+
429
+ with col2:
430
+ if st.button("Initialize AI", type="primary"):
431
+ chatbot.initialize()
432
+
433
+ # Chat interface
434
+ if chatbot.is_loaded:
435
+ st.success("AI Ready")
436
+
437
+ # Quick questions
438
+ st.subheader("Quick Questions")
439
+ col1, col2 = st.columns(2)
440
+
441
+ with col1:
442
+ if st.button("How to improve experience section?"):
443
+ st.session_state.quick_question = "What's wrong with my experience section?"
444
+
445
+ with col2:
446
+ if st.button("Make resume ATS-friendly?"):
447
+ st.session_state.quick_question = "How do I make it more ATS-friendly?"
448
+
449
+ col3, col4 = st.columns(2)
450
+ with col3:
451
+ if st.button("Add better keywords?"):
452
+ st.session_state.quick_question = "What keywords should I add?"
453
+
454
+ with col4:
455
+ if st.button("Improve skills section?"):
456
+ st.session_state.quick_question = "How can I improve my skills section?"
457
+
458
+ # Chat input
459
+ user_question = st.text_input(
460
+ "Ask about your resume:",
461
+ value=st.session_state.get('quick_question', ''),
462
+ placeholder="How can I improve my resume?",
463
+ key="improved_chat_input"
464
+ )
465
+
466
+ # Send button and clear
467
+ col1, col2 = st.columns([1, 3])
468
+ with col1:
469
+ send_clicked = st.button("Send", type="primary")
470
+ with col2:
471
+ if st.button("Clear Chat"):
472
+ st.session_state.improved_chat_history = []
473
+ if 'quick_question' in st.session_state:
474
+ del st.session_state.quick_question
475
+ st.experimental_rerun()
476
+
477
+ # Generate response
478
+ if send_clicked and user_question.strip():
479
+ with st.spinner("Generating advice..."):
480
+ response = chatbot.generate_response(user_question, resume_context)
481
+ if 'quick_question' in st.session_state:
482
+ del st.session_state.quick_question
483
+ st.experimental_rerun()
484
+
485
+ # Display chat history
486
+ if st.session_state.improved_chat_history:
487
+ st.subheader("💬 Conversation")
488
+
489
+ for conv in reversed(st.session_state.improved_chat_history[-3:]): # Show last 3
490
+ st.markdown(f"**You:** {conv['user']}")
491
+ st.markdown(f"**AI:** {conv['bot']}")
492
+ st.caption(f"Time: {conv['timestamp']}")
493
+ st.divider()
494
+
495
+ else:
496
+ st.warning("Click 'Initialize AI' to start chatting")
497
+
498
+ with st.expander("Improved Features"):
499
+ st.markdown("""
500
+ **Model**: DistilGPT2 with enhanced parameters
501
+ **Response time**: 1-3 seconds
502
+ **Quality**: Significantly improved over basic version
503
+ """)
504
  @st.cache_resource
505
  def download_nltk_data():
506
  try:
 
866
  buffer.seek(0)
867
  return buffer
868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
869
  def main():
870
  st.set_page_config(
871
  page_title="Professional Resume Analyzer",