could work
Browse files
components/gateways/headlines_to_wa.py
CHANGED
@@ -2,22 +2,23 @@ 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')
|
10 |
|
11 |
# π Configuration from Environment Variables
|
12 |
-
# These variables MUST be set in your environment (e.g., .env file, shell exports, deployment configs)
|
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()
|
@@ -26,9 +27,8 @@ 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 |
-
# ... (content of your fetch_cached_headlines function) ...
|
32 |
try:
|
33 |
raw = redis_client.get("detailed_news_feed_cache")
|
34 |
if not raw:
|
@@ -56,21 +56,23 @@ def fetch_cached_headlines() -> str:
|
|
56 |
description = item.get("description", "")
|
57 |
|
58 |
message_parts.append(f"{ref_id}. {summary}\n_Why this matters_: {description}")
|
59 |
-
# No extra empty line needed here if we add newline to topic title
|
60 |
|
61 |
return "\n".join(message_parts)
|
62 |
|
63 |
# π€ Send via Gupshup WhatsApp API
|
64 |
-
def send_to_whatsapp(
|
65 |
-
|
|
|
|
|
|
|
|
|
66 |
if not WHATSAPP_TOKEN 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, 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)
|
@@ -83,22 +85,37 @@ def send_to_whatsapp(message_text: str, destination_number: str) -> dict: # dest
|
|
83 |
"Cache-Control": "no-cache"
|
84 |
}
|
85 |
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
payload = {
|
92 |
"channel": "whatsapp",
|
93 |
"source": GUPSHUP_SOURCE_NUMBER,
|
94 |
-
"destination": destination_number,
|
95 |
"src.name": GUPSHUP_APP_NAME,
|
96 |
"message": json.dumps(whatsapp_message_content)
|
97 |
}
|
98 |
|
99 |
try:
|
100 |
-
|
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,
|
@@ -114,8 +131,8 @@ def send_to_whatsapp(message_text: str, destination_number: str) -> dict: # dest
|
|
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():
|
@@ -127,9 +144,20 @@ def send_daily_whatsapp_digest():
|
|
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 |
-
#
|
131 |
-
#
|
132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
|
134 |
if result.get("status") == "success":
|
135 |
logging.info("β
WhatsApp message sent successfully.")
|
@@ -141,13 +169,11 @@ def send_daily_whatsapp_digest():
|
|
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 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
# GUPSHUP_SOURCE_NUMBER="15557926439"
|
150 |
-
# GUPSHUP_APP_NAME="NuseAI"
|
151 |
|
152 |
# Simulate a cached detailed feed for testing
|
153 |
dummy_cached_detailed_feed = {
|
@@ -164,14 +190,18 @@ if __name__ == "__main__":
|
|
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 |
-
|
169 |
-
print(
|
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 |
-
#
|
176 |
-
|
177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import json
|
3 |
import redis
|
4 |
import requests
|
5 |
+
from fastapi import FastAPI
|
6 |
+
from fastapi.responses import JSONResponse
|
7 |
import logging
|
8 |
+
import time # Import time for a simple dynamic msgid if needed
|
9 |
+
from typing import List, Dict, Any, Optional # Import Optional and List for type hints
|
10 |
|
11 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
12 |
|
13 |
# π Configuration from Environment Variables
|
|
|
14 |
REDIS_URL = os.environ.get("UPSTASH_REDIS_URL", "redis://localhost:6379")
|
15 |
WHATSAPP_API_URL = os.environ.get("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
|
16 |
WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN")
|
17 |
+
WHATSAPP_TO_NUMBER = os.environ.get("WHATSAPP_TO_NUMBER", "353899495777")
|
18 |
GUPSHUP_SOURCE_NUMBER = os.environ.get("GUPSHUP_SOURCE_NUMBER")
|
19 |
GUPSHUP_APP_NAME = os.environ.get("GUPSHUP_APP_NAME")
|
20 |
|
21 |
+
# β
Redis connection
|
22 |
try:
|
23 |
redis_client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
|
24 |
redis_client.ping()
|
|
|
27 |
logging.error(f"β Failed to connect to Redis: {e}")
|
28 |
raise
|
29 |
|
30 |
+
# π§Ύ Fetch and format headlines
|
31 |
def fetch_cached_headlines() -> str:
|
|
|
32 |
try:
|
33 |
raw = redis_client.get("detailed_news_feed_cache")
|
34 |
if not raw:
|
|
|
56 |
description = item.get("description", "")
|
57 |
|
58 |
message_parts.append(f"{ref_id}. {summary}\n_Why this matters_: {description}")
|
|
|
59 |
|
60 |
return "\n".join(message_parts)
|
61 |
|
62 |
# π€ Send via Gupshup WhatsApp API
|
63 |
+
def send_to_whatsapp(
|
64 |
+
message_text: str,
|
65 |
+
destination_number: str,
|
66 |
+
quick_reply_options: Optional[List[str]] = None # <<< NEW PARAMETER
|
67 |
+
) -> dict:
|
68 |
+
# Validate critical environment variables
|
69 |
if not WHATSAPP_TOKEN or \
|
70 |
not GUPSHUP_SOURCE_NUMBER or \
|
71 |
+
not GUPSHUP_APP_NAME:
|
72 |
error_msg = "β Missing one or more critical WhatsApp API environment variables (WHATSAPP_TOKEN, GUPSHUP_SOURCE_NUMBER, GUPSHUP_APP_NAME)."
|
73 |
logging.error(error_msg)
|
74 |
return {"status": "failed", "error": error_msg, "code": 500}
|
75 |
|
|
|
76 |
if not destination_number:
|
77 |
error_msg = "β Destination number cannot be empty."
|
78 |
logging.error(error_msg)
|
|
|
85 |
"Cache-Control": "no-cache"
|
86 |
}
|
87 |
|
88 |
+
# <<< CONDITIONAL MESSAGE PAYLOAD BASED ON QUICK REPLY OPTIONS >>>
|
89 |
+
if quick_reply_options:
|
90 |
+
if not (1 <= len(quick_reply_options) <= 10): # WhatsApp quick reply limits
|
91 |
+
logging.error("β Quick reply options must be between 1 and 10.")
|
92 |
+
return {"status": "failed", "error": "Quick reply options count out of range", "code": 400}
|
93 |
+
|
94 |
+
whatsapp_message_content = {
|
95 |
+
"type": "quick_reply",
|
96 |
+
"msgid": f"outgoing_msg_{int(time.time())}", # Dynamic msgid for quick reply
|
97 |
+
"content": {
|
98 |
+
"type": "text",
|
99 |
+
"text": message_text # Main text of the quick reply message
|
100 |
+
},
|
101 |
+
"options": quick_reply_options # The quick reply buttons
|
102 |
+
}
|
103 |
+
else:
|
104 |
+
whatsapp_message_content = {
|
105 |
+
"type": "text",
|
106 |
+
"text": message_text # Standard text message
|
107 |
+
}
|
108 |
|
109 |
payload = {
|
110 |
"channel": "whatsapp",
|
111 |
"source": GUPSHUP_SOURCE_NUMBER,
|
112 |
+
"destination": destination_number,
|
113 |
"src.name": GUPSHUP_APP_NAME,
|
114 |
"message": json.dumps(whatsapp_message_content)
|
115 |
}
|
116 |
|
117 |
try:
|
118 |
+
logging.info(f"Attempting to send {'Quick Reply' if quick_reply_options else 'standard text'} WhatsApp message to {destination_number} via Gupshup. API URL: {WHATSAPP_API_URL}")
|
|
|
119 |
response = requests.post(
|
120 |
WHATSAPP_API_URL,
|
121 |
headers=headers,
|
|
|
131 |
logging.error(f"β An unexpected error occurred during WhatsApp send: {e}")
|
132 |
return {"status": "failed", "error": str(e), "code": 500}
|
133 |
|
134 |
+
# π FastAPI App (assuming this instance is part of app.py now)
|
135 |
+
app = FastAPI() # This should really be in app.py only
|
136 |
|
137 |
@app.get("/send-daily-whatsapp")
|
138 |
def send_daily_whatsapp_digest():
|
|
|
144 |
logging.warning(f"Returning error due to issue fetching headlines: {full_message_text}")
|
145 |
return JSONResponse(status_code=404, content={"error": full_message_text})
|
146 |
|
147 |
+
# Example of how to call send_to_whatsapp with quick replies from this endpoint
|
148 |
+
# You would typically define these options based on your use case
|
149 |
+
quick_reply_options_for_digest = [
|
150 |
+
"Read more",
|
151 |
+
"Unsubscribe",
|
152 |
+
"Contact Support"
|
153 |
+
]
|
154 |
+
|
155 |
+
# Call send_to_whatsapp with quick reply options
|
156 |
+
result = send_to_whatsapp(
|
157 |
+
message_text=full_message_text,
|
158 |
+
destination_number=os.environ.get("WHATSAPP_TO_NUMBER"),
|
159 |
+
quick_reply_options=quick_reply_options_for_digest # Pass the options here
|
160 |
+
)
|
161 |
|
162 |
if result.get("status") == "success":
|
163 |
logging.info("β
WhatsApp message sent successfully.")
|
|
|
169 |
# π§ͺ For local testing
|
170 |
if __name__ == "__main__":
|
171 |
# For local testing, ensure these environment variables are set in your shell or .env file.
|
172 |
+
os.environ.setdefault("WHATSAPP_API_URL", "https://api.gupshup.io/wa/api/v1/msg")
|
173 |
+
os.environ.setdefault("WHATSAPP_TOKEN", "YOUR_GUPSHUP_API_KEY")
|
174 |
+
os.environ.setdefault("WHATSAPP_TO_NUMBER", "919999999999") # Use a valid test number
|
175 |
+
os.environ.setdefault("GUPSHUP_SOURCE_NUMBER", "15557926439")
|
176 |
+
os.environ.setdefault("GUPSHUP_APP_NAME", "NuseAI")
|
|
|
|
|
177 |
|
178 |
# Simulate a cached detailed feed for testing
|
179 |
dummy_cached_detailed_feed = {
|
|
|
190 |
redis_client.set("detailed_news_feed_cache", json.dumps(dummy_cached_detailed_feed))
|
191 |
|
192 |
|
193 |
+
logging.info("\n--- WhatsApp Message Preview (Quick Reply) ---\n")
|
194 |
+
msg_body_preview = fetch_cached_headlines()
|
195 |
+
print(msg_body_preview)
|
|
|
|
|
|
|
|
|
196 |
|
197 |
+
# Test sending a Quick Reply message
|
198 |
+
test_options = ["Yes, I like it!", "No, not for me.", "Tell me more"]
|
199 |
+
logging.info("\n--- Sending WhatsApp Quick Reply Message (Test) ---\n")
|
200 |
+
# This will attempt to send a real Quick Reply message if your env vars are valid
|
201 |
+
test_result = send_to_whatsapp(msg_body_preview, destination_number=os.environ.get("WHATSAPP_TO_NUMBER"), quick_reply_options=test_options)
|
202 |
+
print(test_result)
|
203 |
+
|
204 |
+
logging.info("\n--- Sending WhatsApp Standard Text Message (Test) ---\n")
|
205 |
+
# This will attempt to send a real standard text message
|
206 |
+
test_result_standard = send_to_whatsapp("This is a test of a standard text message.", destination_number=os.environ.get("WHATSAPP_TO_NUMBER"), quick_reply_options=None)
|
207 |
+
print(test_result_standard)
|