Sending photo from URL with Telegram Bot - python

I made a telegram bot which sends photo upon request from URL using pyTelegramBotAPI wrapper. So I tried putting a dummy photo URL and test if the bot can send the image but it failed with the following error.
telebot.apihelper.ApiException: sendPhoto failed. Returned result: <Response [400]>
I'm not sure what the error is, but how can I send a photo from URL using Telegram Bot API correctly? Here is my code
import telebot
import time
import urllib
from io import BytesIO
from PIL import Image
TOKEN = '<token here>'
url='http://scontent-b.cdninstagram.com/hphotos-xfa1/t51.2885-15/e15/10919672_584633251672188_179950734_n.jpg'
def listener(*messages):
for m in messages:
chatid = m.chat.id
if m.content_type == 'text':
text = m.text
name = m.fromUser.first_name
msgid = m.message_id
if(text.startswith('/photo')):
img = BytesIO(urllib.request.urlopen(url).read())
tb.send_chat_action(chatid, 'upload_photo')
tb.send_photo(chatid, img, reply_to_message_id=msgid)
tb = telebot.TeleBot(TOKEN)
tb.get_update() # cache exist message
tb.set_update_listener(listener) #register listener
tb.polling()
while True:
time.sleep(1)
I'm not sure whether I missed something though.

Try this:
import telebot
import time
import urllib
url = 'http://scontent-b.cdninstagram.com/hphotos-xfa1/t51.2885-15/e15/10919672_584633251672188_179950734_n.jpg'
f = open('out.jpg','wb')
f.write(urllib.request.urlopen(url).read())
f.close()
def listener(*messages):
for m in messages:
chat_id = m.chat.id
if m.content_type == 'text':
text = m.text
msgid = m.message_id
if text.startswith('/photo'):
tb.send_chat_action(chat_id, 'upload_photo')
img = open('out.jpg', 'rb')
tb.send_photo(chat_id, img, reply_to_message_id=msgid)
img.close()
tb = telebot.TeleBot(TOKEN)
tb.set_update_listener(listener) #register listener
tb.polling()
while True:
time.sleep(0)
or (using pyTelegramBotAPI 0.2.0)
import telebot
import time
import urllib
url='http://scontent-b.cdninstagram.com/hphotos-xfa1/t51.2885-15/e15/10919672_584633251672188_179950734_n.jpg'
f = open('out.jpg','wb')
f.write(urllib.request.urlopen(url).read())
f.close()
tb = telebot.TeleBot(TOKEN)
#tb.message_handler(commands=['photo'])
def send_photo(message):
tb.send_chat_action(message.chat.id, 'upload_photo')
img = open('out.jpg', 'rb')
tb.send_photo(message.chat.id, img, reply_to_message_id=message.message_id)
img.close()
tb.polling()
while True:
time.sleep(0)

elif 'Hi' in text:
reply(img=urllib2.urlopen('img url').read())

Related

byte/binary response from Microsoft emotion API in Python

I try getting response from the microsoft emotion api and it returned response in binary but no warning or erro please what could be the problem the sample code is below:
capture.py
import base64
import cv2
import time
def capture_image():
CAM_PORT = 0
cam = cv2.VideoCapture(CAM_PORT)
ret, frame = cam.read()
time.sleep(6)
cv2.imshow('emotion', frame)
cv2.imwrite('emotion.png', frame)
#capture_image()
def generate():
img=cv2.imread('emotion.png')
im_byte = img.tobytes()
return base64.b64encode(im_byte).decode('utf8')
main.py
import http.client, urllib.request
import urllib.parse, urllib.error
import base64, sys
import simplejson as json
from capture import generate
SUBSCRIPTION_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX"
HEADERS = {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY,
}
PARAMS = urllib.parse.urlencode({'returnFaceAttributes':'emotion'})
IMAGE_PATH = generate()
BODY = {'url': IMAGE_PATH}
NEWBODY = str(BODY)
try:
conn = http.client.HTTPSConnection('westus2.api.cognitive.microsoft.com')
conn.request("POST", f"face/v1.0/recognise? {PARAMS} {NEWBODY} {HEADERS}")
response = conn.getresponse()
print('successfull')
conn.close()
except Exception as e:
print(e.args)
when i run the main.py file i get binary output.

