Skip to content

feat: new workflow library #7710

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

Merged
merged 33 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
226b726
another new workflow library
Feb 27, 2025
ff7602f
break out actions, start on marketplace categories
Feb 28, 2025
100ef95
add comments
Feb 28, 2025
52c6e52
fix(ui): ts issues
psychedelicious Mar 4, 2025
e0310b5
fix(ui): show workflow thumbnails in library
psychedelicious Mar 4, 2025
91ab034
chore(ui): lint
psychedelicious Mar 4, 2025
1a73e58
fix(app): ensure workflow record get_many stmt is terminated
psychedelicious Mar 4, 2025
64d2f7a
tidy(app): workflow records get_many
psychedelicious Mar 4, 2025
9408411
feat(db): add generated column for tags in db migration
psychedelicious Mar 5, 2025
23c1317
feat(app): add searching by tags to workflow library APIs
psychedelicious Mar 5, 2025
14e66e5
fix(app): incorrect number of bindings for query
psychedelicious Mar 5, 2025
43ac523
chore(ui): bump RTKQ to latest to get infinite query support
psychedelicious Mar 5, 2025
a7a6583
feat(ui): set up RTKQ endpoint for infinite workflows list
psychedelicious Mar 5, 2025
93820de
feat(ui): workflow library modal styling
psychedelicious Mar 5, 2025
4f01496
feat(ui): simpler workflow action buttons
psychedelicious Mar 5, 2025
d758946
feat(ui): workflow library infinite scrolling
psychedelicious Mar 5, 2025
dca4e3e
feat(app): add workflow library get_counts method
psychedelicious Mar 6, 2025
c6495a9
chore(ui): typegen
psychedelicious Mar 6, 2025
9fe5730
chore: update default workflow tags
psychedelicious Mar 6, 2025
92e2929
feat(ui): workflow library tags
psychedelicious Mar 6, 2025
a25e1d5
tweak(ui): workflow tag names
psychedelicious Mar 6, 2025
83aef03
feat(ui): workflow library styling
psychedelicious Mar 6, 2025
321ffe1
fix(ui): workflow library overflow
psychedelicious Mar 6, 2025
d1b0a54
fix(ui): missing translation
psychedelicious Mar 6, 2025
7c53eec
chore(ui): lint
psychedelicious Mar 6, 2025
8e3e584
feat(ui): restore share workflow button
psychedelicious Mar 6, 2025
7a1cc5a
feat(ui): restore upload workflow button
psychedelicious Mar 6, 2025
36f592a
feat(app): add update_opened_at method for workflows
psychedelicious Mar 6, 2025
575aa24
chore(ui): lint
psychedelicious Mar 6, 2025
1a9370b
feat(ui): rough out recent workflows
psychedelicious Mar 6, 2025
be5770e
feat(ui): restore new workflow button
psychedelicious Mar 6, 2025
f6645a2
chore(ui): lint
psychedelicious Mar 6, 2025
dccce9d
chore: ruff
psychedelicious Mar 6, 2025
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
32 changes: 30 additions & 2 deletions invokeai/app/api/routers/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,20 @@ async def list_workflows(
default=WorkflowRecordOrderBy.Name, description="The attribute to order by"
),
direction: SQLiteDirection = Query(default=SQLiteDirection.Ascending, description="The direction to order by"),
category: WorkflowCategory = Query(default=WorkflowCategory.User, description="The category of workflow to get"),
categories: Optional[list[WorkflowCategory]] = Query(default=None, description="The categories of workflow to get"),
tags: Optional[list[str]] = Query(default=None, description="The tags of workflow to get"),
query: Optional[str] = Query(default=None, description="The text to query by (matches name and description)"),
) -> PaginatedResults[WorkflowRecordListItemWithThumbnailDTO]:
"""Gets a page of workflows"""
workflows_with_thumbnails: list[WorkflowRecordListItemWithThumbnailDTO] = []
workflows = ApiDependencies.invoker.services.workflow_records.get_many(
order_by=order_by, direction=direction, page=page, per_page=per_page, query=query, category=category
order_by=order_by,
direction=direction,
page=page,
per_page=per_page,
query=query,
categories=categories,
tags=tags,
)
for workflow in workflows.items:
workflows_with_thumbnails.append(
Expand Down Expand Up @@ -212,3 +219,24 @@ async def get_workflow_thumbnail(
return response
except Exception:
raise HTTPException(status_code=404)


@workflows_router.get("/counts", operation_id="get_counts")
async def get_counts(
tags: Optional[list[str]] = Query(default=None, description="The tags to include"),
categories: Optional[list[WorkflowCategory]] = Query(default=None, description="The categories to include"),
) -> int:
"""Gets a the count of workflows that include the specified tags and categories"""

return ApiDependencies.invoker.services.workflow_records.get_counts(tags=tags, categories=categories)


@workflows_router.put(
"/i/{workflow_id}/opened_at",
operation_id="update_opened_at",
)
async def update_opened_at(
workflow_id: str = Path(description="The workflow to update"),
) -> None:
"""Updates the opened_at field of a workflow"""
ApiDependencies.invoker.services.workflow_records.update_opened_at(workflow_id)
2 changes: 2 additions & 0 deletions invokeai/app/services/shared/sqlite/sqlite_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_14 import build_migration_14
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_15 import build_migration_15
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_16 import build_migration_16
from invokeai.app.services.shared.sqlite_migrator.migrations.migration_17 import build_migration_17
from invokeai.app.services.shared.sqlite_migrator.sqlite_migrator_impl import SqliteMigrator


Expand Down Expand Up @@ -55,6 +56,7 @@ def init_db(config: InvokeAIAppConfig, logger: Logger, image_files: ImageFileSto
migrator.register_migration(build_migration_14())
migrator.register_migration(build_migration_15())
migrator.register_migration(build_migration_16())
migrator.register_migration(build_migration_17())
migrator.run_migrations()

return db
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sqlite3

from invokeai.app.services.shared.sqlite_migrator.sqlite_migrator_common import Migration


class Migration17Callback:
def __call__(self, cursor: sqlite3.Cursor) -> None:
self._add_workflows_tags_col(cursor)

def _add_workflows_tags_col(self, cursor: sqlite3.Cursor) -> None:
"""
- Adds `tags` column to the workflow_library table. It is a generated column that extracts the tags from the
workflow JSON.
"""

cursor.execute(
"ALTER TABLE workflow_library ADD COLUMN tags TEXT GENERATED ALWAYS AS (json_extract(workflow, '$.tags')) VIRTUAL;"
)


def build_migration_17() -> Migration:
"""
Build the migration from database version 16 to 17.

This migration does the following:
- Adds `tags` column to the workflow_library table. It is a generated column that extracts the tags from the
workflow JSON.
"""
migration_17 = Migration(
from_version=16,
to_version=17,
callback=Migration17Callback(),
)

return migration_17
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Sample workflow for using Upscaling with ControlNet with SD1.5",
"version": "2.1.0",
"contact": "[email protected]",
"tags": "upscale, controlnet, default",
"tags": "upscaling, controlnet, default",
"notes": "",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "A simple image-to-image workflow using a FLUX dev model. ",
"version": "1.1.0",
"contact": "",
"tags": "image2image, flux, image-to-image",
"tags": "image2image, flux, image-to-image, image to image",
"notes": "Prerequisite model downloads: T5 Encoder, CLIP-L Encoder, and FLUX VAE. Quantized and un-quantized versions can be found in the starter models tab within your Model Manager. We recommend using FLUX dev models for image-to-image workflows. The image-to-image performance with FLUX schnell models is poor.",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "A simple text-to-image workflow using FLUX dev or schnell models.",
"version": "1.1.0",
"contact": "",
"tags": "text2image, flux",
"tags": "text2image, flux, text to image",
"notes": "Prerequisite model downloads: T5 Encoder, CLIP-L Encoder, and FLUX VAE. Quantized and un-quantized versions can be found in the starter models tab within your Model Manager. We recommend 4 steps for FLUX schnell models and 30 steps for FLUX dev models.",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Sample workflow using Prompt from File node",
"version": "2.1.0",
"contact": "[email protected]",
"tags": "text2image, prompt from file, default",
"tags": "text2image, prompt from file, default, text to image",
"notes": "",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Sample text to image workflow for Stable Diffusion 3.5",
"version": "1.0.0",
"contact": "[email protected]",
"tags": "text2image, SD3.5, default",
"tags": "text2image, SD3.5, text to image",
"notes": "",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Sample text to image workflow for Stable Diffusion 1.5/2",
"version": "2.1.0",
"contact": "[email protected]",
"tags": "text2image, SD1.5, SD2, default",
"tags": "text2image, SD1.5, SD2, text to image",
"notes": "",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Sample text to image workflow for SDXL",
"version": "2.1.0",
"contact": "[email protected]",
"tags": "text2image, SDXL, default",
"tags": "text2image, SDXL, text to image",
"notes": "",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Simple text to image workflow with a LoRA",
"version": "2.1.0",
"contact": "[email protected]",
"tags": "text to image, lora, default",
"tags": "text to image, lora, text to image",
"notes": "",
"exposedFields": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,25 @@ def get_many(
self,
order_by: WorkflowRecordOrderBy,
direction: SQLiteDirection,
category: WorkflowCategory,
categories: Optional[list[WorkflowCategory]],
page: int,
per_page: Optional[int],
query: Optional[str],
tags: Optional[list[str]],
) -> PaginatedResults[WorkflowRecordListItemDTO]:
"""Gets many workflows."""
pass

@abstractmethod
def get_counts(
self,
tags: Optional[list[str]],
categories: Optional[list[WorkflowCategory]],
) -> int:
"""Gets the count of workflows for the given tags and categories."""
pass

@abstractmethod
def update_opened_at(self, workflow_id: str) -> None:
"""Open a workflow."""
pass
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def from_dict(cls, data: dict[str, Any]) -> "WorkflowRecordDTO":
class WorkflowRecordListItemDTO(WorkflowRecordDTOBase):
description: str = Field(description="The description of the workflow.")
category: WorkflowCategory = Field(description="The description of the workflow.")
tags: str = Field(description="The tags of the workflow.")


WorkflowRecordListItemDTOValidator = TypeAdapter(WorkflowRecordListItemDTO)
Expand Down
Loading