How to receive multiple messages in python-telegram-bot? - telegram-bot

I am sending multiple images at a time to a bot in telegram. I am trying to create a conversational chatbot using python-telegram bot.
here is my code:
def main():
updater = Updater("1141074258:Axxxxxxxxxxxxxxxxxxxxxxxxg", use_context=True)
dp = updater.dispatcher
conv_handler = ConversationHandler(
entry_points = [CommandHandler('start',start)],
states = {
CHOSEN_OPTION: [MessageHandler(Filters.regex('^(Option2|Option3|Option4)$'),choose_option)],
PRODUCTS: [MessageHandler(Filters.text | Filters.photo,products)],
Option2: [MessageHandler(Filters.text,option2)],
Option3: [MessageHandler(Filters.text,option3)],
Option4: [CommandHandler('create', create_order)]
},
fallbacks=[CommandHandler('cancel', cancel)]
)
dp.add_handler(conv_handler)
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
#run_async
def products(update,context):
logger.info("update is %s",update)
input_message = update.message.text
if input_message:
data['products'] = input_message
logger.info("product text is:%s",input_message)
elif update.message.photo:
photo_list = []
bot = context.bot
length = len(update.message.photo)
for photo in range(0,length):
ident = update.message.photo[photo].file_id
getFile = context.bot.get_file(ident)
photo_list.append(getFile['file_path'])
data['products_image'] = photo_list
update.message.reply_text("Please type name.",)
return Option3
If i am send 2 images same time, i am getting one image with a different size (3 times), How can I receive the actual two messages?

if update contains photo return PRODUCTS for getting other photos else
get text and return to every state you want
#run_async
def products(update,context):
logger.info("update is %s",update)
if update.message.photo:
# to what you want with your photos
return PRODUCTS
if update.message.text:
# getting product text
return Option3

Related

pyTelegramBotAPI.How to edit/delete message with inline buttons only if message from the same step was already in chat?

I want my TG bot to have inlinebuttons with categories and subcategories in chat with dynamic change.
But how to send message with subcategories if it doesnt exist and edit message with subcategories if it already exists?
Also, I wish to have a "back" inlinebutton among categories that will delete messages with categories and subcategories and turn to main menu.
Attached my code and illustration of goal.
Help me please!
import telebot
from telebot import types
bot = telebot.TeleBot(TELEGRAM_TOKEN,
parse_mode=None)
markup_menu = types.ReplyKeyboardMarkup(resize_keyboard=True)
btns = ["Order"]
for btn in btns:
markup_menu.add(types.KeyboardButton(btn))
menu = {"Snacks": {"Sweet Snack": 150, "Salt snak": 320}, "Drinks": {"Cola": 100, "Sprite": 90},
"Meat": {"Pork": 228, "Beef": 56}}
#bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id,
f"Wellcome, <b>{message.from_user.first_name}</b>",
reply_markup=markup_menu,
parse_mode="html")
#bot.message_handler(content_types="text")
def order(message):
# These are variable values to help change next message after "Choose category:"
order_counter = 0
product_message = 0
switcher = {product_message: order_counter}
if message.text == 'Order':
order_menu = types.InlineKeyboardMarkup()
order_menu.row_width = 2
for category in menu:
order_menu.add(types.InlineKeyboardButton(category,
callback_data=f"{category}"))
bot.send_message(message.chat.id,
"Choose category:",
reply_markup=order_menu)
if order_counter == 0:
#bot.callback_query_handler(func=lambda call: call.data in menu.keys())
def callback_product(call):
product_menu = types.InlineKeyboardMarkup()
product_menu.row_width = 4
for product in menu[call.data]:
product_menu.add(types.InlineKeyboardButton
(f"{product}" +
f" - {menu[call.data][product]}",
callback_data=f"{product}")
)
product_message = bot.send_message(message.chat.id,
f'Choose {call.data}:',
reply_markup=product_menu,
)
product_message
order_counter == 1
switcher = {product_message: order_counter}
return switcher
elif switcher.keys() == 1:
#bot.callback_query_handler(func=lambda call: call.data in menu.keys())
def callback_product1(call):
product_menu = types.InlineKeyboardMarkup()
product_menu.row_width = 4
for product in menu[call.data]:
product_menu.add(types.InlineKeyboardButton
(f"{product}" +
f" - {menu[call.data][product]}",
callback_data=f"{product}")
)
product_message = bot.edit_message_text(chat_id=switcher[0][0].message.chat.id,
message_id=switcher[0][0].message_id,
text=f'Choose {call.data}:',
reply_markup=product_menu
)
product_message
order_counter == 1
return order_counter, product_message
#bot.message_handler(content_types="text")
def missunderstand(message):
bot.reply_to(message, "I don't understand you", reply_markup=markup_menu)
bot.infinity_polling()
I have tried to create a switcher that would signal to func. if message with subcategories exists, but it didn't work. (it's "switcher" in code)

