1

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()
  • FYI: This [github issue](https://github.com/nickoala/telepot/issues/146) on the telepot repo suggests you could use another method. The telegram-bot-api docs for that method is: [`InlineQueryResultCachedPhoto`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.inlinequeryresultcachedphoto.html). However this only accepts a `photo_file_id` which is the ID of a photo on telegram's server. I'm not sure the best way to get that photo there in the first place. – v25 Mar 30 '20 at 10:17

1 Answers1

3

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.

InlineQueryResultCachedPhoto

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.

InlineQueryResultPhoto

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.

Disclaimer

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.

Bonus

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

Community
  • 1
  • 1
SergioR
  • 1,386
  • 1
  • 7
  • 14
  • Thanks! But what do you mean by "the autocomplete won't work?" –  Apr 24 '20 at 08:49
  • Autocomplete may not be the right word. If each time the bot receives a query you generate a result list, telegram will give you a suggestion of queries that match with what you're currently typing. For example: lets say your bot can accept "advice", "argument", "fallacy", "science" and you want to ask for advice you start typing "a", telegram will give you a list of suggestion that starts with "a" (in our case it would be advice and argument). That won't happen with the code I posted because the result list only is generated with the right word. – SergioR Apr 24 '20 at 09:20
  • I wanted to use my bot deployment server as file server as well, but telegram is not sending any request when I do this. For creating file server I have installed apache2 and placed files in apache root directory, i.e. `/var/www/html`. Is there any restriction on telegram side or I need to correct my configurations? – Khasan 24-7 Dec 29 '22 at 05:23