ZainabFatimaa commited on
Commit
301e290
Β·
verified Β·
1 Parent(s): 946b75e

Update src/app.py

Browse files
Files changed (1) hide show
  1. src/app.py +245 -182
src/app.py CHANGED
@@ -70,8 +70,10 @@ import re
70
  from datetime import datetime
71
  from typing import Dict, List
72
 
73
- # Simple NLP processor
74
- class SimpleNLPProcessor:
 
 
75
  def __init__(self):
76
  self.setup_nltk()
77
 
@@ -86,32 +88,30 @@ class SimpleNLPProcessor:
86
  self.stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'with'}
87
  self.lemmatizer = None
88
 
89
- def process_text(self, text: str) -> str:
90
- """Clean and process text for better context"""
91
  try:
92
  tokens = word_tokenize(text.lower())
93
  except:
94
  tokens = text.lower().split()
95
 
96
- # Remove stopwords and short tokens
97
- filtered_tokens = [token for token in tokens
98
- if token not in self.stop_words and len(token) > 2]
99
 
100
- # Lemmatize if available
101
- if self.lemmatizer:
102
- try:
103
- filtered_tokens = [self.lemmatizer.lemmatize(token) for token in filtered_tokens]
104
- except:
105
- pass
106
 
107
- # Return key terms (limit to avoid long prompts)
108
- return ' '.join(filtered_tokens[:15])
109
 
110
- # Simple memory management
111
- class SimpleChatMemory:
112
  def __init__(self):
113
- if 'chat_history' not in st.session_state:
114
- st.session_state.chat_history = []
115
 
116
  def add_conversation(self, user_msg: str, bot_response: str):
117
  conversation = {
@@ -119,62 +119,69 @@ class SimpleChatMemory:
119
  'bot': bot_response,
120
  'timestamp': datetime.now().strftime("%H:%M:%S")
121
  }
122
- st.session_state.chat_history.append(conversation)
123
 
124
- # Keep only last 8 conversations to save memory
125
- if len(st.session_state.chat_history) > 8:
126
- st.session_state.chat_history = st.session_state.chat_history[-8:]
127
 
128
- def get_recent_context(self, limit: int = 2) -> str:
129
- """Get recent conversation context"""
130
- if not st.session_state.chat_history:
131
  return ""
132
 
133
- recent = st.session_state.chat_history[-limit:]
134
- context_parts = []
135
- for conv in recent:
136
- context_parts.append(f"User asked: {conv['user'][:50]}...")
137
-
138
- return " | ".join(context_parts) if context_parts else ""
139
 
140
- # Main chatbot class
141
- class SimpleCPUChatbot:
142
  def __init__(self):
143
- self.model_name = "distilgpt2" # Fast, CPU-friendly model
144
  self.model = None
145
  self.tokenizer = None
146
  self.pipeline = None
147
- self.nlp_processor = SimpleNLPProcessor()
148
- self.memory = SimpleChatMemory()
149
  self.is_loaded = False
 
 
 
 
 
 
 
 
 
150
 
151
  @st.cache_resource
152
  def load_model(_self):
153
- """Load the model (cached for efficiency)"""
154
  try:
155
  with st.spinner("Loading AI model (first time may take 2-3 minutes)..."):
156
- # Load tokenizer
157
  tokenizer = AutoTokenizer.from_pretrained(_self.model_name)
158
  tokenizer.pad_token = tokenizer.eos_token
159
 
160
- # Load model with CPU optimization
161
  model = AutoModelForCausalLM.from_pretrained(
162
  _self.model_name,
163
- torch_dtype=torch.float32, # Use float32 for CPU
164
  low_cpu_mem_usage=True
165
  )
166
 
167
- # Create pipeline
168
  text_generator = pipeline(
169
  "text-generation",
170
  model=model,
171
  tokenizer=tokenizer,
172
  device=-1, # CPU only
173
- max_new_tokens=80,
174
  do_sample=True,
175
- temperature=0.7,
176
- top_p=0.9,
177
- pad_token_id=tokenizer.eos_token_id
 
 
 
178
  )
179
 
180
  return model, tokenizer, text_generator
@@ -192,67 +199,83 @@ class SimpleCPUChatbot:
192
  st.success("AI model loaded successfully!")
193
  return True
194
  else:
195
- st.error("Failed to load AI model")
196
  return False
197
  return True
198
 