i need the list of countries that are supported africa's talking api

I actually want to use Africa's talking api on my ussd app. I am from bangladesh and i am confused if it supports bangladesh or not.there are mainly four service provider in bangladesh namely gameenphone, robi, banglalink, airtel. I want to send ussd from one of the operator to my application.
here is python code:
from flask import Flask, request
import africastalking
import os
app = Flask(__name__)
username = "sandbox"
api_key = "*384*89376#"
africastalking.initialize(username, api_key)
sms = africastalking.SMS
#app.route('/', methods=['POST', 'GET'])
def ussd_callback():
global response
session_id = request.values.get("sessionId", None)
service_code = request.values.get("serviceCode", None)
phone_number = request.values.get("phoneNumber", None)
text = request.values.get("text", "default")
sms_phone_number = []
sms_phone_number.append(phone_number)
#ussd logic
if text == "":
#main menu
response = "CON What would you like to do?\n"
response += "1. Check account details\n"
response += "2. Check phone number\n"
response += "3. Send me a cool message"
elif text == "1":
#sub menu 1
response = "CON What would you like to check on your account?\n"
response += "1. Account number"
response += "2. Account balance"
elif text == "2":
#sub menu 1
response = "END Your phone number is {}".format(phone_number)
elif text == "3":
try:
#sending the sms
sms_response = sms.send("Thank you for going through this tutorial",
sms_phone_number)
print(sms_response)
except Exception as e:
#show us what went wrong
print(f"Houston, we have a problem: {e}")
elif text == "1*1":
#ussd menus are split using *
account_number = "1243324376742"
response = "END Your account number is {}".format(account_number)
elif text == "1*2":
account_balance = "100,000"
response = "END Your account balance is USD {}".format(account_balance)
else:
response = "END Invalid input. Try again."
return response
if __name__ == "__main__":
app.run()
Africa's Talking USSD services are in the following countries:
Kenya,
Uganda,
Tanzania,
Rwanda,
Nigeria
Côte d'Ivoire,
Malawi,
Zambia,
South Africa
Hope this helps. Reach out if you have any more questions.

Django local server: Atomic Database from a text file

I made a Web app that takes in a text file, reads each line, takes the 11th character and saves it to SQLite3 db. How do I lock the database or have two or more separate tables while multiple requests are running?
I have added adding ATOMIC_REQUESTS': True to the settings.py in Django.
and I tried creating temporary tables for each request, but can't figure it out. I am pretty fresh to Django 2.2
My View.py
def home(request):
if request.method == 'GET':
return render(request, 'home.html')
if request.method == 'POST':
form = DocumentForm(data=request.POST, files=request.FILES)
print(form.errors)
if form.is_valid():
try:
f = request.FILES['fileToUpload']
except:
print('\033[0;93m'+ "No File uploaded, Redirecting" +'\033[0m')
return HttpResponseRedirect('/tryagain')
print('\033[32m'+ "Success" +'\033[0m')
print('Working...')
line = f.readline()
while line:
#print(line)
mst = message_typer.messages.create_message(str(line)[11])
line = f.readline()
else:
print('\033[0;91m'+ "Failed to validate Form" +'\033[0m')
return HttpResponseRedirect('/output')
return HttpResponse('Failure')
def output(request):
s = message_typer.messages.filter(message='s').count()
A = message_typer.messages.filter(message='A').count()
d = message_typer.messages.filter(message='d').count()
E = message_typer.messages.filter(message='E').count()
X = message_typer.messages.filter(message='X').count()
P = message_typer.messages.filter(message='P').count()
r = message_typer.messages.filter(message='r').count()
B = message_typer.messages.filter(message='B').count()
H = message_typer.messages.filter(message='H').count()
I = message_typer.messages.filter(message='I').count()
J = message_typer.messages.filter(message='J').count()
R = message_typer.messages.filter(message='R').count()
message_types = {'s':s, 'A':A, 'd':d, 'E':E, 'X':X, 'P':P,\
'r':r, 'B':B, 'H':H, 'I':I, 'J':J, 'R':R }
output = {'output':message_types}
#return HttpResponse('Received')
message_typer.messages.all().delete()
return render(request, 'output.html',output)
When the web page loads, it should display a simple break down each character in the 11th position of the uploaded text file.
However, if two requests are running concurrently, the first page that makes the request gets an Operation Error; Db is locked.
Traceback to here:
message_typer.messages.all().delete()
The second page will sum the total of the two files that were uploaded.
I do want to wipe the table after so that the next user will have an empty table to populate and perform a count on.
Is there a better way?

How to fixing different element text to extract

