Commit Graph

2444 Commits

Author SHA1 Message Date
Will Miao
430e24d70b fix(ui): hide skip-metadata-refresh bulk menu items for recipes 2026-05-28 19:11:49 +08:00
Will Miao
14f0c48fdd fix(recipe): detect and repair corrupted checkpoints in repair flow
Add corruption detection to _repair_single_recipe: if checkpoint.modelVersionId matches any LoRA's modelVersionId, the checkpoint is corrupted (a LoRA was saved as checkpoint). Clear the checkpoint and remove the matching LoRA entry, then let enrichment re-resolve the correct checkpoint from CivitAI metadata.

This fixes the retroactive repair path for the modelVersionIds[0] fallback bug.
2026-05-28 17:19:27 +08:00
Will Miao
34791c2ad7 fix(recipe): use resources type field to identify checkpoint instead of modelVersionIds[0]
When importing a CivitAI image as a recipe, modelVersionIds[0] was blindly used as the checkpoint version ID. This array mixes checkpoints and LoRAs without ordering guarantees, causing LoRAs to be saved as the recipe checkpoint.

Fix by:
1. Removing the modelVersionIds[0] fallback in _download_remote_media
2. Parsing resources entries with type:"model" as the checkpoint
3. Adding model type validation in populate_checkpoint_from_civitai

Also add 2 tests for the new behavior and fix 3 tests whose mocks lacked the required model.type field.
2026-05-28 15:46:38 +08:00
Will Miao
3f6824eef6 fix(example-images): exclude failed_models from check_pending_models pending count
Previously check_pending_models() only skipped models already in
processed_models, so models that had permanently failed (no CivitAI
images available, download errors) were forever reported as "pending".
This caused repeated auto-download cycles with no actual work to do.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 12:00:25 +08:00
Will Miao
3919dfa3f4 fix(metadata): suppress rate-limit propagation when model already confirmed deleted
When CivitAI returns 404 (ResourceNotFoundError) and a fallback provider
like CivArchive subsequently rate-limits, the ChainedMetadataProvider
now suppresses the RateLimitError instead of propagating it. Previously,
the rate-limit error would bubble up through _refresh_single_model and
cause the outer retry loop to re-process the same model repeatedly,
producing dozens of duplicate "Model X is no longer available" log
messages and wasting API quota.

The model is NOT permanently marked as ignored — its last_checked_at
timestamp is preserved, so it will be retried on the next refresh cycle
when the rate limit has cleared and CivArchive may still have the data.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 11:56:22 +08:00
Will Miao
7124b5293f chore(settings): remove unused example_images config, add unet folder_paths example 2026-05-27 19:58:56 +08:00
Will Miao
d2a04f8993 fix(model-hash-index): clean up AutoV2 entry in remove_by_hash 2026-05-27 19:38:08 +08:00
pixelpaws
7027a7c270 Merge pull request #946 from 1756141021/fix/autov2-hash-matching
fix: match local LoRAs by AutoV2 hash when Civitai model is deleted
2026-05-27 19:20:31 +08:00
hein
0a1d7dfd4c fix: match local LoRAs by AutoV2 hash when Civitai model is deleted
When recipe metadata contains AutoV2 hashes (10-char short hash from
image metadata) and the Civitai API cannot resolve them to SHA256
(model deleted, API offline), the local hash index failed to match
because it only stored full SHA256 hashes.

