187 lines
7.1 KiB
Python
187 lines
7.1 KiB
Python
import json
|
|
import logging
|
|
import httpx
|
|
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
|
|
|
|
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 = {
|
|
'messages': messages,
|
|
'settings': settings,
|
|
}
|
|
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.whatsapp_access_token = request.POST.get('whatsapp_access_token', settings.whatsapp_access_token)
|
|
settings.whatsapp_phone_number_id = request.POST.get('whatsapp_phone_number_id', settings.whatsapp_phone_number_id)
|
|
settings.save()
|
|
return redirect('index')
|
|
|
|
return render(request, 'core/settings.html', {'settings': settings})
|
|
|
|
@csrf_exempt
|
|
def get_pairing_code(request):
|
|
if request.method != 'POST':
|
|
return JsonResponse({'error': 'POST required'}, status=405)
|
|
|
|
phone_number = request.POST.get('phone_number')
|
|
if not phone_number:
|
|
return JsonResponse({'error': 'Phone number required'}, status=400)
|
|
|
|
# Call Bridge
|
|
try:
|
|
resp = httpx.post("http://127.0.0.1:3000/pair", json={"phoneNumber": phone_number}, timeout=30)
|
|
if resp.status_code == 200:
|
|
# Auto-configure settings for Bridge Mode
|
|
settings = BotSettings.objects.first()
|
|
if settings:
|
|
settings.whatsapp_access_token = "BRIDGE"
|
|
settings.whatsapp_phone_number_id = "BRIDGE"
|
|
settings.save()
|
|
return JsonResponse(resp.json())
|
|
else:
|
|
return JsonResponse(resp.json(), status=resp.status_code)
|
|
except Exception as e:
|
|
return JsonResponse({'error': str(e)}, status=500)
|
|
|
|
@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 (Meta or Bridge)
|
|
if 'object' in data and data['object'] == 'whatsapp_business_account':
|
|
for entry in data.get('entry', []):
|
|
for change in entry.get('changes', []):
|
|
value = change.get('value', {})
|
|
if 'messages' in value:
|
|
for msg in value['messages']:
|
|
sender_number = msg.get('from')
|
|
message_body = msg.get('text', {}).get('body', '')
|
|
|
|
if message_body and sender_number:
|
|
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",
|
|
})
|
|
|
|
if response.get("success"):
|
|
ai_text = LocalAIApi.extract_text(response)
|
|
db_msg.message_out = ai_text
|
|
db_msg.save()
|
|
|
|
# Send response back to WhatsApp
|
|
send_whatsapp_message(sender_number, ai_text, settings)
|
|
|
|
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)}")
|
|
|
|
def send_whatsapp_message(to_number, text, settings):
|
|
# Check for Bridge Mode
|
|
if settings.whatsapp_access_token == "BRIDGE":
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
"http://127.0.0.1:3000/send",
|
|
json={"to": to_number, "text": text},
|
|
timeout=10
|
|
)
|
|
if response.status_code == 200:
|
|
logger.info(f"Sent via Bridge to {to_number}")
|
|
else:
|
|
logger.error(f"Bridge Send Failed: {response.text}")
|
|
except Exception as e:
|
|
logger.error(f"Bridge Exception: {e}")
|
|
return
|
|
|
|
# Standard Meta Cloud API Mode
|
|
if not settings.whatsapp_access_token or not settings.whatsapp_phone_number_id:
|
|
logger.warning("WhatsApp credentials missing in settings. Cannot send reply.")
|
|
return
|
|
|
|
url = f"https://graph.facebook.com/v17.0/{settings.whatsapp_phone_number_id}/messages"
|
|
headers = {
|
|
"Authorization": f"Bearer {settings.whatsapp_access_token}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
payload = {
|
|
"messaging_product": "whatsapp",
|
|
"to": to_number,
|
|
"type": "text",
|
|
"text": {"body": text},
|
|
}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(url, headers=headers, json=payload, timeout=10)
|
|
if response.status_code != 200:
|
|
logger.error(f"Failed to send WhatsApp message: {response.text}")
|
|
else:
|
|
logger.info("WhatsApp message sent successfully.")
|
|
except Exception as e:
|
|
logger.error(f"Exception sending WhatsApp message: {str(e)}") |