Rubka 4.3.4__tar.gz → 4.4.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {rubka-4.3.4 → rubka-4.4.6}/PKG-INFO +1 -1
  2. {rubka-4.3.4 → rubka-4.4.6}/Rubka.egg-info/PKG-INFO +1 -1
  3. {rubka-4.3.4 → rubka-4.4.6}/Rubka.egg-info/SOURCES.txt +1 -0
  4. {rubka-4.3.4 → rubka-4.4.6}/rubka/__init__.py +2 -3
  5. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/network/socket.py +9 -1
  6. {rubka-4.3.4 → rubka-4.4.6}/rubka/api.py +246 -4
  7. {rubka-4.3.4 → rubka-4.4.6}/rubka/context.py +114 -0
  8. rubka-4.4.6/rubka/rubino.py +1100 -0
  9. {rubka-4.3.4 → rubka-4.4.6}/setup.py +1 -1
  10. {rubka-4.3.4 → rubka-4.4.6}/README.md +0 -0
  11. {rubka-4.3.4 → rubka-4.4.6}/Rubka.egg-info/dependency_links.txt +0 -0
  12. {rubka-4.3.4 → rubka-4.4.6}/Rubka.egg-info/requires.txt +0 -0
  13. {rubka-4.3.4 → rubka-4.4.6}/Rubka.egg-info/top_level.txt +0 -0
  14. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/__init__.py +0 -0
  15. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/client/__init__.py +0 -0
  16. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/client/client.py +0 -0
  17. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/crypto/__init__.py +0 -0
  18. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/crypto/crypto.py +0 -0
  19. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/enums.py +0 -0
  20. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/exceptions.py +0 -0
  21. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/methods/__init__.py +0 -0
  22. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/methods/methods.py +0 -0
  23. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/network/__init__.py +0 -0
  24. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/network/helper.py +0 -0
  25. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/network/network.py +0 -0
  26. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/sessions/__init__.py +0 -0
  27. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/sessions/sessions.py +0 -0
  28. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/types/__init__.py +0 -0
  29. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/types/socket/__init__.py +0 -0
  30. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/types/socket/message.py +0 -0
  31. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/utils/__init__.py +0 -0
  32. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/utils/configs.py +0 -0
  33. {rubka-4.3.4 → rubka-4.4.6}/rubka/adaptorrubka/utils/utils.py +0 -0
  34. {rubka-4.3.4 → rubka-4.4.6}/rubka/button.py +0 -0
  35. {rubka-4.3.4 → rubka-4.4.6}/rubka/config.py +0 -0
  36. {rubka-4.3.4 → rubka-4.4.6}/rubka/decorators.py +0 -0
  37. {rubka-4.3.4 → rubka-4.4.6}/rubka/exceptions.py +0 -0
  38. {rubka-4.3.4 → rubka-4.4.6}/rubka/jobs.py +0 -0
  39. {rubka-4.3.4 → rubka-4.4.6}/rubka/keyboards.py +0 -0
  40. {rubka-4.3.4 → rubka-4.4.6}/rubka/keypad.py +0 -0
  41. {rubka-4.3.4 → rubka-4.4.6}/rubka/logger.py +0 -0
  42. {rubka-4.3.4 → rubka-4.4.6}/rubka/utils.py +0 -0
  43. {rubka-4.3.4 → rubka-4.4.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 4.3.4
3
+ Version: 4.4.6
4
4
  Summary: A Python library for interacting with Rubika Bot API.
5
5
  Home-page: https://github.com/Mahdy-Ahmadi/Rubka
6
6
  Download-URL: https://github.com/Mahdy-Ahmadi/Rubka/archive/refs/tags/v0.1.0.tar.gz
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Rubka
3
- Version: 4.3.4
3
+ Version: 4.4.6
4
4
  Summary: A Python library for interacting with Rubika Bot API.
5
5
  Home-page: https://github.com/Mahdy-Ahmadi/Rubka
6
6
  Download-URL: https://github.com/Mahdy-Ahmadi/Rubka/archive/refs/tags/v0.1.0.tar.gz
@@ -16,6 +16,7 @@ rubka/jobs.py
16
16
  rubka/keyboards.py
17
17
  rubka/keypad.py
18
18
  rubka/logger.py
19
+ rubka/rubino.py
19
20
  rubka/utils.py
20
21
  rubka/adaptorrubka/__init__.py
21
22
  rubka/adaptorrubka/enums.py
@@ -1,11 +1,10 @@
1
1
  from .api import Robot
2
- from .decorators import on_message
2
+ from .rubino import Bot
3
3
  from .exceptions import APIRequestError
4
- from .keyboards import create_simple_keyboard
5
4
 
6
5
  __all__ = [
7
6
  "Robot",
8
7
  "on_message",
9
8
  "APIRequestError",
10
9
  "create_simple_keyboard",
11
- ]
10
+ ]
@@ -1,4 +1,12 @@
1
- from websocket import WebSocketApp
1
+
2
+ try:
3
+ from websocket import WebSocketApp
4
+ except:
5
+ import os
6
+ try:
7
+ os.system("pip install websocket-client")
8
+ except:
9
+ os.system("python -m pip install websocket-client")
2
10
  from .helper import Helper
