feat(nodes): consolidate image routers

This commit is contained in:
psychedelicious 2023-05-22 12:46:37 +10:00 committed by Kent Keirsey
parent 11bd932cba
commit b9375186a5
6 changed files with 137 additions and 146 deletions

View File

@ -1,47 +0,0 @@
# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team
from fastapi import HTTPException, Path
from fastapi.responses import FileResponse
from fastapi.routing import APIRouter
from invokeai.app.models.image import ImageType
from ..dependencies import ApiDependencies
image_files_router = APIRouter(prefix="/v1/files/images", tags=["images", "files"])
@image_files_router.get("/{image_type}/{image_name}", operation_id="get_image")
async def get_image(
image_type: ImageType = Path(description="The type of the image to get"),
image_name: str = Path(description="The id of the image to get"),
) -> FileResponse:
"""Gets an image"""
try:
path = ApiDependencies.invoker.services.images_new.get_path(
image_type=image_type, image_name=image_name
)
return FileResponse(path)
except Exception as e:
raise HTTPException(status_code=404)
@image_files_router.get(
"/{image_type}/{image_name}/thumbnail", operation_id="get_thumbnail"
)
async def get_thumbnail(
image_type: ImageType = Path(
description="The type of the image whose thumbnail to get"
),
image_name: str = Path(description="The id of the image whose thumbnail to get"),
) -> FileResponse:
"""Gets a thumbnail"""
try:
path = ApiDependencies.invoker.services.images_new.get_path(
image_type=image_type, image_name=image_name, thumbnail=True
)
return FileResponse(path)
except Exception as e:
raise HTTPException(status_code=404)

View File

@ -1,71 +0,0 @@
from fastapi import HTTPException, Path, Query
from fastapi.routing import APIRouter
from invokeai.app.models.image import (
ImageCategory,
ImageType,
)
from invokeai.app.services.item_storage import PaginatedResults
from invokeai.app.services.models.image_record import ImageDTO
from ..dependencies import ApiDependencies
image_records_router = APIRouter(
prefix="/v1/images/records", tags=["images", "records"]
)
@image_records_router.get("/{image_type}/{image_name}", operation_id="get_image_record")
async def get_image_record(
image_type: ImageType = Path(description="The type of the image record to get"),
image_name: str = Path(description="The id of the image record to get"),
) -> ImageDTO:
"""Gets an image record by id"""
try:
return ApiDependencies.invoker.services.images_new.get_dto(
image_type=image_type, image_name=image_name
)
except Exception as e:
raise HTTPException(status_code=404)
@image_records_router.get(
"/",
operation_id="list_image_records",
)
async def list_image_records(
image_type: ImageType = Query(description="The type of image records to get"),
image_category: ImageCategory = Query(
description="The kind of image records to get"
),
page: int = Query(default=0, description="The page of image records to get"),
per_page: int = Query(
default=10, description="The number of image records per page"
),
) -> PaginatedResults[ImageDTO]:
"""Gets a list of image records by type and category"""
image_dtos = ApiDependencies.invoker.services.images_new.get_many(
image_type=image_type,
image_category=image_category,
page=page,
per_page=per_page,
)
return image_dtos
@image_records_router.delete("/{image_type}/{image_name}", operation_id="delete_image")
async def delete_image_record(
image_type: ImageType = Query(description="The type of image to delete"),
image_name: str = Path(description="The name of the image to delete"),
) -> None:
"""Deletes an image record"""
try:
ApiDependencies.invoker.services.images_new.delete(
image_type=image_type, image_name=image_name
)
except Exception as e:
# TODO: Does this need any exception handling at all?
pass

View File

