ragV98 commited on
Commit
966434b
Β·
1 Parent(s): ac073c2
components/gateways/headlines_to_wa.py CHANGED
@@ -2,8 +2,8 @@ import os
2
  import json
3
  import redis
4
  import requests
5
- from fastapi import FastAPI # This import is not strictly needed in this file if it's just a module
6
- from fastapi.responses import JSONResponse # This import is not strictly needed in this file if it's just a module
7
  import logging
8
 
9
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -13,21 +13,22 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(
13
  REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
14
  WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
15
  WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN")
16
- WHATSAPP_TO_NUMBER = os.environ.get("WHATSAPP_TO_NUMBER", "353899495777") # e.g., "91xxxxxxxxxx"
17
- GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER") # e.g., your WABA number
18
- GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME") # e.g., your Gupshup app name
19
 
20
- # βœ… Redis connection
21
  try:
22
  redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
23
- redis_client.ping() # Test connection
24
  logging.info("Redis client connected successfully.")
25
  except Exception as e:
26
  logging.error(f"❌ Failed to connect to Redis: {e}")
27
  raise
28
 
29
- # 🧾 Fetch and format headlines
30
  def fetch_cached_headlines() -> str:
 
31
  try:
32
  raw = redis_client.get("detailed_news_feed_cache")
33
  if not raw:
@@ -45,7 +46,7 @@ def fetch_cached_headlines() -> str:
45
  for topic_key in sorted_topics:
46
  stories = data[topic_key]
47
  title = topic_key.replace("_", " ").title()
48
- message_parts.append(f"\n🏷️ *{title}*") # Added newline before topic title
49
 
50
  sorted_story_ids = sorted(stories.keys(), key=int)
51
 
@@ -60,43 +61,50 @@ def fetch_cached_headlines() -> str:
60
  return "\n".join(message_parts)
61
 
62
  # πŸ“€ Send via Gupshup WhatsApp API
63
- def send_to_whatsapp(message_text: str, destination_number: str) -> dict: # Function expects the full message text
64
  # Validate critical environment variables for sending a message
65
  if not WHATSAPP_TOKEN or \
66
- not WHATSAPP_TO_NUMBER or \
67
  not GUPSHUP_SOURCE_NUMBER or \
68
- not GUPSHUP_APP_NAME:
69
- error_msg = "❌ Missing one or more critical WhatsApp API environment variables (WHATSAPP_TOKEN, WHATSAPP_TO_NUMBER, GUPSHUP_SOURCE_NUMBER, GUPSHUP_APP_NAME)."
70
  logging.error(error_msg)
71
  return {"status": "failed", "error": error_msg, "code": 500}
 
 
 
 
 
 
 
72
 
73
  headers = {
74
  "Content-Type": "application/x-www-form-urlencoded",
75
- "apikey": WHATSAPP_TOKEN, # API key in 'apikey' header
76
- "Cache-Control": "no-cache" # Add Cache-Control header
77
  }
78
 
79
  whatsapp_message_content = {
80
  "type": "text",
81
- "text": message_text # This is the full formatted text
82
  }
83
 
84
  payload = {
85
  "channel": "whatsapp",
86
  "source": GUPSHUP_SOURCE_NUMBER,
87
- "destination": destination_number,
88
  "src.name": GUPSHUP_APP_NAME,
89
- "message": json.dumps(whatsapp_message_content) # 'message' parameter with JSON string for text type
90
  }
91
 
92
  try:
93
- logging.info(f"Attempting to send standard text WhatsApp message to {WHATSAPP_TO_NUMBER} via Gupshup. API URL: {WHATSAPP_API_URL}")
 
94
  response = requests.post(
95
  WHATSAPP_API_URL,
96
  headers=headers,
97
  data=payload,
98
  )
99
- response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
100
 
101
  return {"status": "success", "details": response.json()}
102
  except requests.exceptions.RequestException as e:
@@ -106,9 +114,64 @@ def send_to_whatsapp(message_text: str, destination_number: str) -> dict: # Func
106
  logging.error(f"❌ An unexpected error occurred during WhatsApp send: {e}")
107
  return {"status": "failed", "error": str(e), "code": 500}
108
 
109
- # Removed the FastAPI app instance and endpoint from here,
110
- # as it will be defined in routes/api/wa_headlines.py
111
- # and then included in app.py.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
- # Removed the if __name__ == "__main__": block from here,
114
- # as it will be in routes/api/wa_headlines.py for local testing.
 
 
 
 
 
 
 
 
 
 
 
2
  import json
3
  import redis
4
  import requests
5
+ from fastapi import FastAPI
6
+ from fastapi.responses import JSONResponse
7
  import logging
8
 
9
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
13
  REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
14
  WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
15
  WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN")
16
+ WHATSAPP_TO_NUMBER = os.environ.get("WHATSAPP_TO_NUMBER", "353899495777") # Default can be changed
17
+ GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER")
18
+ GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME")
19
 
20
+ # βœ… Redis connection (assuming it's connected successfully elsewhere in the full file)
21
  try:
22
  redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
23
+ redis_client.ping()
24
  logging.info("Redis client connected successfully.")
25
  except Exception as e:
26
  logging.error(f"❌ Failed to connect to Redis: {e}")
27
  raise
28
 
29
+ # 🧾 Fetch and format headlines (assuming this function is defined as before)
30
  def fetch_cached_headlines() -> str:
31
+ # ... (content of your fetch_cached_headlines function) ...
32
  try:
33
  raw = redis_client.get("detailed_news_feed_cache")
34
  if not raw:
 
46
  for topic_key in sorted_topics:
47
  stories = data[topic_key]
48
  title = topic_key.replace("_", " ").title()
49
+ message_parts.append(f"\n🏷️ *{title}*")
50
 
51
  sorted_story_ids = sorted(stories.keys(), key=int)
52
 
 
61
  return "\n".join(message_parts)
62
 
63
  # πŸ“€ Send via Gupshup WhatsApp API
64
+ def send_to_whatsapp(message_text: str, destination_number: str) -> dict: # destination_number is required
65
  # Validate critical environment variables for sending a message
66
  if not WHATSAPP_TOKEN or \
 
67
  not GUPSHUP_SOURCE_NUMBER or \
68
+ not GUPSHUP_APP_NAME: # WHATSAPP_TO_NUMBER is no longer critically validated here, as it's passed as an argument
69
+ error_msg = "❌ Missing one or more critical WhatsApp API environment variables (WHATSAPP_TOKEN, GUPSHUP_SOURCE_NUMBER, GUPSHUP_APP_NAME)."
70
  logging.error(error_msg)
71
  return {"status": "failed", "error": error_msg, "code": 500}
72
+
73
+ # It's good practice to ensure the destination number itself isn't empty
74
+ if not destination_number:
75
+ error_msg = "❌ Destination number cannot be empty."
76
+ logging.error(error_msg)
77
+ return {"status": "failed", "error": error_msg, "code": 400}
78
+
79
 
80
  headers = {
81
  "Content-Type": "application/x-www-form-urlencoded",
82
+ "apikey": WHATSAPP_TOKEN,
83
+ "Cache-Control": "no-cache"
84
  }
85
 
86
  whatsapp_message_content = {
87
  "type": "text",
88
+ "text": message_text
89
  }
90
 
91
  payload = {
92
  "channel": "whatsapp",
93
  "source": GUPSHUP_SOURCE_NUMBER,
94
+ "destination": destination_number, # Use the passed destination_number
95
  "src.name": GUPSHUP_APP_NAME,
96
+ "message": json.dumps(whatsapp_message_content)
97
  }
98
 
99
  try:
100
+ # FIX: Log the actual destination_number being used
101
+ logging.info(f"Attempting to send standard text WhatsApp message to {destination_number} via Gupshup. API URL: {WHATSAPP_API_URL}")
102
  response = requests.post(
103
  WHATSAPP_API_URL,
104
  headers=headers,
105
  data=payload,
106
  )
107
+ response.raise_for_status()
108
 
109
  return {"status": "success", "details": response.json()}
110
  except requests.exceptions.RequestException as e:
 
114
  logging.error(f"❌ An unexpected error occurred during WhatsApp send: {e}")
115
  return {"status": "failed", "error": str(e), "code": 500}
116
 
117
+ # πŸš€ FastAPI App
118
+ app = FastAPI()
119
+
120
+ @app.get("/send-daily-whatsapp")
121
+ def send_daily_whatsapp_digest():
122
+ logging.info("API Call: /send-daily-whatsapp initiated.")
123
+
124
+ full_message_text = fetch_cached_headlines()
125
+
126
+ if full_message_text.startswith("❌") or full_message_text.startswith("⚠️"):
127
+ logging.warning(f"Returning error due to issue fetching headlines: {full_message_text}")
128
+ return JSONResponse(status_code=404, content={"error": full_message_text})
129
+
130
+ # Call send_to_whatsapp with the default destination from environment variable
131
+ # This now requires WHATSAPP_TO_NUMBER to be set and passed
132
+ result = send_to_whatsapp(full_message_text, destination_number=WHATSAPP_TO_NUMBER)
133
+
134
+ if result.get("status") == "success":
135
+ logging.info("βœ… WhatsApp message sent successfully.")
136
+ return JSONResponse(status_code=200, content=result)
137
+ else:
138
+ logging.error(f"❌ Failed to send WhatsApp message: {result.get('error')}")
139
+ return JSONResponse(status_code=result.get("code", 500), content=result)
140
+
141
+ # πŸ§ͺ For local testing
142
+ if __name__ == "__main__":
143
+ # For local testing, ensure these environment variables are set in your shell or .env file.
144
+ # Example .env content:
145
+ # UPSTASH_REDIS_URL="redis://your_redis_url"
146
+ # WHATSAPP_API_URL="https://api.gupshup.io/wa/api/v1/msg"
147
+ # WHATSAPP_TOKEN="YOUR_GUPSHUP_API_KEY"
148
+ # WHATSAPP_TO_NUMBER="919999999999" # Ensure this is set for direct use by send_daily_whatsapp_digest
149
+ # GUPSHUP_SOURCE_NUMBER="15557926439"
150
+ # GUPSHUP_APP_NAME="NuseAI"
151
+
152
+ # Simulate a cached detailed feed for testing
153
+ dummy_cached_detailed_feed = {
154
+ "india": {
155
+ "1": {"title": "India's Economy Surges", "description": "Rapid growth in manufacturing and services sectors signals a strong economic recovery, boosting investor confidence and job creation.", "sources": ["Times of India"]},
156
+ "2": {"title": "New Tech Policy Unveiled", "description": "Government introduces new regulations to foster innovation while addressing data privacy concerns, aiming to balance growth with user protection.", "sources": ["Indian Express"]}
157
+ },
158
+ "world": {
159
+ "3": {"title": "Global Climate Talks Advance", "description": "Nations agree on ambitious new targets for emissions reduction, marking a significant step towards combating climate change despite earlier disagreements.", "sources": ["BBC News"]},
160
+ "4": {"title": "Space Mission Explores Mars", "description": "A new rover successfully lands on Mars, sending back groundbreaking data that could revolutionize our understanding of planetary geology and potential for life.", "sources": ["CNN World"]}
161
+ }
162
+ }
163
+ # Store dummy data in Redis for testing fetch_cached_headlines
164
+ redis_client.set("detailed_news_feed_cache", json.dumps(dummy_cached_detailed_feed))
165
 
166
+
167
+ logging.info("\n--- WhatsApp Message Preview ---\n")
168
+ msg_preview = fetch_cached_headlines()
169
+ print(msg_preview)
170
+
171
+ logging.info("\n--- Sending WhatsApp Message (Test) ---\n")
172
+ # When testing locally, you might pass a specific number here
173
+ # test_result = send_to_whatsapp(msg_preview, destination_number="919999999999")
174
+
175
+ # If running the app via uvicorn and hitting the /send-daily-whatsapp endpoint,
176
+ # it will use WHATSAPP_TO_NUMBER from os.environ.get
177
+ print("Run `uvicorn your_app_file:app --reload` and visit /send-daily-whatsapp in browser or curl.")