AutoV2 is simply SHA256[:10], so we derive it automatically in
add_entry() — no extra file I/O or schema changes needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-27 14:15:01 +08:00
Will Miao
3962b1a96d fix(civitai): fall back to direct version fetch when modelVersions is empty for newly published models 2026-05-27 06:40:13 +08:00
Will Miao
8b856276bf fix(ui): escape HTML entities in parseMarkdown to prevent swallowed angle brackets 2026-05-27 06:40:13 +08:00
willmiao
c97c802956 docs: auto-update supporters list in README 2026-05-26 13:27:45 +00:00
Will Miao
24e2909627 chore(release): bump version to v1.0.8 v1.0.8 2026-05-26 21:27:29 +08:00
Will Miao
b768f1368f fix(i18n): update aria2 annotation from experimental to recommended across all locales 2026-05-26 20:22:25 +08:00
Will Miao
37ccd29fc0 feat(modal): make version name editable in model modal (#931) 2026-05-26 20:16:35 +08:00
Will Miao
7416080cfb fix(civitai): retry transient server errors and cache version info to reduce 504 timeouts
CivitaiClient._make_request now retries 5xx/524/network errors up to 3 times with exponential backoff (1s, 2s) before giving up to the fallback provider chain.

get_model_version_info gains an in-memory OrderedDict cache (LRU, max 500 entries) so duplicate lookups of the same version ID within a single import/scan flow return instantly without a redundant API call.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-26 16:09:08 +08:00
Will Miao
26be187d42 fix(i18n): translate remaining loraSyntaxFormat TODO keys across all locales
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-26 06:15:57 +08:00
Will Miao
d7caa1fa47 fix(license): remove cascading commercial-use bit encoding, clarify Allow Selling label (#941)
- _resolve_commercial_bits() no longer has Sell-implies-Image
  cascading; each CommercialUse value sets only its own bit,
  matching CivitAI's modern array-format API.
- Keep filter tag label as 'Allow Selling' for brevity; add
  title/tooltip 'Allow selling generated images' on hover.
- Same tooltip treatment for 'No Credit Required'.
- Add i18n keys for both tooltips across all 10 locales.
2026-05-26 06:02:17 +08:00
Will Miao
2629fcce23 fix(doctor): add i18n translations for check items, action buttons, and labels
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-25 22:35:48 +08:00
Will Miao
438e7d07b9 fix(i18n): add missing conflictConfirm.detail and conflictConfirm.impact keys to all locales
These keys are referenced in DoctorManager.js via translate() calls but were never added to any locale file, causing the i18n regression test to fail.

Added to all 10 locales: en, zh-CN, zh-TW, ja, ko, ru, de, fr, es, he.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-25 22:25:13 +08:00
Will Miao
e9932ea870 feat(tags): add right-click context menu with copy for trigger word tags
- Add showTagContextMenu() with Copy option for all tags,
  plus Edit Group for multi-item group tags
- Attach contextmenu listener to simple tags
- Move group tag contextmenu outside items.length > 1 guard so
  single-child groups also get the context menu (bugfix)
- Clean up hanging context menu on re-render
2026-05-25 22:16:54 +08:00
Will Miao
5dd8b96422 fix(autocomplete): reactively refresh lora syntax format cache on settings change (#917)
The autocomplete module cached the lora_syntax_format value at module load
but never updated it when the setting changed, causing autocomplete to
always insert legacy A1111 format even when 'full path' was configured.

- Expose refreshLoraSyntaxFormat() to re-fetch the setting from the API
- Listen for cross-tab 'storage' events to react to settings saved in
  the standalone web UI
- Listen for 'visibilitychange' to refresh when the user switches back
  to the ComfyUI tab
- Wire SettingsManager.saveSetting() to set a localStorage key when
  lora_syntax_format changes, triggering the storage event
2026-05-25 22:03:56 +08:00
Will Miao
5e1cf68bbd fix(settings): sync loraSyntaxFormat select value from state on modal open (#917)
was missing the line to set the
select element's value from ,
causing the dropdown to always show the first option ("Full Path")
when reopening the settings modal, regardless of the persisted value.
Runtime behavior was unaffected since  reads from
the state directly.
2026-05-25 21:35:15 +08:00
Will Miao
1044fa3c83 feat(doctor): improve duplicate filename conflict UX with confirm modal, syntax-format nav, and i18n
- Remove [LoRAs] prefix noise from conflict detail display
- Limit inline conflict groups to 5, show remainder count
- Add 'Switch to Full Path Syntax' action in conflict card
- Add confirmation modal before resolving conflicts (shows rename strategy)
- Register resolveFilenameConflictsModal in ModalManager (fix no-op showModal)
- Switch to Interface section and add highlight animation on syntax-format nav
- Sync and translate conflictConfirm strings across all 10 locales
2026-05-25 21:25:35 +08:00
Will Miao
397892bb7f fix(recipe): treat transient server errors (524/5xx) as non-fatal in image info fetch
Extend _is_transient_server_error() check introduced in 15dfaed4 to
get_image_info(), so Cloudflare 524 and generic 5xx errors during
remote recipe import are logged as info instead of error and do not
produce scary tracebacks.

Same pattern as get_model_versions() - transient upstream failures
return None gracefully rather than being logged as errors.
2026-05-25 08:35:35 +08:00
Will Miao
f105500740 feat(doctor): suppress duplicate filename warnings when full path syntax is active (#917) 2026-05-22 22:35:06 +08:00
Will Miao
806555cf06 fix(test): update autocomplete test expectations for legacy lora syntax format (#917) 2026-05-22 21:56:38 +08:00
Will Miao
5cd7204101 fix(autocomplete): prevent blur-on-click race condition causing dropped selection (#939)
Add mousedown(e.preventDefault()) on dropdown items to prevent the textarea blur event from firing before click. Without this, the blur handler's formatAutocompleteTextOnBlur() modifies text with unmatched commas (e.g. "<lora:X:1>,search") and triggers hide() via suppressAutocompleteOnce, removing the item from the DOM before the click handler can execute.

Fixes #939
2026-05-22 21:50:26 +08:00
Will Miao
3b602a3698 feat(lora): add lora_syntax_format setting for syntax version toggle (#917)
Adds lora_syntax_format setting (full/legacy) that controls whether <lora:...> syntax uses relative paths (full) or filename only (legacy). Default is legacy for backward compatibility with A1111 convention. The full path format (<lora:relative/path/filename:strength>) enables lossless model resolution across subfolders.

Ultraworked with Sisyphus (https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-22 21:03:29 +08:00
Will Miao
15dfaed462 fix(api): treat transient server errors (524/5xx) as non-fatal in model updates (#935)
Teach CivitaiClient.get_model_versions() to recognise Cloudflare 524, generic
5xx, and connection-level errors as transient failures and return None
instead of raising RuntimeError, so a single upstream glitch does not
block the entire batch update or produce a scary traceback.

Also downgrade the generic except Exception log level in
ModelUpdateService._refresh_single_model() from error (with exc_info)
to warning (message only), since the full traceback is already logged
upstream in CivitaiClient.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-22 07:05:06 +08:00
Will Miao
0e51851025 fix(preview): stream video files manually to avoid Windows sendfile crash
aiohttp's FileResponse uses _sendfile_native on Windows (IOCP-based), which crashes with ov.getresult() when the client disconnects mid-transfer. This happens constantly when users scroll through a gallery of animated previews (video files like .mp4/.webm).

Detect video extensions and stream manually via StreamResponse + chunked reads instead, gracefully handling ConnectionResetError. Images continue using FileResponse (small files, sendfile works fine).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-21 09:12:10 +08:00
Will Miao
0d0f4defca feat(recipes): enable bulk Add Tags to Selected for recipes (#934)
- Set addTags: true in recipes bulk action config
- Add _saveRecipeTags() helper using recipe API endpoint
- Replace mode: saves tags array directly via PUT recipe/update
- Append mode: merges with existing tags from virtual scroller
- Shows bulk Add Tags modal & target menu item on recipes page
2026-05-20 23:14:38 +08:00
Will Miao
818fa34a48 fix(ui): auto-focus tag input and flush uncommitted text on save (#934)
- ModelModal (ModelTags.js): auto-focus input on entering tag edit mode
- ModelModal (ModelTags.js): flush uncommitted input text as tag on Save
- Bulk Add Tags (BulkManager.js): same two fixes
- RecipeModal already handled both cases correctly
2026-05-20 23:06:40 +08:00
Will Miao
78303b2a5e feat(ui): merge user tags into auto-tag badges and refresh on tag edit (#918)
- Layer 2 fallback: user tags overlapping with auto-tag categories
  (HIGH/LOW/I2V/T2V/TI2V/Lightning/Turbo) are merged into auto_tags,
  providing manual override when filename-based detection fails.
  Matching is case-insensitive so "high"/"High"/"HIGH" all work.
- Refresh on tag edit: save_metadata and add_tags handlers now return
  recalculated auto_tags in the response; the frontend passes them to
  VirtualScroller.updateSingleItem so badges update immediately without
  requiring a page reload.
- 8 new test cases for Layer 2 fallback and case-insensitive matching.
2026-05-20 22:48:44 +08:00
Will Miao
9ce56dd40c feat(lora): support relative paths in <lora:folder/name:strength> syntax (#917)
Autocomplete, copy/send-to-workflow, and recipe syntax now emit
<lora:folder/name:strength> instead of <lora:name:strength>, using
relative paths to disambiguate identically-named loras in different
subfolders without requiring file renames.

Backend: 3-tier hybrid resolution (path → bare → basename fallback)
across get_lora_info, get_lora_info_absolute, get_model_preview_url,
get_model_civitai_url, get_model_info_by_name, get_lora_metadata_by_filename,
and get_hash_by_filename. Also fix get_random_loras and get_cycler_list
to return path-prefixed names for randomizer/cycler consistency.

Frontend: autocomplete, copyLoraSyntax, handleSendToWorkflow emit
folder-prefixed syntax. extract_lora_name preserves relative paths.

Saved image metadata (<lora:...> in EXIF) intentionally keeps basename-only
for compatibility with A1111/Forge ecosystem.
2026-05-20 19:39:12 +08:00
Will Miao
33e5f3d85d fix(#933): compute SHA256 locally when CivitAI API returns empty hashes 2026-05-18 18:30:33 +08:00
Will Miao
031d5e4f40 fix(doctor): exclude checkpoints/embeddings from duplicate filename detection (#934)
Duplicate filename detection is only relevant for LoRAs, which use
basename-only syntax (<lora:name:strength>). Checkpoints and diffusion
models reference files via relative paths with extensions, so filename
conflicts there are false positives — there is no resolution ambiguity.

Both _log_duplicate_filename_summary() and DoctorHandler's
_check_filename_conflicts() now skip scanners with model_type != 'lora'.
2026-05-18 13:57:28 +08:00
willmiao
4ff5774e34 docs: auto-update supporters list in README 2026-05-17 12:40:26 +00:00
Will Miao
94e1a8ac7b chore(release): bump version to v1.0.7 v1.0.7 2026-05-17 20:40:13 +08:00
Will Miao
cc20d3b992 feat(ui): auto-detect HIGH/LOW badges and auto-tag filters (#918)
- Backend auto-tag extraction service: detect HIGH/LOW (Wan-only), I2V/T2V/TI2V,
  Lightning/Turbo from filename, base_model, and CivitAI version name
- HIGH/LOW badge in card footer (inline before version name), color-coded:
  blue for HIGH, teal for LOW; abbreviated to H/L in medium/compact density
- Auto-tag filter panel (I2V, T2V, TI2V, Lightning, Turbo) with tri-state
  include/exclude filtering
- Full filter pipeline: FilterCriteria → ModelFilterSet → baseModelApi params
- AUTO_TAG_GROUPS exported for frontend use
- 19 unit tests for auto-tag extraction edge cases
2026-05-17 17:45:12 +08:00
Will Miao
a74cbe7aa2 fix(test): sync civitai bulk test with nsfw param 2026-05-16 22:15:55 +08:00
Will Miao
94edfaa190 fix(import): discover all resources from CivitAI modelVersionIds
CivitAI image API returns modelVersionIds at the root level of the
response (not inside meta), containing ALL model version IDs across
all resources (checkpoint + LoRAs). Two bugs prevented LoRAs from
being discovered:

1. _download_remote_media only extracted the first modelVersionId for
   enrichment, dropping the rest.
2. CivitAI API meta parsing only ran as an EXIF fallback, but most
   images have embedded EXIF metadata (prompt, steps, etc.), so the
   fallback was never triggered.
3. When civitai_meta_raw itself has a nested 'meta' key, unwrapping
   it stripped the injected modelVersionIds.

Also fixed gen_params merge: API gen_params now overlays EXIF at the
field level instead of full replacement, preserving EXIF-only fields
like detailed generation parameters.
2026-05-16 22:12:30 +08:00
Will Miao
31c54ff068 fix(civitai): add nsfw param to user-models and batch-ids queries (#930)
The CivitAI /api/v1/models endpoint defaults to filtering out NSFW
content when the nsfw query parameter is omitted. Both get_user_models()
and get_model_versions_bulk() hit this endpoint without passing nsfw=true,
causing models whose nsfwLevel doesn't include the PG bit to be silently
dropped from results.

Add nsfw=true to both call sites so all browsing levels are returned.
2026-05-16 20:15:03 +08:00
Will Miao
21872a8e9e fix(ui): default_active in group mode should not propagate to children; hide group badge/edit for single-child groups (#929) 2026-05-16 16:52:06 +08:00
Will Miao
612612f1c7 feat(ui): add Open Source URL action to recipe modal header, align header styles with model modal 2026-05-16 16:11:14 +08:00
Will Miao
ff240db5b1 chore: reduce remote recipe import log verbosity, demote detail fields to debug 2026-05-15 21:04:09 +08:00
Will Miao
bcfed4b874 feat(ui): use recipes terminology in bulk delete confirmation for recipes page
The bulk delete confirmation modal always displayed "models" in its
text (title, message, countMessage) regardless of the current page
type. On the recipes page this is misleading since users are managing
recipes, not models.

- Add bulkDeleteRecipes i18n keys to all 10 locale files
- Update showBulkDeleteModal() to detect currentPageType and use
  recipes-specific wording when on the recipes page
2026-05-15 20:55:02 +08:00
Will Miao
1352c6ecbe fix(recipes): fall back to Civitai API meta when EXIF is empty, enrich checkpoint in analyze_remote_image
- When downloaded Civitai image has no embedded EXIF, parse the
  already-fetched Civitai API meta (resources, hashes) directly
  instead of skipping parser altogether.
- Extract loras and model from parser output to fill metadata gaps
  when the primary import path doesn't provide them.
- Read modelVersionIds[0] as fallback when modelVersionId is None
  (Civitai API returns both but the singular form can be absent).
- Run RecipeEnricher in analyze_remote_image before returning, so
  the LM UI receives complete metadata including checkpoint with
  zero additional API calls (reuses the image_info already fetched).
2026-05-15 20:31:34 +08:00
Will Miao
30b01b8a92 fix(recipes): offload EXIF to thread pool, throttle concurrent imports, eliminate duplicate Civitai API call
- Wrap ExifUtils.extract_image_metadata() with asyncio.to_thread() in
  both import handlers and analysis_service to prevent Pillow/piexif
  from blocking ComfyUI's event loop during batch imports.
- Add asyncio.Semaphore(2) to import_remote_recipe and import_from_url
  endpoints to cap concurrent heavy work and prevent event loop starvation.
- Pre-fetch Civitai image_info during download and pass it to the recipe
  enricher, eliminating a redundant get_image_info() API round-trip.
2026-05-15 18:29:54 +08:00
Will Miao
a105cb322b fix(metadata): prune stale example-image entries when files are deleted on disk (#927) 2026-05-14 20:51:33 +08:00