Users see a trigger word in someone else's prompt and have no way to tell whether the LoRA is already in their library, so they fall back to searching the model sites again. - Read trigger words from civitai.trainedWords through a small helper that tolerates the shapes older sidecars contain (None, a bare string, mixed lists). Provenance does not matter: CivitAI/CivArchive sync, HuggingFace or ModelScope model cards, the AI enrichment skill and manual edits all write the same field. - Add an opt-in trigger_words search option to SearchStrategy, evaluated last before the always-on hash fallback. Matching is case-insensitive substring only: fuzzy would run the sequence matcher over every declared word of every entry and cost seconds on large libraries. - Expose it as a "Trigger Words" chip on the LoRAs page only, plumb the option through page state and the list request, and parse the new search_trigger_words query param. - Cover the strategy (including AI-enriched HuggingFace entries and malformed trainedWords), the param parsing, the chip-to-state wiring and the request query string. The English key is synced with a [TODO: Translate] placeholder in the other locales.
41 lines
1.4 KiB
Python
41 lines
1.4 KiB
Python
"""Helpers for reading trigger words out of a model's ``civitai`` metadata.
|
|
|
|
Trigger words live in ``civitai.trainedWords`` no matter where the model came
|
|
from: CivitAI/CivArchive sync, a HuggingFace/ModelScope model card, the AI
|
|
metadata-enrichment skill, or a manual edit in the model modal. Readers must
|
|
accept the loose shapes older sidecars can contain (``None``, a bare string, a
|
|
list holding non-string entries) instead of assuming a clean list, which is
|
|
also why this lives here rather than repeated at every call site.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Iterator, Mapping
|
|
|
|
|
|
def iter_trigger_words(civitai: Any) -> Iterator[str]:
|
|
"""Yield the non-empty trigger words declared in a ``civitai`` block.
|
|
|
|
Internal whitespace is collapsed so a sidecar holding ``"anime\nstyle"``
|
|
still matches an ``"anime style"`` query. Declaration order and duplicates
|
|
are preserved; callers that need a set can build one themselves.
|
|
"""
|
|
if not isinstance(civitai, Mapping):
|
|
return
|
|
|
|
words = civitai.get("trainedWords")
|
|
if isinstance(words, str):
|
|
words = [words]
|
|
if not isinstance(words, (list, tuple)):
|
|
return
|
|
|
|
for word in words:
|
|
if not isinstance(word, str):
|
|
continue
|
|
normalized = " ".join(word.split())
|
|
if normalized:
|
|
yield normalized
|
|
|
|
|
|
__all__ = ["iter_trigger_words"]
|