Cannot Process decoded Image files, Flask, OpenCV

I am receiving a bunch of images to the flask app via the client file.
client.py
# Generate the parallel requests based on the ThreadPool Executor
from concurrent.futures import ThreadPoolExecutor as PoolExecutor
import sys
import time
import glob
import requests
import threading
import uuid
import base64
import json
import os
#send http request
def call_object_detection_service(image):
try:
url = str(sys.argv[2])
data = {}
#generate uuid for image
id = uuid.uuid5(uuid.NAMESPACE_OID, image)
# Encode image into base64 string
with open (image, 'rb') as image_file:
data['image'] = base64.b64encode(image_file.read()).decode('utf-8')
data['id'] = str(id)
headers = {'Content-Type': 'application/json'}
response = requests.post(url, json= json.dumps(data), headers = headers)
if response.ok:
output = "Thread : {}, input image: {}, output:{}".format(threading.current_thread().getName(),
image, response.text)
print(output)
else:
print ("Error, response status:{}".format(response))
except Exception as e:
print("Exception in webservice call: {}".format(e))
# gets list of all images path from the input folder
def get_images_to_be_processed(input_folder):
images = []
for image_file in glob.iglob(input_folder + "*.jpg"):
images.append(image_file)
return images
def main():
## provide argumetns-> input folder, url, number of wrokers
if len(sys.argv) != 4:
raise ValueError("Arguments list is wrong. Please use the following format: {} {} {} {}".
format("python iWebLens_client.py", "<input_folder>", "<URL>", "<number_of_workers>"))
input_folder = os.path.join(sys.argv[1], "")
images = get_images_to_be_processed(input_folder)
num_images = len(images)
num_workers = int(sys.argv[3])
start_time = time.time()
#craete a worker thread to invoke the requests in parallel
with PoolExecutor(max_workers=num_workers) as executor:
for _ in executor.map(call_object_detection_service, images):
pass
#elapsed_time = time.time() - start_time
#print("Total time spent: {} average response time: {}".format(elapsed_time, elapsed_time/num_images))
if __name__ == "__main__":
main()
I decode them like so
Flask App
app = Flask(__name__)
c = 1
#app.route('/api/object_detection', methods = ['POST'])
def main():
global c
try:
data = request.get_json(force=True)
uid = data.get('id')
image = data.get('image')
print(image)
im = base64.decodebytes(image)
with open("image{}".format(c), 'wb') as f:
f.write(im)
c += 1
for l in range(128):
img = cv2.imread("image{}".format(l), cv2.IMREAD_ANYCOLOR);
# load the neural net. Should be local to this method as its multi-threaded endpoint
nets = load_model(CFG, Weights)
s = do_prediction(img, nets, Lables)
return jsonify(s)
except Exception as e:
print(e)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, threaded=True)
This creates the image files with different sizes but I cannot view them in image viewer. The files being recieved are jpg files. Ignoring that, I went ahead with the processing and I get
TypeError: The view function for 'main' did not return a valid response. The function either returned None or ended without a return statement.
Incorrect padding
Incorrect padding
[INFO] loading YOLO from disk...
'NoneType' object has no attribute 'shape'
Images are being sent like this.
python iWebLens_client.py inputfolder/ http://192.168.29.75:5000/api/object_detection 4
The images are being received like this.
b'"{\\"image\\": \\"/9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA......fiU05tQopHNf//Z\\", \\"id\\": \\"e3ad9809-b84c-57f1-bd03-a54e25c59bcc\\"}"'
I am thinking I need to decode('utf-8') this, but don't know how.
Currently, you are double-coding the data on the client side. Within requests, the argument passed is already converted to JSON.
Just pass the dict on as a json parameter.
def call_object_detection_service(image):
try:
url = str(sys.argv[2])
data = {}
#generate uuid for image
id = uuid.uuid5(uuid.NAMESPACE_OID, image)
# Encode image into base64 string
with open (image, 'rb') as image_file:
data['image'] = base64.b64encode(image_file.read()).decode('utf-8')
data['id'] = str(id)
headers = {'Content-Type': 'application/json'}
# HERE IS THE CHANGE !!!
response = requests.post(url, json=data, headers=headers)
if response.ok:
output = "Thread : {}, input image: {}, output:{}".format(
threading.current_thread().getName(),
image,
response.text
)
print(output)
else:
print ("Error, response status:{}".format(response))
except Exception as e:
print("Exception in webservice call: {}".format(e))
The data can now be received on the server as JSON and extracted into a dict.
#app.route('/api/object_detection', methods=['POST'])
def main():
data = request.get_json(force=True)
uid = data.get('id')
image = data.get('image')
# ... decode the base64 data here ...
return jsonify(message='done')

Aiogram python InlineKeyboard

I have some code:
master = InlineKeyboardMarkup()
master.add(InlineKeyboardButton(text='7(800)555-35-35', url='tel:+78005553535'),
InlineKeyboardButton(text='8(800)555-35-35', url='tel:+88005553535'))
But when I try to summon this keyboard I have an error:
aiogram.utils.exceptions.BadRequest: Wrong http url
You need to write the code as follows:
main.py
from aiogram
import Bot, Dispatcher, executor, types
import keyboards as kb
bot = Bot(token = 'BOT_TOKEN')
dp = Dispatcher(bot)
#dp.message_handler(commands = ['inline'])
async def show_items(message: types.Message):
await message.answer('It is buttons', reply_markup = kb.start_keyboard)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates = True)
keybords.py
from aiogram.types
import ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton
inline_keyboard = InlineKeyboardButton(text='7(800)555-35-35', url = 'tel:+78005553535'),
InlineKeyboardButton(text='8(800)555-35-35', url = 'tel:+88005553535')
start_keyboard = ReplyKeyboardMarkup(resize_keyboard = True).add(inline_keyboard)

Telegram bot can't receive multiple pics at one message

I want to setup a telegram bot for receiving multiple images in one message. My bot can receive only the first image, all others are ignored. Here is my code:
# -*- coding: utf-8 -*-
import config
import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton, InputMediaPhoto
bot = telebot.TeleBot(config.token)
main_menu_keyboard = telebot.types.ReplyKeyboardMarkup(True,True)
main_menu_keyboard.add('test1', 'test2')
welcome_message='''Hello,
dude
'''
dict = {}
class nameDict:
def __init__(self, name):
self.name = name
self.media = None
def process_name_step(message):
try:
chat_id = message.chat.id
name = message.text
upload = nameDict(name)
dict[chat_id] = upload
message = bot.send_message(chat_id, 'Upload your photos: ')
bot.register_next_step_handler(message, process_media_step)
except Exception as e:
bot.reply_to(message, 'Error...')
def process_media_step(message):
try:
chat_id = message.chat.id
media = message.photo[-1].file_id
upload = dict[chat_id]
upload.media = media
bot.send_photo(chat_id, str(upload.media))
except Exception as e:
bot.reply_to(message, 'Error...')
bot.register_next_step_handler(message, process_media_step)
bot.enable_save_next_step_handlers(delay=2)
bot.load_next_step_handlers()
#bot.message_handler(commands=['start'])
def start_message(message):
bot.send_message(message.chat.id, welcome_message, reply_markup=main_menu_keyboard)
#bot.message_handler(content_types=['text'])
def send_text(message):
if message.text.lower() == 'test1':
message = bot.send_message(message.chat.id, 'Enter youe name: ')
bot.register_next_step_handler(message, process_name_step)
elif message.text.lower() == 'test2':
bot.send_message(message.chat.id, 'Empty')
bot.polling()
Could you please me find a solution on how to receive multiple images in a single message to the bot?
Thanks!
I found a workaround just add a photo handler that saves them locally.
#bot.message_handler(content_types=['photo'])
def get_photo(message):
fileID = message.photo[-1].file_id
file_info = bot.get_file(fileID)
downloaded_file = bot.download_file(file_info.file_path)
user_path=str(message.from_user.id)
if not os.path.exists(user_path):
os.makedirs(user_path)
with open(str(message.from_user.id) + '/' + fileID, 'wb') as new_file:
new_file.write(downloaded_file)

