zenaight commited on
Commit
ae927ca
Β·
1 Parent(s): 2cce083

trying more ai awareness

Browse files
Files changed (2) hide show
  1. ai_chat.py +6 -1
  2. persona_manager.py +42 -18
ai_chat.py CHANGED
@@ -113,7 +113,12 @@ Key guidelines:
113
  - If someone asks for clarification about property terms, explain clearly and helpfully
114
  - Only ask about their property needs when they show interest in searching or viewing properties
115
  - Keep responses conversational and not robotic
116
- - If user says "hi" or "hello", respond with a greeting like "Hi [Name]! How can I help you with industrial properties today?" """
 
 
 
 
 
117
 
118
  if user_info.get("name") and user_info["name"] != "Unknown":
119
  system_message += f"\nThe user's name is {user_info['name']} - use their name to make it personal."
 
113
  - If someone asks for clarification about property terms, explain clearly and helpfully
114
  - Only ask about their property needs when they show interest in searching or viewing properties
115
  - Keep responses conversational and not robotic
116
+ - If user says "hi" or "hello", respond with a greeting like "Hi [Name]! How can I help you with industrial properties today?"
117
+ - If someone mentions they need space for a specific business type (like "manufacturing plant"), understand the context and suggest appropriate sizes
118
+ - Don't keep asking the same question if the user has already given context about their needs
119
+ - Be understanding and helpful, not pushy or repetitive
120
+ - If someone says "big enough for manufacturing plant" or similar, understand they want a large industrial space and suggest appropriate sizes
121
+ - Don't be robotic - respond like a real human would in a conversation"""
122
 
123
  if user_info.get("name") and user_info["name"] != "Unknown":
124
  system_message += f"\nThe user's name is {user_info['name']} - use their name to make it personal."
