Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4407650
Added backend and frontend support for a modal image search dialog
JPPhoto Feb 14, 2026
e3ebb6e
Fixed 'All Boards' selection
JPPhoto Feb 15, 2026
e6dc69f
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Feb 16, 2026
50990e1
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Feb 21, 2026
0e1eba2
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Feb 23, 2026
350326f
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Feb 24, 2026
f5bb034
Updated schema / ruff
JPPhoto Feb 24, 2026
91b45a9
ruff format
JPPhoto Feb 24, 2026
4084472
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Feb 25, 2026
ca7d671
Merge branch 'main' into search-modal
JPPhoto Feb 26, 2026
45dc4c6
Merge branch 'main' into search-modal
JPPhoto Feb 27, 2026
7672d77
Merge branch 'main' into search-modal
JPPhoto Feb 27, 2026
f404702
Fixed indentation
JPPhoto Feb 27, 2026
e99a133
Merge branch 'main' into search-modal
JPPhoto Feb 28, 2026
bed7a82
Merge branch 'main' into search-modal
JPPhoto Mar 2, 2026
30b8e73
Merge branch 'main' into search-modal
JPPhoto Mar 9, 2026
ef66566
Merge branch 'main' into search-modal
JPPhoto Mar 10, 2026
7c7b06e
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Mar 11, 2026
fca755e
Added tests for search filters
JPPhoto Mar 11, 2026
38e64f5
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Mar 11, 2026
fcfc94a
Merge branch 'main' into search-modal
JPPhoto Mar 20, 2026
686fed1
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Mar 24, 2026
83c8784
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Mar 24, 2026
00e618b
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Mar 24, 2026
339fc06
Merge branch 'invoke-ai:main' into search-modal
JPPhoto Mar 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 118 additions & 1 deletion invokeai/app/api/routers/images.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import io
import json
import traceback
from typing import ClassVar, Optional
from typing import ClassVar, Literal, Optional

from fastapi import BackgroundTasks, Body, HTTPException, Path, Query, Request, Response, UploadFile
from fastapi.responses import FileResponse
Expand Down Expand Up @@ -38,6 +38,19 @@
IMAGE_MAX_AGE = 31536000


class ImageSearchBody(BaseModel):
file_name_term: Optional[str] = Field(default=None)
metadata_term: Optional[str] = Field(default=None)
width_min: Optional[int] = Field(default=None)
width_max: Optional[int] = Field(default=None)
width_exact: Optional[int] = Field(default=None)
height_min: Optional[int] = Field(default=None)
height_max: Optional[int] = Field(default=None)
height_exact: Optional[int] = Field(default=None)
board_ids: Optional[list[str]] = Field(default=None)
starred_mode: Literal["include", "exclude", "only"] = Field(default="include")


class ResizeToDimensions(BaseModel):
width: int = Field(..., gt=0)
height: int = Field(..., gt=0)
Expand Down Expand Up @@ -389,6 +402,18 @@ async def list_image_dtos(
order_dir: SQLiteDirection = Query(default=SQLiteDirection.Descending, description="The order of sort"),
starred_first: bool = Query(default=True, description="Whether to sort by starred images first"),
search_term: Optional[str] = Query(default=None, description="The term to search for"),
file_name_term: Optional[str] = Query(default=None, description="File name search term"),
metadata_term: Optional[str] = Query(default=None, description="Metadata search term"),
width_min: Optional[int] = Query(default=None, description="Minimum image width"),
width_max: Optional[int] = Query(default=None, description="Maximum image width"),
width_exact: Optional[int] = Query(default=None, description="Exact image width"),
height_min: Optional[int] = Query(default=None, description="Minimum image height"),
height_max: Optional[int] = Query(default=None, description="Maximum image height"),
height_exact: Optional[int] = Query(default=None, description="Exact image height"),
board_ids: Optional[list[str]] = Query(default=None, description="Boards to include, supports 'none'"),
starred_mode: Literal["include", "exclude", "only"] = Query(
default="include", description="How to handle starred images"
),
) -> OffsetPaginatedResults[ImageDTO]:
"""Gets a list of image DTOs for the current user"""

Expand All @@ -402,6 +427,16 @@ async def list_image_dtos(
is_intermediate,
board_id,
search_term,
file_name_term,
metadata_term,
width_min,
width_max,
width_exact,
height_min,
height_max,
height_exact,
board_ids,
starred_mode,
current_user.user_id,
)