3
11
  from json import dumps, loads
4
12
  from threading import Thread
@@ -5,6 +5,10 @@ from .adaptorrubka import Client as Client_get
5
5
  from .logger import logger
6
6
  from typing import Callable
7
7
  from .context import Message,InlineMessage
8
+ from typing import Optional, Union, Literal, Dict, Any
9
+ from pathlib import Path
10
+ import requests
11
+
8
12
  API_URL = "https://botapi.rubika.ir/v3"
9
13
  import sys
10
14
  import subprocess
@@ -59,14 +63,43 @@ check_rubka_version()
59
63
  def show_last_six_words(text):
60
64
  text = text.strip()
61
65
  return text[-6:]
66
+ import requests
67
+ from pathlib import Path
68
+ from typing import Union, Optional, Dict, Any, Literal
69
+ import tempfile
70
+ import os
62
71
  class Robot:
63
72
  """
64
73
  Main class to interact with Rubika Bot API.
65
74
  Initialized with bot token.
66
75
  """
67
76
 
68
- def __init__(self, token: str):
77
+ def __init__(self, token: str,session_name : str = None,auth : str = None , Key : str = None,platform : str ="web",timeout : int =10):
78
+ """
79
+ راه‌اندازی اولیه ربات روبیکا و پیکربندی پارامترهای پایه.
80
+
81
+ Parameters:
82
+ token (str): توکن اصلی ربات برای احراز هویت با Rubika Bot API. این مقدار الزامی است.
83
+ session_name (str, optional): نام نشست دلخواه برای شناسایی یا جداسازی کلاینت‌ها. پیش‌فرض None.
84
+ auth (str, optional): مقدار احراز هویت اضافی برای اتصال به کلاینت سفارشی. پیش‌فرض None.
85
+ Key (str, optional): کلید اضافی برای رمزنگاری یا تأیید. در صورت نیاز استفاده می‌شود. پیش‌فرض None.
86
+ platform (str, optional): پلتفرم اجرایی مورد نظر (مثل "web" یا "android"). پیش‌فرض "web".
87
+ timeout (int, optional): مدت‌زمان تایم‌اوت برای درخواست‌های HTTP بر حسب ثانیه. پیش‌فرض 10 ثانیه.
88
+
89
+ توضیحات:
90
+ - این تابع یک شیء Session از requests می‌سازد برای استفاده در تمام درخواست‌ها.
91
+ - هندلرهای مختلف مانند پیام، دکمه، کوئری اینلاین و ... در این مرحله مقداردهی اولیه می‌شوند.
92
+ - لیست `self._callback_handlers` برای مدیریت چندین callback مختلف الزامی است.
93
+
94
+ مثال:
95
+ >>> bot = Robot(token="BOT_TOKEN", platform="android", timeout=15)
96
+ """
69
97
  self.token = token