Python Flask API - post and receive bytearray and metadata

I am creating an API to receive and process images. I have to receive the image in bytearray format. The following is my code to post:
Approach 1
Posting the image to api
with open("test.jpg", "rb") as imageFile:
f = imageFile.read()
b = bytearray(f)
url = 'http://127.0.0.1:5000/lastoneweek'
headers = {'Content-Type': 'application/octet-stream'}
res = requests.get(url, data=b, headers=headers)
##print received json response
print(res.text)
My API: Receiving image at api
#app.route('/lastoneweek', methods=['GET'])
def get():
img=request.files['data']
image = Image.open(io.BytesIO(img))
image=cv2.imread(image)
##do all image processing and return json response
Within my api I have tried, request.get['data'] request.params['data']....I am getting object has no attribute error.
I tried passing the bytearray to json along with width and height of the image like:
Approach 2:Posting image to api
data = '{"IMAGE":b,"WIDTH":16.5,"HEIGHT":20.5}'
url = 'http://127.0.0.1:5000/lastoneweek'
headers = {'Content-Type': 'application/json'}
res = requests.get(url, data=data, headers=headers)
and changed my get function at the API as
Receive image at api
#app.route('/lastoneweek', methods=['GET'])
def get():
data=request.get_json()
w = data['WIDTH']
h = data['HEIGHT']
but have received the following error for example:
TypeError: 'LocalProxy' does not have the buffer interface
server.py file:
from flask import Flask
from flask import request
import cv2
from PIL import Image
import io
import requests
import numpy as np
app = Flask(__name__)
#app.route('/lastoneweek', methods=['POST'])
def get():
print(request.files['image_data'])
img = request.files['image_data']
image = cv2.imread(img.filename)
rows, cols, channels = image.shape
M = cv2.getRotationMatrix2D((cols/2, rows/2), 90, 1)
dst = cv2.warpAffine(image, M, (cols, rows))
cv2.imwrite('output.png', dst)
##do all image processing and return json response
return 'image: success'
if __name__ == '__main__':
try:
app.run()
except Exception as e:
print(e)
with client.py file as:
import requests
with open("test.png", "rb") as imageFile:
# f = imageFile.read()
# b = bytearray(f)
url = 'http://127.0.0.1:5000/lastoneweek'
headers = {'Content-Type': 'application/octet-stream'}
try:
response = requests.post(url, files=[('image_data',('test.png', imageFile, 'image/png'))])
print(response.status_code)
print(response.json())
except Exception as e:
print(e)
# res = requests.put(url, files={'image': imageFile}, headers=headers)
# res = requests.get(url, data={'image': imageFile}, headers=headers)
##print received json response
print(response.text)
I referred this link: http://docs.python-requests.org/en/master/user/advanced/#post-multiple-multipart-encoded-files
This solves the first issue.
The line image = Image.open(io.BytesIO(img)) is wrong since img is a <class 'werkzeug.datastructures.FileStorage'> which should not be passed to io.BytesIO, since it takes bytes-like object as mentioned here: https://docs.python.org/3/library/io.html#io.BytesIO, and explanation of bytes-like object here: https://docs.python.org/3/glossary.html#term-bytes-like-object
So, instead of doing this. Passing filename directly to cv2.imread(img.filename) solved the issue.

Categories

Resources