How to send base64 image using Python requests and FastAPI? - python

I am trying to make a code for image style transfer based on FastAPI. I found it effective to convert the byte of the image into base64 and transmit it.
So, I designed my client codeto encode the image into a base64 string and send it to the server, which received it succesfully. However, I face some difficulties in restoring the image bytes to ndarray.
I get the following this errors:
image_array = np.frombuffer(base64.b64decode(image_byte)).reshape(image_shape)
ValueError: cannot reshape array of size 524288 into shape (512,512,4)
This is my client code :
import base64
import requests
import numpy as np
import json
from matplotlib.pyplot import imread
from skimage.transform import resize
if __name__ == '__main__':
path_to_img = "my image path"
image = imread(path_to_img)
image = resize(image, (512, 512))
image_byte = base64.b64encode(image.tobytes())
data = {"shape": image.shape, "image": image_byte.decode()}
response = requests.get('http://127.0.0.1:8000/myapp/v1/filter/a', data=json.dumps(data))
and this is my server code:
import json
import base64
import uvicorn
import model_loader
import numpy as np
from fastapi import FastAPI
from typing import Optional
app = FastAPI()
#app.get("/")
def read_root():
return {"Hello": "World"}
#app.get("/myapp/v1/filter/a")
async def style_transfer(data: dict):
image_byte = data.get('image').encode()
image_shape = tuple(data.get('shape'))
image_array = np.frombuffer(base64.b64decode(image_byte)).reshape(image_shape)
if __name__ == '__main__':
uvicorn.run(app, port='8000', host="127.0.0.1")