98
+ self.timeout = timeout
99
+ self.auth = auth
100
+ self.session_name = session_name
101
+ self.Key = Key
102
+ self.platform = platform
70
103
  self._offset_id = None
71
104
  self.session = requests.Session()
72
105
  self.sessions: Dict[str, Dict[str, Any]] = {}
@@ -82,7 +115,7 @@ class Robot:
82
115
  def _post(self, method: str, data: Dict[str, Any]) -> Dict[str, Any]:
83
116
  url = f"{API_URL}/{self.token}/{method}"
84
117
  try:
85
- response = self.session.post(url, json=data, timeout=10)
118
+ response = self.session.post(url, json=data, timeout=self.timeout)
86
119
  response.raise_for_status()
87
120
  try:
88
121
  json_resp = response.json()
@@ -236,9 +269,13 @@ class Robot:
236
269
  return self._post("sendMessage", payload)
237
270
 
238
271
  def _get_client(self):
239
- return Client_get(show_last_six_words(self.token))
272
+ if self.session_name:
273
+ return Client_get(self.session_name,self.auth,self.Key,self.platform)
274
+ else :
275
+ return Client_get(show_last_six_words(self.token),self.auth,self.Key,self.platform)
276
+ from typing import Union
240
277
 
241
- def check_join(self, channel_guid: str, chat_id: str = None) -> bool | list[str]:
278
+ def check_join(self, channel_guid: str, chat_id: str = None) -> Union[bool, list[str]]:
242
279
  client = self._get_client()
243
280
 
244
281
  if chat_id:
@@ -330,6 +367,211 @@ class Robot:
330
367
  def get_chat(self, chat_id: str) -> Dict[str, Any]:
331
368
  """Get chat info."""
332
369
  return self._post("getChat", {"chat_id": chat_id})
