Root cause: 231 concurrent /check-model-exists requests on 175K-lora library
caused ~9.4s wall clock time. The bottleneck was two-fold:
1. DownloadedVersionHistoryService opened a new sqlite3.connect() for every
query under asyncio.Lock. With a large WAL from 175K entries, each
connect() took ~8ms. Serialized by the lock across 231 requests, the
230th request waited ~1848ms just for lock acquisition.
2. check_model_exists always queried download history even when the model
was found locally. The history result (hasBeenDownloaded /
downloadedVersionIds) is only used by the UI when the model is NOT
found locally; when found, the 'in library' indicator takes priority.
Changes:
- downloaded_version_history_service.py: added persistent _get_conn() that
creates the SQLite connection once and reuses it across all queries
- misc_handlers.py: early-return from check_model_exists when the model
exists locally, bypassing the history service entirely (lock skipped)
Expected: per-request wait time drops from ~1912ms to <3ms, wall clock
from ~9.4s to <0.3s for the 175K-lora user's 231-card page.
Handle models that are only available for on-site generation (usageControl:
"Generation" or "InternalGeneration") rather than downloadable.
Backend changes:
- Add usage_control field to ModelVersionRecord dataclass
- Extract usageControl from Civitai API responses
- Filter non-downloadable versions from update availability checks
- Add database schema migration for usage_control column
- Include usageControl in version response JSON
Frontend changes:
- Add isDownloadAllowed() helper function
- Show disabled download button for non-downloadable versions
- Add "On-Site Only" badge for restricted versions
- Update resolveUpdateAvailability() to filter non-downloadable versions
- Add CSS styling for disabled action button
Internationalization:
- Add translations for onSiteOnly badge and downloadNotAllowedTooltip
- Complete translations for all 10 supported languages
Detects when multiple model files share the same basename (causing
ambiguity in LoRA resolution), logs warnings during scanning, and
provides a "Resolve Conflicts" button in the Doctor panel. Resolution
renames duplicates with hash-prefixed unique filenames, migrates all
sidecar and preview files, and updates the cache and frontend scroller
in-place so the model modal immediately reflects the new filename.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CivitAI returns file type "Diffusion Model" for checkpoint files (e.g., Anima
models), but the file selection logic only accepted "Model" and "Negative",
causing "No suitable file found in metadata" errors.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
_split _get_records_bulk into 500-id batches so the WHERE IN clause
never exceeds SQLite's 999-parameter ceiling.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When importing recipes from Civitai image URLs, the API returns modelVersionIds
at the root level instead of inside the meta object. This caused LoRA information
to not be recognized and imported.
Changes:
- analysis_service.py: Merge modelVersionIds from image_info into metadata
- civitai_image.py: Add modelVersionIds field recognition and processing logic
- test_civitai_image_parser.py: Add test for modelVersionIds handling
Implement automatic fetching of base models from Civitai API to keep
data up-to-date without manual updates.
Backend:
- Add CivitaiBaseModelService with 7-day TTL caching
- Add /api/lm/base-models endpoints for fetching and refreshing
- Merge hardcoded and remote models for backward compatibility
- Smart abbreviation generation for unknown models
Frontend:
- Add civitaiBaseModelApi client for API communication
- Dynamic base model loading on app initialization
- Update SettingsManager to use merged model lists
- Add support for 8 new models: Anima, CogVideoX, LTXV 2.3, Mochi,
Pony V7, Wan Video 2.5 T2V/I2V
API Endpoints:
- GET /api/lm/base-models - Get merged models
- POST /api/lm/base-models/refresh - Force refresh
- GET /api/lm/base-models/categories - Get categories
- GET /api/lm/base-models/cache-status - Check cache status
Closes#854
Add new setting 'mature_blur_level' with options PG13/R/X/XXX to control
which NSFW rating level triggers blur filtering when NSFW blur is enabled.
- Backend: update preview selection logic to respect threshold
- Frontend: update UI components to use configurable threshold
- Settings: add validation and normalization for mature_blur_level
- Tests: add coverage for new threshold behavior
- Translations: add keys for all supported languages
Fixes#867