-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSHIM_tele_bot.PY
441 lines (374 loc) · 20.9 KB
/
SHIM_tele_bot.PY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# Information
"""
Smart-Home-Inventory-Manager / SHIM Telegram Bot
Put together by: SIM x UOL Agile Software Projects @Team 102, Aug 2024
Website Information and Support Link: https://shim-web.vercel.app/
Binded to Telegram User: WZJ99
Telegram: https://t.me/WZJ99
"""
# Commands
"""
start - Starts the bot
help - Provides help for SHIM Tele Bot
add_room - Adds a new room / space
view_rooms - View all rooms / spaces for the user
delete_room - deletes a specific room
update_room - updates the name of a room
add_item_to_room - adds an item to a room
view_room_items - views the items in a room
edit_room_item - edit the items in a room
delete_room_item - deletes a specific item from a room
"""
# Pre-requisites and maintenance info
"""
Make sure to pip install python-telegram-bot and requests
Run the command:
pip install python-telegram-bot requests
Run the script with command:
python SHIM_tele_bot.PY
"""
# imports
import requests
from typing import Final
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
import spacy
# Load the English NLP model
nlp = spacy.load('en_core_web_sm')
TOKEN = '7056035301:AAGfskXNZ6JxZjxOt0yjcDvaegZ3zcUMO9Q'
BOT_USERNAME: Final = '@SHIM_Tele_Bot'
API_URL = 'https://smart-home-inventory-manager-api.vercel.app'
# start and help commands
async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text('Hello! I am SHIM Bot! Select /help for more info!')
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text('Select /add_room to add rooms\nSelect /view_rooms to view your rooms\nSelect /delete_room to delete a room.\nSelect /update_room to update a room name.\nSelect /edit_room_item to edit an item in a room.')
# Add rooms
async def add_room_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
context.user_data['awaiting_room'] = True
await update.message.reply_text('Please enter the room details in the format: room_name')
async def handle_add_room_message(update: Update, context: ContextTypes.DEFAULT_TYPE, room_name=None):
if room_name is None:
room_name = update.message.text.strip()
user_id = str(update.message.from_user.id)
try:
headers = {'Content-Type': 'application/json'}
response = requests.post(f'{API_URL}/room/addRoom', json={'username': user_id, 'roomName': room_name}, headers=headers)
if response.status_code == 200:
await update.message.reply_text('Room added successfully!')
else:
print(f'Failed to add room. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text('Failed to add room. Please check the details and try again.')
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text('An error occurred while adding the room.')
context.user_data['awaiting_room'] = False
# View rooms
async def view_rooms_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_id = str(update.message.from_user.id)
try:
headers = {'Content-Type': 'application/json'}
response = requests.post(f'{API_URL}/room/getAllRooms', json={'username': user_id}, headers=headers)
if response.status_code == 200:
try:
rooms = response.json()
if rooms:
room_list = "\n".join([f"- {room}" for room in rooms])
await update.message.reply_text(f'Your rooms:\n{room_list}')
else:
await update.message.reply_text('You have no rooms added yet.')
except ValueError as json_err:
print(f'JSON decode error: {json_err}')
await update.message.reply_text('Failed to decode the response. Please try again later.')
elif response.status_code == 503:
await update.message.reply_text('No rooms found for this user.')
elif response.status_code == 501:
await update.message.reply_text('User not found, please initiate contact with the bot.')
else:
print(f'Failed to retrieve rooms. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text('Failed to retrieve rooms. Please try again later.')
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text('An error occurred while retrieving the rooms.')
# Update room name
async def update_room_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
context.user_data['awaiting_update_room'] = True
await update.message.reply_text('Please provide the current room name followed by the new room name, e.g., "kitchen1, kitchen2" or "rename kitchen1 to kitchen2".')
async def handle_update_room_message(update: Update, context: ContextTypes.DEFAULT_TYPE, old_name=None, new_name=None):
if old_name is None or new_name is None:
await update.message.reply_text('Please provide both the current room name and the new room name.')
return
user_id = str(update.message.from_user.id)
try:
headers = {'Content-Type': 'application/json'}
response = requests.patch(f'{API_URL}/room/editRoom', json={'username': user_id, 'oldName': old_name, 'newName': new_name}, headers=headers)
if response.status_code == 200:
await update.message.reply_text('Room updated successfully!')
else:
print(f'Failed to update room. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text('Failed to update room. Please check the details and try again.')
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text('An error occurred while updating the room.')
context.user_data['awaiting_update_room'] = False
# Delete rooms
async def delete_room_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
context.user_data['awaiting_room_deletion'] = True
await update.message.reply_text('Please enter the room name to delete.')
async def handle_delete_room_message(update: Update, context: ContextTypes.DEFAULT_TYPE, room_name=None):
if room_name is None:
room_name = update.message.text.strip()
user_id = str(update.message.from_user.id)
try:
headers = {'Content-Type': 'application/json'}
response = requests.delete(f'{API_URL}/room/deleteRoom', json={'username': user_id, 'roomName': room_name}, headers=headers)
if response.status_code == 200:
await update.message.reply_text('Room deleted successfully!')
else:
print(f'Failed to delete room. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text('Failed to delete room. Please check the details and try again.')
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text('An error occurred while deleting the room.')
context.user_data['awaiting_room_deletion'] = False
# Add item to room
async def add_item_to_room_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
context.user_data['awaiting_item'] = True
await update.message.reply_text('Please enter the room name followed by the item name in the format: room_name, item_name.')
async def handle_add_item_to_room_message(update: Update, context: ContextTypes.DEFAULT_TYPE, room_name=None, item_name=None):
if room_name is None or item_name is None:
await update.message.reply_text('Please provide both the room name and the item name.')
return
user_id = str(update.message.from_user.id)
try:
headers = {'Content-Type': 'application/json'}
response = requests.post(f'{API_URL}/room/addItem', json={'username': user_id, 'roomName': room_name, 'itemName': item_name}, headers=headers)
if response.status_code == 200:
await update.message.reply_text('Item added to room successfully!')
else:
print(f'Failed to add item to room. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text('Failed to add item to room. Please check the details and try again.')
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text('An error occurred while adding the item to the room.')
context.user_data['awaiting_item'] = False
# View items in a room
async def view_room_items_command(update, context, room_name: str):
user_id = str(update.message.from_user.id)
api_url = f"{API_URL}/room/getItemsOfRoom"
try:
headers = {'Content-Type': 'application/json'}
response = requests.post(api_url, json={'username': user_id, 'roomName': room_name}, headers=headers)
if response.status_code == 200:
items = response.json()
if isinstance(items, list) and items:
items_list = "\n".join(items)
await update.message.reply_text(f"Items in {room_name}:\n{items_list}")
else:
await update.message.reply_text(f"No items found in {room_name}.")
else:
print(f'Failed to retrieve items. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text("Failed to retrieve items. Please try again.")
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text("An error occurred while retrieving items.")
# Edit item in room
async def edit_room_item_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
context.user_data['awaiting_item_edit'] = True
await update.message.reply_text('Please provide the room name, current item name, and the new item name in the format: room_name, current_item_name, new_item_name.')
async def handle_edit_room_item_message(update: Update, context: ContextTypes.DEFAULT_TYPE, room_name=None, old_item_name=None, new_item_name=None):
if room_name is None or old_item_name is None or new_item_name is None:
await update.message.reply_text('Please provide the room name, current item name, and the new item name.')
return
user_id = str(update.message.from_user.id)
try:
headers = {'Content-Type': 'application/json'}
response = requests.patch(f'{API_URL}/room/editItem', json={'username': user_id, 'roomName': room_name, 'oldName': old_item_name, 'newName': new_item_name}, headers=headers)
# payload for dubugging
payload = {'username': user_id, 'roomName': room_name, 'oldName': old_item_name, 'newName': new_item_name}
print(f'Sending payload: {payload}')
if response.status_code == 200:
await update.message.reply_text('Item updated successfully!')
else:
print(f'Failed to update item. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text('Failed to update item. Please check the details and try again.')
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text('An error occurred while updating the item.')
context.user_data['awaiting_item_edit'] = False
# Delete item from room
async def delete_room_item_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
context.user_data['awaiting_item_deletion'] = True
await update.message.reply_text('Please provide the room name and item name in the format: room_name, item_name.')
async def handle_delete_room_item_message(update: Update, context: ContextTypes.DEFAULT_TYPE, room_name=None, item_name=None):
if room_name is None or item_name is None:
await update.message.reply_text('Please provide both the room name and the item name.')
return
user_id = str(update.message.from_user.id)
try:
headers = {'Content-Type': 'application/json'}
response = requests.delete(f'{API_URL}/room/deleteItem', json={'username': user_id, 'roomName': room_name, 'itemName': item_name}, headers=headers)
if response.status_code == 200:
await update.message.reply_text('Item deleted successfully!')
else:
print(f'Failed to delete item. Status code: {response.status_code}, Response: {response.text}')
await update.message.reply_text('Failed to delete item. Please check the details and try again.')
except Exception as e:
print(f'Exception occurred: {e}')
await update.message.reply_text('An error occurred while deleting the item.')
context.user_data['awaiting_item_deletion'] = False
# Extract intents and entities
def extract_intent_and_entities(text):
doc = nlp(text)
intent = None
room_name = None
item_name = None
new_room_name = None
new_item_name = None
if 'add' in text.lower() and any(word in text.lower() for word in ['room', 'rooms']):
intent = 'add_room'
elif 'add' in text.lower() and 'item' in text.lower():
intent = 'add_item_to_room'
elif any(word in text.lower() for word in ['view', 'see']) and 'items' in text.lower() and any(word in text.lower() for word in ['room', 'rooms']):
intent = 'view_room_items'
elif any(word in text.lower() for word in ['view', 'see']) and any(word in text.lower() for word in ['room', 'rooms']):
intent = 'view_rooms'
elif 'delete' in text.lower() and 'item' in text.lower():
intent = 'delete_room_item'
elif 'delete' in text.lower() and any(word in text.lower() for word in ['room', 'rooms']):
intent = 'delete_room'
elif any(word in text.lower() for word in ['update', 'rename']):
if 'item' in text.lower():
intent = 'edit_room_item'
else:
intent = 'update_room'
for ent in doc.ents:
if ent.label_ in {'ORG', 'GPE', 'FACILITY', 'LOC'}:
room_name = ent.text
elif ent.label_ == 'PRODUCT': # You may adjust the entity label based on your model
item_name = ent.text
tokens = [token.text for token in doc if not token.is_stop and not token.is_punct]
if not room_name or not item_name:
tokens = [token.text for token in doc if not token.is_stop and not token.is_punct]
if 'to' in tokens:
to_index = tokens.index('to')
if not room_name:
room_name_candidates = tokens[to_index + 1:]
room_name = " ".join(room_name_candidates) if room_name_candidates else None
if not item_name:
item_name_candidates = tokens[:to_index]
item_name = " ".join(item_name_candidates) if item_name_candidates else None
if not room_name and len(tokens) > 1:
room_name = tokens[-1] # Last token as the room name
if not item_name and len(tokens) > 1:
item_name = tokens[0] # First token as the item name
if intent == 'add_item_to_room':
if 'to' in text.lower():
parts = text.lower().split('to')
item_name = parts[0].strip().split()[-1]
room_name = parts[1].strip()
if intent == 'edit_room_item':
if 'to' in text.lower():
parts = text.lower().split('to')
remaining_text = parts[1].strip()
if 'in' in remaining_text:
in_parts = remaining_text.split('in')
new_item_name = in_parts[0].strip()
room_name = in_parts[1].strip()
else:
new_item_name = remaining_text.strip()
item_name = parts[0].strip().split()[-1]
elif ',' in text:
parts = text.split(',')
if len(parts) == 3:
room_name = parts[0].strip()
item_name = parts[1].strip()
new_item_name = parts[2].strip()
if intent == 'update_room':
if 'to' in text.lower():
parts = text.lower().split('to')
room_name = parts[0].strip().split()[-1]
new_room_name = parts[1].strip()
elif ',' in text:
parts = text.lower().split(',')
room_name = parts[0].strip()
new_room_name = parts[1].strip()
return intent, room_name, new_room_name, item_name, new_item_name
# Handle messages
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = update.message.text.strip()
if context.user_data.get('awaiting_subspace'):
await handle_add_subspace_message(update, context)
elif context.user_data.get('awaiting_room'):
await handle_add_room_message(update, context)
elif context.user_data.get('awaiting_room_deletion'):
await handle_delete_room_message(update, context)
elif context.user_data.get('awaiting_update_room'):
if ',' in text:
old_name, new_name = map(str.strip, text.split(','))
elif 'to' in text.lower():
parts = text.lower().split('to')
old_name = parts[0].strip().split()[-1]
new_name = parts[1].strip()
else:
await update.message.reply_text('Please use the format: old_room_name, new_room_name or rename old_room_name to new_room_name.')
return
await handle_update_room_message(update, context, old_name=old_name, new_name=new_name)
elif context.user_data.get('awaiting_item'):
if ',' in text:
room_name, item_name = map(str.strip, text.split(','))
await handle_add_item_to_room_message(update, context, room_name=room_name, item_name=item_name)
else:
await update.message.reply_text('Please use the format: room_name, item_name.')
elif context.user_data.get('awaiting_item_edit'):
if ',' in text:
room_name, old_item_name, new_item_name = map(str.strip, text.split(','))
await handle_edit_room_item_message(update, context, room_name=room_name, old_item_name=old_item_name, new_item_name=new_item_name)
else:
await update.message.reply_text('Please use the format: room_name, current_item_name, new_item_name.')
elif context.user_data.get('awaiting_item_deletion'):
if ',' in text:
room_name, item_name = map(str.strip, text.split(','))
await handle_delete_room_item_message(update, context, room_name=room_name, item_name=item_name)
else:
await update.message.reply_text('Please use the format: room_name, item_name.')
else:
intent, room_name, new_room_name, item_name, new_item_name = extract_intent_and_entities(text)
if intent == 'add_room' and room_name:
await handle_add_room_message(update, context, room_name)
elif intent == 'view_rooms':
await view_rooms_command(update, context)
elif intent == 'view_room_items' and room_name:
await view_room_items_command(update, context, room_name)
elif intent == 'delete_room' and room_name:
await handle_delete_room_message(update, context, room_name)
elif intent == 'update_room' and room_name and new_room_name:
await handle_update_room_message(update, context, old_name=room_name, new_name=new_room_name)
elif intent == 'add_item_to_room' and room_name and item_name:
await handle_add_item_to_room_message(update, context, room_name=room_name, item_name=item_name)
elif intent == 'edit_room_item' and room_name and item_name and new_item_name:
await handle_edit_room_item_message(update, context, room_name=room_name, old_item_name=item_name, new_item_name=new_item_name)
elif intent == 'delete_room_item' and room_name and item_name:
await handle_delete_room_item_message(update, context, room_name=room_name, item_name=item_name)
else:
await update.message.reply_text("Sorry, I didn't understand that. Could you please clarify?")
async def error(update: Update, context: ContextTypes.DEFAULT_TYPE):
print(f'Update {update} caused error {context.error}')
# '__main__'
if __name__ == '__main__':
print('Bot Starting...')
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler('start', start_command))
app.add_handler(CommandHandler('help', help_command))
app.add_handler(CommandHandler('add_room', add_room_command))
app.add_handler(CommandHandler('view_rooms', view_rooms_command))
app.add_handler(CommandHandler('delete_room', delete_room_command))
app.add_handler(CommandHandler('update_room', update_room_command))
app.add_handler(CommandHandler('add_item_to_room', add_item_to_room_command))
app.add_handler(CommandHandler('view_room_items', view_room_items_command))
app.add_handler(CommandHandler('edit_room_item', edit_room_item_command))
app.add_handler(CommandHandler('delete_room_item', delete_room_item_command))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
app.add_error_handler(error)
print('Polling...')
app.run_polling(poll_interval=3)