import uuid import builtins from django.db import models from pgvector.django import VectorField from django.conf import settings class GlobalQA(models.Model): """Global Q&A for greetings - works across ALL properties and agencies""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) question = models.TextField(unique=True) answer = models.TextField() question_embedding = VectorField(dimensions=384) language = models.CharField(max_length=20, choices=[ ('en', 'English'), ('ur', 'Roman Urdu'), ('both', 'Both') ], default='both') is_active = models.BooleanField(default=True) priority = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-priority', 'question'] indexes = [ models.Index(fields=['is_active', '-priority']), models.Index(fields=['language', 'is_active']), ] def __str__(self): return f"{self.question[:50]}" class MasterQuestion(models.Model): """Pre-defined questions created by admin that agencies must answer""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) question = models.TextField(unique=True) is_active = models.BooleanField(default=True) order = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['order'] indexes = [ models.Index(fields=['is_active', 'order']), ] def __str__(self): return self.question[:100] class PropertyQA(models.Model): """Agency's answers to master questions for a specific property""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) agency = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='property_qa_answers' ) property = models.ForeignKey( 'Property.Property', on_delete=models.CASCADE, related_name='ai_qa' ) master_question = models.ForeignKey( MasterQuestion, on_delete=models.CASCADE, null=True, blank=True ) answer = models.TextField() # Embedding for similarity search question_embedding = VectorField(dimensions=384) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) # FIX #5: Track updates class Meta: unique_together = ['property', 'master_question'] # FIX #2: Database indexes for performance indexes = [ models.Index(fields=['property', 'is_active']), models.Index(fields=['agency', 'is_active']), models.Index(fields=['master_question', 'is_active']), # Vector index will be added via migration ] @builtins.property def question_text(self): return self.master_question.question if self.master_question else None def __str__(self): return f"{self.property.title}: {self.question_text[:50] if self.question_text else 'No question'}" class AgencyAutoChatSetting(models.Model): """Auto-chat settings per agency""" agency = models.OneToOneField( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='auto_chat_setting' ) is_enabled = models.BooleanField(default=False) delay_seconds = models.IntegerField(default=30, help_text="Seconds to wait before AI replies") confidence_threshold = models.FloatField(default=0.6, help_text="Minimum similarity score (0-1)") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: indexes = [ models.Index(fields=['is_enabled']), ] def __str__(self): return f"{self.agency.email}: {'ON' if self.is_enabled else 'OFF'}" class PropertyAutoChatState(models.Model): """Track auto-chat state per property""" property = models.OneToOneField( 'Property.Property', on_delete=models.CASCADE, related_name='auto_chat_state' ) is_auto_chat_enabled = models.BooleanField(default=False) last_auto_reply_at = models.DateTimeField(null=True, blank=True) total_auto_replies = models.IntegerField(default=0) last_agency_reply_at = models.DateTimeField(null=True, blank=True) class Meta: indexes = [ models.Index(fields=['is_auto_chat_enabled']), models.Index(fields=['property', 'is_auto_chat_enabled']), ] def __str__(self): return f"{self.property.title}: Auto Chat {'ON' if self.is_auto_chat_enabled else 'OFF'}" class PropertyCustomQA(models.Model): """ Custom Q&A for a specific property (max 5 per property) Agency writes these when enabling auto-chat """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) # Relationships agency = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='property_custom_qa' ) property = models.ForeignKey( 'Property.Property', on_delete=models.CASCADE, related_name='custom_qa' ) # The actual Q&A question = models.TextField() answer = models.TextField() # For AI similarity search question_embedding = VectorField(dimensions=384) # Metadata order = models.IntegerField(default=0) # 1-5 for display order is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['order'] # Ensure max 5 per property constraints = [ models.UniqueConstraint( fields=['property', 'order'], name='unique_order_per_property' ) ] indexes = [ models.Index(fields=['property', 'is_active']), models.Index(fields=['agency', 'is_active']), ] def __str__(self): return f"{self.property.title}: Q{self.order} - {self.question[:50]}"