Skip to content
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

Maryhipp/trigger phrases #5825

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 40 additions & 0 deletions invokeai/app/api/routers/model_manager.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Copyright (c) 2023 Lincoln D. Stein
"""FastAPI route for model configuration records."""

import pathlib
import shutil
from hashlib import sha1
from random import randbytes
import traceback

Check failure on line 8 in invokeai/app/api/routers/model_manager.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

invokeai/app/api/routers/model_manager.py:8:8: F401 `traceback` imported but unused
from typing import Any, Dict, List, Optional, Set

from fastapi import Body, Path, Query, Response
Expand All @@ -14,6 +15,7 @@
from typing_extensions import Annotated

from invokeai.app.services.model_install import ModelInstallJob
from invokeai.app.services.model_metadata.metadata_store_base import ModelMetadataChanges
from invokeai.app.services.model_records import (
DuplicateModelException,
InvalidModelException,
Expand All @@ -32,6 +34,7 @@
)
from invokeai.backend.model_manager.merge import MergeInterpolationMethod, ModelMerger
from invokeai.backend.model_manager.metadata import AnyModelRepoMetadata
from invokeai.backend.model_manager.metadata.metadata_base import BaseMetadata
from invokeai.backend.model_manager.search import ModelSearch

from ..dependencies import ApiDependencies
Expand Down Expand Up @@ -242,6 +245,43 @@

return result

@model_manager_router.patch(
"/i/{key}/metadata",
operation_id="update_model_metadata",
responses={
201: {
"description": "The model metadata was updated successfully",
"content": {"application/json": {"example": example_model_metadata}},
},
400: {"description": "Bad request"},
},
)
async def update_model_metadata(
key: str = Path(description="Key of the model repo metadata to fetch."),
changes: ModelMetadataChanges = Body(description="The changes")
) -> Optional[AnyModelRepoMetadata]:
"""Updates or creates a model metadata object."""
record_store = ApiDependencies.invoker.services.model_manager.store
metadata_store = ApiDependencies.invoker.services.model_manager.store.metadata_store

Check failure on line 266 in invokeai/app/api/routers/model_manager.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W293)

invokeai/app/api/routers/model_manager.py:266:1: W293 Blank line contains whitespace
try:
original_metadata = record_store.get_metadata(key)
if original_metadata:
original_metadata.trigger_phrases = changes.trigger_phrases

metadata_store.update_metadata(key, original_metadata)
else:
metadata_store.add_metadata(key, BaseMetadata(name="", author="",trigger_phrases=changes.trigger_phrases))
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"An error occurred while updating the model metadata: {e}",
)

result: Optional[AnyModelRepoMetadata] = record_store.get_metadata(key)

return result


@model_manager_router.get(
"/tags",
Expand Down
15 changes: 14 additions & 1 deletion invokeai/app/services/model_metadata/metadata_store_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,24 @@
Storage for Model Metadata
"""

from abc import ABC, abstractmethod
from typing import List, Set, Tuple
from typing import List, Optional, Set, Tuple

from pydantic import Field
from invokeai.app.util.model_exclude_null import BaseModelExcludeNull

from invokeai.backend.model_manager.metadata import AnyModelRepoMetadata

class ModelMetadataChanges(BaseModelExcludeNull, extra="allow"):

Check failure on line 14 in invokeai/app/services/model_metadata/metadata_store_base.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

invokeai/app/services/model_metadata/metadata_store_base.py:6:1: I001 Import block is un-sorted or un-formatted
"""A set of changes to apply to model metadata.

Only limited changes are valid:
- `trigger_phrases`: the list of trigger phrases for this model
"""

trigger_phrases: Optional[List[str]] = Field(default=None, description="The model's list of trigger phrases")
"""The model's list of trigger phrases"""


class ModelMetadataStoreBase(ABC):
"""Store, search and fetch model metadata retrieved from remote repositories."""
Expand Down
73 changes: 38 additions & 35 deletions invokeai/app/services/model_metadata/metadata_store_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ def update_metadata(self, model_key: str, metadata: AnyModelRepoMetadata) -> Any
except sqlite3.Error as e:
self._db.conn.rollback()
raise e
except Exception as e:
raise e

return self.get_metadata(model_key)

Expand Down Expand Up @@ -179,44 +181,45 @@ def search_by_name(self, name: str) -> Set[str]:
)
return {x[0] for x in self._cursor.fetchall()}

def _update_tags(self, model_key: str, tags: Set[str]) -> None:
def _update_tags(self, model_key: str, tags: Optional[Set[str]]) -> None:
"""Update tags for the model referenced by model_key."""
if tags:
# remove previous tags from this model
self._cursor.execute(
"""--sql
DELETE FROM model_tags
WHERE model_id=?;
""",
(model_key,),
)

