Skip to content

Commit aabf9bd

Browse files
authored
Merge branch 'main' into raster_layer_adjustments
2 parents b8f27f5 + 4be6ddb commit aabf9bd

File tree

345 files changed

+13949
-5254
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

345 files changed

+13949
-5254
lines changed

.github/pull_request_template.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818

1919
- [ ] _The PR has a short but descriptive title, suitable for a changelog_
2020
- [ ] _Tests added / updated (if applicable)_
21+
- [ ] _❗Changes to a redux slice have a corresponding migration_
2122
- [ ] _Documentation added / updated (if applicable)_
2223
- [ ] _Updated `What's New` copy (if doing a release after this PR)_

.github/workflows/frontend-checks.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,20 @@ jobs:
8383
if: ${{ steps.changed-files.outputs.frontend_any_changed == 'true' || inputs.always_run == true }}
8484
run: 'pnpm lint:knip'
8585
shell: bash
86+
87+
- name: translations
88+
if: ${{ steps.changed-files.outputs.frontend_any_changed == 'true' || inputs.always_run == true }}
89+
run: |
90+
echo "Checking for unused translations..."
91+
if ! pnpm translations:check; then
92+
echo ""
93+
echo "❌ Translation file contains unused keys!"
94+
echo ""
95+
echo "To fix this, run:"
96+
echo " pnpm translations:clean"
97+
echo " pnpm fix"
98+
echo ""
99+
echo "Then commit the changes."
100+
exit 1
101+
fi
102+
shell: bash

.github/workflows/lfs-checks.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Checks that large files and LFS-tracked files are properly checked in with pointer format.
2+
# Uses https://github.com/ppremk/lfs-warning to detect LFS issues.
3+
4+
name: 'lfs checks'
5+
6+
on:
7+
push:
8+
branches:
9+
- 'main'
10+
pull_request:
11+
types:
12+
- 'ready_for_review'
13+
- 'opened'
14+
- 'synchronize'
15+
merge_group:
16+
workflow_dispatch:
17+
18+
jobs:
19+
lfs-check:
20+
runs-on: ubuntu-latest
21+
timeout-minutes: 5
22+
permissions:
23+
# Required to label and comment on the PRs
24+
pull-requests: write
25+
steps:
26+
- name: checkout
27+
uses: actions/checkout@v4
28+
29+
- name: check lfs files
30+
uses: ppremk/[email protected]

docs/contributing/MODEL_MANAGER.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ If the key is unrecognized, this call raises an
265265

266266
#### exists(key) -> AnyModelConfig
267267

268-
Returns True if a model with the given key exists in the databsae.
268+
Returns True if a model with the given key exists in the database.
269269

270270
#### search_by_path(path) -> AnyModelConfig
271271

@@ -718,7 +718,7 @@ When downloading remote models is implemented, additional
718718
configuration information, such as list of trigger terms, will be
719719
retrieved from the HuggingFace and Civitai model repositories.
720720

721-
The probed values can be overriden by providing a dictionary in the
721+
The probed values can be overridden by providing a dictionary in the
722722
optional `config` argument passed to `import_model()`. You may provide
723723
overriding values for any of the model's configuration
724724
attributes. Here is an example of setting the
@@ -841,7 +841,7 @@ variable.
841841

842842
#### installer.start(invoker)
843843

844-
The `start` method is called by the API intialization routines when
844+
The `start` method is called by the API initialization routines when
845845
the API starts up. Its effect is to call `sync_to_config()` to
846846
synchronize the model record store database with what's currently on
847847
disk.

docs/contributing/contributors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ We thank [all contributors](https://github.com/invoke-ai/InvokeAI/graphs/contrib
1616
- @psychedelicious (Spencer Mabrito) - Web Team Leader
1717
- @joshistoast (Josh Corbett) - Web Development
1818
- @cheerio (Mary Rogers) - Lead Engineer & Web App Development
19-
- @ebr (Eugene Brodsky) - Cloud/DevOps/Sofware engineer; your friendly neighbourhood cluster-autoscaler
19+
- @ebr (Eugene Brodsky) - Cloud/DevOps/Software engineer; your friendly neighbourhood cluster-autoscaler
2020
- @sunija - Standalone version
2121
- @brandon (Brandon Rising) - Platform, Infrastructure, Backend Systems
2222
- @ryanjdick (Ryan Dick) - Machine Learning & Training

docs/installation/quick_start.md

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,45 @@ Hardware requirements vary significantly depending on model and image output siz
3333

3434
More detail on system requirements can be found [here](./requirements.md).
3535

36-
## Step 2: Download
36+
## Step 2: Download and Set Up the Launcher
3737

38-
Download the most recent launcher for your operating system:
38+
The Launcher manages your Invoke install. Follow these instructions to download and set up the Launcher.
3939

40-
- [Download for Windows](https://download.invoke.ai/Invoke%20Community%20Edition.exe)
41-
- [Download for macOS](https://download.invoke.ai/Invoke%20Community%20Edition.dmg)
42-
- [Download for Linux](https://download.invoke.ai/Invoke%20Community%20Edition.AppImage)
40+
!!! info "Instructions for each OS"
4341

44-
## Step 3: Install or Update
42+
=== "Windows"
4543

46-
Run the launcher you just downloaded, click **Install** and follow the instructions to get set up.
44+
- [Download for Windows](https://github.com/invoke-ai/launcher/releases/latest/download/Invoke.Community.Edition.Setup.latest.exe)
45+
- Run the `EXE` to install the Launcher and start it.
46+
- A desktop shortcut will be created; use this to run the Launcher in the future.
47+
- You can delete the `EXE` file you downloaded.
4748

48-
If you have an existing Invoke installation, you can select it and let the launcher manage the install. You'll be able to update or launch the installation.
49+
=== "macOS"
50+
51+
- [Download for macOS](https://github.com/invoke-ai/launcher/releases/latest/download/Invoke.Community.Edition-latest-arm64.dmg)
52+
- Open the `DMG` and drag the app into `Applications`.
53+
- Run the Launcher using its entry in `Applications`.
54+
- You can delete the `DMG` file you downloaded.
55+
56+
=== "Linux"
57+
58+
- [Download for Linux](https://github.com/invoke-ai/launcher/releases/latest/download/Invoke.Community.Edition-latest.AppImage)
59+
- You may need to edit the `AppImage` file properties and make it executable.
60+
- Optionally move the file to a location that does not require admin privileges and add a desktop shortcut for it.
61+
- Run the Launcher by double-clicking the `AppImage` or the shortcut you made.
4962

50-
!!! warning "Problem running the launcher on macOS"
63+
## Step 3: Install Invoke
64+
65+
Run the Launcher you just set up if you haven't already. Click **Install** and follow the instructions to install (or update) Invoke.
66+
67+
If you have an existing Invoke installation, you can select it and let the launcher manage the install. You'll be able to update or launch the installation.
5168

52-
macOS may not allow you to run the launcher. We are working to resolve this by signing the launcher executable. Until that is done, you can manually flag the launcher as safe:
69+
!!! tip "Updating"
5370

54-
- Open the **Invoke Community Edition.dmg** file.
55-
- Drag the launcher to **Applications**.
56-
- Open a terminal.
57-
- Run `xattr -d 'com.apple.quarantine' /Applications/Invoke\ Community\ Edition.app`.
71+
The Launcher will check for updates for itself _and_ Invoke.
5872

59-
You should now be able to run the launcher.
73+
- When the Launcher detects an update is available for itself, you'll get a small popup window. Click through this and the Launcher will update itself.
74+
- When the Launcher detects an update for Invoke, you'll see a small green alert in the Launcher. Click that and follow the instructions to update Invoke.
6075

6176
## Step 4: Launch
6277

docs/nodes/NODES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Nodes have a "Use Cache" option in their footer. This allows for performance imp
4141

4242
There are several node grouping concepts that can be examined with a narrow focus. These (and other) groupings can be pieced together to make up functional graph setups, and are important to understanding how groups of nodes work together as part of a whole. Note that the screenshots below aren't examples of complete functioning node graphs (see Examples).
4343

44-
### Noise
44+
### Create Latent Noise
4545

4646
An initial noise tensor is necessary for the latent diffusion process. As a result, the Denoising node requires a noise node input.
4747

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from fastapi import Body, HTTPException
2+
from fastapi.routing import APIRouter
3+
4+
from invokeai.app.services.videos_common import AddVideosToBoardResult, RemoveVideosFromBoardResult
5+
6+
board_videos_router = APIRouter(prefix="/v1/board_videos", tags=["boards"])
7+
8+
9+
@board_videos_router.post(
10+
"/batch",
11+
operation_id="add_videos_to_board",
12+
responses={
13+
201: {"description": "Videos were added to board successfully"},
14+
},
15+
status_code=201,
16+
response_model=AddVideosToBoardResult,
17+
)
18+
async def add_videos_to_board(
19+
board_id: str = Body(description="The id of the board to add to"),
20+
video_ids: list[str] = Body(description="The ids of the videos to add", embed=True),
21+
) -> AddVideosToBoardResult:
22+
"""Adds a list of videos to a board"""
23+
raise HTTPException(status_code=501, detail="Not implemented")
24+
25+
26+
@board_videos_router.post(
27+
"/batch/delete",
28+
operation_id="remove_videos_from_board",
29+
responses={
30+
201: {"description": "Videos were removed from board successfully"},
31+
},
32+
status_code=201,
33+
response_model=RemoveVideosFromBoardResult,
34+
)
35+
async def remove_videos_from_board(
36+
video_ids: list[str] = Body(description="The ids of the videos to remove", embed=True),
37+
) -> RemoveVideosFromBoardResult:
38+
"""Removes a list of videos from their board, if they had one"""
39+
raise HTTPException(status_code=501, detail="Not implemented")

invokeai/app/api/routers/videos.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from typing import Optional
2+
3+
from fastapi import Body, HTTPException, Path, Query
4+
from fastapi.routing import APIRouter
5+
6+
from invokeai.app.services.shared.pagination import OffsetPaginatedResults
7+
from invokeai.app.services.shared.sqlite.sqlite_common import SQLiteDirection
8+
from invokeai.app.services.videos_common import (
9+
DeleteVideosResult,
10+
StarredVideosResult,
11+
UnstarredVideosResult,
12+
VideoDTO,
13+
VideoIdsResult,
14+
VideoRecordChanges,
15+
)
16+
17+
videos_router = APIRouter(prefix="/v1/videos", tags=["videos"])
18+
19+
20+
@videos_router.patch(
21+
"/i/{video_id}",
22+
operation_id="update_video",
23+
response_model=VideoDTO,
24+
)
25+
async def update_video(
26+
video_id: str = Path(description="The id of the video to update"),
27+
video_changes: VideoRecordChanges = Body(description="The changes to apply to the video"),
28+
) -> VideoDTO:
29+
"""Updates a video"""
30+
31+
raise HTTPException(status_code=501, detail="Not implemented")
32+
33+
34+
@videos_router.get(
35+
"/i/{video_id}",
36+
operation_id="get_video_dto",
37+
response_model=VideoDTO,
38+
)
39+
async def get_video_dto(
40+
video_id: str = Path(description="The id of the video to get"),
41+
) -> VideoDTO:
42+
"""Gets a video's DTO"""
43+
44+
raise HTTPException(status_code=501, detail="Not implemented")
45+
46+
47+
@videos_router.post("/delete", operation_id="delete_videos_from_list", response_model=DeleteVideosResult)
48+
async def delete_videos_from_list(
49+
video_ids: list[str] = Body(description="The list of ids of videos to delete", embed=True),
50+
) -> DeleteVideosResult:
51+
raise HTTPException(status_code=501, detail="Not implemented")
52+
53+
54+
@videos_router.post("/star", operation_id="star_videos_in_list", response_model=StarredVideosResult)
55+
async def star_videos_in_list(
56+
video_ids: list[str] = Body(description="The list of ids of videos to star", embed=True),
57+
) -> StarredVideosResult:
58+
raise HTTPException(status_code=501, detail="Not implemented")
59+
60+
61+
@videos_router.post("/unstar", operation_id="unstar_videos_in_list", response_model=UnstarredVideosResult)
62+
async def unstar_videos_in_list(
63+
video_ids: list[str] = Body(description="The list of ids of videos to unstar", embed=True),
64+
) -> UnstarredVideosResult:
65+
raise HTTPException(status_code=501, detail="Not implemented")
66+
67+
68+
@videos_router.delete("/uncategorized", operation_id="delete_uncategorized_videos", response_model=DeleteVideosResult)
69+
async def delete_uncategorized_videos() -> DeleteVideosResult:
70+
"""Deletes all videos that are uncategorized"""
71+
72+
raise HTTPException(status_code=501, detail="Not implemented")
73+
74+
75+
@videos_router.get("/", operation_id="list_video_dtos", response_model=OffsetPaginatedResults[VideoDTO])
76+
async def list_video_dtos(
77+
is_intermediate: Optional[bool] = Query(default=None, description="Whether to list intermediate videos."),
78+
board_id: Optional[str] = Query(
79+
default=None,
80+
description="The board id to filter by. Use 'none' to find videos without a board.",
81+
),
82+
offset: int = Query(default=0, description="The page offset"),
83+
limit: int = Query(default=10, description="The number of videos per page"),
84+
order_dir: SQLiteDirection = Query(default=SQLiteDirection.Descending, description="The order of sort"),
85+
starred_first: bool = Query(default=True, description="Whether to sort by starred videos first"),
86+
search_term: Optional[str] = Query(default=None, description="The term to search for"),
87+
) -> OffsetPaginatedResults[VideoDTO]:
88+
"""Lists video DTOs"""
89+
90+
raise HTTPException(status_code=501, detail="Not implemented")
91+
92+
93+
@videos_router.get("/ids", operation_id="get_video_ids")
94+
async def get_video_ids(
95+
is_intermediate: Optional[bool] = Query(default=None, description="Whether to list intermediate videos."),
96+
board_id: Optional[str] = Query(
97+
default=None,
98+
description="The board id to filter by. Use 'none' to find videos without a board.",
99+
),
100+
order_dir: SQLiteDirection = Query(default=SQLiteDirection.Descending, description="The order of sort"),
101+
starred_first: bool = Query(default=True, description="Whether to sort by starred videos first"),
102+
search_term: Optional[str] = Query(default=None, description="The term to search for"),
103+
) -> VideoIdsResult:
104+
"""Gets ordered list of video ids with metadata for optimistic updates"""
105+
106+
raise HTTPException(status_code=501, detail="Not implemented")
107+
108+
109+
@videos_router.post(
110+
"/videos_by_ids",
111+
operation_id="get_videos_by_ids",
112+
responses={200: {"model": list[VideoDTO]}},
113+
)
114+
async def get_videos_by_ids(
115+
video_ids: list[str] = Body(embed=True, description="Object containing list of video ids to fetch DTOs for"),
116+
) -> list[VideoDTO]:
117+
"""Gets video DTOs for the specified video ids. Maintains order of input ids."""
118+
119+
raise HTTPException(status_code=501, detail="Not implemented")

invokeai/app/api_app.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from invokeai.app.api.routers import (
1919
app_info,
2020
board_images,
21+
board_videos,
2122
boards,
2223
client_state,
2324
download_queue,
@@ -27,6 +28,7 @@
2728
session_queue,
2829
style_presets,
2930
utilities,
31+
videos,
3032
workflows,
3133
)
3234
from invokeai.app.api.sockets import SocketIO
@@ -125,8 +127,10 @@ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
125127
app.include_router(model_manager.model_manager_router, prefix="/api")
126128
app.include_router(download_queue.download_queue_router, prefix="/api")
127129
app.include_router(images.images_router, prefix="/api")
130+
app.include_router(videos.videos_router, prefix="/api")
128131
app.include_router(boards.boards_router, prefix="/api")
129132
app.include_router(board_images.board_images_router, prefix="/api")
133+
app.include_router(board_videos.board_videos_router, prefix="/api")
130134
app.include_router(model_relationships.model_relationships_router, prefix="/api")
131135
app.include_router(app_info.app_router, prefix="/api")
132136
app.include_router(session_queue.session_queue_router, prefix="/api")

0 commit comments

Comments
 (0)