Spaces:
Running
Running
Chandima Prabhath
commited on
Commit
·
1fbbc17
1
Parent(s):
a9740d0
Refactor BotConfig validation to include BOT_JID; improve help text formatting and clarity in command descriptions.
Browse files
app.py
CHANGED
|
@@ -16,24 +16,28 @@ from polLLM import generate_llm
|
|
| 16 |
# --- Configuration and Client Classes ---
|
| 17 |
|
| 18 |
class BotConfig:
|
| 19 |
-
GREEN_API_URL
|
| 20 |
-
GREEN_API_MEDIA_URL
|
| 21 |
-
GREEN_API_TOKEN
|
| 22 |
-
GREEN_API_ID_INSTANCE
|
| 23 |
-
WEBHOOK_AUTH_TOKEN
|
| 24 |
-
BOT_GROUP_CHAT
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
|
|
|
| 28 |
|
| 29 |
@classmethod
|
| 30 |
def validate(cls):
|
| 31 |
-
missing = [
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
| 37 |
if missing:
|
| 38 |
raise ValueError(f"Environment variables not set: {', '.join(missing)}")
|
| 39 |
|
|
@@ -147,14 +151,10 @@ def handle_image_generation(task):
|
|
| 147 |
prompt = task["prompt"]
|
| 148 |
count = task.get("num_images", BotConfig.DEFAULT_IMAGE_COUNT)
|
| 149 |
|
| 150 |
-
# simple loop: one generate_image call per image
|
| 151 |
for i in range(1, count + 1):
|
| 152 |
try:
|
| 153 |
img, path, ret_prompt, url = generate_image(
|
| 154 |
-
prompt,
|
| 155 |
-
message_id,
|
| 156 |
-
message_id,
|
| 157 |
-
BotConfig.IMAGE_DIR
|
| 158 |
)
|
| 159 |
if not img:
|
| 160 |
raise RuntimeError("generate_image returned no image")
|
|
@@ -179,23 +179,22 @@ send_startup_message()
|
|
| 179 |
# --- FastAPI App & Webhook ---
|
| 180 |
|
| 181 |
app = FastAPI()
|
|
|
|
| 182 |
help_text = (
|
| 183 |
"🤖 *Hi there, I'm Eve!* Here are the commands you can use:\n\n"
|
| 184 |
-
"• */help* –
|
| 185 |
-
"• */
|
| 186 |
-
"• */
|
| 187 |
-
"• */
|
| 188 |
-
"• */
|
| 189 |
-
"• */
|
| 190 |
-
"• */
|
| 191 |
-
"• */
|
| 192 |
-
"• */
|
| 193 |
-
"• */meme <text
|
| 194 |
-
"• */poll Q
|
| 195 |
-
"
|
| 196 |
-
"
|
| 197 |
-
"• */gen <prompt>|<count>* – _Generate images (default 4)._ \n\n"
|
| 198 |
-
"Any other text → I'll send you a voice reply!"
|
| 199 |
)
|
| 200 |
|
| 201 |
@app.post("/whatsapp")
|
|
@@ -207,34 +206,49 @@ async def whatsapp_webhook(request: Request):
|
|
| 207 |
if request.headers.get("Authorization") != f"Bearer {BotConfig.WEBHOOK_AUTH_TOKEN}":
|
| 208 |
raise HTTPException(403, "Unauthorized")
|
| 209 |
|
| 210 |
-
data
|
| 211 |
chat_id = data.get("senderData", {}).get("chatId")
|
| 212 |
if chat_id != BotConfig.BOT_GROUP_CHAT or data.get("typeWebhook") != "incomingMessageReceived":
|
| 213 |
return {"success": True}
|
| 214 |
|
| 215 |
-
md
|
| 216 |
-
mid
|
| 217 |
-
|
| 218 |
-
# Extract text + context
|
| 219 |
text_data = md.get("textMessageData") or md.get("extendedTextMessageData")
|
| 220 |
if not text_data:
|
| 221 |
return {"success": True}
|
|
|
|
| 222 |
body = text_data.get("textMessage", text_data.get("text", "")).strip()
|
| 223 |
ctx = text_data.get("contextInfo", {})
|
| 224 |
|
| 225 |
-
#
|
| 226 |
-
if ctx.get("quotedMessageId")
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
return {"success": True}
|
| 229 |
|
| 230 |
-
# Skip
|
| 231 |
if ctx.get("mentionedJidList"):
|
| 232 |
-
logging.debug("Skipping mention")
|
| 233 |
return {"success": True}
|
| 234 |
|
| 235 |
low = body.lower()
|
| 236 |
|
| 237 |
-
# --- COMMANDS ---
|
| 238 |
if low == "/help":
|
| 239 |
client.send_message(mid, chat_id, help_text)
|
| 240 |
return {"success": True}
|
|
|
|
| 16 |
# --- Configuration and Client Classes ---
|
| 17 |
|
| 18 |
class BotConfig:
|
| 19 |
+
GREEN_API_URL = os.getenv("GREEN_API_URL")
|
| 20 |
+
GREEN_API_MEDIA_URL = os.getenv("GREEN_API_MEDIA_URL", "https://api.green-api.com")
|
| 21 |
+
GREEN_API_TOKEN = os.getenv("GREEN_API_TOKEN")
|
| 22 |
+
GREEN_API_ID_INSTANCE = os.getenv("GREEN_API_ID_INSTANCE")
|
| 23 |
+
WEBHOOK_AUTH_TOKEN = os.getenv("WEBHOOK_AUTH_TOKEN")
|
| 24 |
+
BOT_GROUP_CHAT = "[email protected]"
|
| 25 |
+
BOT_JID = os.getenv("BOT_JID") # e.g. "[email protected]"
|
| 26 |
+
IMAGE_DIR = "/tmp/images"
|
| 27 |
+
AUDIO_DIR = "/tmp/audio"
|
| 28 |
+
DEFAULT_IMAGE_COUNT = 4
|
| 29 |
|
| 30 |
@classmethod
|
| 31 |
def validate(cls):
|
| 32 |
+
missing = [
|
| 33 |
+
name for name in (
|
| 34 |
+
"GREEN_API_URL",
|
| 35 |
+
"GREEN_API_TOKEN",
|
| 36 |
+
"GREEN_API_ID_INSTANCE",
|
| 37 |
+
"WEBHOOK_AUTH_TOKEN",
|
| 38 |
+
"BOT_JID",
|
| 39 |
+
) if not getattr(cls, name)
|
| 40 |
+
]
|
| 41 |
if missing:
|
| 42 |
raise ValueError(f"Environment variables not set: {', '.join(missing)}")
|
| 43 |
|
|
|
|
| 151 |
prompt = task["prompt"]
|
| 152 |
count = task.get("num_images", BotConfig.DEFAULT_IMAGE_COUNT)
|
| 153 |
|
|
|
|
| 154 |
for i in range(1, count + 1):
|
| 155 |
try:
|
| 156 |
img, path, ret_prompt, url = generate_image(
|
| 157 |
+
prompt, message_id, message_id, BotConfig.IMAGE_DIR
|
|
|
|
|
|
|
|
|
|
| 158 |
)
|
| 159 |
if not img:
|
| 160 |
raise RuntimeError("generate_image returned no image")
|
|
|
|
| 179 |
# --- FastAPI App & Webhook ---
|
| 180 |
|
| 181 |
app = FastAPI()
|
| 182 |
+
|
| 183 |
help_text = (
|
| 184 |
"🤖 *Hi there, I'm Eve!* Here are the commands you can use:\n\n"
|
| 185 |
+
"• */help* – list commands\n"
|
| 186 |
+
"• */gen <prompt>|<count>* – generate images (default 4)\n"
|
| 187 |
+
"• */summarize <text>*\n"
|
| 188 |
+
"• */translate <lang>|<text>*\n"
|
| 189 |
+
"• */joke*\n"
|
| 190 |
+
"• */weather <location>*\n"
|
| 191 |
+
"• */weatherpoem <location>*\n"
|
| 192 |
+
"• */inspire*\n"
|
| 193 |
+
"• */trivia* / *answer*\n"
|
| 194 |
+
"• */meme <text>*\n"
|
| 195 |
+
"• */poll <Q>|<opt1>|… / /results / /endpoll*\n\n"
|
| 196 |
+
"Reply to one of my messages → I'll LLM‑answer it.\n"
|
| 197 |
+
"Any other text → voice reply."
|
|
|
|
|
|
|
| 198 |
)
|
| 199 |
|
| 200 |
@app.post("/whatsapp")
|
|
|
|
| 206 |
if request.headers.get("Authorization") != f"Bearer {BotConfig.WEBHOOK_AUTH_TOKEN}":
|
| 207 |
raise HTTPException(403, "Unauthorized")
|
| 208 |
|
| 209 |
+
data = await request.json()
|
| 210 |
chat_id = data.get("senderData", {}).get("chatId")
|
| 211 |
if chat_id != BotConfig.BOT_GROUP_CHAT or data.get("typeWebhook") != "incomingMessageReceived":
|
| 212 |
return {"success": True}
|
| 213 |
|
| 214 |
+
md = data.get("messageData", {})
|
| 215 |
+
mid = data["idMessage"]
|
|
|
|
|
|
|
| 216 |
text_data = md.get("textMessageData") or md.get("extendedTextMessageData")
|
| 217 |
if not text_data:
|
| 218 |
return {"success": True}
|
| 219 |
+
|
| 220 |
body = text_data.get("textMessage", text_data.get("text", "")).strip()
|
| 221 |
ctx = text_data.get("contextInfo", {})
|
| 222 |
|
| 223 |
+
# --- Quoted‑reply handling ---
|
| 224 |
+
if ctx.get("quotedMessageId"):
|
| 225 |
+
# only if the quoted message was sent by our bot
|
| 226 |
+
quoted_sender = ctx.get("participant") or ctx.get("quotedMessageSender")
|
| 227 |
+
if quoted_sender == BotConfig.BOT_JID:
|
| 228 |
+
# extract quoted text
|
| 229 |
+
qm = ctx.get("quotedMessage", {})
|
| 230 |
+
if "textMessageData" in qm:
|
| 231 |
+
quoted_text = qm["textMessageData"].get("textMessage", "")
|
| 232 |
+
else:
|
| 233 |
+
quoted_text = qm.get("extendedTextMessageData", {}).get("text", "")
|
| 234 |
+
# build and send LLM reply
|
| 235 |
+
prompt = (
|
| 236 |
+
f"You asked: {quoted_text}\n"
|
| 237 |
+
f"User replied: {body}\n"
|
| 238 |
+
"Provide a helpful, concise follow‑up."
|
| 239 |
+
)
|
| 240 |
+
reply = generate_llm(prompt)
|
| 241 |
+
client.send_message(mid, chat_id, reply)
|
| 242 |
+
# in either case, do not process further
|
| 243 |
return {"success": True}
|
| 244 |
|
| 245 |
+
# --- Skip @‑mentions of others ---
|
| 246 |
if ctx.get("mentionedJidList"):
|
|
|
|
| 247 |
return {"success": True}
|
| 248 |
|
| 249 |
low = body.lower()
|
| 250 |
|
| 251 |
+
# --- COMMANDS (unchanged) ---
|
| 252 |
if low == "/help":
|
| 253 |
client.send_message(mid, chat_id, help_text)
|
| 254 |
return {"success": True}
|