I use Python telegram bot API for my bot.
I want to generate photos locally and send them as inline results but InlineQueryResultPhoto
accepts only photo URLs.
Suppose my project structure looks like this:
main.py
photo.jpg
How do I send photo.jpg
as an inline result?
Here is the code of main.py
:
from uuid import uuid4
from telegram.ext import InlineQueryHandler, Updater
from telegram import InlineQueryResultPhoto
def handle_inline_request(update, context):
update.inline_query.answer([
InlineQueryResultPhoto(
id=uuid4(),
photo_url='', # WHAT DO I PUT HERE?
thumb_url='', # AND HERE?
)
])
updater = Updater('TELEGRAM_TOKEN', use_context=True)
updater.dispatcher.add_handler(InlineQueryHandler(handle_inline_request))
updater.start_polling()
updater.idle()
There is no direct answer because Telegram Bot API doesn't provide it.
But there are two workaounds: you can use upload a photo to telegram servers and then use InlineQueryResultCachedPhoto
or you can upload to any image server and then use InlineQueryResultPhoto
.
This first option requires you to previously upload the photo to telegram servers before creating the result list. Which options do you have? The bot can message you the photo, get that information and use what you need. Another option is creating a private channel where your bot can post the photos it will reuse. The only detail of this method is getting to know the channel_id (How to obtain the chat_id of a private Telegram channel?).
Now lets see some code:
from config import tgtoken, privchannID
from uuid import uuid4
from telegram import Bot, InlineQueryResultCachedPhoto
bot = Bot(tgtoken)
def inlinecachedphoto(update, context):
query = update.inline_query.query
if query == "/CachedPhoto":
infophoto = bot.sendPhoto(chat_id=privchannID,photo=open('logo.png','rb'),caption="some caption")
thumbphoto = infophoto["photo"][0]["file_id"]
originalphoto = infophoto["photo"][-1]["file_id"]
results = [
InlineQueryResultCachedPhoto(
id=uuid4(),
title="CachedPhoto",
photo_file_id=originalphoto)
]
update.inline_query.answer(results)
when you send a photo to a chat/group/channel, you can obtain the file_id, the file_id of the thumbnail, the caption and other details I'm going to skip. What the problem? If you don't filter the right query, you may end up sending the photo multiple times to your private channel. It also means the autocomplete won't work.
The other alternative is upload the photo to internet and then use the url. Excluding options like your own hosting, you can use some free image hostings that provides APIs (for example: imgur, imgbb). For this code, generating your own key in imgbb is simpler than imgur. Once generated:
import requests
import json
import base64
from uuid import uuid4
from config import tgtoken, key_imgbb
from telegram import InlineQueryResultPhoto
def uploadphoto():
with open("figure.jpg", "rb") as file:
url = "https://api.imgbb.com/1/upload"
payload = {
"key": key_imgbb,
"image": base64.b64encode(file.read()),
}
response = requests.post(url, payload)
if response.status_code == 200:
return {"photo_url":response.json()["data"]["url"], "thumb_url":response.json()["data"]["thumb"]["url"]}
return None
def inlinephoto(update, context):
query = update.inline_query.query
if query == "/URLPhoto":
upphoto = uploadphoto()
if upphoto:
results = [
InlineQueryResultPhoto(
id=uuid4(),
title="URLPhoto",
photo_url=upphoto["photo_url"],
thumb_url=upphoto["thumb_url"])
]
update.inline_query.answer(results)
This code is similar to the previous method (and that includes the same problems): uploading multiple times if you don't filter the query and you won't have the autocomplete when writing the inline.
Both code were written thinking the images you want to upload are generated at the moment you receive the query, otherwise you can do the work previous to receiving the query, saving that info in a database.
You can run your own bot to get the channel_id of your private channel with pyTelegramBotAPI
import telebot
bot = telebot.TeleBot(bottoken)
@bot.channel_post_handler(commands=["getchannelid"])
def chatid(message):
bot.reply_to(message,'channel_id = {!s}'.format(message.chat.id))
bot.polling()
To get the id you need to write in the channel /getchannelid@botname