370
+ def upload_media_file(self, upload_url: str, name: str, path: Union[str, Path]) -> str:
371
+ # بررسی اینکه ورودی URL است یا مسیر محلی
372
+ is_temp_file = False
373
+ if isinstance(path, str) and path.startswith("http"):
374
+ response = requests.get(path)
375
+ if response.status_code != 200:
376
+ raise Exception(f"Failed to download file from URL ({response.status_code})")
377
+ temp_file = tempfile.NamedTemporaryFile(delete=False)
378
+ temp_file.write(response.content)
379
+ temp_file.close()
380
+ path = temp_file.name
381
+ is_temp_file = True
382
+
383
+ with open(path, 'rb') as file:
384
+ files = {
385
+ 'file': (name, file, 'application/octet-stream')
386
+ }
387
+ response = requests.post(upload_url, files=files)
388
+ if response.status_code != 200:
389
+ raise Exception(f"Upload failed ({response.status_code}): {response.text}")
390
+ data = response.json()
391
+
392
+ if is_temp_file:
393
+ os.unlink(path) # حذف فایل موقت
394
+
395
+ return data.get('data', {}).get('file_id')
396
+
397
+ def get_upload_url(self, media_type: Literal['File', 'Image', 'Voice', 'Music', 'Gif']) -> str:
398
+ allowed = ['File', 'Image', 'Voice', 'Music', 'Gif']
399
+ if media_type not in allowed:
400
+ raise ValueError(f"Invalid media type. Must be one of {allowed}")
401
+ result = self._post("requestSendFile", {"type": media_type})
402
+ return result.get("data", {}).get("upload_url")
403
+ def _send_uploaded_file(
404
+ self,
405
+ chat_id: str,
406
+ file_id: str,
407
+ text: Optional[str] = None,
408
+ chat_keypad: Optional[Dict[str, Any]] = None,
409
+ inline_keypad: Optional[Dict[str, Any]] = None,
410
+ disable_notification: bool = False,
411
+ reply_to_message_id: Optional[str] = None,
412
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None"
413
+ ) -> Dict[str, Any]:
414
+ payload = {
415
+ "chat_id": chat_id,
416
+ "file_id": file_id,
417
+ "text": text,
418
+ "disable_notification": disable_notification,
419
+ "chat_keypad_type": chat_keypad_type,
420
+ }
421
+ if chat_keypad:
422
+ payload["chat_keypad"] = chat_keypad
423
+ if inline_keypad:
424
+ payload["inline_keypad"] = inline_keypad
425
+ if reply_to_message_id:
426
+ payload["reply_to_message_id"] = str(reply_to_message_id)
427
+
428
+ return self._post("sendFile", payload)
429
+
430
+ def send_document(
431
+ self,
432
+ chat_id: str,
433
+ path: Optional[Union[str, Path]] = None,
434
+ file_id: Optional[str] = None,
435
+ text: Optional[str] = None,
436
+ file_name: Optional[str] = None,
437
+ inline_keypad: Optional[Dict[str, Any]] = None,
438
+ chat_keypad: Optional[Dict[str, Any]] = None,
439
+ reply_to_message_id: Optional[str] = None,
440
+ disable_notification: bool = False,
441
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
442
+ ) -> Dict[str, Any]:
443
+ if path:
444
+ file_name = file_name or Path(path).name
445
+ upload_url = self.get_upload_url("File")
446
+ file_id = self.upload_media_file(upload_url, file_name, path)
447
+ if not file_id:
448
+ raise ValueError("Either path or file_id must be provided.")
449
+ return self._send_uploaded_file(
450
+ chat_id=chat_id,
451
+ file_id=file_id,
452
+ text=text,
453
+ inline_keypad=inline_keypad,
454
+ chat_keypad=chat_keypad,
455
+ reply_to_message_id=reply_to_message_id,
456
+ disable_notification=disable_notification,
457
+ chat_keypad_type=chat_keypad_type
458
+ )
459
+ def send_music(
460
+ self,
461
+ chat_id: str,
462
+ path: Optional[Union[str, Path]] = None,
463
+ file_id: Optional[str] = None,
464
+ text: Optional[str] = None,
465
+ file_name: Optional[str] = None,
466
+ inline_keypad: Optional[Dict[str, Any]] = None,
467
+ chat_keypad: Optional[Dict[str, Any]] = None,
468
+ reply_to_message_id: Optional[str] = None,
469
+ disable_notification: bool = False,
470
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
471
+ ) -> Dict[str, Any]:
472
+ if path:
473
+ file_name = file_name or Path(path).name
474
+ upload_url = self.get_upload_url("Music")
475
+ file_id = self.upload_media_file(upload_url, file_name, path)
476
+ if not file_id:
477
+ raise ValueError("Either path or file_id must be provided.")
478
+ return self._send_uploaded_file(
479
+ chat_id=chat_id,
480
+ file_id=file_id,
481
+ text=text,
482
+ inline_keypad=inline_keypad,
483
+ chat_keypad=chat_keypad,
484
+ reply_to_message_id=reply_to_message_id,
485
+ disable_notification=disable_notification,
486
+ chat_keypad_type=chat_keypad_type
487
+ )
488
+ def send_voice(
489
+ self,
490
+ chat_id: str,
491
+ path: Optional[Union[str, Path]] = None,
492
+ file_id: Optional[str] = None,
493
+ text: Optional[str] = None,
494
+ file_name: Optional[str] = None,
495
+ inline_keypad: Optional[Dict[str, Any]] = None,
496
+ chat_keypad: Optional[Dict[str, Any]] = None,
497
+ reply_to_message_id: Optional[str] = None,
498
+ disable_notification: bool = False,
499
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
500
+ ) -> Dict[str, Any]:
501
+ if path:
502
+ file_name = file_name or Path(path).name
503
+ upload_url = self.get_upload_url("Voice")
504
+ file_id = self.upload_media_file(upload_url, file_name, path)
505
+ if not file_id:
506
+ raise ValueError("Either path or file_id must be provided.")
507
+ return self._send_uploaded_file(
508
+ chat_id=chat_id,
509
+ file_id=file_id,
510
+ text=text,
511
+ inline_keypad=inline_keypad,
512
+ chat_keypad=chat_keypad,
513
+ reply_to_message_id=reply_to_message_id,
514
+ disable_notification=disable_notification,
515
+ chat_keypad_type=chat_keypad_type
516
+ )
517
+ def send_image(
518
+ self,
519
+ chat_id: str,
520
+ path: Optional[Union[str, Path]] = None,
521
+ file_id: Optional[str] = None,
522
+ text: Optional[str] = None,
523
+ file_name: Optional[str] = None,
524
+ inline_keypad: Optional[Dict[str, Any]] = None,
525
+ chat_keypad: Optional[Dict[str, Any]] = None,
526
+ reply_to_message_id: Optional[str] = None,
527
+ disable_notification: bool = False,
528
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
529
+ ) -> Dict[str, Any]:
530
+ if path:
531
+ file_name = file_name or Path(path).name
532
+ upload_url = self.get_upload_url("Image")
533
+ file_id = self.upload_media_file(upload_url, file_name, path)
534
+ if not file_id:
535
+ raise ValueError("Either path or file_id must be provided.")
536
+ return self._send_uploaded_file(
537
+ chat_id=chat_id,
538
+ file_id=file_id,
539
+ text=text,
540
+ inline_keypad=inline_keypad,
541
+ chat_keypad=chat_keypad,
542
+ reply_to_message_id=reply_to_message_id,
543
+ disable_notification=disable_notification,
544
+ chat_keypad_type=chat_keypad_type
545
+ )
546
+ def send_gif(
547
+ self,
548
+ chat_id: str,
549
+ path: Optional[Union[str, Path]] = None,
550
+ file_id: Optional[str] = None,
551
+ text: Optional[str] = None,
552
+ file_name: Optional[str] = None,
553
+ inline_keypad: Optional[Dict[str, Any]] = None,
554
+ chat_keypad: Optional[Dict[str, Any]] = None,
555
+ reply_to_message_id: Optional[str] = None,
556
+ disable_notification: bool = False,
557
+ chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "New"
558
+ ) -> Dict[str, Any]:
559
+ if path:
560
+ file_name = file_name or Path(path).name
561
+ upload_url = self.get_upload_url("Gif")
562
+ file_id = self.upload_media_file(upload_url, file_name, path)
563
+ if not file_id:
564
+ raise ValueError("Either path or file_id must be provided.")
565
+ return self._send_uploaded_file(
566
+ chat_id=chat_id,
567
+ file_id=file_id,
568
+ text=text,
569
+ inline_keypad=inline_keypad,
570
+ chat_keypad=chat_keypad,
571
+ reply_to_message_id=reply_to_message_id,
572
+ disable_notification=disable_notification,
573
+ chat_keypad_type=chat_keypad_type
574
+ )
333
575
 
