ragV98 commited on
Commit
eb4b0f5
·
1 Parent(s): f58b18a
components/gateways/headlines_to_wa.py CHANGED
@@ -3,11 +3,11 @@ import json
3
  import redis
4
  import requests
5
  import logging
6
- import datetime
7
 
8
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
9
 
10
- # 🌐 Configuration from Environment Variables (rest of the file's global section)
11
  REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
12
  WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
13
  WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN")
@@ -15,7 +15,7 @@ WHATSAPP_TO_NUMBER = os.environ.get("WHATSAPP_TO_NUMBER", "353899495777")
15
  GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER")
16
  GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME")
17
 
18
- # ✅ Redis connection (rest of the file's redis connection)
19
  try:
20
  redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
21
  redis_client.ping()
@@ -24,9 +24,18 @@ except Exception as e:
24
  logging.error(f"❌ Failed to connect to Redis: {e}")
25
  raise
26
 
27
- # 🧾 Fetch and format headlines (rest of the file's fetch_cached_headlines)
 
 
 
 
 
 
 
 
 
 
28
  def fetch_cached_headlines() -> str:
29
- # ... (rest of your fetch_cached_headlines function) ...
30
  try:
31
  raw = redis_client.get("detailed_news_feed_cache")
32
  if not raw:
@@ -39,7 +48,6 @@ def fetch_cached_headlines() -> str:
39
 
40
  # Get current date for the header
41
  today = datetime.date.today()
42
- # Format: July 22, 2025
43
  formatted_date = today.strftime("%B %d, %Y")
44
 
45
  message_parts = []
@@ -48,17 +56,8 @@ def fetch_cached_headlines() -> str:
48
  message_parts.append(f"Nuse Daily - {formatted_date}")
49
  message_parts.append("")
50
 
51
- # --- New: Topic mapping for display names and emojis ---
52
- TOPIC_DISPLAY_MAP = {
53
- "india": {"name": "India", "emoji": "🇮🇳"},
54
- "world": {"name": "World", "emoji": "🌍"},
55
- "tech": {"name": "Technology", "emoji": "🧠"}, # Used brain emoji from your curl
56
- "finance": {"name": "Business & Markets", "emoji": "💰"}, # Used money bag emoji from your curl
57
- "sports": {"name": "Sports", "emoji": "🏆"}, # Used trophy emoji from your curl
58
- }
59
-
60
  # Iterate through topics in a defined order for consistent output
61
- for topic_key, display_info in TOPIC_DISPLAY_MAP.items(): # TOPIC_DISPLAY_MAP needs to be defined
62
  stories_for_topic = data.get(topic_key)
63
 
64
  if stories_for_topic:
@@ -71,16 +70,17 @@ def fetch_cached_headlines() -> str:
71
  summary = item.get("title", "")
72
  description = item.get("description", "")
73
 
74
- message_parts.append(f"\u2007{ref_id}. \u2007{summary}\n_Why this matters_: {description}")
 
 
75
  message_parts.append("")
76
 
77
  # Footer section
78
- message_parts.append("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
79
- message_parts.append("🟠 Curated by Nuse Editorial Desk")
80
 
81
  return "\n".join(message_parts)
82
 
83
-
84
  # 📤 Send via Gupshup WhatsApp API
85
  def send_to_whatsapp(message_text: str, destination_number: str) -> dict:
86
  # Validate critical environment variables
@@ -101,7 +101,7 @@ def send_to_whatsapp(message_text: str, destination_number: str) -> dict:
101
  "Content-Type": "application/x-www-form-urlencoded",
102
  "apikey": WHATSAPP_TOKEN,
103
  "Cache-Control": "no-cache",
104
- "accept": "application/json" # <<< ADDED: Accept header
105
  }
106
 
107
  whatsapp_message_content = {
@@ -115,8 +115,8 @@ def send_to_whatsapp(message_text: str, destination_number: str) -> dict:
115
  "destination": destination_number,
116
  "src.name": GUPSHUP_APP_NAME,
117
  "message": json.dumps(whatsapp_message_content),
118
- "disablePreview": False, # <<< ADDED: disablePreview parameter
119
- "encode": False # <<< ADDED: encode parameter
120
  }
