diff --git a/ai/__pycache__/__init__.cpython-311.pyc b/ai/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..8c285ba 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..7aca17c Binary files /dev/null and b/ai/__pycache__/local_ai_api.cpython-311.pyc differ diff --git a/config/__pycache__/__init__.cpython-311.pyc b/config/__pycache__/__init__.cpython-311.pyc index 423a636..7f03f11 100644 Binary files a/config/__pycache__/__init__.cpython-311.pyc and b/config/__pycache__/__init__.cpython-311.pyc differ diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 96bce55..0b7fd80 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index 0b85e94..fabf89a 100644 Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ diff --git a/config/__pycache__/wsgi.cpython-311.pyc b/config/__pycache__/wsgi.cpython-311.pyc index 9c49e09..2793f32 100644 Binary files a/config/__pycache__/wsgi.cpython-311.pyc and b/config/__pycache__/wsgi.cpython-311.pyc differ diff --git a/core/__pycache__/__init__.cpython-311.pyc b/core/__pycache__/__init__.cpython-311.pyc index 74b1112..b6deebb 100644 Binary files a/core/__pycache__/__init__.cpython-311.pyc and b/core/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..13193bc 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/apps.cpython-311.pyc b/core/__pycache__/apps.cpython-311.pyc index 6f131d4..560452b 100644 Binary files a/core/__pycache__/apps.cpython-311.pyc and b/core/__pycache__/apps.cpython-311.pyc differ diff --git a/core/__pycache__/context_processors.cpython-311.pyc b/core/__pycache__/context_processors.cpython-311.pyc index 75bf223..42aed24 100644 Binary files a/core/__pycache__/context_processors.cpython-311.pyc and b/core/__pycache__/context_processors.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..fccbac6 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 5a69659..0506fe0 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 2a36fd6..24fe1b7 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..0b49036 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,11 @@ from django.contrib import admin +from .models import BotSettings, Message -# Register your models here. +@admin.register(BotSettings) +class BotSettingsAdmin(admin.ModelAdmin): + list_display = ('id', 'is_active', 'system_prompt') + +@admin.register(Message) +class MessageAdmin(admin.ModelAdmin): + list_display = ('sender_number', 'message_in', 'message_out', 'timestamp') + list_filter = ('timestamp', 'sender_number') \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..8e22945 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.7 on 2026-02-07 14:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='BotSettings', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('system_prompt', models.TextField(default='You are a helpful assistant.')), + ('is_active', models.BooleanField(default=True)), + ('verify_token', models.CharField(default='my_secure_token_123', max_length=255)), + ], + ), + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sender_number', models.CharField(max_length=50)), + ('message_in', models.TextField()), + ('message_out', models.TextField(blank=True, null=True)), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ], + ), + ] 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..366c4d4 Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/migrations/__pycache__/__init__.cpython-311.pyc b/core/migrations/__pycache__/__init__.cpython-311.pyc index 9c833c8..ba2a78c 100644 Binary files a/core/migrations/__pycache__/__init__.cpython-311.pyc and b/core/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..cced9e9 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,18 @@ from django.db import models -# Create your models here. +class BotSettings(models.Model): + system_prompt = models.TextField(default="You are a helpful assistant.") + is_active = models.BooleanField(default=True) + verify_token = models.CharField(max_length=255, default="my_secure_token_123") + + def __str__(self): + return f"Bot Settings (Active: {self.is_active})" + +class Message(models.Model): + sender_number = models.CharField(max_length=50) + message_in = models.TextField() + message_out = models.TextField(null=True, blank=True) + timestamp = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"From {self.sender_number} at {self.timestamp}" \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..bc07479 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,105 @@ +{% load static %} - - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}WhatsApp AI Bot{% endblock %} + + + + + + + + + {% block extra_css %}{% endblock %} - - {% block content %}{% endblock %} - + - +
+ {% block content %}{% endblock %} +
+ + + {% block extra_js %}{% endblock %} + + \ No newline at end of file diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..8f4ecb8 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,65 @@ -{% extends "base.html" %} +{% extends 'base.html' %} -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% block title %}Dashboard - WhatsApp AI Bot{% endblock %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+
+

Live Chat Monitor

+

Real-time view of incoming and AI-generated messages.

-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
- -{% endblock %} \ No newline at end of file +
+
+ Bot Status: + {% if settings.is_active %} + Active + {% else %} + Paused + {% endif %} +
+
+ + +
+
+ + + + + + + + + + + {% for msg in messages %} + + + + + + + {% empty %} + + + + {% endfor %} + +
SenderMessage InAI ResponseTime
+ {{ msg.sender_number }} + {{ msg.message_in }} + {% if msg.message_out %} +
+ {{ msg.message_out }} +
+ {% else %} + Processing... + {% endif %} +
+ {{ msg.timestamp|date:"M d, H:i:s" }} +
+ No messages received yet. Send a message to your WhatsApp number to see it here. +
+
+
+{% endblock %} diff --git a/core/templates/core/settings.html b/core/templates/core/settings.html new file mode 100644 index 0000000..568554a --- /dev/null +++ b/core/templates/core/settings.html @@ -0,0 +1,51 @@ +{% extends 'base.html' %} + +{% block title %}Bot Settings - WhatsApp AI Bot{% endblock %} + +{% block content %} +
+
+
+

AI Bot Personality

+
+ {% csrf_token %} +
+ + +
+ This instruction defines the bot's tone, personality, and knowledge limits. +
+
+ +
+ + +
+ Use this token when setting up the webhook in the Meta Developer Portal. +
+
+ +
+ + +
+ +
+ +
+ Back to Dashboard + +
+
+
+ +
+
Setup Tip
+

+ Your Meta Webhook URL: https://your-domain.com/webhook/whatsapp/
+ Verification Token: {{ settings.verify_token }} +

+
+
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..4ebe1dd 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,8 @@ from django.urls import path - -from .views import home +from . import views urlpatterns = [ - path("", home, name="home"), -] + path('', views.index, name='index'), + path('settings/', views.settings_view, name='settings'), + path('webhook/whatsapp/', views.webhook, name='whatsapp_webhook'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c9aed12..a307687 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,113 @@ -import os -import platform +import json +import logging +from django.shortcuts import render, redirect +from django.http import HttpResponse, JsonResponse +from django.views.decorators.csrf import csrf_exempt +from .models import Message, BotSettings +from ai.local_ai_api import LocalAIApi -from django import get_version as django_version -from django.shortcuts import render -from django.utils import timezone - - -def home(request): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() +logger = logging.getLogger(__name__) +def index(request): + messages = Message.objects.all().order_by('-timestamp')[:50] + settings = BotSettings.objects.first() + if not settings: + settings = BotSettings.objects.create() + context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + 'messages': messages, + 'settings': settings, } - return render(request, "core/index.html", context) + return render(request, 'core/index.html', context) + +def settings_view(request): + settings = BotSettings.objects.first() + if not settings: + settings = BotSettings.objects.create() + + if request.method == 'POST': + settings.system_prompt = request.POST.get('system_prompt', settings.system_prompt) + settings.is_active = 'is_active' in request.POST + settings.verify_token = request.POST.get('verify_token', settings.verify_token) + settings.save() + return redirect('index') + + return render(request, 'core/settings.html', {'settings': settings}) + +@csrf_exempt +def webhook(request): + if request.method == 'GET': + # Meta Webhook verification + mode = request.GET.get('hub.mode') + token = request.GET.get('hub.verify_token') + challenge = request.GET.get('hub.challenge') + + settings = BotSettings.objects.first() + verify_token = settings.verify_token if settings else "my_secure_token_123" + + if mode and token: + if mode == 'subscribe' and token == verify_token: + logger.info("WEBHOOK_VERIFIED") + return HttpResponse(challenge) + else: + return HttpResponse('Verification failed', status=403) + return HttpResponse('Verification failed', status=403) + + elif request.method == 'POST': + try: + data = json.loads(request.body.decode('utf-8')) + logger.info(f"Incoming WhatsApp data: {json.dumps(data)}") + + # Check if it's a message from WhatsApp + if 'object' in data and data['object'] == 'whatsapp_business_account': + for entry in data['entry']: + for change in entry['changes']: + value = change['value'] + if 'messages' in value: + for msg in value['messages']: + sender_number = msg['from'] + message_body = msg.get('text', {}).get('body', '') + + if message_body: + process_whatsapp_message(sender_number, message_body) + + return JsonResponse({'status': 'ok'}) + except Exception as e: + logger.error(f"Error processing webhook: {str(e)}") + return JsonResponse({'status': 'error', 'message': str(e)}, status=500) + +def process_whatsapp_message(sender_number, message_body): + settings = BotSettings.objects.first() + if not settings or not settings.is_active: + return + + # Store incoming message + db_msg = Message.objects.create( + sender_number=sender_number, + message_in=message_body + ) + + # Call Gemini via AI Proxy + prompt_input = [ + {"role": "system", "content": settings.system_prompt}, + {"role": "user", "content": message_body}, + ] + + try: + response = LocalAIApi.create_response({ + "input": prompt_input, + "model": "gemini-1.5-flash", # Explicitly request gemini-1.5-flash + }) + + if response.get("success"): + ai_text = LocalAIApi.extract_text(response) + db_msg.message_out = ai_text + db_msg.save() + + # NOTE: In a real app, you'd call Meta API here to send db_msg.message_out back to sender_number. + # For this task, we focus on the integration and dashboard as requested. + logger.info(f"Gemini response for {sender_number}: {ai_text}") + else: + logger.error(f"AI Proxy Error: {response.get('error')}") + except Exception as e: + logger.error(f"Error calling Gemini: {str(e)}") \ No newline at end of file