import os import json import redis import requests import logging import datetime # Import datetime for dynamic date logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # ๐ŸŒ Configuration from Environment Variables 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") GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER") GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME") # โœ… Redis connection try: redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True) redis_client.ping() logging.info("Redis client connected successfully.") except Exception as e: logging.error(f"โŒ Failed to connect to Redis: {e}") raise # --- New: Topic mapping for display names and emojis --- TOPIC_DISPLAY_MAP = { "india": {"name": "India", "emoji": "๐Ÿ‡ฎ๐Ÿ‡ณ"}, "world": {"name": "World", "emoji": "๐ŸŒ"}, "tech": {"name": "Technology", "emoji": "๐Ÿง "}, "finance": {"name": "Business & Markets", "emoji": "๐Ÿ’ฐ"}, "sports": {"name": "Sports", "emoji": "๐Ÿ†"}, } # ๐Ÿงพ Fetch and format headlines # UPDATED: To match the exact "NUSE DAILY" format and new item format def fetch_cached_headlines() -> str: try: raw = redis_client.get("daily_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}" # Get current date for the header today = datetime.date.today() formatted_date = today.strftime("%B %d, %Y") message_parts = [] # Header section message_parts.append(f"Nuse Daily - {formatted_date}") message_parts.append("") # Iterate through topics in a defined order for consistent output for topic_key, display_info in TOPIC_DISPLAY_MAP.items(): stories_for_topic = data.get(topic_key) if stories_for_topic: message_parts.append(f"{display_info['emoji']} *{display_info['name']}*") sorted_story_ids = sorted(stories_for_topic.keys(), key=int) for ref_id in sorted_story_ids: item = stories_for_topic[ref_id] summary = item.get("summary", "") description = item.get("explanation", "") # <<< UPDATED: Item format to "1. - " >>> # Using U+2007 (Figure Space) for alignment message_parts.append(f"\u2007{ref_id}. \u2007{summary} - {description}") message_parts.append("") # Footer section message_parts.append("") message_parts.append("Curated by Nuse.") return "\n".join(message_parts) # ๐Ÿ“ค Send via Gupshup WhatsApp API def send_to_whatsapp(message_text: str, destination_number: str) -> dict: # Validate critical environment variables if not WHATSAPP_TOKEN or \ not GUPSHUP_SOURCE_NUMBER or \ not GUPSHUP_APP_NAME: error_msg = "โŒ Missing one or more critical WhatsApp API environment variables (WHATSAPP_TOKEN, GUPSHUP_SOURCE_NUMBER, GUPSHUP_APP_NAME)." logging.error(error_msg) return {"status": "failed", "error": error_msg, "code": 500} if not destination_number: error_msg = "โŒ Destination number cannot be empty." logging.error(error_msg) return {"status": "failed", "error": error_msg, "code": 400} headers = { "Content-Type": "application/x-www-form-urlencoded", "apikey": WHATSAPP_TOKEN, "Cache-Control": "no-cache", "accept": "application/json" } whatsapp_message_content = { "type": "text", "text": message_text } payload = { "channel": "whatsapp", "source": GUPSHUP_SOURCE_NUMBER, "destination": destination_number, "src.name": GUPSHUP_APP_NAME, "message": message_text, "disablePreview": False, "encode": False } try: logging.info(f"Attempting to send standard text WhatsApp message to {destination_number}, {GUPSHUP_SOURCE_NUMBER}, {GUPSHUP_APP_NAME}, {WHATSAPP_TOKEN} via Gupshup. API URL: {WHATSAPP_API_URL} and message text is {message_text}") response = requests.post( WHATSAPP_API_URL, headers=headers, data=payload, ) response.raise_for_status() 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}