121
 
122
  try:
@@ -134,4 +134,76 @@ def send_to_whatsapp(message_text: str, destination_number: str) -> dict:
134
  return {"status": "failed", "error": str(e), "code": e.response.status_code if e.response else 500}
135
  except Exception as e:
136
  logging.error(f"❌ An unexpected error occurred during WhatsApp send: {e}")
137
- return {"status": "failed", "error": str(e), "code": 500}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import redis
4
  import requests
5
  import logging
6
+ import datetime # Import datetime for dynamic date
7
 
8
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
9
 
10
+ # 🌐 Configuration from Environment Variables
11
  REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
12
  WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
13
  WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN")
 
15
  GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER")
16
  GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME")
17
 
18
+ # ✅ Redis connection
19
  try:
20
  redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
21
  redis_client.ping()
 
24
  logging.error(f"❌ Failed to connect to Redis: {e}")
25
  raise
26
 
27
+ # --- New: Topic mapping for display names and emojis ---
28
+ TOPIC_DISPLAY_MAP = {
29
+ "india": {"name": "India", "emoji": "🇮🇳"},
30
+ "world": {"name": "World", "emoji": "🌍"},
31
+ "tech": {"name": "Technology", "emoji": "🧠"},
32
+ "finance": {"name": "Business & Markets", "emoji": "💰"},
33
+ "sports": {"name": "Sports", "emoji": "🏆"},
34
+ }
35
+
36
+ # 🧾 Fetch and format headlines
37
+ # UPDATED: To match the exact "NUSE DAILY" format and new item format
38
  def fetch_cached_headlines() -> str:
 
39
  try:
40
  raw = redis_client.get("detailed_news_feed_cache")
41
  if not raw:
 
48
 
49
  # Get current date for the header
50
  today = datetime.date.today()
 
51
  formatted_date = today.strftime("%B %d, %Y")
52
 
53
  message_parts = []
 
56
  message_parts.append(f"Nuse Daily - {formatted_date}")
57
  message_parts.append("")
58
 
 
 
 
 
 
 
 
 
 
59
  # Iterate through topics in a defined order for consistent output
60
+ for topic_key, display_info in TOPIC_DISPLAY_MAP.items():
61
  stories_for_topic = data.get(topic_key)
62
 
63
  if stories_for_topic:
 
70
  summary = item.get("title", "")
71
  description = item.get("description", "")
72
 
73
+ # <<< UPDATED: Item format to "1. <summary> - <explanation>" >>>
74
+ # Using U+2007 (Figure Space) for alignment
75
+ message_parts.append(f"\u2007{ref_id}. \u2007{summary} - {description}")
76
  message_parts.append("")
77
 
78
  # Footer section
79
+ message_parts.append("")
80
+ message_parts.append("Curated by Nuse.")
81
 
82
  return "\n".join(message_parts)
83
 
 
84
  # 📤 Send via Gupshup WhatsApp API
85
  def send_to_whatsapp(message_text: str, destination_number: str) -> dict:
86
  # Validate critical environment variables
 
101
  "Content-Type": "application/x-www-form-urlencoded",
102
  "apikey": WHATSAPP_TOKEN,
103
  "Cache-Control": "no-cache",
104
+ "accept": "application/json"
105
  }
106
 
107
  whatsapp_message_content = {
 
115
  "destination": destination_number,
116
  "src.name": GUPSHUP_APP_NAME,
117
  "message": json.dumps(whatsapp_message_content),
118
+ "disablePreview": False,
119
+ "encode": False
120
  }
121
 
122
  try:
 
134
  return {"status": "failed", "error": str(e), "code": e.response.status_code if e.response else 500}
135
  except Exception as e:
136
  logging.error(f"❌ An unexpected error occurred during WhatsApp send: {e}")