@ -1,15 +1,13 @@
import io import io
import uuid
from fastapi import HTTPException, Path, Query, Request, Response, UploadFile from fastapi import HTTPException, Path, Query, Request, Response, UploadFile
from fastapi.routing import APIRouter from fastapi.routing import APIRouter
from fastapi.responses import FileResponse
from PIL import Image from PIL import Image
from invokeai.app.models.image import ( from invokeai.app.models.image import (
ImageCategory, ImageCategory,
ImageType, ImageType,
) )
from invokeai.app.services.image_record_storage import ImageRecordStorageBase from invokeai.app.services.models.image_record import ImageDTO, ImageUrlsDTO
from invokeai.app.services.image_file_storage import ImageFileStorageBase
from invokeai.app.services.models.image_record import ImageRecord
from invokeai.app.services.item_storage import PaginatedResults from invokeai.app.services.item_storage import PaginatedResults
from ..dependencies import ApiDependencies from ..dependencies import ApiDependencies
@ -32,7 +30,7 @@ async def upload_image(
request: Request, request: Request,
response: Response, response: Response,
image_category: ImageCategory = ImageCategory.IMAGE, image_category: ImageCategory = ImageCategory.IMAGE,
) -> ImageRecord: ) -> ImageDTO:
"""Uploads an image""" """Uploads an image"""
if not file.content_type.startswith("image"): if not file.content_type.startswith("image"):
raise HTTPException(status_code=415, detail="Not an image") raise HTTPException(status_code=415, detail="Not an image")
@ -40,38 +38,145 @@ async def upload_image(
contents = await file.read() contents = await file.read()
try: try:
img = Image.open(io.BytesIO(contents)) pil_image = Image.open(io.BytesIO(contents))
except: except:
# Error opening the image # Error opening the image
raise HTTPException(status_code=415, detail="Failed to read image") raise HTTPException(status_code=415, detail="Failed to read image")
try: try:
image_record = ApiDependencies.invoker.services.images_new.create( image_dto = ApiDependencies.invoker.services.images_new.create(
image=img, pil_image,
image_type=image_type, image_type,
image_category=image_category, image_category,
) )
response.status_code = 201 response.status_code = 201
response.headers["Location"] = image_record.image_url response.headers["Location"] = image_dto.image_url
return image_record return image_dto
except Exception as e: except Exception as e:
raise HTTPException(status_code=500) raise HTTPException(status_code=500, detail="Failed to create image")
@images_router.delete("/{image_type}/{image_name}", operation_id="delete_image") @images_router.delete("/{image_type}/{image_name}", operation_id="delete_image")
async def delete_image_record( async def delete_image(
image_type: ImageType = Query(description="The type of image to delete"), image_type: ImageType = Query(description="The type of image to delete"),
image_name: str = Path(description="The name of the image to delete"), image_name: str = Path(description="The name of the image to delete"),
) -> None: ) -> None:
"""Deletes an image record""" """Deletes an image"""
try: try:
ApiDependencies.invoker.services.images_new.delete( ApiDependencies.invoker.services.images_new.delete(image_type, image_name)
image_type=image_type, image_name=image_name
)
except Exception as e: except Exception as e:
# TODO: Does this need any exception handling at all? # TODO: Does this need any exception handling at all?
pass pass
@images_router.get(
"/{image_type}/{image_name}/record",
operation_id="get_image_record",
response_model=ImageDTO,
)
async def get_image_record(
image_type: ImageType = Path(description="The type of the image record to get"),
image_name: str = Path(description="The id of the image record to get"),
) -> ImageDTO:
"""Gets an image record by id"""
try:
return ApiDependencies.invoker.services.images_new.get_dto(
image_type, image_name
)
except Exception as e:
raise HTTPException(status_code=404)
@images_router.get("/{image_type}/{image_name}/image", operation_id="get_image")
async def get_image(
image_type: ImageType = Path(description="The type of the image to get"),
image_name: str = Path(description="The id of the image to get"),
) -> FileResponse:
"""Gets an image"""
try:
path = ApiDependencies.invoker.services.images_new.get_path(
image_type, image_name
)
return FileResponse(path)
except Exception as e:
raise HTTPException(status_code=404)
@images_router.get("/{image_type}/{image_name}/thumbnail", operation_id="get_thumbnail")
async def get_thumbnail(
image_type: ImageType = Path(
description="The type of the image whose thumbnail to get"
),
image_name: str = Path(description="The id of the image whose thumbnail to get"),
) -> FileResponse:
"""Gets a thumbnail"""
try:
path = ApiDependencies.invoker.services.images_new.get_path(
image_type, image_name, thumbnail=True
)
return FileResponse(path)
except Exception as e:
raise HTTPException(status_code=404)
@images_router.get(
"/{image_type}/{image_name}/urls",
operation_id="get_image_urls",
response_model=ImageUrlsDTO,
)
async def get_image_urls(
image_type: ImageType = Path(description="The type of the image whose URL to get"),
image_name: str = Path(description="The id of the image whose URL to get"),
) -> ImageUrlsDTO:
"""Gets an image and thumbnail URL"""
try:
image_url = ApiDependencies.invoker.services.images_new.get_url(
image_type, image_name
)
thumbnail_url = ApiDependencies.invoker.services.images_new.get_url(
image_type, image_name, thumbnail=True
)
return ImageUrlsDTO(
image_type=image_type,
image_name=image_name,
image_url=image_url,
thumbnail_url=thumbnail_url,
)
except Exception as e:
raise HTTPException(status_code=404)
@images_router.get(
"/",
operation_id="list_image_records",
response_model=PaginatedResults[ImageDTO],
)
async def list_image_records(
image_type: ImageType = Query(description="The type of image records to get"),
image_category: ImageCategory = Query(
description="The kind of image records to get"
),
page: int = Query(default=0, description="The page of image records to get"),
per_page: int = Query(
default=10, description="The number of image records per page"
),
) -> PaginatedResults[ImageDTO]:
"""Gets a list of image records by type and category"""
image_dtos = ApiDependencies.invoker.services.images_new.get_many(
image_type,
image_category,
page,
per_page,
)
return image_dtos

View File

@ -15,7 +15,7 @@ from fastapi_events.middleware import EventHandlerASGIMiddleware
from pydantic.schema import schema from pydantic.schema import schema
from .api.dependencies import ApiDependencies from .api.dependencies import ApiDependencies
from .api.routers import image_files, image_records, sessions, models, images from .api.routers import sessions, models, images
from .api.sockets import SocketIO from .api.sockets import SocketIO
from .invocations.baseinvocation import BaseInvocation from .invocations.baseinvocation import BaseInvocation
from .services.config import InvokeAIAppConfig from .services.config import InvokeAIAppConfig
@ -73,10 +73,6 @@ app.include_router(sessions.session_router, prefix="/api")
app.include_router(models.models_router, prefix="/api") app.include_router(models.models_router, prefix="/api")
app.include_router(image_files.image_files_router, prefix="/api")
app.include_router(image_records.image_records_router, prefix="/api")
app.include_router(images.images_router, prefix="/api") app.include_router(images.images_router, prefix="/api")
# Build a custom OpenAPI to include all outputs # Build a custom OpenAPI to include all outputs

View File

@ -23,13 +23,21 @@ class ImageRecord(BaseModel):
) )
class ImageDTO(ImageRecord): class ImageUrlsDTO(BaseModel):
"""Deserialized image record with URLs.""" """The URLs for an image and its thumbnaill"""
image_name: str = Field(description="The name of the image.")
image_type: ImageType = Field(description="The type of the image.")
image_url: str = Field(description="The URL of the image.") image_url: str = Field(description="The URL of the image.")
thumbnail_url: str = Field(description="The thumbnail URL of the image.") thumbnail_url: str = Field(description="The thumbnail URL of the image.")
class ImageDTO(ImageRecord, ImageUrlsDTO):
"""Deserialized image record with URLs."""
pass
def image_record_to_dto( def image_record_to_dto(
image_record: ImageRecord, image_url: str, thumbnail_url: str image_record: ImageRecord, image_url: str, thumbnail_url: str
) -> ImageDTO: ) -> ImageDTO:

View File

@ -25,6 +25,6 @@ class LocalUrlService(UrlServiceBase):
) -> str: ) -> str:
image_basename = os.path.basename(image_name) image_basename = os.path.basename(image_name)
if thumbnail: if thumbnail:
return f"{self._base_url}/files/images/{image_type.value}/{image_basename}/thumbnail" return f"{self._base_url}/images/{image_type.value}/{image_basename}/thumbnail"
return f"{self._base_url}/files/images/{image_type.value}/{image_basename}" return f"{self._base_url}/images/{image_type.value}/{image_basename}/image"