Design for a shim that stores CivitAI stats (downloads, rating, thumbs up) in a separate SQLite DB and enriches the list API response via the proxy middleware. Includes bulk fetch button, card badges, and new sort options. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.3 KiB
CivitAI Extended Stats Shim — Design
Problem
The LoRA Manager fetches metadata from CivitAI but discards stats (download count, rating, thumbs up). Users want to sort and filter loras by popularity/quality, and see these stats on model cards — like CivitAI's own UI.
Constraints
- No modifications to the original LoRA Manager codebase (avoid merge conflicts on upstream sync)
- Lives inside ComfyUI-LM-Remote, which already has proxy middleware intercepting API responses
- Must handle CivitAI API rate limits gracefully when bulk-fetching stats
- Stats should persist across restarts (SQLite)
Architecture
Hybrid Shim Approach
- Separate SQLite DB (
civitai_stats.db) for extended stats — avoids schema conflicts with the manager's own cache - Proxy enrichment — the existing middleware intercepts
/api/lm/loras/listresponses from the remote and merges stats into each item before forwarding to the browser - New API endpoints on LM-Remote for the bulk fetch button and status checks
- Frontend JS injected via LM-Remote's
web/comfyui/directory, patches sort dropdown and card rendering
Data Flow
List request:
Browser → GET /api/lm/loras/list
→ proxy fetches response from remote
→ enriches each item with stats from local civitai_stats.db
→ returns merged response to browser
Bulk fetch (initial):
Browser → POST /api/lm-extra/fetch-stats
→ handler reads models from remote list API
→ extracts civitai_model_id + sha256 for each
→ batches CivitAI API calls (/api/v1/models?ids=id1,id2,...)
→ stores stats in civitai_stats.db
→ WebSocket progress updates
→ frontend auto-refreshes grid when done
Piggyback (ongoing):
When proxy intercepts metadata sync responses that contain stats,
opportunistically store them in civitai_stats.db
SQLite Schema
File: civitai_stats.db (stored alongside LM-Remote's config)
CREATE TABLE model_stats (
sha256 TEXT PRIMARY KEY,
civitai_model_id INTEGER,
civitai_version_id INTEGER,
download_count INTEGER,
rating REAL,
rating_count INTEGER,
thumbs_up_count INTEGER,
fetched_at REAL
);
Keyed by sha256 — the common identifier between the manager's cache and CivitAI. Joins naturally regardless of file paths or renames.
API Endpoints (LM-Remote)
| Method | Path | Purpose |
|---|---|---|
| POST | /api/lm-extra/fetch-stats |
Bulk fetch stats for all models (button) |
| GET | /api/lm-extra/stats-status |
Check if stats DB is populated, staleness info |
Proxy Response Enrichment
The middleware intercepts the /api/lm/loras/list response and:
- Parses the JSON response body
- Collects all
sha256values from items - Batch-queries
civitai_stats.db(single SELECT with IN clause) - Merges
download_count,rating,rating_count,thumbs_up_countinto each item - Returns the enriched response
Sorting
New Sort Options
Added to the sort dropdown alongside existing options (name, date, size, usage):
| Value | Label |
|---|---|
downloads:desc |
Most downloaded |
downloads:asc |
Least downloaded |
rating:desc |
Highest rated |
rating:asc |
Lowest rated |
thumbsup:desc |
Most liked |
thumbsup:asc |
Least liked |
Sort Implementation
When the proxy sees these sort values in the list request, sorting is handled locally:
- Fetch the full (unpaginated) list from remote
- Join with stats DB
- Sort locally
- Apply pagination
- Return result
Items without stats sort to the end.
Frontend Changes
All in ComfyUI-LM-Remote/web/comfyui/.
Card Badges
Small badges on each model card (styled like the existing base model badge):
- Download icon + count (e.g., "12.3k")
- Star icon + rating (e.g., "4.8")
- Thumbs-up icon + count (e.g., "89")
Numbers use compact formatting (1000 → "1k", 12345 → "12.3k").
Toolbar Button
A "Fetch Stats" button in the toolbar (next to existing Fetch/Download buttons):
- Chart-bar icon
- Triggers POST to
/api/lm-extra/fetch-stats - Shows progress via WebSocket
- Auto-refreshes grid on completion
Sort Dropdown Patch
JS extension adds the new sort options to the existing #sortSelect dropdown on page load.
Bulk Fetch Strategy
CivitAI's /api/v1/models?ids= endpoint accepts multiple model IDs per request.
- Collect all unique
civitai_model_idvalues from the lora list - Batch into groups (e.g., 50 IDs per request)
- For each batch, fetch model data and extract
statsfrom the matching version - Rate-limit: 1-2 requests/second with backoff on 429 responses
- Broadcast progress via WebSocket (e.g., "Fetching stats: 150/300 models")
Piggyback Strategy
When the existing metadata sync runs (triggered by the manager's refresh/fetch), the proxy can intercept the CivitAI API response if it flows through, and opportunistically extract stats. This covers new models added after the initial bulk fetch.
Files to Create/Modify
| File | Action |
|---|---|
stats_db.py |
NEW — SQLite wrapper for civitai_stats.db |
stats_service.py |
NEW — bulk fetch logic, CivitAI API calls, rate limiting |
proxy.py |
MODIFY — intercept list response, enrich with stats; add sort handling |
web/comfyui/lm_stats_ui.js |
NEW — card badges, toolbar button, sort dropdown patch |