Queer European MD passionate about IT

a_simple_bot.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. """This example script shows how to develop a simple bot with davtelepot.
  2. 1. Install davtelepot
  3. ```bash
  4. # Create a new python virtual environment
  5. pip -m venv env
  6. # Activate the virtual environment
  7. source env/bin/activate
  8. # Install davtelepot library in this environment
  9. pip install davtelepot
  10. # Run the current script within this environment
  11. python a_simple_bot.py
  12. ```
  13. 2. To run your bot, you will need a bot token. You can get up to 20 bot tokens
  14. from https://t.me/botfather
  15. 3. This script will look for your bot token in a gitignored `secrets.py` file
  16. in the same folder as the current script. If no `secrets` module is found,
  17. user will be prompted at runtime for a token, and the entry will be stored
  18. in `secrets.py` for later use.
  19. 4. Standard library, third party and project modules will be imported, and
  20. `logging` preferences set. You are free to edit these settings, e.g. adding
  21. one or more file and error loggers or setting different levels.
  22. 5. `simple_bot` is an instance of `davtelepot.bot.Bot` class.
  23. To instantiate a bot you need to provide at least a Telegram bot API token,
  24. and you may also provide a path to a database (if no path is provided,
  25. a `./bot.db` SQLite database will be used).
  26. 6. `initialize_bot` function is defined and called on `simple_bot`. It assigns
  27. commands, parsers, callback and inline query handlers to the bot.
  28. 7. `Bot.run()` method is called, causing the script to hang while asynchronous
  29. tasks run checking for updates and routing them to get and send replies.
  30. Send a KeyboardInterrupt (ctrl+C) to stop the bot.
  31. """
  32. # Standard library modules
  33. import logging
  34. import os
  35. import sys
  36. # Third party modules
  37. try:
  38. from davtelepot.bot import Bot
  39. from davtelepot.utilities import (
  40. get_cleaned_text, get_user, make_inline_keyboard, make_button
  41. )
  42. except ImportError:
  43. logging.error(
  44. "Please install davtelepot library.\n"
  45. "Using a python virtual environment is advised.\n\n"
  46. "```bash\n"
  47. "pip -m venv env\n"
  48. "env/bin/pip install davtelepot\n"
  49. "env/bin/python davtelepot/examples/a_simple_bot.py"
  50. "```"
  51. )
  52. sys.exit(1)
  53. # Get path of current script
  54. path = os.path.dirname(os.path.abspath(__file__))
  55. def initialize_bot(telegram_bot):
  56. """Take a bot and set commands."""
  57. telegram_bot.set_callback_data_separator('|')
  58. @telegram_bot.command(command='foo', aliases=['Foo'],
  59. show_in_keyboard=True,
  60. description="Reply 'bar' to 'foo'",
  61. authorization_level='everybody')
  62. async def foo_command(bot, update, user_record):
  63. return (
  64. "Bar!\n\n"
  65. f"You wrote: {update['text']}\n"
  66. f"I am @{bot.name} and you are {get_user(user_record)}"
  67. )
  68. def is_bar_text_message(lowered_text):
  69. return lowered_text.startswith('bar')
  70. @telegram_bot.parser(condition=is_bar_text_message,
  71. description='Reply Foo to users who write Bar',
  72. authorization_level='everybody')
  73. async def bar_parser(bot, update):
  74. text_except_foo = get_cleaned_text(update, bot, ['bar'])
  75. return f"Foo!\n{text_except_foo}"
  76. def get_keyboard(chosen_button=-1):
  77. return make_inline_keyboard(
  78. [
  79. make_button(
  80. prefix='button:///',
  81. delimiter='|',
  82. data=[i],
  83. text=f"{'✅' if chosen_button == i else '☑️'} Button #{i}"
  84. )
  85. for i in range(1, 13)
  86. ],
  87. 3
  88. )
  89. @telegram_bot.command(command='buttons')
  90. async def buttons_command():
  91. return dict(
  92. text="Press a button!",
  93. reply_markup=get_keyboard()
  94. )
  95. @telegram_bot.button(prefix='button:///', separator='|',
  96. authorization_level='everybody')
  97. async def buttons_button(data):
  98. button_number = data[0]
  99. return dict(
  100. edit=dict(
  101. text=f"You pressed button #{button_number}",
  102. reply_markup=get_keyboard(button_number)
  103. )
  104. )
  105. def starts_with_a(text):
  106. return text.startswith('a')
  107. @telegram_bot.query(
  108. condition=starts_with_a,
  109. description='Mirror query text if it starts with letter `a`',
  110. authorization_level='everybody'
  111. )
  112. async def inline_query(update):
  113. return dict(
  114. type='article',
  115. id=10,
  116. title="Click here to send your query text as a message.",
  117. input_message_content=dict(
  118. message_text=update['query']
  119. )
  120. )
  121. telegram_bot.set_default_inline_query_answer(
  122. dict(
  123. type='article',
  124. id=0,
  125. title="Start query text with `a` to mirror it.",
  126. input_message_content=dict(
  127. message_text="This query does not start with `a`."
  128. )
  129. )
  130. )
  131. telegram_bot.set_unknown_command_message(
  132. "<b>Currently supported features</b>\n\n"
  133. "- /foo (or text starting with `foo`): replies `Bar!`.\n"
  134. "- Text starting with `bar`: replies `Foo!` followed by the rest of "
  135. "text in your bar-starting message.\n"
  136. "- /buttons demonstrates the use of buttons.\n"
  137. "- Inline queries starting with letter `a` will be mirrored as text "
  138. "messages. To use this feature, try writing <code>@{bot.name} "
  139. "your_text_here</code>"
  140. )
  141. def _main():
  142. # Import or prompt user for bot token
  143. try:
  144. from secrets import simple_bot_token
  145. except ImportError:
  146. simple_bot_token = input("Enter bot token:\t\t")
  147. with open(
  148. f'{path}/secrets.py',
  149. 'a' # Append to file, create it if it does not exist
  150. ) as secrets_file:
  151. secrets_file.write(f'simple_bot_token = "{simple_bot_token}"\n')
  152. # Set logging preferences
  153. log_formatter = logging.Formatter(
  154. "%(asctime)s [%(module)-15s %(levelname)-8s] %(message)s",
  155. style='%'
  156. )
  157. root_logger = logging.getLogger()
  158. root_logger.setLevel(logging.DEBUG)
  159. console_handler = logging.StreamHandler()
  160. console_handler.setFormatter(log_formatter)
  161. console_handler.setLevel(logging.DEBUG)
  162. root_logger.addHandler(console_handler)
  163. # Instantiate, initialize and make `simple_bot` run.
  164. simple_bot = Bot(token=simple_bot_token, database_url=f"{path}/bot.db")
  165. initialize_bot(simple_bot)
  166. logging.info("Send a KeyboardInterrupt (ctrl+C) to stop bots.")
  167. Bot.run()
  168. if __name__ == '__main__':
  169. _main()