I was wondering if i can make input() using TeleBot dependency.
e.g. console way:
POL = float(input("Enter your POL: ))
Is there a way to do using Telebot, like:
bot.send_message(message.chat.id, "Enter your POL")
## Get message.text into POL variable.
From what I understand, there isn't a direct way of doing this, but you can look at the message that the user has replied to from
replied_message = message.reply_to_message.message_id
If it matches the id of the message that you sent then that would be the reply to your message. You can get the id of your sent message from
sent_message = bot.send_message(message.chat.id, "Enter your POL")
sent_message_id = sent_message.message_id
import telebot
TELEGRAM_TOKEN = '<TOKEN>'
bot = telebot.TeleBot(TELEGRAM_TOKEN)
user_register_dict = {}
#bot.message_handler(commands=['start'])
def start(message):
bot.reply_to(message , 'now send your name')
user_register_dict[message.chat.id] = {}
bot.register_next_step_handler(message , start_step2)
def start_step2(message):
user_register_dict[message.chat.id]['name'] = message.text
bot.reply_to(message , 'now send your age')
bot.register_next_step_handler(message , start_step3)
def start_step3(message):
user_register_dict[message.chat.id]['age'] = message.text
bot.reply_to(message , 'your name is {} and you are {} years old!'
.format(user_register_dict[message.chat.id]['name'] ,
[message.chat.id]['age'] ))
start(message = message)
Create a dict for handling the data, which is important because if you use lists (eg.) maybe 2 people starts to register in same time and data gonna crash!
Difference between create bot.register_next_step_handler (line 13 for example) with connect directly for example start(message = message) in end line is in register_next_step_handler bot waits for new message and when received puts it in message and start defection but in direct start defection bot doesn't wait for user message, and start defection with current message start(message = message)
Related
I am writing my first bot. The problem occurs right after send_to_club() function sends "hello". I tried to instead use a message handler with a lambda function but it didn't help either. Can you please help me find the mistake?
import telebot
from telebot import types
from scraper import get_clubs_from_search
import state
bot = telebot.TeleBot('###')
#bot.message_handler(commands=['start'])
def start(message):
msg = f"""Hello, <b>{message.from_user.first_name}</b> \n/help for commands list \n/search for search options"""
bot.send_message(message.chat.id, msg, parse_mode='html')
#bot.message_handler(commands=['help'])
def help(message):
msg = f"""You can use the following commands: \n/search to search for a team or a player"""
bot.send_message(message.chat.id, msg, parse_mode='html')
#bot.message_handler(commands=['search'])
def search(message):
markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
player_search = types.KeyboardButton("Search for a player")
team_search = types.KeyboardButton("Search for a team")
markup.add(player_search, team_search)
bot.send_message(message.chat.id, 'Choose an option:', reply_markup=markup)
#bot.message_handler(func = lambda message: message.text in ['Search for a player','Search for a team'])
def team_search(message):
if message.text == 'Search for a team':
msg = bot.send_message(message.chat.id, "Type the name of the team", reply_markup=types.ForceReply(selective=False))
bot.register_next_step_handler(msg, get_search_url)
def get_search_url(message):
"""Taking user request and forming a search url. then calling get_clubs_from_search """
search_request = message.text.split()
final_query = ""
for i in range(len(search_request)):
if i != (len(search_request)-1):
final_query += f"{search_request[i]}+"
else:
final_query += f"{search_request[i]}"
url = f"https://www.transfermarkt.com/schnellsuche/ergebnis/schnellsuche?query={final_query}"
data = get_clubs_from_search(url)
bot.register_next_step_handler(message, return_search(message, data))
def return_search(message, data):
"""Presenting dataframe to user and asking to choose a team"""
msg = "Please choose the team:\n\n"
markup = types.ReplyKeyboardMarkup(True)
for i in range(len(data)):
msg += f"""{i+1}. {data.loc[i]['club_names']} from {data.loc[i]['country_names']}\n"""
markup.add(types.KeyboardButton(i+1))
final_message = bot.send_message(message.chat.id, msg, reply_markup=markup)
bot.register_next_step_handler(final_message, send_to_club_page, data)
This is where the problem occurs. Both this method and using a message_handler lead to the same error and break the bot. It seems no different to the way I registered message handlers above, and those work just fine
def send_to_club_page(message, data):
msg = "hello"
bot.send_message(message.chat.id, msg, parse_mode='html')
while True:
bot.polling(none_stop=True, timeout=5)
Ok. So the correct answer was given to me by Tim Roberts in the comments.
The problem was with me not passing the function object and instead calling it. The NoneType object is the return of the function return_search. I was supposed to pass the function object like this: bot.register_next_step_handler(message, return_search, data)
Thank you very much for your criticism about the error message too. I will make sure to post more well-thought questions in the future
I am trying to get images from User on telegram bot.
Before that, getting some information from the user (using bot.register_next_step_handler).
Example code:
def admin_panel_add_sneakers_type (message):
sneakers_type = message.text
message_text = 'Send sneakers price:'
msg = bot.send_message(message.chat.id, message_text)
bot.register_next_step_handler(msg, admin_panel_add_sneakers_price, sneakers_type )
def admin_panel_add_sneakers_price (message, sneakers_type):
sneakers_price = message.text
message_text = 'Send sneakers count:'
msg = bot.send_message(message.chat.id, message_text)
bot.register_next_step_handler(msg, admin_panel_add_sneakers_count, sneakers_type, sneakers_price )
After that, I'm trying to get photos of sneakers from the user
def admin_panel_add_sneakers_to_db(message, sneakers_type, sneakers_price, sneakers_count):
if message.content_type == 'photo':
fileID = message.photo[-1].file_id
file_info = bot.get_file(fileID)
downloaded_file = bot.download_file(file_info.file_path)
message.photo contains an array of one photo (the first image of several sended by the user) of different quality, but how i can get all photos?
Also, i saw this method for solve my problem - #bot.message_handler(content_types=['photo'])
But I need to remember the user's choice, before send photos - sneakers_type, sneakers_price, sneakers_count
everyone having a small issue with the Slash commands.
The idea is that I fetch an Array of Assetdata convert each into an embedded and then send the embedded. If there is an image it will show an image and if a .mp4 is linked to the asset it will convert the mp4 to gif and then attache the file locally with file = discord.File(). This all worked just fine bevor moving to Slash commands. For some reason, the slash command wants to send a response bevor receiving all the data. This is an issue because the gif processing takes time or if a large sum of data is requested the request takes longer. The function works fine if have a single asset to display and an Image.
So my question is how do I get ctx.send() to wait??
Thanks in Advance everyone!
client = commands.Bot(command_prefix = "!")
slash = SlashCommand(client, sync_commands=True)
#slash.slash(
name="assetsearch",
description="Sends a Message",
guild_ids=[XXXXXXXXXXXXXXXX], #Hidden for StackOverflow
options = [
create_option(
name = "searchtype",
description = "Please choose how you would like to search for an Asset.",
required = True,
option_type = 3,
choices = [
create_choice(
name = "Search by Asset Id",
value = "id"
),
create_choice(
name = "Search by Collection",
value = "colec"
),
create_choice(
name = "Search by Accountname",
value = "acc"
),
create_choice(
name = "Search by Asset Name",
value = 'match'
)
]
),
create_option(
name = "searchterm",
description = "Please enter an Asset Id, an Account name, the name of an Asset or the Collection name.",
required = True,
option_type = 3
),
create_option(
name = "amount",
description = "Please enter how many Assets you would like to display.",
required = True,
option_type = 3
),
],
)
async def _assetsearch(ctx:SlashContext, searchtype: str, searchterm: str, amount: str):
response = await getAssetData(searchtype, searchterm, amount) #Fetches an Array of AssetData, async function
for asset in response:
nftEmbed, nftFile = await __formatMessage(asset) #formats the message, converts mp4 from website to gif, returns the gif and ebeded
print(nftEmbed,nftFile)
await ctx.send(embed=nftEmbed, file=nftFile) #send the embeded and gif, ISSUE!!!
if os.path.isfile('Nft.gif'): os.remove("Nft.gif")
response = ""
Working Function bevor using slash-command
if msg.startswith('$search'):
try:
searchType = msg.split(",")[1]
except:
searchType = 'match'
try:
searchTerm = msg.split(",")[2]
except:
searchTerm = 'abcd'
try:
searchLimit = msg.split(",")[3]
except:
searchLimit = '1'
response = getAssetData(searchType,searchTerm,searchLimit)
for asset in response:
nftEmbed, file = __formatMessage(asset)
await message.channel.send(embed=nftEmbed, file=file)
if os.path.isfile('Nft.gif'): os.remove("Nft.gif")
response = ""
I figured it out. The Slashcomands are expecting a response within 3s if you are working with an API in the background and then precessing data this could become a criterium you cant meet consistently. This is why you would have the Bot itself respond directly upon request. Once you are done with processing your data you can respond normaly
async def _slashcomandfunction(ctx:SlashContext, str:otherparameters,):
message = await ctx.send('Sometext') #Direct respond
await ctx.channel.send(embed=embed, file=file) #Actual message
If you don't want the Bots message
message = await ctx.send('Sometext',delete_after=1)
...or edit the message the Bot sent.
message = await ctx.send('Sometext')
await message.edit(content="newcontent")
Can't you just use asyncio?
import asyncio
await asyncio.sleep(number)
Or is this not what you are looking for?
I have this welcome bot for telegram from github. I would like that every time a new user joins the group in addition to sending him the message it was mentioned and reply to "id has join in group" as the classic group help does.
I attach below the code to work on:
#run_async
def send_async(context, *args, **kwargs):
context.bot.send_message(*args, **kwargs)
def check(update, context, override_lock=None):
"""
Perform some checks on the update. If checks were successful, returns True,
else sends an error message to the chat and returns False.
"""
chat_id = update.message.chat_id
chat_str = str(chat_id)
if chat_id > 0:
send_async(
context, chat_id=chat_id, text="Please add me to a group first!",
)
return False
locked = override_lock if override_lock is not None else db.get(chat_str + "_lck")
if locked and db.get(chat_str + "_adm") != update.message.from_user.id:
if not db.get(chat_str + "_quiet"):
send_async(
context,
chat_id=chat_id,
text="Sorry, only the person who invited me can do that.",
)
return False
return True
# Welcome a user to the chat
def welcome(update, context, new_member):
""" Welcomes a user to the chat """
message = update.message
chat_id = message.chat.id
logger.info(
"%s joined to chat %d (%s)",
escape(new_member.first_name),
chat_id,
escape(message.chat.title),
)
# Pull the custom message for this chat from the database
text = db.get(str(chat_id))
# Use default message if there's no custom one set
if text is None:
text = "Hello $username! Welcome to $title 😊"
# Replace placeholders and send message
text = text.replace("$username", new_member.first_name)
text = text.replace("$title", message.chat.title)
send_async(context, chat_id=chat_id, text=text, parse_mode=ParseMode.HTML)
this is the result I would like to achieve.
would anyone know how to help me in this simple task? Thank you!
it's complicated code... keep it simple.
you have an event in group "new chat members". so handle this event and send reply with first_name and link to the account.
Pyrogram example:
from pyrogram import Client
from pyrogram import filters
ACCOUNT = '77777777777'
config = 'config.ini'
__client = Client(session_name=ACCOUNT, config_file=config)
def user_link(user):
USER_LINK = '{first_name} : #{username}'
USERID_LINK = '{first_name} : {id}'
return USER_LINK.format(**user.__dict__) if user.username else USERID_LINK.format(**user.__dict__)
#__client.on_message(filters.new_chat_members)
def welcome(client, message):
users = ", ".join([user_link(message.from_user.__dict__) for m in message.new_chat_members])
message.reply(f"Hello, {users}")
I'm new in StackOverflow. I'm currently making a telegram bot with the python-telegram-bot library. Unfortunately I'm having a problem that I tried so many times to solve, with no results. I'm wondering how I can make the bot sends a message, waits for an user response and answers it correctly.
My code
def request_help_function(update: Update, context: CallbackContext):
bot.send_message(
chat_id=update.effective_chat.id,
text="You are sending a help request to an admin. Type 'Cancel' if you don't want to do it."
)
user_response = update.message.text
if user_esponse == "Cancel":
message = "Ok, I cancelled the message"
else:
message = "Ok, I sent the message to an admin"
bot.send_message(
chat_id=update.effective_chat.id,
text=message
)
reqhelp_value = CommandHandler("reqhelp", request_help_function)
dispatcher.add_handler(reqhelp_value)
The problem here is that the bot doesn't wait for the user response and it jumps directly to the else statement. Do you know how could I solve it?
I recommend you not to try handel multiple tasks in one single function , follow this steps instead :
1 : firstly , you should make a conversation handler , where user enters the conversation using a command and then step by step communicates with the bot . this is quite useful in tasks like users registering (enter name ? [Behrad] | thanks , enter age ? [21] | thanks , enter phone number ? [+98993...]) etc .
2 : when you fully wrote that conversation handler , you should simply add it to bot !
this is exactly what I mean (in the registering example):
imagine user enters "/register" command ...
# ---------- defining states ---------
ONE , TWO = range(2)
# ---------- functions ---------
def register(update: Update, context: CallbackContext):
chat_id = update.message.chat_id
bot.send_message(chat_id , text = "hello , you are registering ! please enter your name | type 'cancel' anytime to cancel process")
return ONE
def got_name(update: Update, context: CallbackContext):
chat_id = update.message.chat_id
name = update.message.text # now we got the name
context.user_data["name"] = name # to use it later (in next func)
bot.send_message(chat_id , text = f"thanks {name} ! please enter your phone number")
return TWO
def got_phone_number(update: Update, context: CallbackContext):
chat_id = update.message.chat_id
phone_number = update.message.text # now we got the phone number
name = context.user_data["name"] # we had the name , remember ?!
bot.send_message(chat_id , text = f"completed ! your name is {name} and your phone number is {phone_number}")
return ConversationHandler.END
def cancel(update: Update, context: CallbackContext):
chat_id = update.message.chat_id
bot.send_message(chat_id , text = "process canceled !")
return ConversationHandler.END
# ---------- conversation handler ---------
CH = ConversationHandler (entry_points = [CommandHandler("register", register)],
states = {ONE : [MessageHandler(Filters.text , got_name)],
TWO : [MessageHandler(Filters.text , got_phone_number]
},
fallbacks = [MessageHandler(Filters.regex('cancel'), cancel)],
allow-reentry = True)
# -------- add handler ---------
updater.dispatcher.add_handler(CH)
in the end , remember it's way better to write any function to do 1 task , not more !
I hope it helps you , have a nice day .