Option 1
As previously mentioned here, as well as here and here, one should use UploadFile, in order to upload files from client apps (for async read/write have a look at this answer). For example:
server side:
#app.post("/upload")
def upload(file: UploadFile = File(...)):
try:
contents = file.file.read()
with open(file.filename, 'wb') as f:
f.write(contents)
except Exception:
return {"message": "There was an error uploading the file"}
finally:
file.file.close()
return {"message": f"Successfuly uploaded {file.filename}"}
client side:
import requests
url = 'http://127.0.0.1:8000/upload'
file = {'file': open('images/1.png', 'rb')}
resp = requests.post(url=url, files=file)
print(resp.json())
Option 2
If, however, you still need to send a base64 encoded image, you can do it as previously described here (Option 2). On client side, you can encode the image to base64 and send it using a POST request as follows:
client side:
import base64
import requests
url = 'http://127.0.0.1:8000/upload'
with open("photo.png", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
payload ={"filename": "photo.png", "filedata": encoded_string}
resp = requests.post(url=url, data=payload)
On server side you can receive the image using a Form field, and decode the image as follows:
server side:
#app.post("/upload")
def upload(filename: str = Form(...), filedata: str = Form(...)):
image_as_bytes = str.encode(filedata) # convert string to bytes
img_recovered = base64.b64decode(image_as_bytes) # decode base64string
try:
with open("uploaded_" + filename, "wb") as f:
f.write(img_recovered)
except Exception:
return {"message": "There was an error uploading the file"}
return {"message": f"Successfuly uploaded {filename}"}

Related

how do i send image files to server

The method i used is to send an image to a chatbot and enter the server.
I want to send the image to the server without going through the chatbot.
I'm encoding the image file into base64 and sending it to the same port, but 400 or 500 errors keep coming out.
I was going to send it this way.
import os
import glob
import requests
import base64
folder_path = "./images"
image_files = glob.glob(os.path.join(folder_path, "*.jpg")) +
glob.glob(os.path.join(folder_path, "*.jpeg")) +
glob.glob(os.path.join(folder_path, "*.png"))
url="http://000000000/"
headers = {'Content-type':'application/json; charset=utf-8'}
for file_path in image_files:
with open(file_path, "rb") as file:
file_content = file.read()
encoded_file = base64.b64encode(file_content).decode()
data = {"file": (os.path.basename(file_path), encoded_file)}
r = requests.post(url, files=data, headers=headers)
print(f'{os.path.basename(file_path)} sent with status code {r.status_code}')
error message is :
requests.exceptions.ChunkedEncodingError: ("Connection broken: ConnectionAbortedError(10053
it is using ocr system which is in server
since i have to change the method to send imgae files. i wrote those codes but it's not working

Trying to send an audio file and text to flask api but getting 400 bad request error

So, i am trying to send an audiofile and text as arguments to a flask api, it works fine when i send them through postman but i get a bad request error when i post it through python code.
Here is my python code:
import requests
import json
url= 'http://192.168.100.14:8000/v1/translate'
with open('/home/faizi/ai-chatbot-with-voice-driven-facial-animation/01_smalltalk_bot/game.wav', 'rb') as file:
files = {'input_file': file}
d = {"text":"hello, my name is faizan"}
req = requests.post(url, files=files, json=d)
print(req.status_code)
print(req.text)
And here is my flask api:
from flask import Flask
from flask_cors import cross_origin
from flask import Blueprint, request, Response
import json
from Voice_Cloning_Module import demo_cli
from flask import send_file
app = Flask("foo")
#app.route('/v1/translate', methods=['POST', 'OPTIONS'])
#cross_origin()
def translate_mbart():
data = request.get_json()
audio_file = request.files['input_file']
audio_file.save("./bufferaudiofile/"+audio_file.filename)
text = request.form['text']
returnedfile = demo_cli.clone(text,"./bufferaudiofile/"+audio_file.filename)
path_to_clonefile = returnedfile
return send_file(
path_to_clonefile,
mimetype="audio/wav",
as_attachment=True,
attachment_filename="test.wav")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
I am getting 400 bad request error and i dont understand what could be the issue, it works fine in postman
I was able to successfully send a wav file using the following code. I suggest stripping it back to bare bones and focussing on receiving the file to make sure nothing else is causing the issue.
For the API:
from flask import Flask
from flask import request
import json
app = Flask(__name__)
#app.route('/main', methods=['POST', 'OPTIONS'])
def main():
file = request.files['file']
print(file)
return { "ok": True }
if __name__ == '__main__':
app.run(host = 'localhost', port = 8000)
And for the request:
import requests
import json
url = 'http://localhost:8000/main'
with open('test_file.wav', 'rb') as wav:
files = { "file": wav }
d = { "body" : "Foo Bar" }
req = requests.post(url, files=files, json=d)
print(req.status_code)
print(req.text)

Python3 Flask API - Sending and receiving image as bytearray

I am using the following code to send images as byte array to a python3 flask api. When I am sending a image from the server which is serving the api, I get the response, though with some errors, however, when I send an image from an external machine to the server, I am getting getting an attribute error indicating that the image is not delivered. The following is the code and the error messages:
server.py
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.jpg', dst)
##do all image processing and return json response
return 'image: success'
if __name__ == '__main__':
try:
app.run(host="0.0.0.0",port=5000,debug=True,threaded=True)
except Exception as e:
print(e)
client.py
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.jpg', imageFile, 'image/jpg'))])
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)
When I send the image from the same machine which renders the api, I get the following message:
200
Expecting value: line 1 column 1 (char 0)
The intention is to save a file with the name 'output.jpg'. This is getting accomplished.
When I send the image from an external machine to the server, I get the error 500 with following message:
rows, cols, channels = image.shape
AttributeError: 'NoneType' object has no attribute 'shape'
indicating that the image had not reached the server. My images are around 2.5 MB each. I am afraid if the api gets triggered even before the complete bytearray is delivered.
How do I send images as bytearray and make opencv read the same. I am equally open to other options as well as long as it is python.

POST method to upload file with json object in python flask app

I am stuck in a problem where I am trying to build single API which will upload file along with json object. I need this API to create webhook.
Using multi part, I am able to upload file and in option filed I am able to send json object.
In flask app when I am trying to retrieve json object its converting as blob type. I tried to convert it base64 then again converting into string but whole process is not working.
Let me know if anyone has good solution I can combine file and json object together and fetch it by flask python app.
zz is the variable in my code where I am trying to store my json object. name is the field where I am passing my json object with file.
Thanks in advance.
My current code
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#app.route('/upload/',methods = ['POST'])
def upload():
customer_name='abc'
if request.method == 'POST':
zz=base64.b64encode(request.files['name'].read())
try:
file = request.files['file']
if file:
file.filename=customer_name+'_'+str(datetime.now())+'.'+file.filename.split('.')[-1]
filename = secure_filename(file.filename)
path=os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(path)
return jsonify({
'status':success,
'junk_data':[],
'message':error
})
except Exception as err:
logger.error(str(datetime.now())+' '+str(err))
return jsonify({
'status':False,
'junk_data':[],
'message':str(err)
})
if __name__ == '__main__':
app.run(host='localhost',debug=True, use_reloader=True,port=5000)
I have got the answer after lot R&D.
request format
//user any client-side
content-type:multipart/form-data
file: file need to upload
data: {"name":"abc","new_val":1}
python code to fetch from request object
data=json.loads(request.form.get('data'))
file = request.files['file']
Just send the file and json at once and let request handle the rest.
You can try the code below:
Server side:
import json
import os
from flask import Flask, request
from werkzeug import secure_filename
app = Flask(__name__)
#app.route('/test_api',methods=['GET','POST'])
def test_api():
uploaded_file = request.files['document']
data = json.load(request.files['data'])
filename = secure_filename(uploaded_file.filename)
uploaded_file.save(os.path.join('path/where/to/save', filename))
print(data)
return 'success'
if __name__ == '__main__':
app.run(host='localhost', port=8080)
Client Side:
import json
import requests
data = {'test1':1, 'test2':2}
filename = 'test.txt'
with open(filename, 'w') as f:
f.write('this is a test file\n')
url = "http://localhost:8080/test_api"
files = [
('document', (filename, open(filename, 'rb'), 'application/octet')),
('data', ('data', json.dumps(data), 'application/json')),
]
r = requests.post(url, files=files)
print(r)

Flask OpenCV Send and Receive Images in Bytes

I want to send and receive images in bytes in my flask API. I also want to send some json alongside the image. How can I achieve this?
Below is my current solution that does not work
flask:
#app.route('/add_face', methods=['GET', 'POST'])
def add_face():
if request.method == 'POST':
# print(request.json)
nparr = np.fromstring(request.form['img'], np.uint8)
print(request.form['img'])
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
cv2.imshow("frame", img)
cv2.waitKey(1)
return "list of names & faces"
client:
def save_encoding(img_file):
URL = "http://localhost:5000/add_face"
img = open(img_file, 'rb').read()
response = requests.post(URL, data={"name":"obama", "img":str(img)})
print(response.content)
produced error:
cv2.imshow("frame", img)
cv2.error: OpenCV(3.4.3) /io/opencv/modules/highgui/src/window.cpp:356: error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'imshow'
The following has worked for me.
I don't have the client code but I have a curl request. That should do the trick,
SERVER
from flask import request
from PIL import Image
import io
#app.route("/add_face", methods=["POST"])
def predict():
image = request.files["image"]
image_bytes = Image.open(io.BytesIO(image.read()))
CLIENT SIDE
curl -X POST -F image=#PATH/TO/FILE 'http://localhost:5000/add_face'
It is easier to send images in base64 format, by doing that you get rid of problems about sending/receiving binary data since you just work with a string. Also it is more convenient in web stuff. Tested code below:
Server side:
from flask import Flask, render_template, request
import pandas as pd
import cv2
import numpy as np
import base64
app = Flask(__name__)
#app.route('/add_face', methods=['GET', 'POST'])
def add_face():
if request.method == 'POST':
# read encoded image
imageString = base64.b64decode(request.form['img'])
# convert binary data to numpy array
nparr = np.fromstring(imageString, np.uint8)
# let opencv decode image to correct format
img = cv2.imdecode(nparr, cv2.IMREAD_ANYCOLOR);
cv2.imshow("frame", img)
cv2.waitKey(0)
return "list of names & faces"
if __name__ == '__main__':
app.run(debug=True, port=5000)
Client side:
import requests
import base64
URL = "http://localhost:5000/add_face"
# first, encode our image with base64
with open("block.png", "rb") as imageFile:
img = base64.b64encode(imageFile.read())
response = requests.post(URL, data={"name":"obama", "img":str(img)})
print(response.content)
You can use COLOR instead of ANYCOLOR if you are sure about your input images.

Categories