22"""
33WhatsApp Message Scheduler - Send scheduled messages via WhatsApp Web
44"""
5+
56import argparse
67import asyncio
78import json
@@ -42,18 +43,16 @@ async def parse_messages():
4243 """Parse messages.txt and extract scheduling info"""
4344 messages_file = Path ('messages.txt' )
4445 if not messages_file .exists ():
45- print (" ❌ messages.txt not found!" )
46+ print (' ❌ messages.txt not found!' )
4647 return []
47-
48- with open (messages_file , 'r' ) as f :
49- content = f .read ()
50-
51- llm = ChatGoogle (
52- model = 'gemini-2.0-flash-exp' ,
53- temperature = 0.1 ,
54- api_key = GOOGLE_API_KEY
55- )
56-
48+
49+ import aiofiles
50+
51+ async with aiofiles .open (messages_file ) as f :
52+ content = await f .read ()
53+
54+ llm = ChatGoogle (model = 'gemini-2.0-flash-exp' , temperature = 0.1 , api_key = GOOGLE_API_KEY )
55+
5756 now = datetime .now ()
5857 prompt = f"""
5958 Parse these WhatsApp message instructions and extract:
@@ -93,11 +92,12 @@ async def parse_messages():
9392 - "tomorrow" means { (now + timedelta (days = 1 )).strftime ('%Y-%m-%d' )}
9493 - "next tuesday" or similar means the next occurrence of that day
9594 """
96-
95+
9796 from browser_use .llm .messages import UserMessage
97+
9898 response = await llm .ainvoke ([UserMessage (content = prompt )])
9999 response_text = response .completion if hasattr (response , 'completion' ) else str (response )
100-
100+
101101 # Extract JSON
102102 json_match = re .search (r'\[.*?\]' , response_text , re .DOTALL )
103103 if json_match :
@@ -108,21 +108,17 @@ async def parse_messages():
108108 msg ['message' ] = re .sub (r'\n+' , ' • ' , msg ['message' ])
109109 msg ['message' ] = re .sub (r'\s+' , ' ' , msg ['message' ]).strip ()
110110 return messages
111- except :
111+ except json . JSONDecodeError :
112112 pass
113113 return []
114114
115115
116116async def send_message (contact , message ):
117117 """Send a WhatsApp message"""
118- print (f"\n 📱 Sending to { contact } : { message } " )
119-
120- llm = ChatGoogle (
121- model = 'gemini-2.0-flash-exp' ,
122- temperature = 0.3 ,
123- api_key = GOOGLE_API_KEY
124- )
125-
118+ print (f'\n 📱 Sending to { contact } : { message } ' )
119+
120+ llm = ChatGoogle (model = 'gemini-2.0-flash-exp' , temperature = 0.3 , api_key = GOOGLE_API_KEY )
121+
126122 task = f"""
127123 Send WhatsApp message:
128124 1. Go to https://web.whatsapp.com
@@ -132,104 +128,104 @@ async def send_message(contact, message):
132128 5. Press Enter to send
133129 6. Confirm sent
134130 """
135-
131+
136132 browser = BrowserSession (
137133 headless = not args .debug , # headless=False only when debug=True
138134 user_data_dir = str (USER_DATA_DIR ),
139- storage_state = str (STORAGE_STATE_FILE ) if STORAGE_STATE_FILE .exists () else None
135+ storage_state = str (STORAGE_STATE_FILE ) if STORAGE_STATE_FILE .exists () else None ,
140136 )
141-
137+
142138 agent = Agent (task = task , llm = llm , browser_session = browser )
143139 await agent .run ()
144- print (f" ✅ Sent to { contact } " )
140+ print (f' ✅ Sent to { contact } ' )
145141
146142
147143async def main ():
148144 if not GOOGLE_API_KEY :
149- print (" ❌ Set GOOGLE_API_KEY or GEMINI_API_KEY environment variable" )
145+ print (' ❌ Set GOOGLE_API_KEY or GEMINI_API_KEY environment variable' )
150146 return
151-
152- print (" WhatsApp Scheduler" )
153- print (f" Profile: { USER_DATA_DIR } " )
147+
148+ print (' WhatsApp Scheduler' )
149+ print (f' Profile: { USER_DATA_DIR } ' )
154150 print ()
155-
151+
156152 # Parse messages
157- print (" Parsing messages.txt..." )
153+ print (' Parsing messages.txt...' )
158154 messages = await parse_messages ()
159-
155+
160156 if not messages :
161- print (" No messages found" )
157+ print (' No messages found' )
162158 return
163-
164- print (f" \n Found { len (messages )} messages:" )
159+
160+ print (f' \n Found { len (messages )} messages:' )
165161 for msg in messages :
166- print (f" • { msg [' datetime' ]} : { msg [' message' ][:30 ]} ... to { msg [' contact' ] } " )
167-
162+ print (f' • { msg [" datetime" ]} : { msg [" message" ][:30 ]} ... to { msg [" contact" ] } ' )
163+
168164 now = datetime .now ()
169165 immediate = []
170166 future = []
171-
167+
172168 for msg in messages :
173169 msg_time = datetime .strptime (msg ['datetime' ], '%Y-%m-%d %H:%M' )
174170 if msg_time <= now :
175171 immediate .append (msg )
176172 else :
177173 future .append (msg )
178-
174+
179175 if args .test :
180- print (f" \n === TEST MODE - Preview ===" )
176+ print (' \n === TEST MODE - Preview ===' )
181177 if immediate :
182- print (f" \n Would send { len (immediate )} past-due messages NOW:" )
178+ print (f' \n Would send { len (immediate )} past-due messages NOW:' )
183179 for msg in immediate :
184- print (f" 📱 To { msg [' contact' ]} : { msg [' message' ] } " )
180+ print (f' 📱 To { msg [" contact" ]} : { msg [" message" ] } ' )
185181 if future :
186- print (f" \n Would monitor { len (future )} future messages:" )
182+ print (f' \n Would monitor { len (future )} future messages:' )
187183 for msg in future :
188- print (f" ⏰ { msg [' datetime' ]} : To { msg [' contact' ]} : { msg [' message' ] } " )
189- print (" \n Test mode complete. No messages sent." )
184+ print (f' ⏰ { msg [" datetime" ]} : To { msg [" contact" ]} : { msg [" message" ] } ' )
185+ print (' \n Test mode complete. No messages sent.' )
190186 return
191-
187+
192188 if immediate :
193- print (f" \n Sending { len (immediate )} past-due messages NOW..." )
189+ print (f' \n Sending { len (immediate )} past-due messages NOW...' )
194190 for msg in immediate :
195191 await send_message (msg ['contact' ], msg ['message' ])
196-
192+
197193 if future :
198- print (f" \n ⏰ Monitoring { len (future )} future messages..." )
199- print (" Press Ctrl+C to stop.\n " )
200-
194+ print (f' \n ⏰ Monitoring { len (future )} future messages...' )
195+ print (' Press Ctrl+C to stop.\n ' )
196+
201197 last_status = None
202-
198+
203199 while future :
204200 now = datetime .now ()
205201 due = []
206202 remaining = []
207-
203+
208204 for msg in future :
209205 msg_time = datetime .strptime (msg ['datetime' ], '%Y-%m-%d %H:%M' )
210206 if msg_time <= now :
211207 due .append (msg )
212208 else :
213209 remaining .append (msg )
214-
210+
215211 for msg in due :
216- print (f" \n ⏰ Time reached for { msg [' contact' ] } " )
212+ print (f' \n ⏰ Time reached for { msg [" contact" ] } ' )
217213 await send_message (msg ['contact' ], msg ['message' ])
218-
214+
219215 future = remaining
220-
216+
221217 if future :
222218 next_msg = min (future , key = lambda x : datetime .strptime (x ['datetime' ], '%Y-%m-%d %H:%M' ))
223- current_status = f" Next: { next_msg [' datetime' ]} to { next_msg [' contact' ] } "
224-
219+ current_status = f' Next: { next_msg [" datetime" ]} to { next_msg [" contact" ] } '
220+
225221 if current_status != last_status :
226222 print (current_status )
227223 last_status = current_status
228-
224+
229225 await asyncio .sleep (30 ) # Check every 30 seconds
230-
231- print (" \n ✅ All messages processed!" )
226+
227+ print (' \n ✅ All messages processed!' )
232228
233229
234230if __name__ == '__main__' :
235- asyncio .run (main ())
231+ asyncio .run (main ())
0 commit comments