fastAPIv2 / components /gateways /headlines_to_wa.py
ragV98's picture
webhook integration
3566f32
raw
history blame
4.9 kB
import os
import json
import redis
import requests
from fastapi import FastAPI # This import is not strictly needed in this file if it's just a module
from fastapi.responses import JSONResponse # This import is not strictly needed in this file if it's just a module
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# 🌐 Configuration from Environment Variables
# These variables MUST be set in your environment (e.g., .env file, shell exports, deployment configs)
REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN")
WHATSAPP_TO_NUMBER = os.environ.get("WHATSAPP_TO_NUMBER", "353899495777") # e.g., "91xxxxxxxxxx"
GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER") # e.g., your WABA number
GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME") # e.g., your Gupshup app name
# βœ… Redis connection
try:
redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
redis_client.ping() # Test connection
logging.info("Redis client connected successfully.")
except Exception as e:
logging.error(f"❌ Failed to connect to Redis: {e}")
raise
# 🧾 Fetch and format headlines
def fetch_cached_headlines() -> str:
try:
raw = redis_client.get("detailed_news_feed_cache")
if not raw:
logging.warning("⚠️ No detailed news headlines found in cache.")
return "⚠️ No daily headlines found in cache."
data = json.loads(raw)
except Exception as e:
logging.error(f"❌ Error reading from Redis: {e}")
return f"❌ Error reading from Redis: {e}"
message_parts = ["πŸ—žοΈ *Your Daily Digest* 🟑\n"]
sorted_topics = sorted(data.keys())
for topic_key in sorted_topics:
stories = data[topic_key]
title = topic_key.replace("_", " ").title()
message_parts.append(f"\n🏷️ *{title}*") # Added newline before topic title
sorted_story_ids = sorted(stories.keys(), key=int)
for ref_id in sorted_story_ids:
item = stories[ref_id]
summary = item.get("title", "")
description = item.get("description", "")
message_parts.append(f"{ref_id}. {summary}\n_Why this matters_: {description}")
# No extra empty line needed here if we add newline to topic title
return "\n".join(message_parts)
# πŸ“€ Send via Gupshup WhatsApp API
def send_to_whatsapp(message_text: str) -> dict: # Function expects the full message text
# Validate critical environment variables for sending a message
if not WHATSAPP_TOKEN or \
not WHATSAPP_TO_NUMBER or \
not GUPSHUP_SOURCE_NUMBER or \
not GUPSHUP_APP_NAME:
error_msg = "❌ Missing one or more critical WhatsApp API environment variables (WHATSAPP_TOKEN, WHATSAPP_TO_NUMBER, GUPSHUP_SOURCE_NUMBER, GUPSHUP_APP_NAME)."
logging.error(error_msg)
return {"status": "failed", "error": error_msg, "code": 500}
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"apikey": WHATSAPP_TOKEN, # API key in 'apikey' header
"Cache-Control": "no-cache" # Add Cache-Control header
}
whatsapp_message_content = {
"type": "text",
"text": message_text # This is the full formatted text
}
payload = {
"channel": "whatsapp",
"source": GUPSHUP_SOURCE_NUMBER,
"destination": WHATSAPP_TO_NUMBER,
"src.name": GUPSHUP_APP_NAME,
"message": json.dumps(whatsapp_message_content) # 'message' parameter with JSON string for text type
}
try:
logging.info(f"Attempting to send standard text WhatsApp message to {WHATSAPP_TO_NUMBER} via Gupshup. API URL: {WHATSAPP_API_URL}")
response = requests.post(
WHATSAPP_API_URL,
headers=headers,
data=payload,
)
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
return {"status": "success", "details": response.json()}
except requests.exceptions.RequestException as e:
logging.error(f"❌ Failed to send WhatsApp message: {e}")
return {"status": "failed", "error": str(e), "code": e.response.status_code if e.response else 500}
except Exception as e:
logging.error(f"❌ An unexpected error occurred during WhatsApp send: {e}")
return {"status": "failed", "error": str(e), "code": 500}
# Removed the FastAPI app instance and endpoint from here,
# as it will be defined in routes/api/wa_headlines.py
# and then included in app.py.
# Removed the if __name__ == "__main__": block from here,
# as it will be in routes/api/wa_headlines.py for local testing.