[Python] How to Send MP3 Audio from S3 via WhatsApp Cloud API Using Pre-Signed URLs?

Discussão em 'Python' iniciado por Stack, Outubro 7, 2024.

  1. Stack

    Stack Membro Participativo

    I'm developing a feature where an audio message generated by the Eleven Labs API is stored in an AWS S3 bucket and should be sent to users through the WhatsApp Cloud API. Although the process works perfectly with public MP3 links, it fails when I try to use pre-signed URLs generated for private S3 bucket objects. This leads me to believe the issue is due to the authentication parameters in the pre-signed URL. Below is the relevant part of my code:

    Function to create data to send back to the user:

    def get_audio_message_input(recipient, audio_url):
    return json.dumps({
    "messaging_product": "whatsapp",
    "recipient_type": "individual",
    "to": recipient,
    "type": "audio",
    "audio": {"link": audio_url},
    })


    Function to process incoming data from the user:

    def process_whatsapp_message(body):
    wa_id = body["entry"][0]["changes"][0]["value"]["contacts"][0]["wa_id"]
    name = body["entry"][0]["changes"][0]["value"]["contacts"][0]["profile"]["name"]
    message_body = body["entry"][0]["changes"][0]["value"]["messages"][0]["text"]["body"]

    audio_url = testingElevenLabs(message_body)
    data = get_audio_message_input(wa_id, audio_url)
    send_message(data)


    S3 handling for uploading and generating pre-signed URLs:

    import boto3
    import uuid

    session = boto3.Session(
    aws_access_key_id='AWS_ACCESS_KEY_ID',
    aws_secret_access_key='AWS_SECRET_ACCESS_KEY',
    region_name='AWS_REGION_NAME'
    )
    s3 = session.client("s3")

    def generate_presigned_url(s3_file_name: str) -> str:
    return s3.generate_presigned_url(
    "get_object",
    Params={"Bucket": "AWS_S3_BUCKET_NAME", "Key": s3_file_name},
    ExpiresIn=3600 # URL expires in 1 hour
    )

    def upload_audiostream_to_s3(audio_stream) -> str:
    s3_file_name = f"{uuid.uuid4()}.mp3"
    s3.upload_fileobj(audio_stream, "AWS_S3_BUCKET_NAME", s3_file_name)
    return s3_file_name


    Function that retrieves the signed URL:

    def testingElevenLabs(text: str):
    audio_stream = text_to_speech_stream(text)
    s3_file_name = upload_audiostream_to_s3(audio_stream)
    signed_url = generate_presigned_url(s3_file_name)
    print(f"Signed URL to access the file: {signed_url}")
    return signed_url


    Send message function:

    import requests
    import logging
    from flask import jsonify, current_app

    def send_message(data):
    headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {current_app.config['ACCESS_TOKEN']}"
    }
    url = f"https://graph.facebook.com/{current_app.config['VERSION']}/{current_app.config['PHONE_NUMBER_ID']}/messages"

    try:
    response = requests.post(url, data=data, headers=headers, timeout=10)
    response.raise_for_status()
    except requests.Timeout:
    logging.error("Timeout occurred while sending message")
    return jsonify({"status": "error", "message": "Request timed out"}), 408
    except requests.RequestException as e:
    logging.error(f"Request failed due to: {e}")
    return jsonify({"status": "error", "message": "Failed to send message"}), 500
    else:
    log_http_response(response)
    return response


    Just to specify what im handling: Public MP3 files are sent with no issues via the WhatsApp Cloud API, but when attempting to send an audio file using an S3 signed URL, nothing happens and there are no errors returned. How can I ensure the WhatsApp API processes these pre-signed URLs correctly or is there a better approach to securely sending these audio files?

    Continue reading...

Compartilhe esta Página