Add detailed logging to model linker and sources

Add extensive observability/logging across ModelLinker and source search modules. __init__.py: introduce summarize_result and log_search_result helpers, replace ad-hoc logger calls with log_info/log_exception, and add start/result/summary logs for local, popular, model_list, HuggingFace and CivitAI searches (including extra metadata like confidence, files_count, results_count). core/sources/civitai.py: log cache hits, API call start, response counts, model/version/file checks, no-result info and improved exception logging. core/sources/huggingface.py: log cache hits, API call start, response counts, per-repo debug info, repo tree sizes, no-result info and improved exception logging. Changes are focused on diagnostics and do not alter core search logic.
This commit is contained in:
Dariusz L
2026-04-25 23:43:17 +02:00
parent 93e79cd17a
commit 1fc404ebfd
3 changed files with 121 additions and 11 deletions
+81 -6
View File
@@ -766,6 +766,37 @@ class ModelLinkerExtension:
async def search_sources(request):
"""Search for model download sources."""
try:
def summarize_result(source_name, result, extra=None):
if isinstance(result, dict):
summary = {
"source": source_name,
"name": result.get("name"),
"filename": result.get("filename"),
"match_type": result.get("match_type"),
"repo_id": result.get("repo_id"),
"model_id": result.get("model_id"),
"version_id": result.get("version_id"),
"url": result.get("url"),
"download_url": result.get("download_url"),
"size": result.get("size"),
}
else:
summary = {"source": source_name, "result": result}
if extra:
summary.update(extra)
return summary
def log_search_result(source_name, result, extra=None):
details = summarize_result(source_name, result, extra)
if result and (
not isinstance(result, list) or len(result) > 0
):
log_info(f"Search source [{source_name}] FOUND: {details}")
else:
log_info(f"Search source [{source_name}] no result: {details}")
data = await request.json()
filename = data.get("filename", "")
category = data.get("category", "")
@@ -809,8 +840,7 @@ class ModelLinkerExtension:
search_huggingface_source = "huggingface" in normalized_sources
search_civitai_source = "civitai" in normalized_sources
# Debug logging
self.logger.info(
log_info(
f"Search request: filename={filename}, category={category}, is_urn={is_urn}, model_id={data.get('model_id')}, version_id={data.get('version_id')}, sources={sorted(normalized_sources)}"
)
@@ -825,7 +855,11 @@ class ModelLinkerExtension:
# 1. Search local databases (curated + model-list)
if search_local:
log_info(
f"Search source [local] start: filename={filename}, category={category}"
)
popular_info = get_popular_model_url(filename)
log_search_result("popular", popular_info)
if popular_info:
results["popular"] = {
"source": "popular",
@@ -835,6 +869,15 @@ class ModelLinkerExtension:
results["found"] = True
model_list_result = search_model_list(filename)
log_search_result(
"model_list",
model_list_result,
{
"confidence": model_list_result.get("confidence")
if model_list_result
else None
},
)
if model_list_result:
confidence = model_list_result.get("confidence", 0)
if is_urn and confidence >= 70:
@@ -846,13 +889,18 @@ class ModelLinkerExtension:
# 2. Search HuggingFace for exact file match
if search_huggingface_source:
log_info(f"Search source [huggingface] start: filename={filename}")
hf_result = search_huggingface_for_file(filename)
log_search_result("huggingface", hf_result)
if hf_result:
results["huggingface"] = hf_result
results["found"] = True
# 3. Search CivitAI - use direct download for URNs
if search_civitai_source:
log_info(
f"Search source [civitai] start: filename={filename}, category={category}, is_urn={is_urn}"
)
# For URNs, use direct model_id/version_id to get download URL
if is_urn:
# Get model_id and version_id from request data
@@ -897,15 +945,40 @@ class ModelLinkerExtension:
"base_model": model_info.get("base_model"),
"tags": model_info.get("tags", []),
}
log_search_result(
"civitai/urn",
results["civitai"],
{
"files_count": len(
model_info.get("files", [])
)
},
)
results["found"] = True
else:
log_search_result(
"civitai/urn",
None,
{
"model_id": model_id,
"version_id": version_id,
},
)
elif category:
# Fallback to search if no IDs
self.logger.info(
log_info(
f"URN: No model_id/version_id, falling back to CivitAI search"
)
civitai_results = search_civitai(
filename, model_type=category
)
log_search_result(
"civitai/fallback",
civitai_results[0] if civitai_results else None,
{
"results_count": len(civitai_results),
},
)
if civitai_results:
first_result = civitai_results[0]
results["civitai"] = {
@@ -924,16 +997,18 @@ class ModelLinkerExtension:
results["found"] = True
else:
civitai_result = search_civitai_for_file(filename)
log_search_result("civitai", civitai_result)
if civitai_result:
results["civitai"] = civitai_result
results["found"] = True
log_info(
f"Search summary: found={results['found']}, searched_sources={results['searched_sources']}"
)
return web.json_response(results)
except Exception as e:
self.logger.error(
f"Model Linker search error: {e}", exc_info=True
)
log_exception(f"Model Linker search error: {e}")
return web.json_response({"error": str(e)}, status=500)
@routes.post("/model_linker/download")
+20 -2
View File
@@ -133,6 +133,7 @@ def search_civitai_for_file(
cache_key = f"civit_{filename}_exact{exact_only}"
if cache_key in _search_cache:
log_debug(f"CivitAI search cache hit for {filename} (exact_only={exact_only})")
return _search_cache[cache_key]
try:
@@ -144,14 +145,22 @@ def search_civitai_for_file(
headers["Authorization"] = f"Bearer {api_key}"
search_url = f"{CIVITAI_API_URL}/models?query={quote(search_term)}&limit=10"
log_info(
f"CivitAI search start: filename={filename}, query={search_term}, exact_only={exact_only}"
)
response = requests.get(search_url, headers=headers, timeout=15)
if response.status_code != 200:
log_debug(f"CivitAI search returned {response.status_code}")
log_warn(
f"CivitAI search returned {response.status_code} for query={search_term}"
)
return None
data = response.json()
items = data.get("items", [])
log_info(
f"CivitAI search API returned {len(items)} models for query={search_term}"
)
filename_base = os.path.splitext(filename.lower())[0]
@@ -159,11 +168,17 @@ def search_civitai_for_file(
model_id = item.get("id")
model_name = item.get("name", "")
model_type = item.get("type", "")
log_debug(
f"CivitAI checking model_id={model_id}, model_name={model_name}, model_type={model_type}"
)
model_versions = item.get("modelVersions", [])
for version in model_versions:
version_id = version.get("id")
files = version.get("files", [])
log_debug(
f"CivitAI checking version_id={version_id} with {len(files)} files for model_id={model_id}"
)
for file_info in files:
file_name = file_info.get("name", "")
@@ -220,10 +235,13 @@ def search_civitai_for_file(
# Not found
_search_cache[cache_key] = None
log_info(
f"CivitAI search no result: filename={filename}, query={search_term}, models_checked={len(items)}"
)
return None
except Exception as e:
log_error(f"CivitAI search error: {e}")
log_exception(f"CivitAI search error for {filename}: {e}")
return None
+20 -3
View File
@@ -98,6 +98,7 @@ def search_huggingface_for_file(
cache_key = f"hf_{filename}_exact{exact_only}"
if cache_key in _search_cache:
log_debug(f"HuggingFace search cache hit for {filename} (exact_only={exact_only})")
return _search_cache[cache_key]
try:
@@ -110,19 +111,29 @@ def search_huggingface_for_file(
# Search for repos containing this filename
search_url = f"{HF_API_URL}/models?search={quote(filename_base)}&limit=10"
log_info(
f"HuggingFace search start: filename={filename}, query={filename_base}, exact_only={exact_only}"
)
response = requests.get(search_url, headers=headers, timeout=10)
if response.status_code != 200:
log_debug(f"HuggingFace search returned {response.status_code}")
log_warn(
f"HuggingFace search returned {response.status_code} for query={filename_base}"
)
return None
repos = response.json()
log_info(
f"HuggingFace search API returned {len(repos)} repos for query={filename_base}"
)
for repo in repos:
repo_id = repo.get("id", "")
if not repo_id:
continue
log_debug(f"HuggingFace checking repo {repo_id} for filename={filename}")
# Check if this repo actually has a matching file
files_url = f"{HF_API_URL}/models/{repo_id}/tree/main"
@@ -130,6 +141,9 @@ def search_huggingface_for_file(
files_response = requests.get(files_url, headers=headers, timeout=10)
if files_response.status_code == 200:
files = files_response.json()
log_debug(
f"HuggingFace repo {repo_id} returned {len(files)} tree items"
)
for file_info in files:
file_path = file_info.get("path", "")
@@ -178,15 +192,18 @@ def search_huggingface_for_file(
return result
except Exception as e:
log_debug(f"Error checking repo {repo_id}: {e}")
log_debug(f"Error checking HuggingFace repo {repo_id}: {e}")
continue
# Not found
_search_cache[cache_key] = None
log_info(
f"HuggingFace search no result: filename={filename}, query={filename_base}, repos_checked={len(repos)}"
)
return None
except Exception as e:
log_error(f"HuggingFace search error: {e}")
log_exception(f"HuggingFace search error for {filename}: {e}")
return None