10bfb846a8
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
3.5 KiB
Python
90 lines
3.5 KiB
Python
"""Lee los ultimos N mensajes de un chat de WhatsApp Web via Chrome DevTools Protocol.
|
|
|
|
Compone dos funciones del registry para extraer la conversacion reciente del chat
|
|
abierto en una pestana ya logueada del navegador, SIN abrir ventana nueva ni darle
|
|
foco al sistema:
|
|
|
|
1. (Opcional) Abre el chat por su nombre exacto con `whatsapp_open_chat`.
|
|
2. Evalua una expresion JS via `cdp_eval` que recoge los ultimos `n` `[role="row"]`
|
|
del panel principal (`#main`), normaliza su texto y detecta si cada mensaje es
|
|
saliente comprobando la presencia de `.message-out` en el row.
|
|
|
|
Devuelve la lista de mensajes mas recientes con su direccion (entrante/saliente).
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import time
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
|
|
from browser.cdp_eval import cdp_eval
|
|
from browser.whatsapp_open_chat import whatsapp_open_chat
|
|
|
|
|
|
def whatsapp_read_chat(
|
|
name: str,
|
|
*,
|
|
n: int = 15,
|
|
port: int = 9222,
|
|
target_url_substr: str = "whatsapp",
|
|
open_first: bool = True,
|
|
) -> dict:
|
|
"""Lee los ultimos n mensajes renderizados de un chat de WhatsApp Web via CDP.
|
|
|
|
Args:
|
|
name: Nombre EXACTO del chat/grupo tal y como aparece en la lista lateral
|
|
(se pasa a `whatsapp_open_chat` cuando `open_first=True`).
|
|
n: Numero maximo de mensajes recientes a leer (los ultimos del viewport).
|
|
Default 15.
|
|
port: Puerto de remote debugging de Chrome. Default 9222.
|
|
target_url_substr: Substring que debe contener la URL del target (pestana).
|
|
Default "whatsapp".
|
|
open_first: Si True, abre el chat con `whatsapp_open_chat` antes de leer.
|
|
Si el chat ya esta abierto y enfocado, puede pasarse False para ahorrar
|
|
el paso de apertura. Default True.
|
|
|
|
Returns:
|
|
dict con claves:
|
|
ok: bool — True si se pudo leer el chat.
|
|
name: str — el nombre solicitado.
|
|
messages: list[dict] — mensajes recientes, cada uno {text: str,
|
|
outgoing: bool}. Lista vacia si no hay mensajes o fallo la apertura.
|
|
count: int — numero de mensajes leidos (solo si ok).
|
|
reason: str — motivo del fallo (solo si ok=False).
|
|
"""
|
|
substr = target_url_substr
|
|
|
|
if open_first:
|
|
o = whatsapp_open_chat(name, port=port, target_url_substr=substr)
|
|
if not o.get("opened"):
|
|
return {
|
|
"ok": False,
|
|
"name": name,
|
|
"messages": [],
|
|
"reason": o.get("reason", "no se pudo abrir el chat"),
|
|
}
|
|
|
|
# Leer los ultimos n rows del panel principal. Detecta mensaje saliente por
|
|
# la presencia de .message-out en el row. Normaliza el texto (colapsa espacios)
|
|
# y lo trunca a 500 caracteres para acotar el payload.
|
|
expr = (
|
|
"(() => { const rows=[...document.querySelectorAll('#main [role=\"row\"]')]"
|
|
".slice(-" + str(int(n)) + ");"
|
|
"return JSON.stringify(rows.map(r=>({"
|
|
"text: r.innerText.replace(/\\s+/g,' ').trim().slice(0,500),"
|
|
"outgoing: !!r.querySelector('.message-out')"
|
|
"})));})()"
|
|
)
|
|
r = cdp_eval(expr, port=port, target_url_substr=substr)
|
|
msgs = json.loads(r.get("value") or "[]")
|
|
return {"ok": True, "name": name, "messages": msgs, "count": len(msgs)}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
chat = sys.argv[1] if len(sys.argv) > 1 else "NOTAS WASAP"
|
|
count = int(sys.argv[2]) if len(sys.argv) > 2 else 15
|
|
out = whatsapp_read_chat(chat, n=count, port=9222, target_url_substr="whatsapp")
|
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|