Home > other >  how to pass a json String to a url using Flask
how to pass a json String to a url using Flask

Time:09-25

I did create a machine learning model using Pytorch which i want to use as a webservice using Flask. The problem is that i don't understand how i can pass a json-String to the url. Below is my code that I wrote to do some tryouts with my model and Flask:

from modelLoader import Model
from imageLoader import Img
import os
from flask import Flask, jsonify, request

app = Flask(__name__)
classes = ["dummy-image", "product-image"]
model_path = os.path.join("data", "models", "model1709", "model1709")
image_path = os.path.join("data", "images", "dummy_images")
m1 = Model(model_path, classes, "cpu")

@app.route('/predict', methods=['POST', 'GET'])
def predict():
    # case for handle json
    input_data = request.get_json()['url']
    if isinstance(input_data, list):
        for elem in input_data:
            img_elem = Img(url=elem)
            res = img_elem.get_prediction(m1)
        return jsonify({"type": "bulk_upload"})
    img_inpdata = Img(url=input_data)
    res, info = img_inpdata.get_prediction(m1)
    return jsonify({input_data: res, "info": str(info)})


if __name__ == '__main__':
    app.run(debug=True)

This would be a request that I want to make using this code:

POST http://192.168.178.13:5000/predict HTTP/1.1
Content-Type: application/json
Accept: application/json

{
    "url" : "https://socialistmodernism.com/wp-content/uploads/2017/07/placeholder-image.png"
}

How exactly can I get the prediction for the image inside the json-string, by passing this json-string to the application?


Here the two classes model and imageLoader for completeness:

from torch import argmax, device, load, nn

class Model:
    def __init__(self, path, class_list=None, dvc=None):
        if class_list is None:
            class_list = [0, 1]
        if dvc is None:
            dvc = 'cpu'
        self.class_list = class_list 
        self.model = load(path, map_location=device(dvc))
        num_ftrs = self.model.fc.in_features                  
        self.model.fc = nn.Linear(num_ftrs, len(class_list))  
        self.model.eval()

import torchvision.transforms as transforms
import io
from PIL import Image
from torch import argmax, device, load, nn
import requests

class Img:
    def __init__(self, url=None, image=None, image_bytes=None):
        if url:
            img = Image.open(requests.get(url, stream=True).raw)
            img_byte_arr = io.BytesIO()
            img.save(img_byte_arr, format=img.format)
            self.image_bytes = img_byte_arr.getvalue()
        elif image:
            f = image.read()
            self.image_bytes = bytearray(f)
        elif image_bytes:
            self.image_bytes = image_bytes

    def transform_image(self):
        data_transforms = transforms.Compose([transforms.Resize((224, 224)),
                                              transforms.CenterCrop(
                                                  224), transforms.ToTensor(),
                                              transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224,
                                                                                           0.225])])
        image = Image.open(io.BytesIO(self.image_bytes)).convert('RGB')
        return data_transforms(image).unsqueeze(0)

    def get_prediction(self, model):
        tensor = self.transform_image()
        output = (model.model(tensor))
        sm = nn.Softmax(output)
        best = output.argmax().item()
        return model.class_list[best], sm

CodePudding user response:

This is an example how I've implemented it for myself in the past:

Server part that receives json:

from flask import request
from flask import Response

@app.route('/stats/online', methods=['POST'])
def record_online_stats():    
    # ... validation before the mongo
    result = ws_mongo.process_online(request.get_data(as_text=True), token)
    if result:
        return Response(status=200)
    else:
        return Response(status=406)

Preparing and sending data from the client:

def __publish_game_stats():
    try:
        data = str(__get_game_stats_json())

        # Convert string to byte
        data = data.encode('utf-8')

        # Post Method is invoked if data != None
        headers = {'content-type': 'application/json', 'token': ''}
        req = request.Request(STATS_PUBLISHER_GAME_STATE_URL, data=data, headers=headers)

        # Response
        resp = request.urlopen(req)
        code = resp.getcode()
        return code

def __get_game_stats_json():
return json.dumps(_Game(),
                  default=lambda x: x.__dict__,
                  skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True,
                  cls=None, indent=None, separators=None, sort_keys=False)

Data-structure example (removed unnecessary parts):

class _Game(object):
    def __init__(self):
        self.map_name = ...
        self.teams = {}
        self.online = 0
        self.__init_teams()

    def __init_teams(self):
        for i in range(...):
            self.teams[i] = _Game.GTeam(i)
        # fill teams with players
        for x in range(...):
            p = _Game.GPlayer(name=..., uid=...)
            self.teams[team_id].players.append(p)

    class GTeam(object):
        def __init__(self, team_id):
            self.team_id = team_id
            self.team_name = ''

        def __str__(self):
            return str(self.__dict__)

    class GPlayer(object):
        def __init__(self, name: str, uid: int):
            self.name = name
            self.uid = uid

        def __str__(self):
            return str(self.__dict__)

    def __str__(self):
        return str(self.__dict__)

As you can see you can form a more complex structure (_Game has GTeam that has GPlayer) and then with the help of the __get_game_stats_json to form a json that can be sent to the server. As for me it was ok since I could operate with the classes and to persist them in the same time.

CodePudding user response:

I am sorry because I can't able to test it on my environment. But I noticed what you are doing wrong.

from modelLoader import Model
from imageLoader import Img
import os
from flask import Flask, jsonify, request

app = Flask(__name__)
classes = ["dummy-image", "product-image"]
model_path = os.path.join("data", "models", "model1709", "model1709")
image_path = os.path.join("data", "images", "dummy_images")
m1 = Model(model_path, classes, "cpu")

@app.route('/predict', methods=['POST', 'GET'])
def predict():
    # case for handle json
    input_data = request.get_json(force=True)['url'] #Try  force=True. Because many flask didn't extract the json from the request.
    if isinstance(input_data, list):
        for elem in input_data:
            img_elem = Img(url=elem)
            res = img_elem.get_prediction(m1)
        return jsonify({"type": "bulk_upload"})
    img_inpdata = Img(url=input_data)
    res, info = img_inpdata.get_prediction(m1)
    return jsonify({"input_data": res, "info": str(info)}) # You need to wrap it "" like "input_data"


if __name__ == '__main__':
    app.run(debug=True)

Try this and if still not works. Please consider sharing the logs. What really happening. Because it's really hard to get to know what's wrong happening with you flask app.

  • Related