import os import uuid import json import threading import time from datetime import datetime from flask import Flask, request, jsonify import requests UPLOAD_DIR = os.path.join(os.path.dirname(__file__), "uploads") os.makedirs(UPLOAD_DIR, exist_ok=True) app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 sessions = {} sessions_lock = threading.Lock() # ---------------- Helpers ---------------- def load_messages(path): with open(path, "r", encoding="utf-8") as f: return [l.strip() for l in f.readlines() if l.strip()] # ---- Cloud API (Meta) ---- def cloud_send_text(phone_number_id, to, text, access_token, api_version="v21.0"): url = f"https://graph.facebook.com/{api_version}/{phone_number_id}/messages" headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } payload = { "messaging_product": "whatsapp", "to": to, "type": "text", "text": {"body": text} } return requests.post(url, headers=headers, json=payload, timeout=30) # ---- Green-API ---- def green_send_message(api_url, id_instance, api_token, to, text): endpoint = f"{api_url}/waInstance{id_instance}/sendMessage/{api_token}" body = {"chatId": to, "message": text} headers = {"Content-Type": "application/json"} return requests.post(endpoint, headers=headers, json=body, timeout=30) # ---------------- Worker ---------------- def session_worker(sid): while True: with sessions_lock: s = sessions.get(sid) if not s or s.get("stopped"): break idx = s.get("next_index", 0) msg = s["messages"][idx % len(s["messages"])] if s.get("sender_name"): msg = f"{s['sender_name']} — {msg}" provider = s["provider"] try: if provider == "cloud": resp = cloud_send_text( phone_number_id=s["creds"]["phone_number_id"], to=s["target"], text=msg, access_token=s["creds"]["access_token"], api_version=s.get("cloud_api_version", "v21.0") ) elif provider == "green": resp = green_send_message( api_url=s["creds"].get("api_url", "https://api.green-api.com"), id_instance=s["creds"]["idInstance"], api_token=s["creds"]["apiTokenInstance"], to=s["target"], text=msg ) else: resp = None except Exception as e: resp = None error_text = str(e) with sessions_lock: if sid not in sessions: break ss = sessions[sid] ss["messages_sent"] = ss.get("messages_sent", 0) + 1 ss["next_index"] = (ss.get("next_index", 0) + 1) % len(ss["messages"]) if resp is not None: ss["last_response"] = {"status": resp.status_code, "body": resp.text, "time": datetime.utcnow().isoformat()} else: ss["last_response"] = {"status": None, "body": error_text if 'error_text' in locals() else "exception", "time": datetime.utcnow().isoformat()} time.sleep(max(0.5, float(s.get("delay", 5)))) with sessions_lock: if sid in sessions: sessions[sid]["stopped"] = True sessions[sid]["stopped_at"] = datetime.utcnow().isoformat() # ---------------- Routes ---------------- @app.route("/") def index(): return """