pixlstash 1.6.0.dev1__tar.gz → 1.6.0.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. {pixlstash-1.6.0.dev1/pixlstash.egg-info → pixlstash-1.6.0.dev2}/PKG-INFO +45 -6
  2. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/README.md +43 -4
  3. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/frontend/package-lock.json +2 -2
  4. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/frontend/package.json +1 -1
  5. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/auth.py +83 -6
  6. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/face.py +6 -0
  7. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/picture.py +78 -409
  8. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/user.py +3 -0
  9. pixlstash-1.6.0.dev2/pixlstash/frontend/dist/assets/Tiny5-Regular-WaYIHWdr.ttf +0 -0
  10. pixlstash-1.6.0.dev1/pixlstash/frontend/dist/assets/index-BIKsiyaO.css → pixlstash-1.6.0.dev2/pixlstash/frontend/dist/assets/index-DrzwWAiV.css +1 -1
  11. pixlstash-1.6.0.dev2/pixlstash/frontend/dist/assets/index-xPNJZNlg.js +19 -0
  12. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/index.html +2 -2
  13. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/engine.py +10 -6
  14. pixlstash-1.6.0.dev2/pixlstash/migrations/versions/0052_drop_import_excluded_sentinel.py +268 -0
  15. pixlstash-1.6.0.dev2/pixlstash/migrations/versions/0053_add_face_model_pack.py +63 -0
  16. pixlstash-1.6.0.dev2/pixlstash/migrations/versions/0054_add_sidebar_docked.py +36 -0
  17. pixlstash-1.6.0.dev2/pixlstash/migrations/versions/0055_add_sidebar_width.py +34 -0
  18. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/picture_scoring.py +0 -2
  19. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/config.py +2 -0
  20. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/import_folders.py +0 -1
  21. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/picture_sets.py +8 -8
  22. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_crud.py +636 -48
  23. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_listing.py +20 -163
  24. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_misc.py +30 -92
  25. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_search.py +9 -5
  26. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/server.py +253 -24
  27. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/startup_checks.py +10 -0
  28. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/__init__.py +4 -0
  29. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/face_extraction_task.py +35 -4
  30. pixlstash-1.6.0.dev2/pixlstash/tasks/face_model_refresh_task.py +417 -0
  31. pixlstash-1.6.0.dev2/pixlstash/tasks/missing_face_model_refresh_finder.py +94 -0
  32. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/reference_folder_scan_task.py +22 -42
  33. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/task_type.py +1 -0
  34. pixlstash-1.6.0.dev2/pixlstash/utils/insightface_model_utils.py +222 -0
  35. pixlstash-1.6.0.dev2/pixlstash/utils/query/__init__.py +3 -0
  36. pixlstash-1.6.0.dev2/pixlstash/utils/query/predicate_filter.py +379 -0
  37. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/picture_stats.py +22 -117
  38. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/user_settings_utils.py +23 -0
  39. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/vault.py +4 -0
  40. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/work_planner.py +7 -0
  41. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2/pixlstash.egg-info}/PKG-INFO +45 -6
  42. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash.egg-info/SOURCES.txt +16 -3
  43. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pyproject.toml +2 -2
  44. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_authentication.py +114 -0
  45. pixlstash-1.6.0.dev2/tests/test_default_device_override.py +62 -0
  46. pixlstash-1.6.0.dev2/tests/test_insightface_model_pack.py +578 -0
  47. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_likeness_and_face_search.py +64 -0
  48. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_migrations.py +6 -3
  49. pixlstash-1.6.0.dev2/tests/test_predicate_filter.py +444 -0
  50. pixlstash-1.6.0.dev2/tests/test_server_external_listener.py +148 -0
  51. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_server_simple.py +188 -2
  52. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_user_settings_tagger_settings.py +1 -0
  53. pixlstash-1.6.0.dev1/pixlstash/frontend/dist/assets/PressStart2P-Regular-DogiNJoF.ttf +0 -0
  54. pixlstash-1.6.0.dev1/pixlstash/frontend/dist/assets/index-9eEGd5YI.js +0 -19
  55. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/LICENSE +0 -0
  56. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/MANIFEST.in +0 -0
  57. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/frontend/LICENSE +0 -0
  58. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/LICENSE +0 -0
  59. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/__init__.py +0 -0
  60. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/alembic.ini +0 -0
  61. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/app.py +0 -0
  62. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/anchors/builtin_bad.npy +0 -0
  63. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/anchors/builtin_good.npy +0 -0
  64. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/comfyui-workflows/built-in/Flux2-Klein-Image-Edit.json +0 -0
  65. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/comfyui-workflows/built-in/Flux2-Klein-t2i.json +0 -0
  66. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/comfyui-workflows/built-in/Upscale-2x-RealESRGAN.json +0 -0
  67. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/scalar-assets/ScreenshotToken.jpg +0 -0
  68. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/scalar-assets/ScreenshotTokens.jpg +0 -0
  69. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/scalar-assets/ScreenshotsUserSettings.jpg +0 -0
  70. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/scalar-assets/WhereIsUserSettings.jpg +0 -0
  71. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/data/scalar-assets/logo.png +0 -0
  72. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/database.py +0 -0
  73. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/__init__.py +0 -0
  74. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/character.py +0 -0
  75. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/deleted_file_log.py +0 -0
  76. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/guest_score.py +0 -0
  77. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/guest_session.py +0 -0
  78. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/import_folder.py +0 -0
  79. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/metadata.py +0 -0
  80. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/picture_likeness.py +0 -0
  81. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/picture_project.py +0 -0
  82. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/picture_set.py +0 -0
  83. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/picture_stack.py +0 -0
  84. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/project.py +0 -0
  85. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/quality.py +0 -0
  86. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/reference_folder.py +0 -0
  87. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/snapshot.py +0 -0
  88. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/tag.py +0 -0
  89. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/tag_prediction.py +0 -0
  90. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/db_models/user_token.py +0 -0
  91. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/event_types.py +0 -0
  92. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/Empty.png +0 -0
  93. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/EmptyTrash.png +0 -0
  94. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/Logo.png +0 -0
  95. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/Watermark.png +0 -0
  96. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
  97. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
  98. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
  99. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
  100. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/favicon.ico +0 -0
  101. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/frontend/dist/vite.svg +0 -0
  102. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_loading_dataset_prepper.py +0 -0
  103. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/__init__.py +0 -0
  104. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/base.py +0 -0
  105. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/built-in/blur_sharpen.py +0 -0
  106. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/built-in/brightness_contrast.py +0 -0
  107. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/built-in/colour_filter.py +0 -0
  108. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/built-in/pixelate.py +0 -0
  109. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/built-in/plugin_template.py +0 -0
  110. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/built-in/rotate.py +0 -0
  111. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/built-in/scaling.py +0 -0
  112. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/registry.py +0 -0
  113. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/image_plugins/service.py +0 -0
  114. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/__init__.py +0 -0
  115. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/model_lifecycle.py +0 -0
  116. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/vram_budget.py +0 -0
  117. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/workflows/__init__.py +0 -0
  118. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/workflows/clip_embedding.py +0 -0
  119. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/workflows/description.py +0 -0
  120. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/workflows/face_embedding.py +0 -0
  121. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/workflows/tagging.py +0 -0
  122. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/inference/workflows/text_embedding.py +0 -0
  123. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/env.py +0 -0
  124. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/script.py.mako +0 -0
  125. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0001_baseline.py +0 -0
  126. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0002_add_text_score.py +0 -0
  127. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0003_add_original_file_name.py +0 -0
  128. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0004_add_comfyui_fields.py +0 -0
  129. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0005_add_projects.py +0 -0
  130. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0006_add_attachment_url.py +0 -0
  131. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0007_add_picture_project_id.py +0 -0
  132. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0008_add_compact_mode.py +0 -0
  133. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0009_add_picture_project_membership.py +0 -0
  134. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0010_project_name_uniqueness.py +0 -0
  135. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0011_pictureset_name_uniqueness.py +0 -0
  136. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0012_character_name_uniqueness.py +0 -0
  137. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0013_tag_prediction.py +0 -0
  138. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0014_tag_prediction_composite_index.py +0 -0
  139. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0015_tag_prediction_model_version_rename.py +0 -0
  140. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0016_tag_prediction_confirm_applied.py +0 -0
  141. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0017_anomaly_tag_uncertainty.py +0 -0
  142. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0018_anomaly_tag_uncertainty_disagreement.py +0 -0
  143. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0019_pending_character_id.py +0 -0
  144. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0020_source_picture_id.py +0 -0
  145. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0021_tagger_enabled_flags.py +0 -0
  146. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0022_add_check_for_updates.py +0 -0
  147. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0023_add_show_keyboard_hint.py +0 -0
  148. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0024_add_deleted_file_log.py +0 -0
  149. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0025_add_reference_folders.py +0 -0
  150. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0026_add_caption_file_and_sync_captions.py +0 -0
  151. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0027_add_caption_file_mtime.py +0 -0
  152. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0028_add_smart_score.py +0 -0
  153. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0029_add_import_excluded_to_picture.py +0 -0
  154. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0030_add_import_folders.py +0 -0
  155. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0031_migrate_watch_folders_to_import_folder.py +0 -0
  156. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0032_add_reference_folder_host_path.py +0 -0
  157. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0033_add_import_folder_host_path.py +0 -0
  158. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0034_add_token_scope_fields.py +0 -0
  159. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0035_drop_face_quality.py +0 -0
  160. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0036_add_token_include_attachments.py +0 -0
  161. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0037_add_user_public_url.py +0 -0
  162. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0038_add_watermark_fields.py +0 -0
  163. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0039_drop_color_histogram.py +0 -0
  164. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0040_move_text_score_to_picture.py +0 -0
  165. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0041_guest_scores.py +0 -0
  166. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0042_guest_session_cookie_token.py +0 -0
  167. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0043_pictureset_icon_color.py +0 -0
  168. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0044_add_grid_sort_indexes.py +0 -0
  169. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0045_tagger_settings.py +0 -0
  170. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0046_tag_sentinel_rename.py +0 -0
  171. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0047_add_stack_leader_grid_indexes.py +0 -0
  172. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0048_normalize_stack_positions.py +0 -0
  173. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0049_snapshots.py +0 -0
  174. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0050_reset_metadata_hash_membership.py +0 -0
  175. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/migrations/versions/0051_deleted_file_log_path_sha.py +0 -0
  176. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/pixl_logging.py +0 -0
  177. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/__init__.py +0 -0
  178. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/_helpers.py +0 -0
  179. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/characters.py +0 -0
  180. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/comfyui.py +0 -0
  181. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/filesystem.py +0 -0
  182. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/guest_scores.py +0 -0
  183. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/__init__.py +0 -0
  184. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_export.py +0 -0
  185. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_face_search.py +0 -0
  186. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_helpers.py +0 -0
  187. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_import.py +0 -0
  188. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_likeness_search.py +0 -0
  189. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/pictures/_thumbnails.py +0 -0
  190. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/projects.py +0 -0
  191. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/reference_folders.py +0 -0
  192. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/share.py +0 -0
  193. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/snapshots.py +0 -0
  194. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/stacks.py +0 -0
  195. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/tag_predictions.py +0 -0
  196. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/taggers.py +0 -0
  197. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/routes/tags.py +0 -0
  198. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/__init__.py +0 -0
  199. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/config_service.py +0 -0
  200. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/plugin_service.py +0 -0
  201. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/restore_service.py +0 -0
  202. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/search_query_service.py +0 -0
  203. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/share_service.py +0 -0
  204. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/snapshot_service.py +0 -0
  205. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/stack_membership.py +0 -0
  206. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/services/tag_prediction_service.py +0 -0
  207. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/stacking.py +0 -0
  208. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/__init__.py +0 -0
  209. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/base.py +0 -0
  210. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/clip_service.py +0 -0
  211. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/florence2.py +0 -0
  212. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/joycaption.py +0 -0
  213. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/pixlstash_tagger.py +0 -0
  214. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/registry.py +0 -0
  215. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/sbert.py +0 -0
  216. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tagger_plugins/wd14.py +0 -0
  217. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/task_runner.py +0 -0
  218. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/base_task.py +0 -0
  219. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/base_task_finder.py +0 -0
  220. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/comfyui_extraction_task.py +0 -0
  221. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/description_task.py +0 -0
  222. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/ensure_gfs_snapshot_finder.py +0 -0
  223. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/ensure_gfs_snapshot_task.py +0 -0
  224. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/face_detection_task.py +0 -0
  225. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/image_embedding_task.py +0 -0
  226. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/likeness_parameters_task.py +0 -0
  227. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/likeness_task.py +0 -0
  228. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_comfyui_extraction_finder.py +0 -0
  229. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_description_finder.py +0 -0
  230. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_face_extraction_finder.py +0 -0
  231. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_file_purge_finder.py +0 -0
  232. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_file_purge_task.py +0 -0
  233. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_image_embedding_finder.py +0 -0
  234. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_likeness_finder.py +0 -0
  235. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_likeness_parameters_finder.py +0 -0
  236. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_quality_finder.py +0 -0
  237. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_smart_score_finder.py +0 -0
  238. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_source_face_likeness_finder.py +0 -0
  239. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_tag_finder.py +0 -0
  240. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_text_embedding_finder.py +0 -0
  241. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_text_score_finder.py +0 -0
  242. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/missing_watch_folder_import_finder.py +0 -0
  243. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/quality_task.py +0 -0
  244. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/reference_folder_scan_finder.py +0 -0
  245. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/smart_score_task.py +0 -0
  246. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/source_face_likeness_task.py +0 -0
  247. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/tag_task.py +0 -0
  248. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/text_embedding_task.py +0 -0
  249. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/text_score_task.py +0 -0
  250. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/tasks/watch_folder_import_task.py +0 -0
  251. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/__init__.py +0 -0
  252. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/atomic_write.py +0 -0
  253. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/caption_file_utils.py +0 -0
  254. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/comfyui_utilities.py +0 -0
  255. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/face_tags.py +0 -0
  256. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/host_path_utils.py +0 -0
  257. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/image_processing/__init__.py +0 -0
  258. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/image_processing/face_utils.py +0 -0
  259. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/image_processing/image_utils.py +0 -0
  260. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/image_processing/video_utils.py +0 -0
  261. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/insightface_batched.py +0 -0
  262. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/likeness/__init__.py +0 -0
  263. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/likeness/likeness_parameter_utils.py +0 -0
  264. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/likeness/likeness_utils.py +0 -0
  265. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/model_utils.py +0 -0
  266. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/path_mapper.py +0 -0
  267. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/quality/__init__.py +0 -0
  268. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/quality/quality_utils.py +0 -0
  269. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/quality/smart_score_utils.py +0 -0
  270. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/rate_limiter.py +0 -0
  271. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/reference_folder_validator.py +0 -0
  272. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/reference_folder_watcher.py +0 -0
  273. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/__init__.py +0 -0
  274. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/caption_utils.py +0 -0
  275. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/export_utils.py +0 -0
  276. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/filter_helpers.py +0 -0
  277. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/path_utils.py +0 -0
  278. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/serialization_utils.py +0 -0
  279. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/system_utils.py +0 -0
  280. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/service/tag_prediction_utils.py +0 -0
  281. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/snapshot_compression.py +0 -0
  282. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/stack/__init__.py +0 -0
  283. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/stack/stack_utils.py +0 -0
  284. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/vram_utils.py +0 -0
  285. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/utils/watermark.py +0 -0
  286. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash/worker_config.py +0 -0
  287. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash.egg-info/dependency_links.txt +0 -0
  288. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash.egg-info/entry_points.txt +0 -0
  289. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash.egg-info/requires.txt +0 -0
  290. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/pixlstash.egg-info/top_level.txt +0 -0
  291. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/setup.cfg +0 -0
  292. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/setup.py +0 -0
  293. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_api_coverage.py +0 -0
  294. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_architecture_guardrails.py +0 -0
  295. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_backend_order_stability.py +0 -0
  296. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_batch_apply_scores.py +0 -0
  297. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_characters_api.py +0 -0
  298. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_clip_text_embedding_similarity.py +0 -0
  299. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_comfyui_workflow_extraction.py +0 -0
  300. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_docker_windows_host_paths.py +0 -0
  301. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_export_api.py +0 -0
  302. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_face_detection_extreme_aspect_ratio.py +0 -0
  303. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_face_extraction_speed.py +0 -0
  304. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_facial_features_worker.py +0 -0
  305. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_find_orphaned_files.py +0 -0
  306. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_florence.py +0 -0
  307. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_full_pipeline.py +0 -0
  308. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_gfs_snapshot_schedule.py +0 -0
  309. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_guest_scoring.py +0 -0
  310. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_image_embedding_worker.py +0 -0
  311. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_image_plugins_api.py +0 -0
  312. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_likeness_worker.py +0 -0
  313. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_many_to_many_face_data.py +0 -0
  314. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_metadata_hash.py +0 -0
  315. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_openapi_response_schemas.py +0 -0
  316. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_picture_plugins.py +0 -0
  317. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_picture_sets.py +0 -0
  318. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_picture_stack_utils.py +0 -0
  319. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_pictures_stream.py +0 -0
  320. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_projects_api.py +0 -0
  321. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_quality_task_shutdown.py +0 -0
  322. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_rate_limiter.py +0 -0
  323. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_read_token_security.py +0 -0
  324. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_restore.py +0 -0
  325. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_server.py +0 -0
  326. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_smart_score_consistency.py +0 -0
  327. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_snapshot_compression.py +0 -0
  328. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_snapshots.py +0 -0
  329. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_snapshots_auth.py +0 -0
  330. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_ssl_generation.py +0 -0
  331. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_stack_position_invariant.py +0 -0
  332. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_stacks_api.py +0 -0
  333. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_stacks_membership.py +0 -0
  334. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_stats_api.py +0 -0
  335. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_tag_predictions_api.py +0 -0
  336. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_tag_task.py +0 -0
  337. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_tag_worker.py +0 -0
  338. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_tagger_plugin_registry.py +0 -0
  339. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_vram_batch_budget.py +0 -0
  340. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_watch_folder_worker.py +0 -0
  341. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_websocket_auth.py +0 -0
  342. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_work_planner.py +0 -0
  343. {pixlstash-1.6.0.dev1 → pixlstash-1.6.0.dev2}/tests/test_workers_api.py +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixlstash
3
- Version: 1.6.0.dev1
3
+ Version: 1.6.0.dev2
4
4
  Summary: Self-hosted picture library with AI tagging, semantic search, and a clean web UI
5
- Author: Gaute Lindkvist
5
+ Author-email: Gaute Lindkvist <lindkvis@gmail.com>
6
6
  License-Expression: GPL-3.0-only AND MIT
7
7
  Project-URL: Homepage, https://pikselkroken.github.io/pixlstash
8
8
  Project-URL: Repository, https://github.com/pikselkroken/pixlstash
@@ -110,6 +110,13 @@ PixlStash runs on your machine and serves the UI at a local (or Internet-facing)
110
110
  </a>
111
111
  </p>
112
112
 
113
+ PixlStash is available as a **native desktop app for Windows, macOS, and Linux**
114
+ (no Python or browser tab required), as a Windows installer, a Docker image, or a
115
+ pip package. The desktop app ships a ready-to-run CPU runtime (Metal on Apple
116
+ Silicon), so it works offline out of the box, and auto-detects your hardware to
117
+ offer optional GPU acceleration (NVIDIA CUDA / AMD ROCm), which it installs on
118
+ demand straight from PyPI / PyTorch.
119
+
113
120
  Detailed installation instructions on <a href="http://pixlstash.dev/install.html">pixlstash.dev</a>.
