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 uuid
from fastapi import HTTPException, Path, Query, Request, Response, UploadFile
from fastapi.routing import APIRouter
from fastapi.responses import FileResponse
from PIL import Image
from invokeai.app.models.image import (
ImageCategory,
ImageType,
)
from invokeai.app.services.image_record_storage import ImageRecordStorageBase
from invokeai.app.services.image_file_storage import ImageFileStorageBase
from invokeai.app.services.models.image_record import ImageRecord
from invokeai.app.services.models.image_record import ImageDTO, ImageUrlsDTO
from invokeai.app.services.item_storage import PaginatedResults
from ..dependencies import ApiDependencies
@ -32,7 +30,7 @@ async def upload_image(
request: Request,
response: Response,
image_category: ImageCategory = ImageCategory.IMAGE,
) -> ImageRecord:
) -> ImageDTO:
"""Uploads an image"""
if not file.content_type.startswith("image"):
raise HTTPException(status_code=415, detail="Not an image")
@ -40,38 +38,145 @@ async def upload_image(
contents = await file.read()
try:
img = Image.open(io.BytesIO(contents))
pil_image = Image.open(io.BytesIO(contents))
except:
# Error opening the image
raise HTTPException(status_code=415, detail="Failed to read image")
try:
image_record = ApiDependencies.invoker.services.images_new.create(
image=img,
image_type=image_type,
image_category=image_category,
image_dto = ApiDependencies.invoker.services.images_new.create(
pil_image,
image_type,
image_category,
)
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:
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")
async def delete_image_record(
async def delete_image(
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"""
"""Deletes an image"""
try:
ApiDependencies.invoker.services.images_new.delete(
image_type=image_type, image_name=image_name
)
ApiDependencies.invoker.services.images_new.delete(image_type, image_name)
except Exception as e:
# TODO: Does this need any exception handling at all?
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 .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 .invocations.baseinvocation import BaseInvocation
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(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")
# Build a custom OpenAPI to include all outputs

View File

@ -23,13 +23,21 @@ class ImageRecord(BaseModel):
)
class ImageDTO(ImageRecord):
"""Deserialized image record with URLs."""
class ImageUrlsDTO(BaseModel):
"""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.")
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(
image_record: ImageRecord, image_url: str, thumbnail_url: str
) -> ImageDTO:

View File

@ -25,6 +25,6 @@ class LocalUrlService(UrlServiceBase):
) -> str:
image_basename = os.path.basename(image_name)
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"