199
- def create_prompt(self, user_input: str, resume_context: str = "") -> str:
200
- """Create a focused prompt for resume advice"""
201
- # Process user input for key terms
202
- key_terms = self.nlp_processor.process_text(user_input)
203
-
204
- # Get conversation context
205
- recent_context = self.memory.get_recent_context()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
- # Build prompt
208
- prompt_parts = [
209
- "You are a professional resume consultant. Give specific, helpful advice."
210
- ]
211
 
212
- # Add resume context if available (limited)
213
  if resume_context:
214
- resume_excerpt = resume_context[:200] + "..." if len(resume_context) > 200 else resume_context
215
- prompt_parts.append(f"Resume excerpt: {resume_excerpt}")
216
-
217
- # Add conversation context
218
- if recent_context:
219
- prompt_parts.append(f"Previous topics: {recent_context}")
220
-
221
- # Add key terms from current question
222
- if key_terms:
223
- prompt_parts.append(f"Focus areas: {key_terms}")
224
-
225
- # Add the actual question
226
- prompt_parts.append(f"Question: {user_input}")
227
- prompt_parts.append("Advice:")
228
 
229
- return " | ".join(prompt_parts)
230
 
231
  def generate_response(self, user_input: str, resume_context: str = "") -> str:
232
- """Generate response using the loaded model"""
233
  if not self.is_loaded:
234
  return "Please initialize the AI model first by clicking 'Initialize AI'."
235
 
 
 
 
 
 
 
236
  try:
237
- # Create prompt
238
- prompt = self.create_prompt(user_input, resume_context)
 
 
 
 
 
239
 
240
- # Generate response
241
  result = self.pipeline(
242
  prompt,
243
- max_new_tokens=60, # Keep responses concise
244
  num_return_sequences=1,
245
  temperature=0.7,
246
  do_sample=True,
247
- top_p=0.9
 
248
  )
249
 
250
  # Extract and clean response
251
  generated_text = result[0]['generated_text']
252
  response = generated_text.replace(prompt, "").strip()
253
 
254
- # Clean up the response
255
- response = self.clean_response(response, user_input)
256
 
257
  # Add to memory
258
  self.memory.add_conversation(user_input, response)
@@ -260,30 +283,157 @@ class SimpleCPUChatbot:
260
  return response
261
 
262
  except Exception as e:
263
- return f"Sorry, I encountered an error: {str(e)}. Please try a simpler question."
 
 
264
 
265
- def clean_response(self, response: str, user_input: str) -> str:
266
- """Clean and improve the generated response"""
267
- # Remove extra whitespace and newlines
268
- response = re.sub(r'\s+', ' ', response).strip()
269
-
270
- # Split into sentences and take first few good ones
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  sentences = [s.strip() for s in response.split('.') if s.strip()]
272
  good_sentences = []
273
 
274
- for sentence in sentences[:3]: # Max 3 sentences
275
- if len(sentence) > 10 and not sentence.lower().startswith(('you are', 'i am', 'as a')):
 
 
 
 
 
276
  good_sentences.append(sentence)
 
277
 
278
  if good_sentences:
279
  response = '. '.join(good_sentences)
280
  if not response.endswith('.'):
281
  response += '.'
282
  else:
283
- # Fallback response
284
- response = "I'd be happy to help with your resume. Could you be more specific about what you need assistance with?"
285
 
286
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  # Download NLTK data if not already present
288
  @st.cache_resource
289
  def download_nltk_data():
@@ -708,94 +858,7 @@ class ResumeAnalyzer:
708
  doc.build(story)
709
  buffer.seek(0)
710
  return buffer
711
-
712
- def create_simple_chat_interface(resume_context: str = ""):
713
- """Create simple chat interface for the resume analyzer"""
714
-
715
- st.header("πŸ€– AI Resume Assistant")
716
-
717
- # Initialize chatbot
718
- if 'simple_chatbot' not in st.session_state:
719
- st.session_state.simple_chatbot = SimpleCPUChatbot()
720
-
721
- chatbot = st.session_state.simple_chatbot
722
-
723
- # Model initialization
724
- col1, col2 = st.columns([3, 1])
725
-
726
- with col1:
727
- st.info("Using DistilGPT2 - Fast CPU-only model (β‰ˆ250MB download)")
728
-
729
- with col2:
730
- if st.button("Initialize AI", type="primary"):
731
- chatbot.initialize()
732
-
733
- # Chat interface
734
- if chatbot.is_loaded:
735
- st.success("βœ… AI Ready")
736
-
737
- # Sample questions
738
- with st.expander("πŸ’‘ Try asking"):
739
- sample_questions = [
740
- "How can I improve my resume?",
741
- "What skills should I add?",
742
- "How do I make it more ATS-friendly?",
743
- "What's wrong with my experience section?"
744
- ]
745
- for q in sample_questions:
746
- if st.button(q, key=f"sample_{hash(q)}"):
747
- st.session_state.current_question = q
748
 