I'm setting up a new scrapy spider and developed
I am using windows 10 and it's running.
My problem is extracting text from different element. This elements sometime on (strong tag, p,) sometime have class , sometime have id but i need to implement to one element to extracting a row text.
Please checkout the link of site
https://exhibits.otcnet.org/otc2019/Public/eBooth.aspx?IndexInList=404&FromPage=Exhibitors.aspx&ParentBoothID=&ListByBooth=true&BoothID=193193&fromFeatured=1
https://exhibits.otcnet.org/otc2019/Public/eBooth.aspx?IndexInList=0&FromPage=Exhibitors.aspx&ParentBoothID=&ListByBooth=true&BoothID=202434
https://exhibits.otcnet.org/otc2019/Public/eBooth.aspx?IndexInList=1218&FromPage=Exhibitors.aspx&ParentBoothID=&ListByBooth=true&BoothID=193194&fromFeatured=1
https://prnt.sc/nkl1vc,
https://prnt.sc/nkl1zy,
https://prnt.sc/nkl247,
# -*- coding: utf-8 -*-
import scrapy
class OtcnetSpider(scrapy.Spider):
name = 'otcnet'
# allowed_domains = ['otcnet.org']
start_urls = ['https://exhibits.otcnet.org/otc2019/Public/Exhibitors.aspx?Index=All&ID=26006&sortMenu=107000']
def parse(self, response):
links = response.css('a.exhibitorName::attr(href)').extract()
for link in links:
ab_link = response.urljoin(link)
yield scrapy.Request(ab_link, callback=self.parse_p)
def parse_p(self, response):
url = response.url
Company = response.xpath('//h1/text()').extract_first()
if Company:
Company = Company.strip()
Country = response.xpath('//*[#class="BoothContactCountry"]/text()').extract_first()
State = response.xpath('//*[#class="BoothContactState"]/text()').extract_first()
if State:
State = State.strip()
Address1 = response.xpath('//*[#class="BoothContactAdd1"]/text()').extract_first()
City = response.xpath('//*[#class="BoothContactCity"]/text()').extract_first()
if City:
City = City.strip()
zip_c = response.xpath('//*[#class="BoothContactZip"]/text()').extract_first()
Address = str(Address1)+' '+str(City)+' '+str(State)+' '+str(zip_c)
Website = response.xpath('//*[#id="BoothContactUrl"]/text()').extract_first()
Booth = response.css('.eBoothControls li:nth-of-type(1)::text').extract_first().replace('Booth: ','')
Description = ''
Products = response.css('.caption b::text').extract()
Products= ', '.join(Products)
vid_bulien = response.css('.aa-videos span.hidden-md::text').extract_first()
if vid_bulien=="Videos":
vid_bulien = "Yes"
else:
vid_bulien = "No"
Video_present = vid_bulien
Conference_link = url
Categories = response.css('.ProductCategoryLi a::text').extract()
Categories = ', '.join(Categories)
Address = Address.replace('None','')
yield {
'Company':Company,
'Country':Country,
'State':State,
'Address':Address,
'Website':Website,
'Booth':Booth,
'Description':Description,
'Products':Products,
'Video_present':Video_present,
'Conference_link':Conference_link,
'Categories':Categories
}
I expect the output would be a row description from different element
According to this post and excellent #dimitre-novatchev answer you need to find a node-set intersection:
$ns1 for your page is:
//p[#class="BoothProfile"]/following-sibling::p
$ns2 is:
p[#class="BoothProfile"]/following-sibling::div[1]/preceding-sibling::p
as a result you need to process these p elements:
//p[#class="BoothProfile"]/following-sibling::p[count(.|//p[#class="BoothProfile"]/following-sibling::div[1]/preceding-sibling::p) = count(//p[#class="BoothProfile"]/following-sibling::div[1]/preceding-sibling::p)]
You can use this Scrapy code:
for p_elem in response.xpath('//p[#class="BoothProfile"]/following-sibling::p[count(.|//p[#class="BoothProfile"]/following-sibling::div[1]/preceding-sibling::p) = count(//p[#class="BoothProfile"]/following-sibling::div[1]/preceding-sibling::p)]'):
# using string() to stringify <p>
Description += p_elem.xpath('string(.)').extract_first()

Telegram bot: How to get chosen inline result

I'm sending InlineQueryResultArticle to clients and i'm wondering how to get chosen result and it's data (like result_id,...).
here is the code to send results:
token = 'Bot token'
bot = telegram.Bot(token)
updater = Updater(token)
dispatcher = updater.dispatcher
def get_inline_results(bot, update):
query = update.inline_query.query
results = list()
results.append(InlineQueryResultArticle(id='1000',
title="Book 1",
description='Description of this book, author ...',
thumb_url='https://fakeimg.pl/100/?text=book%201',
input_message_content=InputTextMessageContent(
'chosen book:')))
results.append(InlineQueryResultArticle(id='1001',
title="Book 2",
description='Description of the book, author...',
thumb_url='https://fakeimg.pl/300/?text=book%202',
input_message_content=InputTextMessageContent(
'chosen book:')
))
update.inline_query.answer(results)
inline_query_handler = InlineQueryHandler(get_inline_results)
dispatcher.add_handler(inline_query_handler)
I'm looking for a method like on_inline_chosen(data) to get id of the chosen item. (1000 or 1001 for snippet above) and then send the appropriate response to user.
You should set /setinlinefeedback in #BotFather, then you will get this update
OK, i got my answer from here
Handling user chosen result:
from telegram.ext import ChosenInlineResultHandler
def on_result_chosen(bot, update):
print(update.to_dict())
result = update.chosen_inline_result
result_id = result.result_id
query = result.query
user = result.from_user.id
print(result_id)
print(user)
print(query)
print(result.inline_message_id)
bot.send_message(user, text='fetching book data with id:' + result_id)
result_chosen_handler = ChosenInlineResultHandler(on_result_chosen)
dispatcher.add_handler(result_chosen_handler)