whatsapp-toolkit 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.3
2
+ Name: whatsapp-toolkit
3
+ Version: 1.0.4
4
+ Summary: Una biblioteca para interactuar con la API de WhatsApp desde Python usando Evolution API
5
+ Author: Fernando Leon Franco
6
+ Author-email: Fernando Leon Franco <fernanlee2131@gmail.com>
7
+ License: MIT
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Requires-Dist: requests>=2.32.5
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+
13
+
14
+ # Whatsapp Toolkit
15
+
16
+ Este módulo permite el envío de mensajes, archivos y multimedia por WhatsApp, con manejo avanzado de conexión, errores y administración de instancias.
17
+
18
+
19
+ ## Componentes principales
20
+
21
+ - **whatsapp.py**: Cliente principal para WhatsApp, incluye administración de instancias, conexión QR, envío de mensajes, archivos, multimedia, ubicación, audio y stickers.
22
+ - **whatsapp_instanced.py**: Utilidades avanzadas para instancias y flujos personalizados, incluyendo envío asíncrono de mensajes y archivos usando Celery.
23
+
24
+ ---
25
+
26
+ ## Ejemplos y recomendaciones de uso
27
+
28
+ ### 1. Inicialización y conexión
29
+ Conecta tu cliente y asegura la conexión antes de enviar mensajes.
30
+ ```python
31
+ from epok_toolkit.messaging.whatsapp import WhatsappClient
32
+
33
+ client = WhatsappClient(api_key="tu_api_key", server_url="https://api.whatsapp.com", instance_name="EPOK")
34
+ client.ensure_connected() # Muestra QR y enlaza la instancia si es necesario
35
+ ```
36
+ **Tip:** El método `ensure_connected` reintenta y muestra QR hasta enlazar la instancia.
37
+
38
+ ### 2. Enviar mensajes de texto
39
+ ```python
40
+ client.send_text(number="521234567890", text="Hola desde EPOK Toolkit!")
41
+ ```
42
+
43
+ ### 3. Enviar archivos y multimedia
44
+ Envía documentos, imágenes, stickers, audio y ubicación:
45
+ ```python
46
+ # Enviar PDF
47
+ with open("ticket.pdf", "rb") as f:
48
+ import base64
49
+ pdf_b64 = base64.b64encode(f.read()).decode()
50
+ client.send_media(number="521234567890", media_b64=pdf_b64, filename="ticket.pdf", caption="Tu ticket", mediatype="document", mimetype="application/pdf")
51
+
52
+ # Enviar sticker
53
+ client.send_sticker(number="521234567890", sticker_b64=sticker_b64)
54
+
55
+ # Enviar ubicación
56
+ client.send_location(number="521234567890", name="EPOK", address="Calle 123", latitude=21.123, longitude=-101.456)
57
+
58
+ # Enviar audio
59
+ client.send_audio(number="521234567890", audio_b64=audio_b64)
60
+ ```
61
+
62
+ ### 4. Administración de instancias y grupos
63
+ ```python
64
+ client.create_instance() # Crea una nueva instancia en el servidor
65
+ client.delete_instance() # Elimina la instancia
66
+ client.fetch_groups() # Obtiene todos los grupos y participantes
67
+ ```
68
+
69
+
70
+ ### 6. Envío asíncrono con whatsapp_instanced.py
71
+ Envía mensajes y archivos en segundo plano usando Celery:
72
+ ```python
73
+ from epok_toolkit.messaging.whatsapp_instanced import send_text, send_media
74
+
75
+ # Enviar mensaje de texto de forma asíncrona
76
+ send_text(number="521234567890", message="Hola desde EPOK Toolkit!")
77
+
78
+ # Enviar archivo PDF de forma asíncrona
79
+ send_media(number="521234567890", media_b64=pdf_b64, filename="ticket.pdf", caption="Tu ticket")
80
+ ```
81
+ **Tip:** Configura Celery y los settings de API_KEY, INSTANCE y SERVER_URL para habilitar el envío asíncrono.
82
+
83
+ ---
84
+
85
+ ## Más información
86
+ Consulta la documentación de cada archivo para detalles avanzados, recomendaciones y ejemplos específicos.
87
+
88
+ ## Instalación
89
+
90
+ Con UV Package Manager:
91
+ ```bash
92
+ uv add whatsapp-toolkit
93
+ ```
94
+
95
+ Con pip:
96
+ ```bash
97
+ pip install whatsapp-toolkit
98
+ ```
99
+ ## Requisitos
100
+ - Python 3.10 o superior
101
+ - requests >=2.32.5
102
+
@@ -0,0 +1,90 @@
1
+
2
+ # Whatsapp Toolkit
3
+
4
+ Este módulo permite el envío de mensajes, archivos y multimedia por WhatsApp, con manejo avanzado de conexión, errores y administración de instancias.
5
+
6
+
7
+ ## Componentes principales
8
+
9
+ - **whatsapp.py**: Cliente principal para WhatsApp, incluye administración de instancias, conexión QR, envío de mensajes, archivos, multimedia, ubicación, audio y stickers.
10
+ - **whatsapp_instanced.py**: Utilidades avanzadas para instancias y flujos personalizados, incluyendo envío asíncrono de mensajes y archivos usando Celery.
11
+
12
+ ---
13
+
14
+ ## Ejemplos y recomendaciones de uso
15
+
16
+ ### 1. Inicialización y conexión
17
+ Conecta tu cliente y asegura la conexión antes de enviar mensajes.
18
+ ```python
19
+ from epok_toolkit.messaging.whatsapp import WhatsappClient
20
+
21
+ client = WhatsappClient(api_key="tu_api_key", server_url="https://api.whatsapp.com", instance_name="EPOK")
22
+ client.ensure_connected() # Muestra QR y enlaza la instancia si es necesario
23
+ ```
24
+ **Tip:** El método `ensure_connected` reintenta y muestra QR hasta enlazar la instancia.
25
+
26
+ ### 2. Enviar mensajes de texto
27
+ ```python
28
+ client.send_text(number="521234567890", text="Hola desde EPOK Toolkit!")
29
+ ```
30
+
31
+ ### 3. Enviar archivos y multimedia
32
+ Envía documentos, imágenes, stickers, audio y ubicación:
33
+ ```python
34
+ # Enviar PDF
35
+ with open("ticket.pdf", "rb") as f:
36
+ import base64
37
+ pdf_b64 = base64.b64encode(f.read()).decode()
38
+ client.send_media(number="521234567890", media_b64=pdf_b64, filename="ticket.pdf", caption="Tu ticket", mediatype="document", mimetype="application/pdf")
39
+
40
+ # Enviar sticker
41
+ client.send_sticker(number="521234567890", sticker_b64=sticker_b64)
42
+
43
+ # Enviar ubicación
44
+ client.send_location(number="521234567890", name="EPOK", address="Calle 123", latitude=21.123, longitude=-101.456)
45
+
46
+ # Enviar audio
47
+ client.send_audio(number="521234567890", audio_b64=audio_b64)
48
+ ```
49
+
50
+ ### 4. Administración de instancias y grupos
51
+ ```python
52
+ client.create_instance() # Crea una nueva instancia en el servidor
53
+ client.delete_instance() # Elimina la instancia
54
+ client.fetch_groups() # Obtiene todos los grupos y participantes
55
+ ```
56
+
57
+
58
+ ### 6. Envío asíncrono con whatsapp_instanced.py
59
+ Envía mensajes y archivos en segundo plano usando Celery:
60
+ ```python
61
+ from epok_toolkit.messaging.whatsapp_instanced import send_text, send_media
62
+
63
+ # Enviar mensaje de texto de forma asíncrona
64
+ send_text(number="521234567890", message="Hola desde EPOK Toolkit!")
65
+
66
+ # Enviar archivo PDF de forma asíncrona
67
+ send_media(number="521234567890", media_b64=pdf_b64, filename="ticket.pdf", caption="Tu ticket")
68
+ ```
69
+ **Tip:** Configura Celery y los settings de API_KEY, INSTANCE y SERVER_URL para habilitar el envío asíncrono.
70
+
71
+ ---
72
+
73
+ ## Más información
74
+ Consulta la documentación de cada archivo para detalles avanzados, recomendaciones y ejemplos específicos.
75
+
76
+ ## Instalación
77
+
78
+ Con UV Package Manager:
79
+ ```bash
80
+ uv add whatsapp-toolkit
81
+ ```
82
+
83
+ Con pip:
84
+ ```bash
85
+ pip install whatsapp-toolkit
86
+ ```
87
+ ## Requisitos
88
+ - Python 3.10 o superior
89
+ - requests >=2.32.5
90
+
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "whatsapp-toolkit"
3
+ version = "1.0.4"
4
+ description = "Una biblioteca para interactuar con la API de WhatsApp desde Python usando Evolution API"
5
+ authors = [
6
+ { name="Fernando Leon Franco", email="fernanlee2131@gmail.com" }
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.10"
10
+ license = { text = "MIT" }
11
+ dependencies = [
12
+ "requests>=2.32.5",
13
+ ]
14
+
15
+ classifiers = [
16
+ "License :: OSI Approved :: MIT License",
17
+ ]
18
+
19
+
20
+ [build-system]
21
+ requires = ["uv_build>=0.9.17,<0.10.0"]
22
+ build-backend = "uv_build"
@@ -0,0 +1 @@
1
+ from .whatsapp_instanced import send_text, send_media
@@ -0,0 +1,367 @@
1
+ import requests
2
+ from typing import Optional
3
+ from functools import wraps
4
+ from dataclasses import dataclass
5
+
6
+
7
+ def timeout_response(func):
8
+ @wraps(func)
9
+ def wrapper(*args, **kwargs):
10
+ try:
11
+ return func(*args, **kwargs)
12
+ except requests.Timeout:
13
+ print("La solicitud ha excedido el tiempo de espera.")
14
+ return HttpResponse(status_code=408, text="Timeout", json_data=None)
15
+ except requests.RequestException as e:
16
+ print(f"Error en la solicitud: {e}")
17
+ return HttpResponse(
18
+ status_code=500, text="Error", json_data={"error": str(e)}
19
+ )
20
+
21
+ return wrapper
22
+
23
+
24
+ def require_connection(method):
25
+ """
26
+ Decorador para métodos de WhatsappClient que necesitan una conexión activa.
27
+ Llama a `self.ensure_connected()` y solo ejecuta el método original si la
28
+ conexión se confirma; de lo contrario devuelve False.
29
+ """
30
+ from functools import wraps
31
+
32
+ @wraps(method)
33
+ def _wrapper(self, *args, **kwargs):
34
+ if not self.ensure_connected():
35
+ print("❌ No fue posible establecer conexión.")
36
+ return False
37
+ return method(self, *args, **kwargs)
38
+
39
+ return _wrapper
40
+
41
+
42
+ @dataclass
43
+ class HttpResponse:
44
+ status_code: int
45
+ text: str
46
+ json_data: Optional[dict] = None
47
+
48
+
49
+ class WhatsAppInstance:
50
+ def __init__(self, api_key: str, instance: str, server_url: str):
51
+ self.api_key = api_key
52
+ self.name_instance = instance
53
+ self.status = "disconnected"
54
+ self.server_url = server_url.rstrip("/")
55
+ self.headers = {"apikey": self.api_key, "Content-Type": "application/json"}
56
+
57
+ def create_instance(self) -> HttpResponse:
58
+ """Crea una nueva instancia de WhatsApp usando la API de Envole."""
59
+ url = f"{self.server_url}/instance/create"
60
+ payload = {
61
+ "instanceName": self.name_instance,
62
+ "integration": "WHATSAPP-BAILEYS",
63
+ "syncFullHistory": False,
64
+ }
65
+ response = requests.post(url, json=payload, headers=self.headers)
66
+ return HttpResponse(response.status_code, response.text, response.json())
67
+
68
+ def delete_instance(self) -> HttpResponse:
69
+ """Elimina una instancia de WhatsApp usando la API de Envole."""
70
+ url = f"{self.server_url}/instance/delete/{self.name_instance}"
71
+ response = requests.delete(url, headers=self.headers)
72
+ return HttpResponse(response.status_code, response.text)
73
+
74
+ def show_qr(self, qr_text: str) -> None:
75
+ """Genera un código QR a partir de `qr_text` y lo muestra con el visor por defecto."""
76
+ import qrcode
77
+
78
+ qr = qrcode.QRCode(border=2)
79
+ qr.add_data(qr_text)
80
+ qr.make(fit=True)
81
+ img = qr.make_image()
82
+ img.show()
83
+
84
+ def connect_instance_qr(self) -> None:
85
+ """Conecta una instancia de WhatsApp y muestra una imagen"""
86
+ url = f"{self.server_url}/instance/connect/{self.name_instance}"
87
+ response = requests.get(url, headers=self.headers)
88
+ codigo = response.json().get("code")
89
+ self.show_qr(codigo)
90
+
91
+ def mode_connecting(self):
92
+ """
93
+ Se intentará por 30 min el mantenter intentos de conexión a la instancia
94
+ generando un qr cada 10 segundos, si es exitoso se podra enviar un mensaje,
95
+ si después de eso no se conecta, se devolvera un error
96
+ """
97
+ pass
98
+
99
+
100
+ class WhatsAppSender:
101
+ def __init__(self, instance: WhatsAppInstance):
102
+ self.instance = instance.name_instance
103
+ self.server_url = instance.server_url
104
+ self.headers = instance.headers
105
+ self._instance_obj = instance
106
+ self.connected = True # estado de conexión conocido
107
+
108
+ def test_connection_status(self) -> bool:
109
+ cel_epok = "5214778966517"
110
+ print(f"Probando conexión enviando mensaje a {cel_epok}...")
111
+ ok = bool(self.send_text(cel_epok, "ping"))
112
+ self.connected = ok
113
+ return ok
114
+
115
+ @timeout_response
116
+ def get(self, endpoint: str, params: Optional[dict] = None) -> requests.Response:
117
+ url = f"{self.server_url}{endpoint}"
118
+ return requests.get(url, headers=self.headers, params=params)
119
+
120
+ def put(self, endpoint: str) -> requests.Response:
121
+ url = f"{self.server_url}{endpoint}"
122
+ return requests.put(url, headers=self.headers)
123
+
124
+ def post(self, endpoint: str, payload: dict):
125
+ url = f"{self.server_url}{endpoint}"
126
+ request = requests.post(url, json=payload, headers=self.headers, timeout=10)
127
+ # if timeout:
128
+ try:
129
+ return request
130
+ except requests.Timeout:
131
+ print("Request timed out")
132
+ return HttpResponse(status_code=408, text="Timeout", json_data=None)
133
+
134
+ def send_text(self, number: str, text: str, link_preview: bool = True, delay_ms: int = 0) -> str:
135
+ payload = {
136
+ "number": number,
137
+ "text": text,
138
+ "delay": delay_ms,
139
+ "linkPreview": link_preview,
140
+ }
141
+ print(f"Enviando mensaje a {number}: {text}")
142
+ resp = self.post(f"/message/sendText/{self.instance}", payload)
143
+
144
+ # Si la solicitud se convirtió en HttpResponse por timeout
145
+ status = resp.status_code if hasattr(resp, "status_code") else 0
146
+
147
+ if 200 <= status < 300:
148
+ self.connected = True
149
+ return resp.text
150
+
151
+ # Fallo: marcar desconexión y reportar
152
+ print(f"Error al enviar mensaje a {number}: {status} - {resp.text}")
153
+ self.connected = False
154
+ return False
155
+
156
+ def send_media(self, number: str, media_b64: str, filename: str, caption: str, mediatype: str = "document", mimetype: str = "application/pdf") -> str:
157
+ payload = {
158
+ "number": number,
159
+ "mediatype": mediatype,
160
+ "mimetype": mimetype,
161
+ "caption": caption,
162
+ "media": media_b64,
163
+ "fileName": filename,
164
+ "delay": 0,
165
+ "linkPreview": False,
166
+ "mentionsEveryOne": False,
167
+ }
168
+ resp = self.post(f"/message/sendMedia/{self.instance}", payload)
169
+ return resp.text
170
+
171
+ def send_sticker(self, number: str, sticker_b64: str, delay: int = 0, link_preview: bool = True, mentions_everyone: bool = True) -> str:
172
+ """Envía un sticker a un contacto específico."""
173
+ payload = {
174
+ "number": number,
175
+ "sticker": sticker_b64,
176
+ "delay": delay,
177
+ "linkPreview": link_preview,
178
+ "mentionsEveryOne": mentions_everyone,
179
+ }
180
+ resp = self.post(f"/message/sendSticker/{self.instance}", payload)
181
+ return resp.text
182
+
183
+ def send_location(self, number: str, name: str, address: str, latitude: float, longitude: float, delay: int = 0) -> str:
184
+ """Envía una ubicación a un contacto."""
185
+ payload = {
186
+ "number": number,
187
+ "name": name,
188
+ "address": address,
189
+ "latitude": latitude,
190
+ "longitude": longitude,
191
+ "delay": delay,
192
+ }
193
+ resp = self.post(f"/message/sendLocation/{self.instance}", payload)
194
+ return resp.text
195
+
196
+ def send_audio(self, number: str, audio_b64: str, delay: int = 0) -> str:
197
+ """Envía un audio en formato base64 a un contacto."""
198
+ payload = {
199
+ "audio": audio_b64,
200
+ "number": number,
201
+ "delay": delay,
202
+ }
203
+ resp = self.post(f"/message/sendWhatsAppAudio/{self.instance}", payload)
204
+ return resp.text
205
+
206
+ def connect(self, number: str) -> str:
207
+ querystring = {"number": number}
208
+ resp = self.get(f"/instance/connect/{self.instance}", params=querystring)
209
+ return resp.text
210
+
211
+ def set_webhook(self, webhook_url: str, enabled: bool = True, webhook_by_events: bool = True, webhook_base64: bool = True, events: Optional[list] = None) -> str:
212
+ """Configura el webhook para la instancia."""
213
+ if events is None:
214
+ events = ["SEND_MESSAGE"]
215
+ payload = {
216
+ "url": webhook_url,
217
+ "enabled": enabled,
218
+ "webhookByEvents": webhook_by_events,
219
+ "webhookBase64": webhook_base64,
220
+ "events": events,
221
+ }
222
+ resp = self.post(f"/webhook/set/{self.instance}", payload)
223
+ return resp.text
224
+
225
+ def fetch_groups(self, get_participants: bool = True) -> list:
226
+ """Obtiene todos los grupos y sus participantes."""
227
+ params = {"getParticipants": str(get_participants).lower()}
228
+ resp = self.get(f"/group/fetchAllGroups/{self.instance}", params=params)
229
+ if resp.status_code == 200:
230
+ return resp.json()
231
+ else:
232
+ raise Exception(
233
+ f"Error al obtener grupos: {resp.status_code} - {resp.text}"
234
+ )
235
+
236
+ @staticmethod
237
+ def fetch_instances(api_key: str, server_url: str) -> list:
238
+ """Obtiene todas las instancias disponibles en el servidor."""
239
+ url = f"{server_url}/instance/fetchInstances"
240
+ headers = {"apikey": api_key}
241
+ response = requests.get(url, headers=headers, verify=False)
242
+ # Puede ser una lista o dict, depende del backend
243
+ try:
244
+ return response.json()
245
+ except Exception:
246
+ return []
247
+
248
+ @staticmethod
249
+ def get_instance_info(api_key: str, instance_name: str, server_url: str):
250
+ """Busca la info de una instancia específica por nombre, robusto a diferentes formatos de respuesta."""
251
+ instances = WhatsAppSender.fetch_instances(api_key, server_url)
252
+
253
+ # Normalizar a lista para iterar
254
+ if isinstance(instances, dict):
255
+ instances = [instances]
256
+ # print(f"Buscando instancia: {instance_name} en {len(instances)} instancias disponibles.")
257
+ for item in instances:
258
+ data = (
259
+ item.get("instance")
260
+ if isinstance(item, dict) and "instance" in item
261
+ else item
262
+ )
263
+ # print(data)
264
+ if not isinstance(data, dict):
265
+ continue # Formato inesperado para us
266
+
267
+ if data.get("name") == instance_name:
268
+ return data
269
+ return {}
270
+
271
+
272
+
273
+ class WhatsappClient:
274
+ """
275
+ Cliente para interactuar con la API de WhatsApp.
276
+ """
277
+ def __init__(self, api_key: str, server_url: str, instance_name: str = "EPOK"):
278
+ self.instance = WhatsAppInstance(api_key, instance_name, server_url)
279
+ self.sender: Optional[WhatsAppSender] = None
280
+ self._auto_initialize_sender()
281
+
282
+ def _auto_initialize_sender(self):
283
+ """Solo asigna sender si la instancia está enlazada a WhatsApp."""
284
+ info = WhatsAppSender.get_instance_info(
285
+ self.instance.api_key, self.instance.name_instance, self.instance.server_url
286
+ )
287
+ if info.get("ownerJid"): # <- si tiene owner, significa que ya está enlazada
288
+ self.sender = WhatsAppSender(self.instance)
289
+
290
+ def ensure_connected(self, retries: int = 3, delay: int = 30) -> bool:
291
+ """
292
+ Garantiza que la instancia esté conectada.
293
+ Si aún no existe `self.sender`, intentará crearlo.
294
+ Si la prueba de conexión falla, muestra un QR y reintenta.
295
+ """
296
+ import time
297
+
298
+ # Si ya tenemos sender y está marcado como conectado, salimos rápido
299
+ if self.sender and getattr(self.sender, "connected", False):
300
+ return True
301
+
302
+ def _init_sender():
303
+ if self.sender is None:
304
+ # Intentar inicializar si la instancia ya está enlazada
305
+ info = WhatsAppSender.get_instance_info(
306
+ self.instance.api_key,
307
+ self.instance.name_instance,
308
+ self.instance.server_url,
309
+ )
310
+ if info.get("ownerJid"):
311
+ self.sender = WhatsAppSender(self.instance)
312
+
313
+ # Primer intento de inicializar el sender
314
+ _init_sender()
315
+
316
+ for attempt in range(1, retries + 1):
317
+ if self.sender and self.sender.test_connection_status():
318
+ return True
319
+
320
+ print(
321
+ f"[{attempt}/{retries}] Conexión no disponible, mostrando nuevo QR (espera {delay}s)…"
322
+ )
323
+ self.instance.connect_instance_qr() # muestra nuevo QR
324
+ time.sleep(delay)
325
+
326
+ # Reintentar inicializar sender después de mostrar QR
327
+ _init_sender()
328
+
329
+ print("❌ No fue posible establecer conexión después de varios intentos.")
330
+ return False
331
+
332
+ @require_connection
333
+ def send_text(self, number: str, text: str, link_preview: bool = True, delay_ms: int = 1000):
334
+ return self.sender.send_text(number, text, link_preview, delay_ms=delay_ms)
335
+
336
+ @require_connection
337
+ def send_media(self, number: str, media_b64: str, filename: str, caption: str, mediatype: str = "document", mimetype: str = "application/pdf"):
338
+ return self.sender.send_media(number, media_b64, filename, caption, mediatype, mimetype)
339
+
340
+ @require_connection
341
+ def send_sticker(self, number: str, sticker_b64: str, delay: int = 0, link_preview: bool = True, mentions_everyone: bool = True):
342
+ return self.sender.send_sticker(number, sticker_b64, delay, link_preview, mentions_everyone)
343
+
344
+ @require_connection
345
+ def send_location(self, number: str, name: str, address: str, latitude: float, longitude: float, delay: int = 0):
346
+ return self.sender.send_location(number, name, address, latitude, longitude, delay)
347
+
348
+ @require_connection
349
+ def send_audio(self, number: str, audio_b64: str, delay: int = 0):
350
+ return self.sender.send_audio(number, audio_b64, delay)
351
+
352
+ @require_connection
353
+ def connect_number(self, number: str):
354
+ return self.sender.connect(number)
355
+
356
+ @require_connection
357
+ def fetch_groups(self, get_participants: bool = True):
358
+ return self.sender.fetch_groups(get_participants)
359
+
360
+ def create_instance(self):
361
+ return self.instance.create_instance()
362
+
363
+ def delete_instance(self):
364
+ return self.instance.delete_instance()
365
+
366
+ def connect_instance_qr(self):
367
+ return self.instance.connect_instance_qr()
@@ -0,0 +1,36 @@
1
+ from colorstreak import log
2
+ from .whatsapp import WhatsappClient
3
+ from django.conf import settings
4
+ from celery import shared_task
5
+
6
+
7
+ API_KEY = settings.API_KEY
8
+ INSTANCE = settings.INSTANCE
9
+ SERVER_URL = settings.SERVER_URL
10
+
11
+ @shared_task
12
+ def send_whatsapp_message_async(number: str, message: str):
13
+ log.library(f"Enviando mensaje a {number}: '{message}'")
14
+ client = WhatsappClient(api_key=API_KEY, server_url=SERVER_URL, instance_name=INSTANCE)
15
+ return client.send_text(number, message)
16
+
17
+
18
+ @shared_task
19
+ def send_whatsapp_media_async(number: str, media_b64: str, filename: str, caption: str, mediatype: str = "document", mimetype: str = "application/pdf"):
20
+ log.library(f"Enviando media a {number}: '{filename}'")
21
+ client = WhatsappClient(api_key=API_KEY, server_url=SERVER_URL, instance_name=INSTANCE)
22
+ return client.send_media(number, media_b64, filename, caption, mediatype, mimetype)
23
+
24
+
25
+
26
+
27
+ def send_text(number: str, message: str):
28
+ from colorstreak import log
29
+ log.library(f"Programando tarea para {number}")
30
+ send_whatsapp_message_async.delay(number, message)
31
+
32
+
33
+ def send_media(number: str, media_b64: str, filename: str, caption: str, mediatype: str = "document", mimetype: str = "application/pdf"):
34
+ from colorstreak import log
35
+ log.library(f"Programando tarea para enviar media a {number}")
36
+ send_whatsapp_media_async.delay(number, media_b64, filename, caption, mediatype, mimetype)