19
votes

Comment renvoyer une image dans fastAPI?

En utilisant le module python fastAPI , je ne peux pas comprendre comment renvoyer une image. Dans le flacon, je ferais quelque chose comme ceci:

@app.route("/vector_image", methods=["POST"])
def image_endpoint():
    # img = ... # Create the image here
    return Response(img, mimetype="image/png")

quel est l'appel correspondant dans ce module?


0 commentaires

6 Réponses :


12
votes

Ce n'est pas encore correctement documenté, mais vous pouvez utiliser n'importe quoi de Starlette.

Ainsi, vous pouvez utiliser un FileResponse s'il s'agit d'un fichier sur disque avec un chemin: https://www.starlette.io/responses/#fileresponse

S'il s'agit d'un objet de type fichier créé dans votre opération de chemin , dans la prochaine version stable de Starlette (utilisée en interne par FastAPI), vous pourrez également le renvoyer dans un StreamingResponse .


2 commentaires

Merci pour la réponse! Je l'ai fait fonctionner avec votre suggestion mais ce n'était pas facile (et probablement exagéré!). Voir ma solution ci-dessous. En dehors de ce problème, fastAPI a été un plaisir de travailler avec un très bien documenté, merci de l'avoir fourni!


J'ai également créé une balise pour votre bibliothèque dans la question. N'hésitez pas à le modifier et à le «regarder» pour voir les questions des autres utilisateurs.



10
votes

La réponse de @ SebastiánRamírez m'a orienté dans la bonne direction, mais pour ceux qui cherchent à résoudre le problème, j'avais besoin de quelques lignes de code pour le faire fonctionner. J'avais besoin d'importer FileResponse de starlette (pas de fastAPI?), D'ajouter le support CORS et de revenir à partir d'un fichier temporaire. Il existe peut-être un meilleur moyen, mais je n'ai pas pu faire fonctionner le streaming:

from starlette.responses import FileResponse
from starlette.middleware.cors import CORSMiddleware
import tempfile

app = FastAPI()
app.add_middleware(
    CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
)

@app.post("/vector_image")
def image_endpoint(*, vector):
    # Returns a raw PNG from the document vector (define here)
    img = my_function(vector)

    with tempfile.NamedTemporaryFile(mode="w+b", suffix=".png", delete=False) as FOUT:
        FOUT.write(img)
        return FileResponse(FOUT.name, media_type="image/png")


2 commentaires

pourriez-vous être plus précis s'il vous plaît? comme où est le nom du fichier? quel est l'article, où est l'itinéraire?


@PekoChan Vous avez raison, il me manquait certaines parties. J'essayais d'adapter le code que j'utilisais réellement à un exemple minimal. Je l'ai fait un peu trop minimal, j'espère que je l'ai corrigé.



25
votes

J'ai eu un problème similaire mais avec une image cv2. Cela peut être utile pour d'autres. Utilise StreamingResponse .

import io
from starlette.responses import StreamingResponse

app = FastAPI()

@app.post("/vector_image")
def image_endpoint(*, vector):
    # Returns a cv2 image array from the document vector
    cv2img = my_function(vector)
    res, im_png = cv2.imencode(".png", cv2img)
    return StreamingResponse(io.BytesIO(im_png.tobytes()), media_type="image/png")


2 commentaires

Merci! Je pense que c'est une bien meilleure réponse que mon hack qui nécessitait un fichier temporaire.


Si vous utilisez BytesIO particulier avec PIL / skimage, assurez-vous de faire également img.seek(0) avant de retourner!



6
votes

Merci à la réponse de @ biophetik, avec un rappel important qui m'a semé la confusion: si vous utilisez BytesIO particulier avec PIL / skimage, assurez-vous de faire également img.seek(0) avant de revenir!

@app.get("/generate")
def generate(data: str):
  img = generate_image(data)
  print('img=%s' % (img.shape,))
  buf = BytesIO()
  imsave(buf, img, format='JPEG', quality=100)
  buf.seek(0) # important here!
  return StreamingResponse(buf, media_type="image/jpeg",
    headers={'Content-Disposition': 'inline; filename="%s.jpg"' %(data,)})


0 commentaires

8
votes

Toutes les autres réponses sont sur le point, mais maintenant il est si facile de renvoyer une image

from fastapi.responses import FileResponse

@app.get("/")
async def main():
    return FileResponse("your_image.jpeg")


0 commentaires

0
votes

Vous pouvez faire quelque chose de très similaire dans FastAPI

from fastapi import FastAPI, Response

app = FastAPI()

@app.post("/vector_image/")
async def image_endpoint():
    # img = ... # Create the image here
    return Response(content=img, media_type="image/png")


0 commentaires