Expand Down Expand Up @@ -591,6 +626,18 @@ async def get_image_names(
order_dir: SQLiteDirection = Query(default=SQLiteDirection.Descending, description="The order of sort"),
starred_first: bool = Query(default=True, description="Whether to sort by starred images first"),
search_term: Optional[str] = Query(default=None, description="The term to search for"),
file_name_term: Optional[str] = Query(default=None, description="File name search term"),
metadata_term: Optional[str] = Query(default=None, description="Metadata search term"),
width_min: Optional[int] = Query(default=None, description="Minimum image width"),
width_max: Optional[int] = Query(default=None, description="Maximum image width"),
width_exact: Optional[int] = Query(default=None, description="Exact image width"),
height_min: Optional[int] = Query(default=None, description="Minimum image height"),
height_max: Optional[int] = Query(default=None, description="Maximum image height"),
height_exact: Optional[int] = Query(default=None, description="Exact image height"),
board_ids: Optional[list[str]] = Query(default=None, description="Boards to include, supports 'none'"),
starred_mode: Literal["include", "exclude", "only"] = Query(
default="include", description="How to handle starred images"
),
) -> ImageNamesResult:
"""Gets ordered list of image names with metadata for optimistic updates"""

Expand All @@ -603,6 +650,16 @@ async def get_image_names(
is_intermediate=is_intermediate,
board_id=board_id,
search_term=search_term,
file_name_term=file_name_term,
metadata_term=metadata_term,
width_min=width_min,
width_max=width_max,
width_exact=width_exact,
height_min=height_min,
height_max=height_max,
height_exact=height_exact,
board_ids=board_ids,
starred_mode=starred_mode,
user_id=current_user.user_id,
is_admin=current_user.is_admin,
)
Expand All @@ -611,6 +668,66 @@ async def get_image_names(
raise HTTPException(status_code=500, detail="Failed to get image names")


@images_router.post("/search", operation_id="search_images", response_model=OffsetPaginatedResults[ImageDTO])
async def search_images(
body: ImageSearchBody,
image_origin: Optional[ResourceOrigin] = Query(default=None),
categories: Optional[list[ImageCategory]] = Query(default=None),
is_intermediate: Optional[bool] = Query(default=None),
offset: int = Query(default=0),
limit: int = Query(default=100),
order_dir: SQLiteDirection = Query(default=SQLiteDirection.Descending),
starred_first: bool = Query(default=True),
) -> OffsetPaginatedResults[ImageDTO]:
return ApiDependencies.invoker.services.images.get_many(
offset=offset,
limit=limit,
starred_first=starred_first,
order_dir=order_dir,
image_origin=image_origin,
categories=categories,
is_intermediate=is_intermediate,
file_name_term=body.file_name_term,
metadata_term=body.metadata_term,
width_min=body.width_min,
width_max=body.width_max,
width_exact=body.width_exact,
height_min=body.height_min,
height_max=body.height_max,
height_exact=body.height_exact,
board_ids=body.board_ids,
starred_mode=body.starred_mode,
)


@images_router.post("/search/names", operation_id="search_image_names", response_model=ImageNamesResult)
async def search_image_names(
body: ImageSearchBody,
image_origin: Optional[ResourceOrigin] = Query(default=None),
categories: Optional[list[ImageCategory]] = Query(default=None),
is_intermediate: Optional[bool] = Query(default=None),
order_dir: SQLiteDirection = Query(default=SQLiteDirection.Descending),
starred_first: bool = Query(default=True),
) -> ImageNamesResult:
return ApiDependencies.invoker.services.images.get_image_names(
starred_first=starred_first,
order_dir=order_dir,
image_origin=image_origin,
categories=categories,
is_intermediate=is_intermediate,
file_name_term=body.file_name_term,
metadata_term=body.metadata_term,
width_min=body.width_min,
width_max=body.width_max,
width_exact=body.width_exact,
height_min=body.height_min,
height_max=body.height_max,
height_exact=body.height_exact,
board_ids=body.board_ids,
starred_mode=body.starred_mode,
)


@images_router.post(
"/images_by_names",
operation_id="get_images_by_names",
Expand Down
20 changes: 20 additions & 0 deletions invokeai/app/services/image_records/image_records_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ def get_many(
is_intermediate: Optional[bool] = None,
board_id: Optional[str] = None,
search_term: Optional[str] = None,
file_name_term: Optional[str] = None,
metadata_term: Optional[str] = None,
width_min: Optional[int] = None,
width_max: Optional[int] = None,
width_exact: Optional[int] = None,
height_min: Optional[int] = None,
height_max: Optional[int] = None,
height_exact: Optional[int] = None,
board_ids: Optional[list[str]] = None,
starred_mode: Optional[str] = None,
user_id: Optional[str] = None,
is_admin: bool = False,
) -> OffsetPaginatedResults[ImageRecord]:
Expand Down Expand Up @@ -112,6 +122,16 @@ def get_image_names(
is_intermediate: Optional[bool] = None,
board_id: Optional[str] = None,
search_term: Optional[str] = None,
file_name_term: Optional[str] = None,
metadata_term: Optional[str] = None,
width_min: Optional[int] = None,
width_max: Optional[int] = None,
width_exact: Optional[int] = None,
height_min: Optional[int] = None,
height_max: Optional[int] = None,
height_exact: Optional[int] = None,
board_ids: Optional[list[str]] = None,
starred_mode: Optional[str] = None,
user_id: Optional[str] = None,
is_admin: bool = False,
) -> ImageNamesResult:
Expand Down
Loading
Loading