Merge PR #1325: add message deduplication to WhatsApp channel
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
from collections import OrderedDict
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
@@ -15,18 +16,19 @@ from nanobot.config.schema import WhatsAppConfig
|
|||||||
class WhatsAppChannel(BaseChannel):
|
class WhatsAppChannel(BaseChannel):
|
||||||
"""
|
"""
|
||||||
WhatsApp channel that connects to a Node.js bridge.
|
WhatsApp channel that connects to a Node.js bridge.
|
||||||
|
|
||||||
The bridge uses @whiskeysockets/baileys to handle the WhatsApp Web protocol.
|
The bridge uses @whiskeysockets/baileys to handle the WhatsApp Web protocol.
|
||||||
Communication between Python and Node.js is via WebSocket.
|
Communication between Python and Node.js is via WebSocket.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "whatsapp"
|
name = "whatsapp"
|
||||||
|
|
||||||
def __init__(self, config: WhatsAppConfig, bus: MessageBus):
|
def __init__(self, config: WhatsAppConfig, bus: MessageBus):
|
||||||
super().__init__(config, bus)
|
super().__init__(config, bus)
|
||||||
self.config: WhatsAppConfig = config
|
self.config: WhatsAppConfig = config
|
||||||
self._ws = None
|
self._ws = None
|
||||||
self._connected = False
|
self._connected = False
|
||||||
|
self._processed_message_ids: OrderedDict[str, None] = OrderedDict()
|
||||||
|
|
||||||
async def start(self) -> None:
|
async def start(self) -> None:
|
||||||
"""Start the WhatsApp channel by connecting to the bridge."""
|
"""Start the WhatsApp channel by connecting to the bridge."""
|
||||||
@@ -105,26 +107,34 @@ class WhatsAppChannel(BaseChannel):
|
|||||||
# Incoming message from WhatsApp
|
# Incoming message from WhatsApp
|
||||||
# Deprecated by whatsapp: old phone number style typically: <phone>@s.whatspp.net
|
# Deprecated by whatsapp: old phone number style typically: <phone>@s.whatspp.net
|
||||||
pn = data.get("pn", "")
|
pn = data.get("pn", "")
|
||||||
# New LID sytle typically:
|
# New LID sytle typically:
|
||||||
sender = data.get("sender", "")
|
sender = data.get("sender", "")
|
||||||
content = data.get("content", "")
|
content = data.get("content", "")
|
||||||
|
message_id = data.get("id", "")
|
||||||
|
|
||||||
|
if message_id:
|
||||||
|
if message_id in self._processed_message_ids:
|
||||||
|
return
|
||||||
|
self._processed_message_ids[message_id] = None
|
||||||
|
while len(self._processed_message_ids) > 1000:
|
||||||
|
self._processed_message_ids.popitem(last=False)
|
||||||
|
|
||||||
# Extract just the phone number or lid as chat_id
|
# Extract just the phone number or lid as chat_id
|
||||||
user_id = pn if pn else sender
|
user_id = pn if pn else sender
|
||||||
sender_id = user_id.split("@")[0] if "@" in user_id else user_id
|
sender_id = user_id.split("@")[0] if "@" in user_id else user_id
|
||||||
logger.info("Sender {}", sender)
|
logger.info("Sender {}", sender)
|
||||||
|
|
||||||
# Handle voice transcription if it's a voice message
|
# Handle voice transcription if it's a voice message
|
||||||
if content == "[Voice Message]":
|
if content == "[Voice Message]":
|
||||||
logger.info("Voice message received from {}, but direct download from bridge is not yet supported.", sender_id)
|
logger.info("Voice message received from {}, but direct download from bridge is not yet supported.", sender_id)
|
||||||
content = "[Voice Message: Transcription not available for WhatsApp yet]"
|
content = "[Voice Message: Transcription not available for WhatsApp yet]"
|
||||||
|
|
||||||
await self._handle_message(
|
await self._handle_message(
|
||||||
sender_id=sender_id,
|
sender_id=sender_id,
|
||||||
chat_id=sender, # Use full LID for replies
|
chat_id=sender, # Use full LID for replies
|
||||||
content=content,
|
content=content,
|
||||||
metadata={
|
metadata={
|
||||||
"message_id": data.get("id"),
|
"message_id": message_id,
|
||||||
"timestamp": data.get("timestamp"),
|
"timestamp": data.get("timestamp"),
|
||||||
"is_group": data.get("isGroup", False)
|
"is_group": data.get("isGroup", False)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user