for tag in tags:
self._cursor.execute(
"""--sql
INSERT OR IGNORE INTO tags (
tag_text
)
VALUES (?);
""",
(tag,),
)
self._cursor.execute(
"""--sql
SELECT tag_id
FROM tags
WHERE tag_text = ?
LIMIT 1;
""",
(tag,),
)
tag_id = self._cursor.fetchone()[0]
self._cursor.execute(
"""--sql
INSERT OR IGNORE INTO model_tags (
model_id,
tag_id
)
VALUES (?,?);
DELETE FROM model_tags
WHERE model_id=?;
""",
(model_key, tag_id),
(model_key,),
)

for tag in tags:
self._cursor.execute(
"""--sql
INSERT OR IGNORE INTO tags (
tag_text
)
VALUES (?);
""",
(tag,),
)
self._cursor.execute(
"""--sql
SELECT tag_id
FROM tags
WHERE tag_text = ?
LIMIT 1;
""",
(tag,),
)
tag_id = self._cursor.fetchone()[0]
self._cursor.execute(
"""--sql
INSERT OR IGNORE INTO model_tags (
model_id,
tag_id
)
VALUES (?,?);
""",
(model_key, tag_id),
)
1 change: 1 addition & 0 deletions invokeai/backend/model_manager/metadata/fetch/civitai.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ def _from_model_json(self, model_json: Dict[str, Any], version_id: Optional[int]
AllowDerivatives=model_json["allowDerivatives"],
AllowDifferentLicense=model_json["allowDifferentLicense"],
),
trigger_phrases=version_json["trainedWords"],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already on the metadata object as trained_words

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was trying to not use the civit key just to spite them

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the metadata schema already extracts it a few lines earlier

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you prefer trained_words? I don't feel strongly

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trigger_phrases works for me, and is more consistent with the terminology we use for textual inversion embeddings.

)

def from_civitai_versionid(self, version_id: int, model_id: Optional[int] = None) -> CivitaiMetadata:
Expand Down
3 changes: 2 additions & 1 deletion invokeai/backend/model_manager/metadata/metadata_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ class ModelMetadataBase(BaseModel):

name: str = Field(description="model's name")
author: str = Field(description="model's author")
tags: Set[str] = Field(description="tags provided by model source")
tags: Optional[Set[str]] = Field(description="tags provided by model source", default=None)
trigger_phrases: Optional[List[str]] = Field(description="trigger phrases for this model", default=None)


class BaseMetadata(ModelMetadataBase):
Expand Down
10 changes: 10 additions & 0 deletions invokeai/frontend/web/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"aboutDesc": "Using Invoke for work? Check out:",
"aboutHeading": "Own Your Creative Power",
"accept": "Accept",
"add": "Add",
"advanced": "Advanced",
"advancedOptions": "Advanced Options",
"ai": "ai",
Expand Down Expand Up @@ -303,6 +304,12 @@
"method": "High Resolution Fix Method"
}
},
"prompt": {
"addPromptTrigger": "Add Prompt Trigger",
"compatibleEmbeddings": "Compatible Embeddings",
"noPromptTriggers": "No triggers available",
"noMatchingTriggers": "No matching triggers"
},
"embedding": {
"addEmbedding": "Add Embedding",
"incompatibleModel": "Incompatible base model:",
Expand Down Expand Up @@ -768,6 +775,7 @@
"mergedModelName": "Merged Model Name",
"mergedModelSaveLocation": "Save Location",
"mergeModels": "Merge Models",
"metadata": "Metadata",
"model": "Model",
"modelAdded": "Model Added",
"modelConversionFailed": "Model Conversion Failed",
Expand Down Expand Up @@ -839,6 +847,8 @@
"statusConverting": "Converting",
"syncModels": "Sync Models",
"syncModelsDesc": "If your models are out of sync with the backend, you can refresh them up using this option. This is generally handy in cases where you add models to the InvokeAI root folder or autoimport directory after the application has booted.",
"triggerPhrases": "Trigger Phrases",
"typePhraseHere": "Type phrase here",
"upcastAttention": "Upcast Attention",
"updateModel": "Update Model",
"useCustomConfig": "Use Custom Config",
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const ModelPane = () => {
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
return (
<Box layerStyle="first" p={2} borderRadius="base" w="50%" h="full">
{selectedModelKey ? <Model /> : <ImportModels />}
{selectedModelKey ? <Model key={selectedModelKey} /> : <ImportModels />}
</Box>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Box, Flex } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query';
import { useAppSelector } from 'app/store/storeHooks';
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
import { useGetModelMetadataQuery } from 'services/api/endpoints/models';

import { TriggerPhrases } from './TriggerPhrases';

export const ModelMetadata = () => {
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
const { data: metadata } = useGetModelMetadataQuery(selectedModelKey ?? skipToken);

return (
<Flex flexDir="column" height="full" gap="3">
<Box layerStyle="second" borderRadius="base" p={3}>
<TriggerPhrases />
</Box>
<DataViewer label="metadata" data={metadata || {}} />
</Flex>
);
};
Loading
Loading