again
Browse files
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
|
6 |
-
from fastapi.responses import JSONResponse
|
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") #
|
17 |
-
GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER")
|
18 |
-
GUPSHUP_APP_NAME = os.environ.get("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()
|
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}*")
|
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: #
|
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,
|
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,
|
76 |
-
"Cache-Control": "no-cache"
|
77 |
}
|
78 |
|
79 |
whatsapp_message_content = {
|
80 |
"type": "text",
|
81 |
-
"text": message_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)
|
90 |
}
|
91 |
|
92 |
try:
|
93 |
-
|
|
|
94 |
response = requests.post(
|
95 |
WHATSAPP_API_URL,
|
96 |
headers=headers,
|
97 |
data=payload,
|
98 |
)
|
99 |
-
response.raise_for_status()
|
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 |
-
#
|
110 |
-
|
111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
|
113 |
-
|
114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.")
|