137
+ return {"status": "failed", "error": str(e), "code": 500}
138
+
139
+ # 🚀 FastAPI App (This part should ideally be in routes/api/wa_headlines.py, not here)
140
+ app = FastAPI()
141
+
142
+ @app.get("/send-daily-whatsapp")
143
+ def send_daily_whatsapp_digest():
144
+ logging.info("API Call: /send-daily-whatsapp initiated.")
145
+
146
+ full_message_text = fetch_cached_headlines()
147
+
148
+ if full_message_text.startswith("❌") or full_message_text.startswith("⚠️"):
149
+ logging.warning(f"Returning error due to issue fetching headlines: {full_message_text}")
150
+ return JSONResponse(status_code=404, content={"error": full_message_text})
151
+
152
+ result = send_to_whatsapp(full_message_text, destination_number=os.environ.get("WHATSAPP_TO_NUMBER"))
153
+
154
+ if result.get("status") == "success":
155
+ logging.info("✅ WhatsApp message sent successfully.")
156
+ return JSONResponse(status_code=200, content=result)
157
+ else:
158
+ logging.error(f"❌ Failed to send WhatsApp message: {result.get('error')}")
159
+ return JSONResponse(status_code=result.get("code", 500), content=result)
160
+
161
+ # 🧪 For local testing
162
+ if __name__ == "__main__":
163
+ # For local testing, ensure these environment variables are set in your shell or .env file.
164
+ os.environ.setdefault("UPSTASH_REDIS_URL", "redis://localhost:6379")
165
+ os.environ.setdefault("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
166
+ os.environ.setdefault("WHATSAPP_TOKEN", "YOUR_GUPSHUP_API_KEY")
167
+ os.environ.setdefault("WHATSAPP_TO_NUMBER", "353899495777") # Use a valid test number
168
+ os.environ.setdefault("GUPSHUP_SOURCE_NUMBER", "15557926439")
169
+ os.environ.setdefault("GUPSHUP_APP_NAME", "NuseAI")
170
+
171
+ # Simulate a cached detailed feed for testing
172
+ dummy_cached_detailed_feed = {
173
+ "india": {
174
+ "1": {"title": "RBI Holds Rates at 6.5% as Inflation Cools to 5.1%, Boosting Confidence Ahead of Festive Demand", "description": "The central bank's decision signals stability and aims to encourage consumer spending during the upcoming festive season, crucial for economic momentum. Lower inflation provides relief to households and supports growth prospects. The cautious approach balances economic recovery with price control.", "sources": ["Times of India"]},
175
+ "2": {"title": "Modi Inaugurates Global Summit Venue in Gandhinagar to Cement India’s Role as East–West Diplomatic Bridge", "description": "This new venue positions India as a key player in international diplomacy, fostering dialogue and collaboration between Asian and Western nations. It highlights the country's growing influence on global affairs and capacity for large-scale international events, boosting its soft power.", "sources": ["Indian Express"]},
176
+ "3": {"title": "Adani Pursues $50B Gulf Green Hydrogen Deal to Accelerate India’s Clean Energy Ambitions", "description": "This massive investment underscores India's commitment to renewable energy and its transition away from fossil fuels. Partnering with Gulf nations secures critical resources and technology, advancing India's position as a leader in green hydrogen production and reducing its carbon footprint.", "sources": ["The Economic Times"]}
177
+ },
178
+ "world": {
179
+ "4": {"title": "Biden Signs $95B Indo-Pacific Aid Bill, Reinforcing U.S. Strategy Against Chinese Expansion", "description": "The bill provides significant financial assistance to allies in the Indo-Pacific, strengthening regional security and economic ties. This move aims to counter China's growing influence and maintain stability in a strategically vital area, signaling continued U.S. commitment to its partners.", "sources": ["Reuters"]},
180
+ "5": {"title": "Hurricane Felix Strengthens Into Category 4, Florida Declares Statewide Emergency", "description": "The rapid intensification of Hurricane Felix poses a severe threat to coastal communities in Florida, prompting urgent evacuation orders and extensive preparedness measures. Residents are urged to secure their homes and follow safety guidelines as the storm approaches, emphasizing climate change impacts.", "sources": ["CNN World"]},
181
+ "6": {"title": "Iran’s Hardliner President Takes Office Amid Nuclear Tensions and Diplomatic Uncertainty", "description": "The new leadership in Iran signals a potential shift in foreign policy, raising concerns among international observers about the future of nuclear negotiations. Diplomatic tensions could escalate, impacting regional stability and global energy markets as nations reassess their strategies.", "sources": ["BBC News"]}
182
+ },
183
+ "finance": {
184
+ "7": {"title": "Nasdaq Surges as Nvidia and AI Stocks Power New Record Highs", "description": "The technology-heavy Nasdaq's rise reflects robust investor confidence in the artificial intelligence sector, with Nvidia leading the charge. This surge indicates strong market enthusiasm for innovation and potential future growth in tech, driving overall market performance.", "sources": ["CNBC"]},
185
+ "8": {"title": "Eurozone Inflation Falls Below 2.5%, Raising Hopes for ECB Rate Cuts in Q4", "description": "Declining inflation figures in the Eurozone signal easing price pressures, increasing the likelihood of interest rate reductions by the European Central Bank. Such cuts could stimulate economic activity and provide relief to consumers and businesses, supporting recovery efforts.", "sources": ["Financial Times"]},
186
+ "9": {"title": "Infosys Beats Earnings Expectations, Announces $1.5B Buyback", "description": "Infosys' strong financial performance demonstrates resilience in the IT services sector despite global economic uncertainties. The share buyback initiative signals confidence in the company's future prospects and aims to return value to shareholders, potentially boosting stock performance.", "sources": ["Economic Times"]}
187
+ },
188
+ "tech": {
189
+ "10": {"title": "Meta’s Llama 3.5 Rivals GPT-4 in Benchmarks, Marking Breakthrough for Open-Source AI", "description": "Meta's latest large language model, Llama 3.5, demonstrates impressive performance, challenging proprietary models like GPT-4. This development significantly advances open-source AI capabilities, promoting wider accessibility and innovation in artificial intelligence research and application development globally.", "sources": ["Wired"]},
190
+ "11": {"title": "Apple Unveils Foldable iPhone 17 with AI-Native OS, Signaling Shift Toward Software Innovation", "description": "Apple's new foldable smartphone, featuring a deeply integrated AI operating system, marks a significant technological leap. This move emphasizes a strategic shift towards software-driven experiences and design innovation, potentially reshaping the smartphone market and user interaction paradigms.", "sources": ["The Verge"]},
191
+ "12": {"title": "Google Partners With Indian Startups to Expand Regional AI Tools", "description": "Google's collaboration with Indian startups aims to foster localized AI solutions, addressing unique market needs and promoting technological advancement in the region. This initiative supports the growth of India's tech ecosystem and expands Google's reach into emerging markets, boosting digital transformation.", "sources": ["TechCrunch"]}
192
+ },
193
+ "sports": {
194
+ "13": {"title": "India Clinches T20 Series vs West Indies With Last-Over Thriller in Port of Spain", "description": "India's dramatic series victory showcases their resilience and strategic prowess in high-pressure cricket matches. This win boosts team morale and demonstrates strong form ahead of upcoming international tournaments, solidifying their position in global T20 rankings.", "sources": ["ESPN Cricinfo"]},
195
+ "14": {"title": "Messi Breaks MLS Scoring Record With Hat-Trick for Inter Miami", "description": "Lionel Messi continues to redefine Major League Soccer, setting a new scoring record with his exceptional performance for Inter Miami. His consistent brilliance elevates the league's global profile and inspires a new generation of football fans across North America.", "sources": ["MLS Soccer"]},
196
+ "15": {"title": "Olympic Torch Relay Kicks Off in Paris With 100 Days Until Opening", "description": "The ceremonial start of the Olympic Torch Relay in Paris ignites excitement and anticipation for the upcoming Summer Games. This milestone event symbolizes unity and athletic spirit, bringing the global community together in the countdown to the prestigious sporting spectacle.", "sources": ["Olympic.org"]}
197
+ }
198
+ }
199
+ # Store dummy data in Redis for testing fetch_cached_headlines
200
+ redis_client.set("detailed_news_feed_cache", json.dumps(dummy_cached_detailed_feed))
201
+
202
+
203
+ logging.info("\n--- WhatsApp Message Preview ---\n")
204
+ msg_preview = fetch_cached_headlines()
205
+ print(msg_preview)
206
+
207
+ logging.info("\n--- Sending WhatsApp Message (Test) ---\n")
208
+ test_result = send_to_whatsapp(msg_preview, destination_number=os.environ.get("WHATSAPP_TO_NUMBER"))
209
+ print(test_result)