Reemplaza Evolution API con bridge Node.js propio usando Baileys. QR se genera en ~10 segundos. Auto-reply con chatbot IA. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
156 lines
4.7 KiB
Python
156 lines
4.7 KiB
Python
# /home/Autopartes/pos/blueprints/whatsapp_bp.py
|
|
"""WhatsApp via Baileys Bridge.
|
|
|
|
Endpoints:
|
|
GET /pos/api/whatsapp/status -- Connection status
|
|
GET /pos/api/whatsapp/qr -- Get QR code
|
|
POST /pos/api/whatsapp/connect -- Start connection
|
|
POST /pos/api/whatsapp/logout -- Disconnect
|
|
POST /pos/api/whatsapp/webhook -- Receive messages (public)
|
|
POST /pos/api/whatsapp/send -- Send message
|
|
GET /pos/api/whatsapp/conversations -- List conversations
|
|
"""
|
|
|
|
from flask import Blueprint, request, jsonify, g
|
|
from middleware import require_auth
|
|
from tenant_db import get_tenant_conn
|
|
from services import whatsapp_service
|
|
|
|
whatsapp_bp = Blueprint('whatsapp', __name__, url_prefix='/pos/api/whatsapp')
|
|
|
|
|
|
@whatsapp_bp.route('/status', methods=['GET'])
|
|
@require_auth()
|
|
def status():
|
|
return jsonify(whatsapp_service.get_status())
|
|
|
|
|
|
@whatsapp_bp.route('/qr', methods=['GET'])
|
|
@require_auth()
|
|
def qr():
|
|
return jsonify(whatsapp_service.get_qr())
|
|
|
|
|
|
@whatsapp_bp.route('/connect', methods=['POST'])
|
|
@require_auth()
|
|
def connect():
|
|
return jsonify(whatsapp_service.connect())
|
|
|
|
|
|
@whatsapp_bp.route('/logout', methods=['POST'])
|
|
@require_auth()
|
|
def logout():
|
|
return jsonify(whatsapp_service.logout())
|
|
|
|
|
|
@whatsapp_bp.route('/webhook', methods=['POST'])
|
|
def webhook():
|
|
"""Receive messages from Baileys bridge (public, no auth)."""
|
|
data = request.get_json(force=True, silent=True) or {}
|
|
|
|
if data.get('event') != 'messages.upsert':
|
|
return jsonify({'ok': True})
|
|
|
|
msg = whatsapp_service.process_incoming(data)
|
|
if not msg.get('phone') or msg.get('from_me'):
|
|
return jsonify({'ok': True})
|
|
|
|
# Save to DB if tenant connection available
|
|
try:
|
|
# Try to get a tenant connection (use default tenant for webhook)
|
|
conn = get_tenant_conn(11) # TODO: resolve tenant from phone number
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
INSERT INTO whatsapp_messages (phone, direction, message_text, wa_message_id)
|
|
VALUES (%s, 'incoming', %s, %s)
|
|
ON CONFLICT DO NOTHING
|
|
""", (msg['phone'], msg['text'], msg['message_id']))
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
except Exception:
|
|
pass
|
|
|
|
# Auto-reply with AI chatbot
|
|
if msg.get('text'):
|
|
try:
|
|
from services.ai_chat import chat
|
|
ai_resp = chat(msg['text'])
|
|
reply = ai_resp.get('message', '')
|
|
if reply:
|
|
whatsapp_service.send_message(msg['phone'], reply)
|
|
except Exception:
|
|
pass
|
|
|
|
return jsonify({'ok': True})
|
|
|
|
|
|
@whatsapp_bp.route('/send', methods=['POST'])
|
|
@require_auth()
|
|
def send():
|
|
data = request.get_json() or {}
|
|
phone = data.get('phone', '')
|
|
message = data.get('message', '')
|
|
if not phone or not message:
|
|
return jsonify({'error': 'phone and message required'}), 400
|
|
|
|
result = whatsapp_service.send_message(phone, message)
|
|
|
|
# Save outgoing message
|
|
try:
|
|
conn = get_tenant_conn(g.tenant_id)
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
INSERT INTO whatsapp_messages (phone, direction, message_text)
|
|
VALUES (%s, 'outgoing', %s)
|
|
""", (phone, message))
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
except Exception:
|
|
pass
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
@whatsapp_bp.route('/conversations', methods=['GET'])
|
|
@require_auth()
|
|
def conversations():
|
|
try:
|
|
conn = get_tenant_conn(g.tenant_id)
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
SELECT phone, MAX(message_text) as last_message, MAX(created_at) as last_at, COUNT(*) as msg_count
|
|
FROM whatsapp_messages
|
|
GROUP BY phone
|
|
ORDER BY MAX(created_at) DESC
|
|
LIMIT 50
|
|
""")
|
|
convos = [{'phone': r[0], 'last_message': r[1], 'last_at': str(r[2]), 'count': r[3]} for r in cur.fetchall()]
|
|
cur.close()
|
|
conn.close()
|
|
return jsonify({'conversations': convos})
|
|
except Exception as e:
|
|
return jsonify({'conversations': [], 'error': str(e)})
|
|
|
|
|
|
@whatsapp_bp.route('/conversations/<phone>', methods=['GET'])
|
|
@require_auth()
|
|
def conversation_messages(phone):
|
|
try:
|
|
conn = get_tenant_conn(g.tenant_id)
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
SELECT id, direction, message_text, created_at
|
|
FROM whatsapp_messages
|
|
WHERE phone = %s
|
|
ORDER BY created_at
|
|
LIMIT 100
|
|
""", (phone,))
|
|
msgs = [{'id': r[0], 'direction': r[1], 'text': r[2], 'date': str(r[3])} for r in cur.fetchall()]
|
|
cur.close()
|
|
conn.close()
|
|
return jsonify({'messages': msgs})
|
|
except Exception as e:
|
|
return jsonify({'messages': [], 'error': str(e)})
|