persona_manager.py CHANGED
@@ -197,19 +197,19 @@ async def fallback_parse_response(user_message: str, field: str) -> Tuple[bool,
197
  if any(word in user_message_lower for word in affirmative_words):
198
  # For affirmative responses, we need to get the value from context
199
  # This will be handled by the LLM parsing, but we can provide a fallback
200
- return True, "confirmed", "Got it! Thanks for confirming."
201
 
202
  # Check for skip requests
203
  skip_words = ["not sure", "skip", "later", "don't know", "maybe later", "pass", "no idea"]
204
  if any(word in user_message_lower for word in skip_words):
205
- return True, None, PERSONA_FIELDS[field]["skip_response"]
206
 
207
  # Basic field-specific parsing
208
  if field == "intent":
209
  if any(word in user_message_lower for word in ["buy", "purchase", "own"]):
210
- return True, "buy", "Got it, you're looking to buy. That's great!"
211
  elif any(word in user_message_lower for word in ["lease", "rent"]):
212
- return True, "lease", "Perfect, leasing gives you flexibility."
213
 
214
  elif field == "budget":
215
  import re
@@ -235,7 +235,7 @@ async def fallback_parse_response(user_message: str, field: str) -> Tuple[bool,
235
  elif "m" in pattern or "million" in pattern:
236
  budget *= 1000000
237
 
238
- return True, budget, f"Thanks! I'll look for properties around ${budget:,}."
239
 
240
  # Fallback: just look for numbers
241
  numbers = re.findall(r'\d+', user_message)
@@ -245,7 +245,7 @@ async def fallback_parse_response(user_message: str, field: str) -> Tuple[bool,
245
  budget *= 1000
246
  elif "m" in user_message_lower or "million" in user_message_lower:
247
  budget *= 1000000
248
- return True, budget, f"Thanks! I'll look for properties around ${budget:,}."
249
 
250
  elif field == "size_preference_sqm":
251
  import re
@@ -266,13 +266,20 @@ async def fallback_parse_response(user_message: str, field: str) -> Tuple[bool,
266
  # Convert sq ft to sqm if needed
267
  if 'ft' in pattern and 'sq' in pattern:
268
  size = int(size * 0.0929) # Convert sq ft to sqm
269
- return True, size, f"Perfect! {size} sqm should give you good options."
 
 
 
 
 
 
 
270
 
271
  # Fallback: just look for numbers
272
  numbers = re.findall(r'\d+', user_message)
273
  if numbers:
274
  size = max(int(n) for n in numbers)
275
- return True, size, f"Perfect! {size} sqm should give you good options."
276
 
277
  elif field == "location_preference":
278
  # Extract location names (basic approach)
@@ -284,10 +291,10 @@ async def fallback_parse_response(user_message: str, field: str) -> Tuple[bool,
284
  break
285
 
286
  if found_location:
287
- return True, found_location, f"Great! {found_location.title()} has good options."
288
  else:
289
  # Assume the whole message is a location
290
- return True, user_message.strip(), f"Got it! I'll look in {user_message.strip()}."
291
 
292
  elif field == "must_have":
293
  features = []
@@ -304,9 +311,9 @@ async def fallback_parse_response(user_message: str, field: str) -> Tuple[bool,
304
  features.append(feature)
305
 
306
  if features:
307
- return True, features, f"Perfect! I'll make sure to find places with {', '.join(features)}."
308
 
309
- return False, None, "I didn't quite understand. Could you try again?"
310
 
311
  async def should_ask_persona_question(persona: Dict, conversation_context: str = "") -> Tuple[bool, Optional[str]]:
312
  """
@@ -352,6 +359,8 @@ Rules:
352
  - If the user is asking about properties, locations, business needs, or showing interest in finding space β†’ return "yes"
353
  - If the user mentions locations (including abbreviations like cpt, pta, jhb) β†’ return "yes"
354
  - If the user mentions business types (clothing, manufacturing, etc.) β†’ return "yes"
 
 
355
 
356
  Return ONLY "yes" or "no"."""
357
 
@@ -415,17 +424,17 @@ Available persona fields:
415
  - size_preference_sqm: Extract size in square meters (convert from sq ft if needed)
416
  - must_have: Extract features as array (e.g., ["truck access", "office space"])
417
 
418
- Return ONLY a JSON object with the extracted fields. Only include fields that are clearly mentioned or implied.
419
- If no relevant information is found for a field, don't include it in the response.
420
-
421
- IMPORTANT: For location_preference, be very generous in extraction. If the user mentions ANY location (including "pretoria", "pta", "johannesburg", "jhb", "cape town", "cpt", etc.), extract it.
422
 
423
  Examples:
424
  - "I want a property in cpt" β†’ {"location_preference": "cape town"}
425
  - "Looking for warehouse in pta around 500k" β†’ {"location_preference": "pretoria", "budget": 500000}
426
  - "Looking for a property in pretoria for my clothing business" β†’ {"location_preference": "pretoria"}
427
  - "Need space for clothing business with office" β†’ {"must_have": ["office"]}
428
- """
 
 
429
 
430
  messages = [
431
  {"role": "system", "content": system_prompt},
@@ -455,7 +464,22 @@ Examples:
455
 
456
  except json.JSONDecodeError:
457
  print(f"Failed to parse AI extraction response: {response.content}")
458
- return {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
 
460
  except Exception as e:
461
  print(f"Error in AI persona extraction: {e}")
 
197
  if any(word in user_message_lower for word in affirmative_words):
198
  # For affirmative responses, we need to get the value from context
199
  # This will be handled by the LLM parsing, but we can provide a fallback
200
+ return True, "confirmed", "Got it! Thanks for confirming.", False, False
201
 
202
  # Check for skip requests
203
  skip_words = ["not sure", "skip", "later", "don't know", "maybe later", "pass", "no idea"]
204
  if any(word in user_message_lower for word in skip_words):
205
+ return True, None, PERSONA_FIELDS[field]["skip_response"], False, True
206
 
207
  # Basic field-specific parsing
208
  if field == "intent":
209
  if any(word in user_message_lower for word in ["buy", "purchase", "own"]):
210
+ return True, "buy", "Got it, you're looking to buy. That's great!", False, False
211
  elif any(word in user_message_lower for word in ["lease", "rent"]):
212
+ return True, "lease", "Perfect, leasing gives you flexibility.", False, False
213
 
214
  elif field == "budget":
215
  import re
 
235
  elif "m" in pattern or "million" in pattern:
236
  budget *= 1000000
237
 
238
+ return True, budget, f"Thanks! I'll look for properties around ${budget:,}.", False, False
239
 
240
  # Fallback: just look for numbers
241
  numbers = re.findall(r'\d+', user_message)
 
245
  budget *= 1000
246
  elif "m" in user_message_lower or "million" in user_message_lower:
247
  budget *= 1000000
248
+ return True, budget, f"Thanks! I'll look for properties around ${budget:,}.", False, False
249
 
250
  elif field == "size_preference_sqm":
251
  import re
 
266
  # Convert sq ft to sqm if needed
267
  if 'ft' in pattern and 'sq' in pattern:
268
  size = int(size * 0.0929) # Convert sq ft to sqm
269
+ return True, size, f"Perfect! {size} sqm should give you good options.", False, False
270
+
271
+ # Check for context-based size suggestions
272
+ if any(word in user_message_lower for word in ["manufacturing", "factory", "plant", "production"]):
273
+ if "large" in user_message_lower or "big" in user_message_lower:
274
+ return True, 5000, "Perfect! For a large manufacturing plant, I'd recommend around 5000 sqm. This gives you plenty of space for production lines, storage, and office areas.", False, False
275
+ else:
276
+ return True, 3000, "Great! For a manufacturing plant, I'd suggest around 3000 sqm. This should accommodate your production needs well.", False, False
277
 
278
  # Fallback: just look for numbers
279
  numbers = re.findall(r'\d+', user_message)
280
  if numbers:
281
  size = max(int(n) for n in numbers)
282
+ return True, size, f"Perfect! {size} sqm should give you good options.", False, False
283
 
284
  elif field == "location_preference":
285
  # Extract location names (basic approach)
 
291
  break
292
 
293
  if found_location:
294
+ return True, found_location, f"Great! {found_location.title()} has good options.", False, False
295
  else:
296
  # Assume the whole message is a location
297
+ return True, user_message.strip(), f"Got it! I'll look in {user_message.strip()}.", False, False
298
 
299
  elif field == "must_have":
300
  features = []
 
311
  features.append(feature)
312
 
313
  if features:
314
+ return True, features, f"Perfect! I'll make sure to find places with {', '.join(features)}.", False, False
315
 
316
+ return False, None, "I didn't quite understand. Could you try again?", False, False
317
 
318
  async def should_ask_persona_question(persona: Dict, conversation_context: str = "") -> Tuple[bool, Optional[str]]:
319
  """
 
359
  - If the user is asking about properties, locations, business needs, or showing interest in finding space β†’ return "yes"
360
  - If the user mentions locations (including abbreviations like cpt, pta, jhb) β†’ return "yes"
361
  - If the user mentions business types (clothing, manufacturing, etc.) β†’ return "yes"
362
+ - If the user has already provided context about their needs (like "big enough for manufacturing plant") β†’ return "no" (they've given enough context)
363
+ - If the user is frustrated or asking you to stop asking questions β†’ return "no"
364
 
365
  Return ONLY "yes" or "no"."""
366
 
 
424
  - size_preference_sqm: Extract size in square meters (convert from sq ft if needed)
425
  - must_have: Extract features as array (e.g., ["truck access", "office space"])
426
 
427
+ IMPORTANT: You MUST return a valid JSON object. If no information is found, return {} (empty object).
428
+ For location_preference, be very generous in extraction. If the user mentions ANY location (including "pretoria", "pta", "johannesburg", "jhb", "cape town", "cpt", etc.), extract it.
 
 
429
 
430
  Examples:
431
  - "I want a property in cpt" β†’ {"location_preference": "cape town"}
432
  - "Looking for warehouse in pta around 500k" β†’ {"location_preference": "pretoria", "budget": 500000}
433
  - "Looking for a property in pretoria for my clothing business" β†’ {"location_preference": "pretoria"}
434
  - "Need space for clothing business with office" β†’ {"must_have": ["office"]}
435
+ - "I want one big enough for a phara manufacturing plant" β†’ {"size_preference_sqm": 5000, "must_have": ["manufacturing"]}
436
+
437
+ Return ONLY the JSON object, no other text."""
438
 
439
  messages = [
440
  {"role": "system", "content": system_prompt},
 
464
 
465
  except json.JSONDecodeError:
466
  print(f"Failed to parse AI extraction response: {response.content}")
467
+ print(f"Response type: {type(response.content)}")
468
+ print(f"Response length: {len(response.content)}")
469
+ # Try to clean the response
470
+ cleaned_response = response.content.strip()
471
+ if cleaned_response.startswith('```json'):
472
+ cleaned_response = cleaned_response[7:]
473
+ if cleaned_response.endswith('```'):
474
+ cleaned_response = cleaned_response[:-3]
475
+ cleaned_response = cleaned_response.strip()
476
+ try:
477
+ extracted = json.loads(cleaned_response)
478
+ print(f"Successfully parsed after cleaning: {extracted}")
479
+ return extracted
480
+ except:
481
+ print(f"Still failed after cleaning: {cleaned_response}")
482
+ return {}
483
 
484
  except Exception as e:
485
  print(f"Error in AI persona extraction: {e}")