File size: 4,177 Bytes
db6bff5
d5c46e9
9569b7d
 
db6bff5
 
 
 
 
d5c46e9
db6bff5
 
 
 
 
 
 
d5c46e9
 
db6bff5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d5c46e9
db6bff5
 
 
 
 
 
 
 
 
e20916c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
db6bff5
 
 
 
 
 
e20916c
db6bff5
 
 
e20916c
 
 
 
 
 
 
 
 
 
 
 
db6bff5
 
 
 
 
 
e20916c
db6bff5
 
 
 
e20916c
db6bff5
 
 
 
 
9569b7d
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse
from fastapi.responses import Response
from fastapi.exceptions import HTTPException
from typing import Dict
from app.services.message import generate_reply, send_reply, process_message_with_retry
import logging
from datetime import datetime
import time

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Initialize FastAPI app
app = FastAPI()

# In-memory cache with timestamp cleanup
class MessageCache:
    def __init__(self, max_age_hours: int = 24):
        self.messages: Dict[str, float] = {}
        self.max_age_seconds = max_age_hours * 3600

    def add(self, message_id: str) -> None:
        self.cleanup()
        self.messages[message_id] = time.time()

    def exists(self, message_id: str) -> bool:
        self.cleanup()
        return message_id in self.messages

    def cleanup(self) -> None:
        current_time = time.time()
        self.messages = {
            msg_id: timestamp 
            for msg_id, timestamp in self.messages.items()
            if current_time - timestamp < self.max_age_seconds
        }

message_cache = MessageCache()

@app.post("/webhook")
async def webhook(request: Request):
    request_id = f"req_{int(time.time()*1000)}"
    logger.info(f"Processing webhook request {request_id}")
    payload = await request.json()

    processed_count = 0
    error_count = 0
    results = []

    entries = payload.get("entry", [])

    for entry in entries:
        entry_id = entry.get("id")
        logger.info(f"Processing entry_id: {entry_id}")

        changes = entry.get("changes", [])
        for change in changes:
            messages = change.get("value", {}).get("messages", [])
            for message in messages:
                message_id = message.get("id")
                timestamp = message.get("timestamp")
                content = message.get("text", {}).get("body")
                sender_id = message.get("from")

                # Deduplicate messages based on message_id
                if message_cache.exists(message_id):
                    logger.info(f"Duplicate message detected and skipped: {message_id}")
                    continue

                try:
                    # Process message with retry logic
                    result = await process_message_with_retry(
                        sender_id,
                        content,
                        timestamp
                    )
                    # Add the message ID to the cache
                    message_cache.add(message_id)
                    processed_count += 1
                    results.append(result)
                except Exception as e:
                    error_count += 1
                    logger.error(
                        f"Failed to process message {message_id}: {str(e)}",
                        exc_info=True
                    )
                    results.append({
                        "status": "error",
                        "message_id": message_id,
                        "error": str(e)
                    })

    response_data = {
        "request_id": request_id,
        "processed": processed_count,
        "errors": error_count,
        "results": results
    }

    logger.info(
        f"Webhook processing completed - "
        f"Processed: {processed_count}, Errors: {error_count}"
    )

    return JSONResponse(
        content=response_data,
        status_code=status.HTTP_200_OK
    )



@app.get("/webhook")
async def verify_webhook(request: Request):
    mode = request.query_params.get('hub.mode')
    token = request.query_params.get('hub.verify_token')
    challenge = request.query_params.get('hub.challenge')

    # Replace 'your_verification_token' with the token you set in Facebook Business Manager
    if mode == 'subscribe' and token == 'test':
           # Return the challenge as plain text
        return Response(content=challenge, media_type="text/plain")
    else:
        raise HTTPException(status_code=403, detail="Verification failed")