Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: Unable to request PILImage with Content-Type image/jpeg with new Service decorator #4651

Open
adrian-arapiles opened this issue Apr 11, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@adrian-arapiles
Copy link

Describe the bug

Unable to get an endpoint with PILImage without Content-Type:multipart/form-data with new Service decorator

To reproduce

I already have working code with bentoml 1.1.11, runners, yolo/pytorch model.
I'm trying to migrate to new decorators @bentoml.service and @bentoml.api to use concurrency feature introduced.

Bentoml version tested: [1.2.9, 1.2.10].

All examples running with bentoml serve -p 8000 service.py:Service.

My working code with 1.1.11 and 1.2.10 with Runner/Runnable looks like

from bentoml.io import Image, JSON


my_runnable = bentoml.Runner(
    MyRunnable,
    name="runnable"
)
svc = bentoml.Service("runnable", runners=[my_runnable])


@svc.api(input=Image(), output=JSON(), route="/v1/inference")
async def inference(image: Image):
        #ofuscated code for prepare image, inference, build response and return
        return output_json

An example curl to before code is

curl -X 'POST' \
        'http://localhost:8000/v1/inference' \
        -H 'accept: application/json' \
           -H 'Content-Type: image/jpeg' \
              --data-binary '@/path/to/my/image.jpg'

Now, I'm trying to migrate to new decorators and my code looks like

from src.Service import Service
from PIL.Image import Image as PILImage


@bentoml.service()
class Service:
    # this class is a sustitute of MyRunnable class. 
    my_new_service = bentoml.depends(Service)

    @bentoml.api(
        route="/v1/debug"
    )
    async def debug(
            self,
            image: PILImage = Field(description="Image to be processed")
    ):
        return {"width": image.width, "height": image.height}

Now my curl for this code (extracted from swagger) is

curl -X 'POST' \
  'http://localhost:8000/v1/inference' \
  -H 'accept: application/json' \
  -H 'Content-Type: multipart/form-data' \
  -F 'image=@/path/to/my/image.jpg'

The code is working, but I don't want to change the endpoint call from Content-Type: image/jpeg to Content-Type: multipart/form-data.

I tried this:

# This is the using the same Image() that `@svc.api(input=Image()` old decorator uses

from bentoml.io import Image
from PIL.Image import Image as PILImage
from src.Service import Service

@bentoml.service()
class Service:
    # this class is a sustitute of MyRunnable class. 
    my_new_service = bentoml.depends(Service)

    @bentoml.api(
        input_spec=Image(),
        route="/v1/debug"
    )
    async def debug(
            self,
            image: PILImage = Field(description="Image to be processed")
    ):
        return {"width": image.width, "height": image.height}

With the following errors:

  File "/.../service.py", line 34, in <module>
    class Service:
  File "/.../service.py", line 37, in Service
    @bentoml.api(
     ^^^^^^^^^^^^
  File "/.../_bentoml_sdk/decorators.py", line 101, in wrapper
    return APIMethod(func, **params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<attrs generated init _bentoml_sdk.method.APIMethod>", line 13, in __init__
  File "/.../_bentoml_sdk/method.py", line 36, in _io_descriptor_converter
    raise ValueError(f"{it} must be a class type")
ValueError: Image must be a class type

I already tried this:

# This is the using the Annotated example in documentation

from typing import Annotated
from bentoml.validators import ContentType
from PIL.Image import Image as PILImage
from src.Service import Service

@bentoml.service()
class Service:
    # this class is a sustitute of MyRunnable class. 
    my_new_service = bentoml.depends(Service)

    @bentoml.api(
        route="/v1/debug"
    )
    async def debug(
            self,
            image: Annotated[PILImage, ContentType('image/jpeg')]
    ):
        return {"width": image.width, "height": image.height}

This code is working too but the same mentioned problem, changed Content-Type to multipart.

I'm not sure if it is a bug or not. It's possible just I was missing something.

The motivation to upgrade to new decorators is the use of concurrency feature introduced.
Is there any way to use with old Runners way?

I really appreciated some help there.

Thanks in advance,
Adrián.

Expected behavior

Using PILImage or bentoml.io.Image in the same way and with the same endpoint result.

Environment

bentoml: 1.2.9 and 1.2.10
python: 3.11.8
platform: Macos Sonoma 14.4.1. M1 PRO cpu.

@adrian-arapiles adrian-arapiles added the bug Something isn't working label Apr 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant