diff --git a/ai/__pycache__/__init__.cpython-311.pyc b/ai/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..8bcb2fb Binary files /dev/null and b/ai/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai/__pycache__/local_ai_api.cpython-311.pyc b/ai/__pycache__/local_ai_api.cpython-311.pyc new file mode 100644 index 0000000..fa9977d Binary files /dev/null and b/ai/__pycache__/local_ai_api.cpython-311.pyc differ diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index cd6f855..d603dbc 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/booking.cpython-311.pyc b/core/__pycache__/booking.cpython-311.pyc new file mode 100644 index 0000000..161d1e6 Binary files /dev/null and b/core/__pycache__/booking.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 9aa598b..9e15426 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 1f807fa..0c4b412 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 6867ddf..83e03cc 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 8c38f3f..b0a9ed4 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,31 @@ from django.contrib import admin +from .models import Business, Service, Contact, Call, Booking -# Register your models here. +@admin.register(Business) +class BusinessAdmin(admin.ModelAdmin): + list_display = ('business_name', 'industry', 'phone_number', 'status') + list_filter = ('industry', 'status') + search_fields = ('business_name', 'phone_number') + +@admin.register(Service) +class ServiceAdmin(admin.ModelAdmin): + list_display = ('name', 'business', 'duration', 'price') + list_filter = ('business',) + search_fields = ('name', 'description') + +@admin.register(Contact) +class ContactAdmin(admin.ModelAdmin): + list_display = ('name', 'phone_number') + search_fields = ('name', 'phone_number') + +@admin.register(Call) +class CallAdmin(admin.ModelAdmin): + list_display = ('contact', 'business', 'start_time', 'end_time') + list_filter = ('business', 'start_time') + search_fields = ('contact__name', 'contact__phone_number') + +@admin.register(Booking) +class BookingAdmin(admin.ModelAdmin): + list_display = ('service', 'contact', 'start_time', 'status') + list_filter = ('status', 'service__business') + search_fields = ('contact__name', 'contact__phone_number', 'service__name') \ No newline at end of file diff --git a/core/booking.py b/core/booking.py new file mode 100644 index 0000000..df3c103 --- /dev/null +++ b/core/booking.py @@ -0,0 +1,28 @@ +from .models import Booking, Service, Contact +from datetime import datetime, timedelta + +def create_booking(contact_phone_number: str, service_name: str, booking_time_str: str) -> str: + """ + Creates a booking for a given service at a specific time. + """ + try: + contact = Contact.objects.get(phone_number=contact_phone_number) + service = Service.objects.get(name__iexact=service_name) + booking_time = datetime.fromisoformat(booking_time_str) + + end_time = booking_time + timedelta(minutes=service.duration) + + booking = Booking.objects.create( + contact=contact, + service=service, + start_time=booking_time, + end_time=end_time, + status='scheduled', + ) + return f"Booking confirmed for {service.name} at {booking_time.strftime('%Y-%m-%d %H:%M')}." + except Contact.DoesNotExist: + return "Error: Contact not found." + except Service.DoesNotExist: + return f"Error: Service '{service_name}' not found." + except Exception as e: + return f"Error: Could not create booking. {e}" diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..dddef36 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.7 on 2026-01-20 16:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Business', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('business_name', models.CharField(max_length=255)), + ('industry', models.CharField(choices=[('real_estate', 'Real Estate'), ('clinic_dental', 'Clinic / Dental'), ('salon_spa', 'Salon / Spa'), ('coaching_consulting', 'Coaching / Consulting'), ('custom', 'Custom (Other)')], default='custom', max_length=50)), + ('phone_number', models.CharField(help_text="Twilio or other provider's phone number", max_length=20)), + ('agent_name', models.CharField(default='AI Assistant', max_length=100)), + ('status', models.BooleanField(default=True, help_text='Active or inactive status')), + ], + options={ + 'verbose_name_plural': 'Businesses', + }, + ), + ] diff --git a/core/migrations/0002_contact_call_service_booking.py b/core/migrations/0002_contact_call_service_booking.py new file mode 100644 index 0000000..9471c7c --- /dev/null +++ b/core/migrations/0002_contact_call_service_booking.py @@ -0,0 +1,56 @@ +# Generated by Django 5.2.7 on 2026-01-20 16:56 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Contact', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('phone_number', models.CharField(max_length=20, unique=True)), + ('name', models.CharField(blank=True, max_length=255)), + ], + ), + migrations.CreateModel( + name='Call', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_time', models.DateTimeField(auto_now_add=True)), + ('end_time', models.DateTimeField(blank=True, null=True)), + ('summary', models.TextField(blank=True)), + ('transcript', models.TextField(blank=True)), + ('business', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='calls', to='core.business')), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='calls', to='core.contact')), + ], + ), + migrations.CreateModel( + name='Service', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True)), + ('duration', models.IntegerField(help_text='Duration in minutes')), + ('price', models.DecimalField(decimal_places=2, max_digits=10)), + ('business', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='services', to='core.business')), + ], + ), + migrations.CreateModel( + name='Booking', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_time', models.DateTimeField()), + ('end_time', models.DateTimeField()), + ('status', models.CharField(choices=[('scheduled', 'Scheduled'), ('completed', 'Completed'), ('canceled', 'Canceled')], default='scheduled', max_length=20)), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bookings', to='core.contact')), + ('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bookings', to='core.service')), + ], + ), + ] diff --git a/core/migrations/0003_call_conversation_history.py b/core/migrations/0003_call_conversation_history.py new file mode 100644 index 0000000..94e543f --- /dev/null +++ b/core/migrations/0003_call_conversation_history.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-01-20 17:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_contact_call_service_booking'), + ] + + operations = [ + migrations.AddField( + model_name='call', + name='conversation_history', + field=models.JSONField(default=list), + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..8e4612a Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0002_contact_call_service_booking.cpython-311.pyc b/core/migrations/__pycache__/0002_contact_call_service_booking.cpython-311.pyc new file mode 100644 index 0000000..f531e37 Binary files /dev/null and b/core/migrations/__pycache__/0002_contact_call_service_booking.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/0003_call_conversation_history.cpython-311.pyc b/core/migrations/__pycache__/0003_call_conversation_history.cpython-311.pyc new file mode 100644 index 0000000..5df818b Binary files /dev/null and b/core/migrations/__pycache__/0003_call_conversation_history.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..7019c0b 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,67 @@ from django.db import models -# Create your models here. +class Business(models.Model): + INDUSTRY_CHOICES = [ + ('real_estate', 'Real Estate'), + ('clinic_dental', 'Clinic / Dental'), + ('salon_spa', 'Salon / Spa'), + ('coaching_consulting', 'Coaching / Consulting'), + ('custom', 'Custom (Other)'), + ] + + business_name = models.CharField(max_length=255) + industry = models.CharField(max_length=50, choices=INDUSTRY_CHOICES, default='custom') + phone_number = models.CharField(max_length=20, help_text="Twilio or other provider's phone number") + agent_name = models.CharField(max_length=100, default='AI Assistant') + status = models.BooleanField(default=True, help_text="Active or inactive status") + + def __str__(self): + return self.business_name + + class Meta: + verbose_name_plural = "Businesses" + +class Service(models.Model): + business = models.ForeignKey(Business, on_delete=models.CASCADE, related_name='services') + name = models.CharField(max_length=255) + description = models.TextField(blank=True) + duration = models.IntegerField(help_text="Duration in minutes") + price = models.DecimalField(max_digits=10, decimal_places=2) + + def __str__(self): + return self.name + +class Contact(models.Model): + phone_number = models.CharField(max_length=20, unique=True) + name = models.CharField(max_length=255, blank=True) + + def __str__(self): + return self.name or self.phone_number + +class Call(models.Model): + business = models.ForeignKey(Business, on_delete=models.CASCADE, related_name='calls') + contact = models.ForeignKey(Contact, on_delete=models.CASCADE, related_name='calls') + start_time = models.DateTimeField(auto_now_add=True) + end_time = models.DateTimeField(null=True, blank=True) + summary = models.TextField(blank=True) + transcript = models.TextField(blank=True) + conversation_history = models.JSONField(default=list) + + def __str__(self): + return f"Call with {self.contact} at {self.start_time}" + +class Booking(models.Model): + STATUS_CHOICES = [ + ('scheduled', 'Scheduled'), + ('completed', 'Completed'), + ('canceled', 'Canceled'), + ] + + service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name='bookings') + contact = models.ForeignKey(Contact, on_delete=models.CASCADE, related_name='bookings') + start_time = models.DateTimeField() + end_time = models.DateTimeField() + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='scheduled') + + def __str__(self): + return f"{self.service} booking for {self.contact} at {self.start_time}" \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..1d97300 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -3,7 +3,7 @@
-