749
- # Chat input
750
- user_question = st.text_input(
751
- "Ask about your resume:",
752
- value=st.session_state.get('current_question', ''),
753
- placeholder="How can I improve my resume for tech jobs?",
754
- key="chat_input"
755
- )
756
-
757
- # Send button and clear
758
- col1, col2 = st.columns([1, 3])
759
- with col1:
760
- send_clicked = st.button("Send", type="primary")
761
- with col2:
762
- if st.button("Clear Chat"):
763
- st.session_state.chat_history = []
764
- if 'current_question' in st.session_state:
765
- del st.session_state.current_question
766
- st.experimental_rerun()
767
-
768
- # Generate response
769
- if send_clicked and user_question.strip():
770
- with st.spinner("Thinking..."):
771
- response = chatbot.generate_response(user_question, resume_context)
772
- if 'current_question' in st.session_state:
773
- del st.session_state.current_question
774
- st.experimental_rerun()
775
-
776
- # Display chat history
777
- if st.session_state.chat_history:
778
- st.subheader("πŸ’¬ Conversation")
779
-
780
- for conv in reversed(st.session_state.chat_history[-5:]): # Show last 5
781
- st.markdown(f"**You:** {conv['user']}")
782
- st.markdown(f"**AI:** {conv['bot']}")
783
- st.caption(f"Time: {conv['timestamp']}")
784
- st.divider()
785
-
786
- else:
787
- st.warning("Click 'Initialize AI' to start chatting")
788
-
789
- with st.expander("ℹ️ About this AI"):
790
- st.markdown("""
791
- **Model**: DistilGPT2 (CPU-optimized)
792
- **Size**: ~250MB download
793
- **Speed**: 2-5 seconds per response
794
- **Memory**: ~1GB RAM usage
795
-
796
- This model runs entirely on your CPU and provides helpful resume advice.
797
- First initialization will download the model files.
798
- """)
799
  def main():
800
  st.set_page_config(
801
  page_title="AI Resume Analyzer with Chatbot",
@@ -1046,7 +1109,7 @@ def main():
1046
  # Chat Interface - Properly indented inside the file upload condition
1047
  st.markdown("---")
1048
  st.header("πŸ’¬ Chat with Resume Assistant")
1049
- create_simple_chat_interface(st.session_state.get('resume_context', ''))
1050
 
1051
  except Exception as e:
1052
  st.error(f"Error during analysis: {str(e)}")
 
70
  from datetime import datetime
71
  from typing import Dict, List
72
 
73
+ # Set seed for reproducibility
74
+ set_seed(42)
75
+
76
+ class ImprovedNLPProcessor:
77
  def __init__(self):
78
  self.setup_nltk()
79
 
 
88
  self.stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'with'}
89
  self.lemmatizer = None
90
 
91
+ def extract_key_terms(self, text: str, max_terms: int = 5) -> str:
92
+ """Extract key terms without overwhelming the model"""
93
  try:
94
  tokens = word_tokenize(text.lower())
95
  except:
96
  tokens = text.lower().split()
97
 
98
+ # Focus on resume-relevant terms
99
+ resume_keywords = ['resume', 'experience', 'skills', 'education', 'job', 'work', 'ats', 'career']
 
100
 
101
+ filtered_tokens = []
102
+ for token in tokens:
103
+ if (len(token) > 2 and
104
+ token not in self.stop_words and
105
+ (token.isalpha() or token in resume_keywords)):
106
+ filtered_tokens.append(token)
107
 
108
+ # Return only the most relevant terms
109
+ return ' '.join(filtered_tokens[:max_terms])
110
 
111
+ class ImprovedChatMemory:
 
112
  def __init__(self):
113
+ if 'improved_chat_history' not in st.session_state:
114
+ st.session_state.improved_chat_history = []
115
 
116
  def add_conversation(self, user_msg: str, bot_response: str):
117
  conversation = {
 
119
  'bot': bot_response,
120
  'timestamp': datetime.now().strftime("%H:%M:%S")
121
  }
122
+ st.session_state.improved_chat_history.append(conversation)
123
 
124
+ # Keep only last 6 conversations
125
+ if len(st.session_state.improved_chat_history) > 6:
126
+ st.session_state.improved_chat_history = st.session_state.improved_chat_history[-6:]
127
 
128
+ def get_simple_context(self) -> str:
129
+ """Get very simple context to avoid confusing the model"""
130
+ if not st.session_state.improved_chat_history:
131
  return ""
132
 
133
+ # Only use the last conversation for context
134
+ last_conv = st.session_state.improved_chat_history[-1]
135
+ last_topic = last_conv['user'][:30] # First 30 chars only
136
+ return f"Previously discussed: {last_topic}"
 
 
137
 
138
+ class ImprovedCPUChatbot:
 
139
  def __init__(self):
140
+ self.model_name = "distilgpt2"
141
  self.model = None
142
  self.tokenizer = None
143
  self.pipeline = None
144
+ self.nlp_processor = ImprovedNLPProcessor()
145
+ self.memory = ImprovedChatMemory()
146
  self.is_loaded = False
147
+
148
+ # Predefined responses for common resume questions
149
+ self.template_responses = {
150
+ '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.",
151
+ '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.",
152
+ '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.",
153
+ '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.",
154
+ '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."
155
+ }
156
 
157
  @st.cache_resource
158
  def load_model(_self):
159
+ """Load the model with better configuration"""
160
  try:
161
  with st.spinner("Loading AI model (first time may take 2-3 minutes)..."):
 
162
  tokenizer = AutoTokenizer.from_pretrained(_self.model_name)
163
  tokenizer.pad_token = tokenizer.eos_token
164
 
 
165
  model = AutoModelForCausalLM.from_pretrained(
166
  _self.model_name,
167
+ torch_dtype=torch.float32,
168
  low_cpu_mem_usage=True
169
  )
170
 
171
+ # Create pipeline with better parameters
172
  text_generator = pipeline(
173
  "text-generation",
174
  model=model,
175
  tokenizer=tokenizer,
176
  device=-1, # CPU only
177
+ max_new_tokens=50, # Reduced for better quality
178
  do_sample=True,
179
+ temperature=0.8,
180
+ top_p=0.85,
181
+ top_k=50,
182
+ repetition_penalty=1.2, # Reduce repetition
183
+ pad_token_id=tokenizer.eos_token_id,
184
+ no_repeat_ngram_size=3 # Prevent 3-gram repetition
185
  )
186
 
187
  return model, tokenizer, text_generator
 
199
  st.success("AI model loaded successfully!")
200
  return True
201
  else:
 
202
  return False
203
  return True
204
 
205
+ def get_template_response(self, user_input: str) -> str:
206
+ """Check if we can use a template response for common questions"""
207
+ user_lower = user_input.lower()
208
+
209
+ # Check for common patterns
210
+ if any(word in user_lower for word in ['experience', 'work history', 'job history']):
211
+ return self.template_responses['experience']
212
+ elif any(word in user_lower for word in ['ats', 'applicant tracking', 'ats-friendly']):
213
+ return self.template_responses['ats']
214
+ elif any(word in user_lower for word in ['skills', 'technical skills', 'abilities']):
215
+ return self.template_responses['skills']
216
+ elif any(word in user_lower for word in ['keywords', 'keyword', 'terms']):
217
+ return self.template_responses['keywords']
218
+ elif any(word in user_lower for word in ['format', 'formatting', 'layout', 'design']):
219
+ return self.template_responses['format']
220
+
221
+ return None
222
+
223
+ def create_simple_prompt(self, user_input: str, resume_context: str = "") -> str:
224
+ """Create a very simple, clear prompt"""
225
+ # Try template response first
226
+ template_response = self.get_template_response(user_input)
227
+ if template_response:
228
+ return template_response
229
 
230
+ # Extract key terms
231
+ key_terms = self.nlp_processor.extract_key_terms(user_input)
 
 
232
 
233
+ # Create simple prompt
234
  if resume_context:
235
+ context_snippet = resume_context[:100].replace('\n', ' ')
236
+ prompt = f"Resume help: {context_snippet}\nQuestion: {user_input}\nAdvice:"
237
+ else:
238
+ prompt = f"Resume question: {user_input}\nHelpful advice:"
 
 
 
 
 
 
 
 
 
 
239
 
240
+ return prompt
241
 
242
  def generate_response(self, user_input: str, resume_context: str = "") -> str:
243
+ """Generate response with better quality control"""
244
  if not self.is_loaded:
245
  return "Please initialize the AI model first by clicking 'Initialize AI'."
246
 
247
+ # Check for template response first
248
+ template_response = self.get_template_response(user_input)
249
+ if template_response:
250
+ self.memory.add_conversation(user_input, template_response)
251
+ return template_response
252
+
253
  try:
254
+ # Create simple prompt
255
+ prompt = self.create_simple_prompt(user_input, resume_context)
256
+
257
+ # If prompt is a template response, return it directly
258
+ if prompt in self.template_responses.values():
259
+ self.memory.add_conversation(user_input, prompt)
260
+ return prompt
261
 
262
+ # Generate with model
263
  result = self.pipeline(
264
  prompt,
265
+ max_new_tokens=40,
266
  num_return_sequences=1,
267
  temperature=0.7,
268
  do_sample=True,
269
+ top_p=0.9,
270
+ repetition_penalty=1.3
271
  )
272
 
273
  # Extract and clean response
274
  generated_text = result[0]['generated_text']
275
  response = generated_text.replace(prompt, "").strip()
276
 
277
+ # Clean the response thoroughly
278
+ response = self.clean_response_thoroughly(response, user_input)
279
 
280
  # Add to memory
281
  self.memory.add_conversation(user_input, response)
 
283
  return response
284
 
285
  except Exception as e:
286
+ error_response = f"I encountered an error. Here's some general advice: {self.get_general_advice(user_input)}"
287
+ self.memory.add_conversation(user_input, error_response)
288
+ return error_response
289
 
290
+ def get_general_advice(self, user_input: str) -> str:
291
+ """Fallback advice for when model fails"""
292
+ user_lower = user_input.lower()
293
+ if 'experience' in user_lower:
294
+ return "Focus on achievements with numbers, use action verbs, and show results."
295
+ elif 'skill' in user_lower:
296
+ return "List skills that match the job description and organize them by category."
297
+ elif 'ats' in user_lower:
298
+ return "Use standard headings, include keywords, and avoid complex formatting."
299
+ else:
300
+ return "Make sure your resume is clear, relevant to the job, and easy to read."
301
+
302
+ def clean_response_thoroughly(self, response: str, user_input: str) -> str:
303
+ """Thoroughly clean the generated response"""
304
+ if not response or len(response.strip()) < 5:
305
+ return self.get_general_advice(user_input)
306
+
307
+ # Remove common problematic patterns
308
+ response = re.sub(r'\|[^|]*\|', '', response) # Remove pipe-separated content
309
+ response = re.sub(r'Advice:\s*', '', response) # Remove "Advice:" repetition
310
+ response = re.sub(r'\s+', ' ', response) # Replace multiple spaces
311
+ response = re.sub(r'[.]{2,}', '.', response) # Replace multiple periods
312
+
313
+ # Split into sentences and filter
314
  sentences = [s.strip() for s in response.split('.') if s.strip()]
315
  good_sentences = []
316
 
317
+ seen_content = set()
318
+ for sentence in sentences[:2]: # Max 2 sentences
319
+ if (len(sentence) > 15 and
320
+ sentence.lower() not in seen_content and
321
+ not sentence.lower().startswith(('you are', 'i am', 'as a', 'how do')) and
322
+ 'advice' not in sentence.lower()):
323
+
324
  good_sentences.append(sentence)
325
+ seen_content.add(sentence.lower())
326
 
327
  if good_sentences:
328
  response = '. '.join(good_sentences)
329
  if not response.endswith('.'):
330
  response += '.'
331
  else:
332
+ response = self.get_general_advice(user_input)
 
333
 
