I am building some telegram bot on python (using this framework pyTelegramBotAPI). And I ran into the problem with user input. I need save user input(it can be any text) after certain bot's message. For example:
Bot: - Please describe your problem.
User: - Our computer doesn't work.
Then I need to save this text "Our computer doesn't work" to some variable and go to the next step.
Here's my code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import telebot
import constants
from telebot import types
bot = telebot.TeleBot(constants.token)
#bot.message_handler(commands=['start'])
def handle_start(message):
keyboard = types.InlineKeyboardMarkup()
callback_button = types.InlineKeyboardButton(text="Help me!", callback_data="start")
keyboard.add(callback_button)
bot.send_message(message.chat.id, "Welcome I am helper bot!", reply_markup=keyboard)
#bot.inline_handler(lambda query: len(query.query) > 0)
def query_text(query):
kb = types.InlineKeyboardMarkup()
kb.add(types.InlineKeyboardButton(text="Help me!", callback_data="start"))
results = []
single_msg = types.InlineQueryResultArticle(
id="1", title="Press me",
input_message_content=types.InputTextMessageContent(message_text="Welcome I am helper bot!"),
reply_markup=kb
)
results.append(single_msg)
bot.answer_inline_query(query.id, results)
#bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
if call.message:
if call.data == "start":
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Please describe your problem.")
#here I need wait for user text response, save it and go to the next step
I have the idea with using message_id in statement, but still can't implement it. How I can solve this? Any ideas? Thank you.
This will help you
https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py
import telebot
import constants
from telebot import types
bot = telebot.TeleBot(constants.token)
#bot.message_handler(commands=['start'])
def start(message):
sent = bot.send_message(message.chat.id, 'Please describe your problem.')
bot.register_next_step_handler(sent, hello)
def hello(message):
open('problem.txt', 'w').write(message.chat.id + ' | ' + message.text + '||')
bot.send_message(message.chat.id, 'Thank you!')
bot.send_message(ADMIN_ID, message.chat.id + ' | ' + message.text)
bot.polling()
its not a python or even programming related question. its more like designing problem. but anyway.
the solution is keeping session for users. for example user send you:
Our computer doesn't work.
at first you create a session for this user(the identity should be a user id) then send him/her a proper message. when user send the next message at first you look at the user status and see if he/she has a session or not. if he/she has session you continue with second step. i develop a bot like this and used dictionary in order to store users sessions. but it make all thing little complicated.
You can use Forcereply.
Upon receiving a message with this object, Telegram clients will display a reply interface to the user (act as if the user has selected the bot‘s message and tapped ’Reply'). This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to sacrifice privacy mode. https://core.telegram.org/bots/api#forcereply
i know how fix that. It took 3 years for solution.
Just look at my code and make your own. Thx
#bot.callback_query_handler(func=lambda call: True)
def callback_inline(call): #your call
UserID = str(call.message.chat.id)
if call.data == 'PhotoTEXT':
#bot.message_handler(content_types=['text'])
def SetTEXTonPHOTO(message): # THIS FUNCTION
sent = bot.send_message(message.chat.id,'send me text')
bot.register_next_step_handler(sent, TextONphoto)
def TextONphoto(message): #Thsi function add text on photo
im = Image.open('UserData/Files/photos/not_converted/'+UserID+'.jpg')
idraw = ImageDraw.Draw(im)
text = message.text
font = ImageFont.truetype("arial.ttf", size=18)
idraw.text((10, 10), text, font=font)
im.save('UserData/Files/photos/converted/'+UserID+'.jpg')
im.show()
SetTEXTonPHOTO(call.message) #just run your function
with open('UserData/Files/photos/converted/'+UserID+'.jpg', 'rb') as file:
bot.send_document(UserID,file)
I think i helped you friends <3
You should save the data in cache or database.
Related
So im making a discord Bot that will notify me when my favorite food is avalable in the cafiteria at my school. Im trying to make it so multiple people can use the bot so im storing the users favorite food in a dictionary with their user id as the key. I've never used slash commands in discord before, normally I just use a command.prefix but decided to try it this way instead.
So far this is what I have:
client = aclient()
tree = app_commands.CommandTree(client)
#tree.command(guild = discord.Object(id=guild_id), name = 'favorite_add', description='Add a food item to your favorite food list') #guild specific slash command
async def addFavorite(interaction: discord.Interaction, content : str = ""):
await interaction.response.send_message(f"{content} has been added to your favorite food list", ephemeral = True)
userFavorites[content.author.id] += [content]
The problem im having is that the str: content doesnt have the author.id attrubite. Is there any way to aquire the id of who posted the command so I can add the content to their favorite food list or potentially add a new key to my dictionary
async def addFavorite(interaction: discord.Interaction, content : str = ""):
^^^^^^^
That's because the content argument is a string since you're telling the library that you wanted it to be. If you want to get the ID of the user who triggered the command, you have to get the user from interaction.user then get the ID.
userFavorites[interaction.user.id] += [content]
discord.py isn't beginner-friendly; you should know the basics before trying it. You can look at some examples here.
Let's say I have this command handler:
#bot.message_handler(commands=['setalarm'])
def setalarmcmd(message):
alarmMessage = "Let's start with setting up alarm.\n\n" \
"First of all, provide the pair you want to observe."
bot.send_message(message.chat.id, alarmMessage)
I want to set some action when user click /setalarm command and replies on this message.
Actually, I know how to do that, but I already have handler on provided text:
#bot.message_handler(content_types=['text'])
def getpairfuncmessage(message):
userMessage = message.text.strip().upper()
pair = getPairApi(userMessage)
if not pair:
return bot.send_message(message.chat.id, "Nah, not that, try something else.")
pairResult = printPairResult(pair)
bot.send_message(message.chat.id, pairResult, parse_mode='html')
And that's the problem. By providing message, user triggers this action, but I want to set another one, after /setalarm command. Is this possible?
Here is how you can do this:
#bot.message_handler(commands=['setalarm'])
def setalarmcmd(message):
alarmMessage = "Let's start with setting up alarm.\n\n" \
"First of all, provide the pair you want to observe."
msg = bot.send_message(message.chat.id, alarmMessage)
bot.register_next_step_handler(msg, setalarmcryptopair)
def setalarmcryptopair(pair):
print(pair.text)
Using send_message and register_next_step_handler to go to next function.
I am wondering how I could store/read out a user chat ID to later send them messages.
Example would be, that the user is adding my telegram bot and sends him a message.
Later on in my program at some point, when a sepcific situation occurs, I want to send a message to the specific user.
For a simple example I have this code:
a=1
b=2
if a > b:
# at this point python should send a message to a user via telegram privat chat
else:
# send a different message
I know how to handle a response to a command sent by the user in the telegram chat, but not how to send a message to a user without receiving a command first. I think there fore I would need to have a way to store the users chat Id first to later refer to that Id when sending the message.
The point is I want to compile my program to .exe later on and send it to some friends and it should work for them as well.
It is very easy, just use a simple database.
MongoDB is the best choose in my opinion.
Create an account on it and follow this tutorial.
First get the user_id
userid1 = str(update.message.chat_id)
Then store it into the database
import pymongo
from pymongo import MongoClient
cluster = MongoClient("mongodb+srv://<user>:<password>#cluster0.uubct.mongodb.net/users?retryWrites=true&w=majority")
db = cluster["users"]
collection = db["users"]
results = collection.find({"_id": int(userid1)})
if results.count() == 0:
print("post")
post = {"_id": int(userid1)}
collection.insert_one(post)
else:
print("User already in the database!")
For getting it you need to use the find() method.
results = collection.find()
for result in results:
var1 = (result["_id"])
print(var1)
context.bot.send_message(chat_id=prova,
text = "Hi")
You can simply add the id in a list WHITOUT ANY THIRD PARTS PAKAGE
import telebot
TOKEN = ""
bot = telebot.TeleBot(TOKEN)
admin = # your chat id
users = []
#bot.message_handler(commands=['start'])
def start_message(msg):
bot.send_message(msg.chat.id, 'Welcome!')
if msg.chat.id not in users: # if the id isn't already in the users list
users.append(msg.chat.id)
#bot.message_handler(commands=['send_at_all']) # A way to use the list
def sendAtAll(msg):
if msg.chat.id == admin: # only if YOU start the command the message will be sent
for id in users: # for every user that has start the bot
bot.send_message(id, "I'm sending this message at all the users")
# If an user wants to stop the notifications...
#bot.message_handler(commands=['unsubscribe'])
def sendAtAll(msg):
del users[msg.chat.id]
bot.send_message(msg.chat.id, "If you want to receive the notification click /start")
# Every time you are going to restart the bot polling the content of the users list will be deleated so...
#bot.message_handler(commands=['save_user_list'])
def sendAtAll(msg):
if msg.chat.id == admin:
bot.send_message(admin, users)
# the list will be sent to your telegram chat, when you activate the bot you can add the list manually
bot.polling()
You can also create a class and save every chat id as an object
import telebot
from random import choice
TOKEN = ''
bot = telebot.TeleBot(TOKEN)
admin = # your chat id
users = []
class Userbot: # The class User is already in the pyTelegramBotAPI
def __init__(self, msg):
self.id = msg.chat.id
self.username = '#' + msg.from_user.username
def contestWinner(self):
text = f'Hi {self.username}, you have win!!!'
bot.send_message(self.id, text)
#bot.message_handler(commands=['start'])
def start(msg):
bot.send_message(msg.chat.id, 'Welcome!')
for el in users:
if msg.chat.id not in el.id:
users.append(Userbot(msg))
# you can't type 'if msg.chat.id not in users.id' because only the object inside the list can use the method id
#bot.message_handler(commands=['extract']) # another way to use the list
def extract(msg):
if msg.chat.id == admin:
winner = choice(users)
winner.contestWinner()
#bot.message_handler(commands=['unsubscribe'])
def sendAtAll(msg):
for el in users:
if msg.chat.id == el.id:
del users[el]
# only if the user inside the object is the same as the user that has sent the message the object will be deleated
bot.send_message(msg.chat.id, "If you want to receive the notification click /start")
#bot.message_handler(commands=['save_user_list'])
def sendAtAll(msg):
if msg.chat.id == admin:
bot.send_message(admin, users)
bot.polling()
Apologise for my terrible english
I am creating a reference bot for chatting in VK in Python using the Callback Api. The bot works correctly if you write to the group messages. However, if you write to a conversation (to which the bot is added), it replies to private messages. All rights to read, etc. issued. As I understand it (studying information on the internet), I use user_id, not chat_id. But I didn't understand how to fix it correctly (
p.s. It is advisable that the bot write both in private messages and in a conversation, depending on where they ask.
p.p.s perhaps the question seems ridiculous, but I just started to study this area, and I did not find the answer on the net :-)
The bot itself:
import vk
import random
import messageHandler
# app.route ('/', methods = ['POST'])
def processing ():
data = json.loads (request.data)
if 'type' not in data.keys ():
return 'not vk'
if data ['type'] == 'confirmation':
return confirmation_token
elif data ['type'] == 'message_new':
messageHandler.create_answer (data ['object'] ['message'], token)
return 'ok'
"Responder":
import importlib
from command_system import command_list
def load_modules ():
# path from the working directory, it can be changed in the application settings
files = os.listdir ("mysite / commands")
modules = filter (lambda x: x.endswith ('. py'), files)
for m in modules:
importlib.import_module ("commands." + m [0: -3])
def get_answer (body):
# Default message if unrecognizable
message = "Sorry, I don't understand you. Write '/ help' to see my commands."
attachment = ''
for c in command_list:
if body in c.keys:
message, attachment = c.process ()
return message, attachment
def create_answer (data, token):
load_modules ()
user_id = data ['from_id']
message, attachment = get_answer (data ['text']. lower ())
vkapi.send_message (user_id, token, message, attachment)
I don't speak English well, so I apologize for the crooked translation)
Use Peer_id, instead of from_id. (data->object->peer_id)
(i used php, but i had a similar problem. this is the solution)
probably something like this:
def create_answer (data, token):
load_modules ()
user_id = data ['peer_id'] # id source edited
message, attachment = get_answer (data ['text']. lower ())
vkapi.send_message (user_id, token, message, attachment)
from_id - person who sent the message
peer_id - in which dealogue message was received. (for groups it looks like 20000005)
So, you will send the message to conversation (does not matter is this PM or conversation with a lot of people)
I am working with python-telegram-bot building a menu system.
I created a Django project, as shown below, using Webhook to connect to Telegram.
When the first message is sent, I ask the contact for their phone number and
keep this number so I don't need to ask for it in the next messages in the conversation,
but it’s not working.
I tried to store it in request.session, but apparently every new message is a new session and so I lose the number.
How can I solve this? Every help is welcome.
view.py
import json
from django.http.response import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from core.message import proccess
#csrf_exempt
def event(request):
json_telegram = json.loads(request.body)
proccess(request, json_telegram)
return HttpResponse()
messages.py
import telegram
from bot_webhook.settings import TOKEN
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
bot = telegram.Bot(token=TOKEN)
def proccess(request, json_telegram):
if 'login' in request.session:
msg_options(json_telegram)
else:
try:
request.session['login'] = json_telegram['message']['contact']['phone_number']
msg_options(json_telegram)
except BaseException:
msg_login(json_telegram)
def msg_login(json_telegram):
chat_id = json_telegram['message']['from']['id']
reply_markup = telegram.ReplyKeyboardMarkup(
[[telegram.KeyboardButton('Click to Login', request_contact=True)]],
resize_keyboard=True,
one_time_keyboard=True
)
bot.sendMessage(chat_id, 'I need to authorize your access.', reply_markup=reply_markup)
def msg_options(json_telegram):
chat_id = json_telegram['message']['from']['id']
first_name = json_telegram['message']['from']['first_name']
last_name = json_telegram['message']['from']['last_name']
button_list = []
button_list.append(InlineKeyboardButton('Button One', callback_data='query_one'))
button_list.append(InlineKeyboardButton('Button two', callback_data='query_two'))
reply_markup = InlineKeyboardMarkup(build_menu(button_list, n_cols=2))
bot.send_message(text='Hello {0} {1}!\nI have this options:'.format(first_name, last_name),
chat_id=chat_id,
reply_markup=reply_markup)
def build_menu(buttons,
n_cols,
header_buttons=None,
footer_buttons=None):
menu = [buttons[i:i + n_cols] for i in range(0, len(buttons), n_cols)]
if header_buttons:
menu.insert(0, [header_buttons])
if footer_buttons:
menu.append([footer_buttons])
return menu
Once I haven't found a solution in Api, I worked with this solution:
When there is an interaction, I check if the contact already exists in my database,
if positive I continue the conversation,
if negative I ask for identification by sharing the phone.
So when I get the information, I record it in the database,
so that in a new interaction I can identify it automatically.
Record it in my database is it a option, another option is as text archive.
If you have a better option, please show it for us.