ragV98 commited on
Commit
5093e27
Β·
1 Parent(s): 1c8e081
Files changed (1) hide show
  1. components/gateways/headlines_to_wa.py +110 -32
components/gateways/headlines_to_wa.py CHANGED
@@ -4,44 +4,83 @@ import redis
4
  import requests
5
  from fastapi import FastAPI
6
  from fastapi.responses import JSONResponse
 
 
 
7
 
8
  # 🌐 Redis config
9
  REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
10
  WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/sm/api/v1/msg")
11
- WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN", "sk_e73f674b797549ed80c85105ded5a0d1")
12
- WHATSAPP_TO_NUMBER = os.environ.get("WHATSAPP_TO_NUMBER", "353899495777") # e.g., "91xxxxxxxxxx"
13
- GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER", "+1 555-792-6439") # e.g., your WABA number
14
- GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME", "NuseAI") # e.g., your Gupshup app name
15
 
16
  # βœ… Redis connection
17
- redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
 
 
 
 
 
 
 
18
 
19
  # 🧾 Fetch and format headlines
20
  def fetch_cached_headlines() -> str:
21
  try:
22
- raw = redis_client.get("daily_news_headline_json")
 
 
23
  if not raw:
 
24
  return "⚠️ No daily headlines found in cache."
25
  data = json.loads(raw)
26
  except Exception as e:
 
27
  return f"❌ Error reading from Redis: {e}"
28
 
29
- message = ["πŸ—žοΈ *Your Daily Digest* 🟑\n"]
30
- for topic, stories in data.items():
31
- title = topic.replace("_", " ").title()
32
- message.append(f"🏷️ *{title}*")
33
- for ref, item in stories.items():
34
- summary = item.get("summary", "")
35
- explanation = item.get("explanation", "")
36
- message.append(f"{ref}. {summary}\n_Why this matters_: {explanation}")
37
- message.append("") # spacing between sections
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- return "\n".join(message)
40
 
41
  # πŸ“€ Send via Gupshup WhatsApp API
42
  def send_to_whatsapp(message_text: str) -> dict:
 
 
 
 
 
 
 
43
  headers = {
44
- "Content-Type": "application/x-www-form-urlencoded"
 
45
  }
46
 
47
  payload = {
@@ -55,35 +94,74 @@ def send_to_whatsapp(message_text: str) -> dict:
55
  "src.name": GUPSHUP_APP_NAME,
56
  }
57
 
58
- response = requests.post(
59
- WHATSAPP_API_URL,
60
- headers=headers,
61
- data=payload,
62
- auth=(WHATSAPP_TOKEN, '') # Gupshup uses Basic Auth (API key as username)
63
- )
 
 
 
64
 
65
- if response.status_code == 200:
66
  return {"status": "success", "details": response.json()}
67
- else:
68
- return {"status": "failed", "error": response.text, "code": response.status_code}
 
 
 
 
69
 
70
  # πŸš€ FastAPI App
71
  app = FastAPI()
72
 
73
  @app.get("/send-daily-whatsapp")
74
  def send_daily_whatsapp_digest():
 
75
  message = fetch_cached_headlines()
76
 
77
  if message.startswith("❌") or message.startswith("⚠️"):
 
78
  return JSONResponse(status_code=404, content={"error": message})
79
 
80
  result = send_to_whatsapp(message)
81
- return result
 
 
 
 
 
 
82
 
83
  # πŸ§ͺ For local testing
84
  if __name__ == "__main__":
85
- msg = fetch_cached_headlines()
86
- print("--- WhatsApp Message Preview ---\n")
87
- print(msg)
88
- result = send_to_whatsapp(msg)
89
- print(result)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import requests
5
  from fastapi import FastAPI
6
  from fastapi.responses import JSONResponse
7
+ import logging # Import logging for better output
8
+
9
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
10
 
11
  # 🌐 Redis config
12
  REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
13
  WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/sm/api/v1/msg")
14
+ WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN")
15
+ WHATSAPP_TO_NUMBER = os.environ.get("WHATSAPP_TO_NUMBER") # e.g., "91xxxxxxxxxx"
16
+ GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER") # e.g., your WABA number
17
+ GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME") # e.g., your Gupshup app name
18
 
19
  # βœ… Redis connection
20
+ try:
21
+ redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
22
+ redis_client.ping() # Test connection
23
+ logging.info("Redis client connected successfully.")
24
+ except Exception as e:
25
+ logging.error(f"❌ Failed to connect to Redis: {e}")
26
+ # Depending on your application's needs, you might want to exit or fail gracefully here.
27
+ raise
28
 
29
  # 🧾 Fetch and format headlines
30
  def fetch_cached_headlines() -> str:
31
  try:
32
+ # Assuming 'detailed_news_feed_cache' is the key for the final detailed headlines
33
+ # This key should match what's used in components/generators/detailed_explainer.py
34
+ raw = redis_client.get("detailed_news_feed_cache")
35
  if not raw:
36
+ logging.warning("⚠️ No detailed news headlines found in cache.")
37
  return "⚠️ No daily headlines found in cache."
38
  data = json.loads(raw)
39
  except Exception as e:
40
+ logging.error(f"❌ Error reading from Redis: {e}")
41
  return f"❌ Error reading from Redis: {e}"
42
 