334
576
  def get_updates(
335
577
  self,
@@ -184,6 +184,9 @@ class Bot:
184
184
  self.username: str = data.get("username")
185
185
  self.start_message: str = data.get("start_message")
186
186
  self.share_url: str = data.get("share_url")
187
+ from typing import Union
188
+ from pathlib import Path
189
+
187
190
  class Message:
188
191
  def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
189
192
  self.bot = bot
@@ -227,6 +230,117 @@ class Message:
227
230
  "reply_to_message_id": self.message_id,
228
231
  **kwargs
229
232
  })
233
+
234
+
235
+ def reply_document(
236
+ self,
237
+ path: Optional[Union[str, Path]] = None,
238
+ file_id: Optional[str] = None,
239
+ text: Optional[str] = None,
240
+ chat_keypad: Optional[Dict[str, Any]] = None,
241
+ inline_keypad: Optional[Dict[str, Any]] = None,
242
+ chat_keypad_type: Optional[str] = "None",
243
+ disable_notification: bool = False
244
+ ):
245
+ return self.bot.send_document(
246
+ chat_id=self.chat_id,
247
+ path=path,
248
+ file_id=file_id,
249
+ text=text,
250
+ chat_keypad=chat_keypad,
251
+ inline_keypad=inline_keypad,
252
+ chat_keypad_type=chat_keypad_type,
253
+ disable_notification=disable_notification,
254
+ reply_to_message_id=self.message_id
255
+ )
256
+
257
+ def reply_image(
258
+ self,
259
+ path: Optional[Union[str, Path]] = None,
260
+ file_id: Optional[str] = None,
261
+ text: Optional[str] = None,
262
+ chat_keypad: Optional[Dict[str, Any]] = None,
263
+ inline_keypad: Optional[Dict[str, Any]] = None,
264
+ chat_keypad_type: Optional[str] = "None",
265
+ disable_notification: bool = False
266
+ ):
267
+ return self.bot.send_image(
268
+ chat_id=self.chat_id,
269
+ path=path,
270
+ file_id=file_id,
271
+ text=text,
272
+ chat_keypad=chat_keypad,
273
+ inline_keypad=inline_keypad,
274
+ chat_keypad_type=chat_keypad_type,
275
+ disable_notification=disable_notification,
276
+ reply_to_message_id=self.message_id
277
+ )
278
+
279
+ def reply_music(
280
+ self,
281
+ path: Optional[Union[str, Path]] = None,
282
+ file_id: Optional[str] = None,
283
+ text: Optional[str] = None,
284
+ chat_keypad: Optional[Dict[str, Any]] = None,
285
+ inline_keypad: Optional[Dict[str, Any]] = None,
286
+ chat_keypad_type: Optional[str] = "None",
287
+ disable_notification: bool = False
288
+ ):
289
+ return self.bot.send_music(
290
+ chat_id=self.chat_id,
291
+ path=path,
292
+ file_id=file_id,
293
+ text=text,
294
+ chat_keypad=chat_keypad,
295
+ inline_keypad=inline_keypad,
296
+ chat_keypad_type=chat_keypad_type,
297
+ disable_notification=disable_notification,
298
+ reply_to_message_id=self.message_id
299
+ )
300
+
301
+ def reply_voice(
302
+ self,
303
+ path: Optional[Union[str, Path]] = None,
304
+ file_id: Optional[str] = None,
305
+ text: Optional[str] = None,
306
+ chat_keypad: Optional[Dict[str, Any]] = None,
307
+ inline_keypad: Optional[Dict[str, Any]] = None,
308
+ chat_keypad_type: Optional[str] = "None",
309
+ disable_notification: bool = False
310
+ ):
311
+ return self.bot.send_voice(
312
+ chat_id=self.chat_id,
313
+ path=path,
314
+ file_id=file_id,
315
+ text=text,
316
+ chat_keypad=chat_keypad,
317
+ inline_keypad=inline_keypad,
318
+ chat_keypad_type=chat_keypad_type,
319
+ disable_notification=disable_notification,
320
+ reply_to_message_id=self.message_id
321
+ )
322
+
323
+ def reply_gif(
324
+ self,
325
+ path: Optional[Union[str, Path]] = None,
326
+ file_id: Optional[str] = None,
327
+ text: Optional[str] = None,
328
+ chat_keypad: Optional[Dict[str, Any]] = None,
329
+ inline_keypad: Optional[Dict[str, Any]] = None,
330
+ chat_keypad_type: Optional[str] = "None",
331
+ disable_notification: bool = False
332
+ ):
333
+ return self.bot.send_gif(
334
+ chat_id=self.chat_id,
335
+ path=path,
336
+ file_id=file_id,
337
+ text=text,
338
+ chat_keypad=chat_keypad,
339
+ inline_keypad=inline_keypad,
340
+ chat_keypad_type=chat_keypad_type,
341
+ disable_notification=disable_notification,
342
+ reply_to_message_id=self.message_id
343
+ )
230
344
 
231
345
  def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
232
346
  return self.bot.send_location(