334
+ return response.strip()
335
+
336
+ def create_improved_chat_interface(resume_context: str = ""):
337
+ """Create improved chat interface"""
338
+
339
+ st.header("πŸ€– AI Resume Assistant")
340
+
341
+ # Initialize chatbot
342
+ if 'improved_chatbot' not in st.session_state:
343
+ st.session_state.improved_chatbot = ImprovedCPUChatbot()
344
+
345
+ chatbot = st.session_state.improved_chatbot
346
+
347
+ # Model initialization
348
+ col1, col2 = st.columns([3, 1])
349
+
350
+ with col1:
351
+ st.info("Using DistilGPT2 with improved response quality")
352
+
353
+ with col2:
354
+ if st.button("Initialize AI", type="primary"):
355
+ chatbot.initialize()
356
+
357
+ # Chat interface
358
+ if chatbot.is_loaded:
359
+ st.success("βœ… AI Ready")
360
+
361
+ # Quick questions
362
+ st.subheader("Quick Questions")
363
+ col1, col2 = st.columns(2)
364
+
365
+ with col1:
366
+ if st.button("How to improve experience section?"):
367
+ st.session_state.quick_question = "What's wrong with my experience section?"
368
+
369
+ with col2:
370
+ if st.button("Make resume ATS-friendly?"):
371
+ st.session_state.quick_question = "How do I make it more ATS-friendly?"
372
+
373
+ col3, col4 = st.columns(2)
374
+ with col3:
375
+ if st.button("Add better keywords?"):
376
+ st.session_state.quick_question = "What keywords should I add?"
377
+
378
+ with col4:
379
+ if st.button("Improve skills section?"):
380
+ st.session_state.quick_question = "How can I improve my skills section?"
381
+
382
+ # Chat input
383
+ user_question = st.text_input(
384
+ "Ask about your resume:",
385
+ value=st.session_state.get('quick_question', ''),
386
+ placeholder="How can I improve my resume?",
387
+ key="improved_chat_input"
388
+ )
389
+
390
+ # Send button and clear
391
+ col1, col2 = st.columns([1, 3])
392
+ with col1:
393
+ send_clicked = st.button("Send", type="primary")
394
+ with col2:
395
+ if st.button("Clear Chat"):
396
+ st.session_state.improved_chat_history = []
397
+ if 'quick_question' in st.session_state:
398
+ del st.session_state.quick_question
399
+ st.experimental_rerun()
400
+
401
+ # Generate response
402
+ if send_clicked and user_question.strip():
403
+ with st.spinner("Generating advice..."):
404
+ response = chatbot.generate_response(user_question, resume_context)
405
+ if 'quick_question' in st.session_state:
406
+ del st.session_state.quick_question
407
+ st.experimental_rerun()
408
+
409
+ # Display chat history
410
+ if st.session_state.improved_chat_history:
411
+ st.subheader("πŸ’¬ Conversation")
412
+
413
+ for conv in reversed(st.session_state.improved_chat_history[-3:]): # Show last 3
414
+ st.markdown(f"**You:** {conv['user']}")
415
+ st.markdown(f"**AI:** {conv['bot']}")
416
+ st.caption(f"Time: {conv['timestamp']}")
417
+ st.divider()
418
+
419
+ else:
420
+ st.warning("Click 'Initialize AI' to start chatting")
421
+
422
+ with st.expander("ℹ️ Improved Features"):
423
+ st.markdown("""
424
+ **Improvements in this version:**
425
+
426
+ βœ… **Better response quality** - Reduced repetition and loops
427
+ βœ… **Template responses** - Instant answers for common questions
428
+ βœ… **Improved prompting** - Cleaner, more focused prompts
429
+ βœ… **Response filtering** - Better cleaning of generated text
430
+ βœ… **Quick questions** - Pre-defined buttons for common queries
431
+
432
+ **Model**: DistilGPT2 with enhanced parameters
433
+ **Response time**: 1-3 seconds
434
+ **Quality**: Significantly improved over basic version
435
+ """)
436
+
437
  # Download NLTK data if not already present
438
  @st.cache_resource
439
  def download_nltk_data():
 
858
  doc.build(story)
859
  buffer.seek(0)
860
  return buffer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
861
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
862
  def main():
863
  st.set_page_config(
864
  page_title="AI Resume Analyzer with Chatbot",
 
1109
  # Chat Interface - Properly indented inside the file upload condition
1110
  st.markdown("---")
1111
  st.header("πŸ’¬ Chat with Resume Assistant")
1112
+ create_improved_chat_interface(st.session_state.get('resume_context', ''))
1113
 
1114
  except Exception as e:
1115
  st.error(f"Error during analysis: {str(e)}")