114
121
 
115
122
 
@@ -121,6 +128,11 @@ On first run, PixlStash creates a user config directory and stores:
121
128
  - Database
122
129
  - Imported media files
123
130
 
131
+ The **desktop app** uses this same platform user data directory, so a desktop
132
+ install shares its library with a pip or Docker install on the same machine. If
133
+ you add GPU acceleration, the desktop app stores the downloaded GPU wheels under
134
+ the app's own user-data directory.
135
+
124
136
  > **Model downloads:** On first startup, PixlStash automatically downloads the AI models required for tagging, captioning, and quality scoring. This includes several hundred MB of model weights. Downloads are stored in the platform user data directory:
125
137
  >
126
138
  > | OS | Path |
@@ -317,10 +329,36 @@ Import Folders UI/API, not in `server-config.json`.
317
329
 
318
330
  ### Processing
319
331
 
320
- | Key | Default | Description |
321
- | -------------------------------- | ------- | ---------------------------------------------------- |
322
- | `default_device` | `"cpu"` | Device used for AI processing (`"cpu"` or `"cuda"`). |
323
- | `generate_thumbnails_on_startup` | `true` | Generate missing thumbnails when the server starts. |
332
+ | Key | Default | Description |
333
+ | -------------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------- |
334
+ | `default_device` | `"cpu"` | Device used for AI processing (`"cpu"` or `"cuda"`). |
335
+ | `insightface_model_pack` | `"buffalo_l"` | InsightFace model pack used by the face detection / recognition pipeline. One of `"buffalo_l"` or `"auraface"`. |
336
+ | `generate_thumbnails_on_startup` | `true` | Generate missing thumbnails when the server starts. |
337
+
338
+ #### Face model pack and licensing
339
+
340
+ `insightface_model_pack` selects which InsightFace model pack powers face
341
+ detection and face recognition. The licensing decision is yours;
342
+ PixlStash simply makes the choice available.
343
+
344
+ - **`buffalo_l`** (default): the standard InsightFace pack. Its recognition
345
+ weights are trained on the WebFace600K dataset, which is licensed for
346
+ **non-commercial research use only**. This is the right choice for personal
347
+ and research use, and it downloads automatically on first use.
348
+ - **`auraface`**: the [`fal/AuraFace-v1`](https://huggingface.co/fal/AuraFace-v1)
349
+ pack, whose weights are **Apache-2.0 licensed** and therefore suitable if you
350
+ need to use face features in a **commercial** setting. It uses the same
351
+ SCRFD-10G face detector as `buffalo_l`, so switching only changes the
352
+ recognition embedding. When selected, PixlStash downloads the pack from a
353
+ pinned HuggingFace revision into `~/.insightface/models/auraface/` on first
354
+ use. If the automatic download fails (for example, no network access), you can
355
+ place the pack's `.onnx` files in that directory manually and restart.
356
+
357
+ Changing this setting on an existing library does **not** delete your faces or
358
+ your manual character assignments. PixlStash detects faces whose embeddings came
359
+ from a different pack and refreshes those embeddings in place, in the background,
360
+ keeping each face's identity intact. New imports are always processed first, so a
361
+ refresh sweep never starves brand-new pictures.
324
362
 
325
363
  To remove stale database records for missing source files at startup, run:
326
364
 
@@ -345,6 +383,7 @@ python -m pixlstash.app --cleanup-missing-pictures
345
383
  "require_ssl": false,
346
384
  "image_root": "/home/user/.config/pixlstash/images",
347
385
  "default_device": "cpu",
386
+ "insightface_model_pack": "buffalo_l",
348
387
  "generate_thumbnails_on_startup": true
349
388
  }
