diff --git a/modules/civitai/api_civitai.py b/modules/civitai/api_civitai.py index a0dcbad0c..ac25130f3 100644 --- a/modules/civitai/api_civitai.py +++ b/modules/civitai/api_civitai.py @@ -681,7 +681,7 @@ def legacy_get_civitai( query=query, tag=tag, types=types, sort=sort, period=period, nsfw=nsfw, limit=limit, base=base, token=token, exact=exact, ) - return [model_to_legacy_dict(m) for m in models] + return [model_to_legacy_dict(m) for m in models.items] return JSONResponse(content=[], status_code=200) diff --git a/modules/civitai/client_civitai.py b/modules/civitai/client_civitai.py index 00bfa3558..ddd695af5 100644 --- a/modules/civitai/client_civitai.py +++ b/modules/civitai/client_civitai.py @@ -141,8 +141,9 @@ class CivitaiClient: params['favorites'] = 'true' r = self._get('/models', params=params, token=token) if r.status_code != 200: - log.error(f'CivitAI search: code={r.status_code} message="{response_message(r)}"') - return CivitSearchResponse() + message = response_message(r) + log.error(f'CivitAI search: code={r.status_code} message="{message}"') + return CivitSearchResponse(error=message) data = r.json() if 'items' not in data: # single model by numeric query — wrap in search response @@ -155,7 +156,7 @@ class CivitaiClient: response = CivitSearchResponse.parse_obj(data) except Exception as e: log.error(f'CivitAI search parse error: {e}') - return CivitSearchResponse() + return CivitSearchResponse(error='search response could not be parsed') # /models rejects server-side level filtering and its nsfw boolean leaks # Mature+ content, so filter on each model's aggregate nsfwLevel here: # nsfw on keeps every level, nsfw off/unset keeps SFW (None + Soft). diff --git a/modules/civitai/models_civitai.py b/modules/civitai/models_civitai.py index 55b6db77a..3a31e0005 100644 --- a/modules/civitai/models_civitai.py +++ b/modules/civitai/models_civitai.py @@ -188,6 +188,7 @@ class CivitSearchResponse(BaseModel): items: list[CivitModel] = Field(default_factory=list) metadata: CivitSearchMetadata = Field(default_factory=CivitSearchMetadata) request_url: str | None = Field(None, alias="requestUrl") + error: str | None = None # server or parse failure text; items is empty when set class CivitTag(BaseModel): diff --git a/modules/civitai/search_civitai.py b/modules/civitai/search_civitai.py index aea995628..65653de56 100644 --- a/modules/civitai/search_civitai.py +++ b/modules/civitai/search_civitai.py @@ -1,5 +1,6 @@ import re import time +from html import escape from installer import log from modules.civitai.client_civitai import client from modules.civitai.models_civitai import CivitModel, CivitSearchResponse @@ -16,10 +17,10 @@ def search_civitai( base: str = '', token: str | None = None, exact: bool = True, -) -> list[CivitModel]: +) -> CivitSearchResponse: if not query and not tag and not sort: log.error('CivitAI: no search criteria provided') - return [] + return CivitSearchResponse(error='no search criteria provided') t0 = time.time() @@ -35,8 +36,8 @@ def search_civitai( if model: t1 = time.time() log.info(f'CivitAI result: id={query} time={t1 - t0:.2f}') - return [model] - return [] + return CivitSearchResponse(items=[model]) + return CivitSearchResponse(error=f'model {query} not found') response: CivitSearchResponse = client.search_models( query=query, @@ -61,17 +62,20 @@ def search_civitai( if any(q_lower in name for name in names): exact_models.append(model) - result = exact_models if exact_models else all_models + response.items = exact_models if exact_models else all_models t1 = time.time() log.info(f'CivitAI result: exact={len(exact_models)} total={len(all_models)} time={t1 - t0:.2f}') - return result + return response -def create_model_cards(all_models: list[CivitModel]) -> str: - details = """ -
-
- """ +def create_model_cards(response: CivitSearchResponse) -> str: + if response.error: + notice = f'CivitAI: {escape(response.error)}' + elif not response.items: + notice = 'No models found' + else: + notice = '' + details = f'
{notice}
' cards = """
{cards} @@ -85,7 +89,7 @@ def create_model_cards(all_models: list[CivitModel]) -> str:
""" all_cards = '' - for model in all_models: + for model in response.items: previews = [] for version in model.versions: for image in version.images: