daveebbelaar / python-whatsapp-bot

Build AI WhatsApp Bots with Pure Python
https://www.datalumina.com
MIT License
795 stars 459 forks source link

open AI whatsapp re-send message automatically #7

Open jdevsan opened 10 months ago

jdevsan commented 10 months ago

Hi im facing some issues with randomness I dont know what it is, but sometimes messages are resending, open ai assitante send a message with no user interaction in th e chat..

kaiofreitas commented 9 months ago

Same here

jdevsan commented 8 months ago

@kaiofreitas did u solve it?

GuidoLorenzetti commented 4 months ago

Hi, did anyone find a solution for this? I´m over my head trying to solve this and currently didn´t have much progress

CeadeS commented 4 months ago

WhatsApp messages are not synchronous. If a WhatsApp message is not received properly, it is resent by meta automatically. Make sure you send meta a 200 every time you push a message into a thread successfully. Otherwise, the message is resent meta. This also happens for status updates of the messages. You would use a more mature what’s app api implementation for python that handles that. In guess this project is not meant to be a productive WhatsApp api implementation but an nice example for beginners.

Edwin2711 commented 4 months ago

@CeadeS Thanks for your explanation, I'm having the same problem. Do you think taking this repo as a base for building something to be on production environment is recommended or not even close. I would really appreciate any suggestion related with launching this project to a production environment. Thanks in advanced.

GuidoLorenzetti commented 4 months ago

I found a solution, basically it implies checking if the message has already been processed before sending it to OpenAI.

Add this to your views.py file

def is_message_processed(message_id):
    with shelve.open(PROCESSED_MESSAGES_DB) as db:
        return message_id in db

def mark_message_as_processed(message_id):
    with shelve.open(PROCESSED_MESSAGES_DB, writeback=True) as db:
        db[message_id] = datetime.datetime.now().timestamp()

Then, in the handle_message function:

    try:
        if is_valid_whatsapp_message(body):
            message = body["entry"][0]["changes"][0]["value"]["messages"][0]
            message_id = message["id"]

            if is_message_processed(message_id):
                logging.info(f"Message {message_id} has already been processed.")
                return jsonify({"status": "ok"}), 200

            mark_message_as_processed(message_id)
            process_whatsapp_message(body)
            return jsonify({"status": "ok"}), 200
        else:
            # if the request is not a WhatsApp API event, return an error
            return (
                jsonify({"status": "error", "message": "Not a WhatsApp API event"}),
                404,
            )
    except json.JSONDecodeError:
        logging.error("Failed to decode JSON")
        return jsonify({"status": "error", "message": "Invalid JSON provided"}), 400
GuidoLorenzetti commented 4 months ago

I found a solution, basically it implies checking if the message has been already processed before sending it to OpenAI.

Add this to your views.py file

def is_message_processed(message_id):
    with shelve.open(PROCESSED_MESSAGES_DB) as db:
        return message_id in db

def mark_message_as_processed(message_id):
    with shelve.open(PROCESSED_MESSAGES_DB, writeback=True) as db:
        db[message_id] = datetime.datetime.now().timestamp()

Then, in the handle_message function:

    try:
        if is_valid_whatsapp_message(body):
            message = body["entry"][0]["changes"][0]["value"]["messages"][0]
            message_id = message["id"]

            if is_message_processed(message_id):
                logging.info(f"Message {message_id} has already been processed.")
                return jsonify({"status": "ok"}), 200

            mark_message_as_processed(message_id)
            process_whatsapp_message(body)
            return jsonify({"status": "ok"}), 200
        else:
            # if the request is not a WhatsApp API event, return an error
            return (
                jsonify({"status": "error", "message": "Not a WhatsApp API event"}),
                404,
            )
    except json.JSONDecodeError:
        logging.error("Failed to decode JSON")
        return jsonify({"status": "error", "message": "Invalid JSON provided"}), 400

PROCESSED_MESSAGES_DB is just a name, you can put anything you like in there or define it before. Mine is: PROCESSED_MESSAGES_DB="pm_db"

GuidoLorenzetti commented 4 months ago

@CeadeS Thanks for your explanation, I'm having the same problem. Do you think taking this repo as a base for building something to be on production environment is recommended or not even close. I would really appreciate any suggestion related with launching this project to a production environment. Thanks in advanced.

I´m been building a bot to be on a production environment and even if the current repo is nothing like the original, I think it´s a pretty good starting point. For someone like me who did not know anything about webhooks or things like that, if i would had to start from scratch it would had been a nightmare.

CeadeS commented 4 months ago

@CeadeS Thanks for your explanation, I'm having the same problem. Do you think taking this repo as a base for building something to be on production environment is recommended or not even close. I would really appreciate any suggestion related with launching this project to a production environment. Thanks in advanced.

I´m been building a bot to be on a production environment and even if the current repo is nothing like the original, I think it´s a pretty good starting point. For someone like me who did not know anything about webhooks or things like that, if i would had to start from scratch it would had been a nightmare.

I would not recommend launching a production environment at this point at all. But you can start with this repo to learn and test and then build you own with libraries that are well maintained and tested. There are libraries that talk to WhatsApp so you do not have to care about all this stuff with webhooks anymore. But it is important that you understand what is happening so this is more bare metal. But one would not use shelve nor would you run a server directly without proxy or single threaded. In the end you would use nginx and uwsgi with flask or django redis db and a WhatsApp python library to implement your stuff and run it productively.

CeadeS commented 4 months ago

I found a solution, basically it implies checking if the message has already been processed before sending it to OpenAI.

Add this to your views.py file

def is_message_processed(message_id):
    with shelve.open(PROCESSED_MESSAGES_DB) as db:
        return message_id in db

def mark_message_as_processed(message_id):
    with shelve.open(PROCESSED_MESSAGES_DB, writeback=True) as db:
        db[message_id] = datetime.datetime.now().timestamp()

Then, in the handle_message function:

    try:
        if is_valid_whatsapp_message(body):
            message = body["entry"][0]["changes"][0]["value"]["messages"][0]
            message_id = message["id"]

            if is_message_processed(message_id):
                logging.info(f"Message {message_id} has already been processed.")
                return jsonify({"status": "ok"}), 200

            mark_message_as_processed(message_id)
            process_whatsapp_message(body)
            return jsonify({"status": "ok"}), 200
        else:
            # if the request is not a WhatsApp API event, return an error
            return (
                jsonify({"status": "error", "message": "Not a WhatsApp API event"}),
                404,
            )
    except json.JSONDecodeError:
        logging.error("Failed to decode JSON")
        return jsonify({"status": "error", "message": "Invalid JSON provided"}), 400

In my view, this is a form of error handling. Meta might not have received a confirmation that you got the message, or a status update might be incorrectly interpreted as a new message. While this was my initial solution, it doesn't address the root cause of the issue. Meta could repeatedly send you thousands of messages if you don't properly acknowledge their receipt. They deliver messages multiple times if they don't receive a proper confirmation from you.