350
389
  ```
@@ -36,6 +36,13 @@ PixlStash runs on your machine and serves the UI at a local (or Internet-facing)
36
36
  </a>
37
37
  </p>
38
38
 
39
+ PixlStash is available as a **native desktop app for Windows, macOS, and Linux**
40
+ (no Python or browser tab required), as a Windows installer, a Docker image, or a
41
+ pip package. The desktop app ships a ready-to-run CPU runtime (Metal on Apple
42
+ Silicon), so it works offline out of the box, and auto-detects your hardware to
43
+ offer optional GPU acceleration (NVIDIA CUDA / AMD ROCm), which it installs on
44
+ demand straight from PyPI / PyTorch.
45
+
39
46
  Detailed installation instructions on <a href="http://pixlstash.dev/install.html">pixlstash.dev</a>.
40
47
 
41
48
 
@@ -47,6 +54,11 @@ On first run, PixlStash creates a user config directory and stores:
47
54
  - Database
48
55
  - Imported media files
49
56
 
57
+ The **desktop app** uses this same platform user data directory, so a desktop
58
+ install shares its library with a pip or Docker install on the same machine. If
59
+ you add GPU acceleration, the desktop app stores the downloaded GPU wheels under
60
+ the app's own user-data directory.
61
+
50
62
  > **Model downloads:** On first startup, PixlStash automatically downloads the AI models required for tagging, captioning, and quality scoring. This includes several hundred MB of model weights. Downloads are stored in the platform user data directory:
51
63
  >
52
64
  > | OS | Path |
@@ -243,10 +255,36 @@ Import Folders UI/API, not in `server-config.json`.
243
255
 
244
256
  ### Processing
245
257
 
246
- | Key | Default | Description |
247
- | -------------------------------- | ------- | ---------------------------------------------------- |
248
- | `default_device` | `"cpu"` | Device used for AI processing (`"cpu"` or `"cuda"`). |
249
- | `generate_thumbnails_on_startup` | `true` | Generate missing thumbnails when the server starts. |
258
+ | Key | Default | Description |
259
+ | -------------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------- |
260
+ | `default_device` | `"cpu"` | Device used for AI processing (`"cpu"` or `"cuda"`). |
261
+ | `insightface_model_pack` | `"buffalo_l"` | InsightFace model pack used by the face detection / recognition pipeline. One of `"buffalo_l"` or `"auraface"`. |
262
+ | `generate_thumbnails_on_startup` | `true` | Generate missing thumbnails when the server starts. |
263
+
264
+ #### Face model pack and licensing
265
+
266
+ `insightface_model_pack` selects which InsightFace model pack powers face
267
+ detection and face recognition. The licensing decision is yours;
268
+ PixlStash simply makes the choice available.
269
+
270
+ - **`buffalo_l`** (default): the standard InsightFace pack. Its recognition
271
+ weights are trained on the WebFace600K dataset, which is licensed for
272
+ **non-commercial research use only**. This is the right choice for personal
273
+ and research use, and it downloads automatically on first use.
274
+ - **`auraface`**: the [`fal/AuraFace-v1`](https://huggingface.co/fal/AuraFace-v1)
275
+ pack, whose weights are **Apache-2.0 licensed** and therefore suitable if you
276
+ need to use face features in a **commercial** setting. It uses the same
277
+ SCRFD-10G face detector as `buffalo_l`, so switching only changes the
278
+ recognition embedding. When selected, PixlStash downloads the pack from a
279
+ pinned HuggingFace revision into `~/.insightface/models/auraface/` on first
280
+ use. If the automatic download fails (for example, no network access), you can
281
+ place the pack's `.onnx` files in that directory manually and restart.
282
+
283
+ Changing this setting on an existing library does **not** delete your faces or
284
+ your manual character assignments. PixlStash detects faces whose embeddings came
285
+ from a different pack and refreshes those embeddings in place, in the background,
286
+ keeping each face's identity intact. New imports are always processed first, so a
287
+ refresh sweep never starves brand-new pictures.
250
288
 
251
289
  To remove stale database records for missing source files at startup, run:
252
290
 
@@ -271,6 +309,7 @@ python -m pixlstash.app --cleanup-missing-pictures
271
309
  "require_ssl": false,
272
310
  "image_root": "/home/user/.config/pixlstash/images",
273
311
  "default_device": "cpu",
312
+ "insightface_model_pack": "buffalo_l",
274
313
  "generate_thumbnails_on_startup": true
275
314
  }
276
315
  ```
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pixlstash-frontend",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pixlstash-frontend",
9
- "version": "1.5.0",
9
+ "version": "1.6.0",
10
10
  "dependencies": {
11
11
  "@mdi/font": "^7.4.47",
12
12
  "axios": "^1.16.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pixlstash-frontend",
3
3
  "private": true,
4
- "version": "1.5.0",
4
+ "version": "1.6.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -1,5 +1,6 @@
1
1
  import hashlib
2
2
  import ipaddress
3
+ import os
3
4
  import re
4
5
  import secrets
5
6
  import threading
@@ -195,6 +196,12 @@ class AuthService:
195
196
  self._server_config_path = server_config_path
196
197
  self._logger = logger
197
198
  self.active_session_ids: dict[str, int] = {}
199
+ # The pre-authenticated Electron desktop owner session, if seeded (see
200
+ # seed_desktop_session). It grants full owner access and is therefore
201
+ # pinned to local connections only: the desktop window reaches the
202
+ # backend over loopback, so this session must never authenticate a
203
+ # request arriving on the optional external listener.
204
+ self._desktop_session_token: Optional[str] = None
198
205
  self.user: Optional[User] = None
199
206
  self.password_hash: Optional[str] = None
200
207
  self.username: Optional[str] = None
@@ -269,12 +276,22 @@ class AuthService:
269
276
  return sum(1 for ts in self._guest_sessions.values() if ts >= active_cutoff)
270
277
 
271
278
  def ensure_secure_when_required(self, request: Request):
272
- if self._server_config.get("require_ssl", False):
273
- if request.url.scheme != "https":
274
- raise HTTPException(
275
- status_code=403,
276
- detail="HTTPS is required for this operation.",
277
- )
279
+ if not self._server_config.get("require_ssl", False):
280
+ return
281
+ if request.url.scheme == "https":
282
+ return
283
+ # require_ssl governs the *external* surface only. The Electron desktop
284
+ # window always reaches the backend over a plain-HTTP loopback connection
285
+ # by design (require_ssl drives the separate external listener, not this
286
+ # one), and a standalone HTTPS-only server never serves plaintext at all.
287
+ # So a local/loopback client must not be forced onto HTTPS — only a
288
+ # genuinely remote plaintext request is rejected.
289
+ if is_local_ip(self._get_real_client_ip(request)):
290
+ return
291
+ raise HTTPException(
292
+ status_code=403,
293
+ detail="HTTPS is required for this operation.",
294
+ )
278
295
 
279
296
  def _get_real_client_ip(self, request: Request) -> str:
280
297
  trusted = self._server_config.get("trusted_proxies", [])
@@ -340,6 +357,49 @@ class AuthService:
340
357
  self.username = user.username if user else None
341
358
  return user
342
359
 
360
+ # Env var the Electron desktop shell uses to hand the server a
361
+ # pre-authenticated owner session token (see seed_desktop_session).
362
+ DESKTOP_SESSION_ENV = "PIXLSTASH_DESKTOP_SESSION"
363
+
364
+ def seed_desktop_session(self) -> Optional[str]:
365
+ """Register a pre-authenticated owner session for the local desktop app.
366
+
367
+ When PixlStash runs inside the Electron desktop shell, the shell
368
+ generates a high-entropy token once per launch, passes it to the server
369
+ via the ``PIXLSTASH_DESKTOP_SESSION`` env var, and injects the same value
370
+ as the ``session_id`` cookie in its own ``BrowserWindow``. Seeding the
371
+ token into :attr:`active_session_ids` here means the local window opens
372
+ straight into the library with no login/registration prompt.
373
+
374
+ This affects only the loopback owner: remote browsers and API clients
375
+ present a *different* cookie/token and continue to authenticate via the
376
+ normal password login (:meth:`login`) or share tokens. Returns the
377
+ seeded token, or ``None`` when no (valid) token was supplied.
378
+ """
379
+ token = os.environ.get(self.DESKTOP_SESSION_ENV, "").strip()
380
+ if not token:
381
+ return None
382
+ # Guard against a weak/guessable token leaking owner access. The shell
383
+ # always supplies a 32+ char random token; reject anything shorter.
384
+ if len(token) < 16:
385
+ self._logger.warning(
386
+ "Ignoring %s: token too short (expected >=16 chars).",
387
+ self.DESKTOP_SESSION_ENV,
388
+ )
389
+ return None
390
+ user = self.ensure_user()
391
+ if not user or user.id is None:
392
+ self._logger.error(
393
+ "Could not seed desktop session: failed to ensure an owner user."
394
+ )
395
+ return None
396
+ self.active_session_ids[token] = user.id
397
+ self._desktop_session_token = token
398
+ self._logger.info(
399
+ "Seeded a pre-authenticated desktop session for the local owner."
400
+ )
401
+ return token
402
+
343
403
  def set_password_hash(self, hashed_password: str):
344
404
  def update_user(session: Session):
345
405
  user = session.exec(select(User)).first()
@@ -1239,6 +1299,23 @@ class AuthService:
1239
1299
  session_id = request.cookies.get("session_id")
1240
1300
  user_id = self.active_session_ids.get(session_id) if session_id else None
1241
1301
 
1302
+ # The seeded Electron desktop owner session is loopback-only: the
1303
+ # window talks to the backend over 127.0.0.1, so this high-privilege
1304
+ # session must never grant access on the optional external listener
1305
+ # (even though the cookie is scoped to the loopback origin and so is
1306
+ # not normally sent there — this is the fail-closed backstop). Drop
1307
+ # it for non-local clients and let normal token auth take over.
1308
+ if (
1309
+ user_id is not None
1310
+ and session_id == self._desktop_session_token
1311
+ and not is_local_ip(self._get_real_client_ip(request))
1312
+ ):
1313
+ self._logger.warning(
1314
+ "Rejected desktop owner session from non-local IP %s.",
1315
+ self._get_real_client_ip(request),
1316
+ )
1317
+ user_id = None
1318
+
1242
1319
  if user_id is not None:
1243
1320
  # Cookie session — full owner access, no scope restriction
1244
1321
  request.state.auth_user_id = user_id
@@ -38,6 +38,12 @@ class Face(SQLModel, table=True):
38
38
  )
39
39
  bbox_: Optional[str] = Field(sa_column=Column("bbox", String, default=None))
40
40
  features: Optional[bytes] = None
41
+ # Name of the InsightFace model pack that produced this face's embedding
42
+ # (e.g. "buffalo_l" or "auraface"). Nullable for rows created before the
43
+ # column existed; backfilled to "buffalo_l" by the Alembic migration.
44
+ model_pack: Optional[str] = Field(
45
+ sa_column=Column("model_pack", String, default=None)
46
+ )
41
47
 
42
48
  # Relationships
43
49
  picture: Optional["Picture"] = Relationship(