43
+ message_parts = ["πŸ—žοΈ *Your Daily Digest* 🟑\n"]
44
+
45
+ # Iterate through topics in the order defined by TOPIC_KEYS (if available, otherwise iterate data.items())
46
+ # Assuming TOPIC_KEYS is available globally or passed here if needed for consistent order
47
+ # For now, just iterate through the data items as they are in the cached JSON
48
+
49
+ # Sort topics alphabetically for consistent output if no external order is provided
50
+ sorted_topics = sorted(data.keys())
51
+
52
+ for topic_key in sorted_topics:
53
+ stories = data[topic_key]
54
+ # Format topic title nicely (e.g., "india" -> "India", "world" -> "World")
55
+ title = topic_key.replace("_", " ").title()
56
+ message_parts.append(f"🏷️ *{title}*")
57
+
58
+ # Sort stories by their sequential ID for consistent order
59
+ sorted_story_ids = sorted(stories.keys(), key=int) # Ensure keys are treated as integers for sorting
60
+
61
+ for ref_id in sorted_story_ids:
62
+ item = stories[ref_id]
63
+ summary = item.get("title", "") # Use 'title' key for the summary/headline
64
+ description = item.get("description", "") # Use 'description' key for the explanation
65
+
66
+ # Ensure ref_id is a string for the message
67
+ message_parts.append(f"{ref_id}. {summary}\n_Why this matters_: {description}")
68
+ message_parts.append("") # spacing between sections
69
 
70
+ return "\n".join(message_parts)
71
 
72
  # πŸ“€ Send via Gupshup WhatsApp API
73
  def send_to_whatsapp(message_text: str) -> dict:
74
+ # Validate environment variables
75
+ if not WHATSAPP_TOKEN or not WHATSAPP_TO_NUMBER or not GUPSHUP_SOURCE_NUMBER or not GUPSHUP_APP_NAME:
76
+ error_msg = "❌ Missing one or more WhatsApp API environment variables (WHATSAPP_TOKEN, WHATSAPP_TO_NUMBER, GUPSHUP_SOURCE_NUMBER, GUPSHUP_APP_NAME)."
77
+ logging.error(error_msg)
78
+ return {"status": "failed", "error": error_msg, "code": 500}
79
+
80
+ # Gupshup requires the API key in the 'apikey' header
81
  headers = {
82
+ "Content-Type": "application/x-www-form-urlencoded",
83
+ "apikey": WHATSAPP_TOKEN # <<< FIX: API key in 'apikey' header
84
  }
85
 
86
  payload = {
 
94
  "src.name": GUPSHUP_APP_NAME,
95
  }
96
 
97
+ try:
98
+ logging.info(f"Attempting to send WhatsApp message to {WHATSAPP_TO_NUMBER} via Gupshup.")
99
+ response = requests.post(
100
+ WHATSAPP_API_URL,
101
+ headers=headers,
102
+ data=payload,
103
+ # auth=(WHATSAPP_TOKEN, '') # <<< REMOVED: This sends Basic Auth, which Gupshup doesn't support for API key
104
+ )
105
+ response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
106
 
 
107
  return {"status": "success", "details": response.json()}
108
+ except requests.exceptions.RequestException as e:
109
+ logging.error(f"❌ Failed to send WhatsApp message: {e}")
110
+ return {"status": "failed", "error": str(e), "code": e.response.status_code if e.response else 500}
111
+ except Exception as e:
112
+ logging.error(f"❌ An unexpected error occurred during WhatsApp send: {e}")
113
+ return {"status": "failed", "error": str(e), "code": 500}
114
 
115
  # πŸš€ FastAPI App
116
  app = FastAPI()
117
 
118
  @app.get("/send-daily-whatsapp")
119
  def send_daily_whatsapp_digest():
120
+ logging.info("API Call: /send-daily-whatsapp initiated.")
121
  message = fetch_cached_headlines()
122
 
123
  if message.startswith("❌") or message.startswith("⚠️"):
124
+ logging.warning(f"Returning error due to issue fetching headlines: {message}")
125
  return JSONResponse(status_code=404, content={"error": message})
126
 
127
  result = send_to_whatsapp(message)
128
+
129
+ if result.get("status") == "success":
130
+ logging.info("βœ… WhatsApp message sent successfully.")
131
+ return JSONResponse(status_code=200, content=result)
132
+ else:
133
+ logging.error(f"❌ Failed to send WhatsApp message: {result.get('error')}")
134
+ return JSONResponse(status_code=result.get("code", 500), content=result)
135
 
136
  # πŸ§ͺ For local testing
137
  if __name__ == "__main__":
138
+ # Set dummy environment variables for local testing if not already set
139
+ os.environ.setdefault("WHATSAPP_API_URL", "https://api.gupshup.io/sm/api/v1/msg")
140
+ os.environ.setdefault("WHATSAPP_TOKEN", "YOUR_GUPSHUP_API_KEY") # Replace with a real dummy or your actual key
141
+ os.environ.setdefault("WHATSAPP_TO_NUMBER", "919999999999") # Replace with a test number
142
+ os.environ.setdefault("GUPSHUP_SOURCE_NUMBER", "918888888888") # Replace with your WABA number
143
+ os.environ.setdefault("GUPSHUP_APP_NAME", "YourTestApp") # Replace with your app name
144
+
145
+ # Simulate a cached detailed feed for testing
146
+ dummy_cached_detailed_feed = {
147
+ "india": {
148
+ "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"]},
149
+ "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"]}
150
+ },
151
+ "world": {
152
+ "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"]},
153
+ "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"]}
154
+ }
155
+ }
156
+ # Store dummy data in Redis for testing fetch_cached_headlines
157
+ redis_client.set("detailed_news_feed_cache", json.dumps(dummy_cached_detailed_feed))
158
+
159
+
160
+ logging.info("\n--- WhatsApp Message Preview ---\n")
161
+ msg_preview = fetch_cached_headlines()
162
+ print(msg_preview)
163
+
164
+ logging.info("\n--- Sending WhatsApp Message (Test) ---\n")
165
+ # This will attempt to send a real message if your env vars are valid
166
+ test_result = send_to_whatsapp(msg_preview)
167
+ print(test_result)