This commit is contained in:
mike
2026-06-27 23:01:16 +02:00
parent 52ae51fef3
commit 2ada5fb559
8 changed files with 282 additions and 105 deletions

View File

@@ -63,7 +63,9 @@ Scenery:
- The UI wants to car.html:2817 GET file:///mnt/zim/tour-comfy/output/_turntable/up_34e48ffb/turntable.jpg?t=1782562827857 net::ERR_FILE_NOT_FOUND, often want to show the wireframe - pose - The UI wants to car.html:2817 GET file:///mnt/zim/tour-comfy/output/_turntable/up_34e48ffb/turntable.jpg?t=1782562827857 net::ERR_FILE_NOT_FOUND, often want to show the wireframe - pose
- Jun 27 14:38:03 MIKE bash[3607206]: INFO: 127.0.0.1:53442 - "GET /output/_turntable/up_a1104f04/views/view_023_345deg.png HTTP/1.1" 304 Not Modified those files should be statically served from filesystem, not via server - Jun 27 14:38:03 MIKE bash[3607206]: INFO: 127.0.0.1:53442 - "GET /output/_turntable/up_a1104f04/views/view_023_345deg.png HTTP/1.1" 304 Not Modified those files should be statically served from filesystem, not via server
- Check face similarity in a group of images. - Check face similarity in a group of images.
- - implement a tag-system for images, will be used to filter, group, sort and search images. Obvious tags are VISIBLE, ARCHIVED, LIKE, DISLIKE, RATED, GROUP_ANCHOR, GROUP_MEMBER, BACKGROUND etc..
- mark image as source
- introduce multiple filmstrips. .
## refine ## refine
- when refresh page, we lose track of current jobs running. - when refresh page, we lose track of current jobs running.
@@ -88,4 +90,9 @@ group-names.json
names.json names.json
groups.json groups.json
config config
videos videos
# generieke stappen
1) 3ref image HQ detail
2) 3ref image MERGE
3) 3ref straight on- head-on - looking viewer

View File

@@ -2220,20 +2220,171 @@
// --- HYDRATION_START --- // --- HYDRATION_START ---
const PRELOADED_IMAGES = [ const PRELOADED_IMAGES = [
"20260627_201629_7_20260627_201343_image.nobg.png",
"20260627_201629_7_20260627_201343_image.png",
"20260627_225051_mr_image.png",
"20260627_224340_mr_image.png",
"20260627_224013_mr_image.png",
"20260627_223316_image.png",
"20260627_223304_image.png",
"20260627_223252_image.png",
"20260627_223028_image.png",
"20260627_223017_image.png",
"20260627_223005_image.png",
"20260627_222926_image.png",
"20260627_222915_image.png",
"20260627_222904_image.png",
"20260627_222806_mr_image.png",
"20260627_222321_image.png",
"20260627_222310_image.png",
"20260627_222259_image.png",
"20260627_222112_mr_image.png",
"20260627_222047_mr_image.png",
"20260627_222015_mr_image.png",
"20260626_034949_pose_jb.nobg.png",
"cg_0ed9a15a_face.png",
"_turntable/cg_7c7b22c9/views/view_022_330deg.png",
"20260618_015124_20260618_010617_20260615_153426_img_12.nobg.png",
"_turntable/cg_5991f3f2/views/view_002_030deg.png",
"_turntable/cg_5991f3f2/views/view_022_330deg.png",
"_turntable/up_6ed4293c/views/view_021_315deg.png",
"_turntable/up_6ed4293c/views/view_020_300deg.png",
"20260627_213910_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_213840_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_213816_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213756_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213743_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213727_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213711_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213626_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_213613_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213559_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213517_image.png",
"20260627_213504_image.png",
"20260627_213451_image.png",
"20260627_213241_12_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_213227_11_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"_turntable/cg_74544975/views/view_023_345deg.png",
"20260627_213215_10_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"_turntable/cg_74544975/views/view_022_330deg.png",
"_turntable/cg_74544975/views/view_021_315deg.png",
"_turntable/cg_74544975/views/view_020_300deg.png",
"_turntable/cg_74544975/views/view_019_285deg.png",
"_turntable/cg_74544975/views/view_018_270deg.png",
"20260627_213202_9_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_213149_8_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"_turntable/cg_74544975/views/view_004_060deg.png",
"_turntable/up_6ed4293c/views/view_019_285deg.png",
"_turntable/cg_74544975/views/view_001_015deg.png",
"_turntable/cg_74544975/views/view_000_000deg.png",
"20260627_213102_12_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213037_11_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213013_10_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212949_9_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212937_3_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212925_8_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212913_2_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212901_7_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212848_1_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212836_6_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212824_0_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212814_best_02_person_0.874_2026-06-27_20-05-05.png",
"20260627_212814_best_02_person_0.874_2026-06-27_20-05-05.jpg",
"20260627_212814_best_01_person_0.874_2026-06-27_20-05-05.png",
"20260627_212814_best_00_person_0.874_2026-06-27_20-05-05.png",
"20260627_212814_best_00_person_0.874_2026-06-27_20-05-05.jpg",
"20260627_212812_5_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg",
"20260627_212800_4_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212748_3_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212735_2_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_01_person_0.874_2026-06-27_12-18-49.jpg",
"20260627_212726_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_00_person_0.874_2026-06-27_12-18-49.jpg",
"20260627_212723_1_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212710_0_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"_turntable/up_6ed4293c/views/view_018_270deg.png",
"_turntable/up_6ed4293c/views/view_017_255deg.png",
"_turntable/up_6ed4293c/views/view_016_240deg.png",
"_turntable/up_6ed4293c/views/view_015_225deg.png",
"_turntable/up_6ed4293c/views/view_014_210deg.png",
"_turntable/up_6ed4293c/views/view_013_195deg.png",
"_turntable/up_6ed4293c/views/view_012_180deg.png",
"_turntable/up_6ed4293c/views/view_011_165deg.png",
"_turntable/up_6ed4293c/views/view_010_150deg.png",
"_turntable/up_6ed4293c/views/view_009_135deg.png",
"_turntable/up_6ed4293c/views/view_008_120deg.png",
"_turntable/up_6ed4293c/views/view_007_105deg.png",
"_turntable/up_6ed4293c/views/view_006_090deg.png",
"_turntable/up_6ed4293c/views/view_005_075deg.png",
"_turntable/up_6ed4293c/views/view_004_060deg.png",
"_turntable/up_6ed4293c/views/view_003_045deg.png",
"_turntable/up_6ed4293c/views/view_002_030deg.png",
"_turntable/up_6ed4293c/views/view_001_015deg.png",
"_turntable/up_6ed4293c/views/view_000_000deg.png", "_turntable/up_6ed4293c/views/view_000_000deg.png",
"20260627_204815_image.png",
"20260627_204804_image.png",
"20260627_204756_image.png",
"_turntable/cg_f85e7ae1/views/view_023_345deg.png",
"_turntable/cg_f85e7ae1/views/view_013_195deg.png",
"_turntable/cg_f85e7ae1/views/view_012_180deg.png",
"_turntable/cg_f85e7ae1/views/view_010_150deg.png",
"_turntable/cg_f85e7ae1/views/view_001_015deg.png",
"_turntable/cg_f85e7ae1/views/view_000_000deg.png",
"_turntable/cg_75340e8e/views/view_017_255deg.png",
"_turntable/cg_75340e8e/views/view_016_240deg.png",
"_turntable/cg_75340e8e/views/view_014_210deg.png",
"_turntable/cg_75340e8e/views/view_013_195deg.png",
"_turntable/cg_75340e8e/views/view_012_180deg.png",
"_turntable/cg_75340e8e/views/view_011_165deg.png",
"_turntable/cg_75340e8e/views/view_010_150deg.png",
"_turntable/cg_75340e8e/views/view_009_135deg.png",
"_turntable/cg_75340e8e/views/view_008_120deg.png",
"_turntable/cg_75340e8e/views/view_007_105deg.png",
"_turntable/cg_75340e8e/views/view_023_345deg.png",
"_turntable/cg_75340e8e/views/view_001_015deg.png",
"_turntable/cg_75340e8e/views/view_000_000deg.png",
"20260627_203706_11_20260627_200330_image.png",
"up_7b6eaabb_face.png",
"20260627_203654_11_20260627_200330_image.png",
"20260627_203642_11_20260627_200330_image.png",
"20260627_203626_image.png",
"20260627_203607_image.png",
"20260627_203549_image.png",
"20260627_203531_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203514_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203459_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203349_image.png",
"20260627_203337_image.png",
"20260627_203324_image.png",
"20260627_203312_image.png",
"20260627_203300_image.png",
"20260627_203247_image.png",
"up_c8be3aa7_face.png",
"20260627_203235_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203223_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203211_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203127_image.png",
"20260627_203105_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203054_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203044_image.png",
"20260627_203032_image.png",
"_turntable/up_c8be3aa7/views/view_002_030deg.png",
"_turntable/up_c8be3aa7/views/view_003_045deg.png",
"20260627_201807_12_20260627_201343_image.png", "20260627_201807_12_20260627_201343_image.png",
"20260627_201753_Screenshot_From_2026-06-27_12-32-39.png", "20260627_201753_Screenshot_From_2026-06-27_12-32-39.png",
"20260627_201751_11_20260627_201343_image.png", "20260627_201751_11_20260627_201343_image.png",
"20260627_201733_10_20260627_201343_image.png", "20260627_201733_10_20260627_201343_image.png",
"20260627_201711_9_20260627_201343_image.png", "20260627_201711_9_20260627_201343_image.png",
"20260627_201648_8_20260627_201343_image.png", "20260627_201648_8_20260627_201343_image.png",
"20260627_201629_7_20260627_201343_image.png",
"20260627_201622_Screenshot_From_2026-06-27_20-04-55.png", "20260627_201622_Screenshot_From_2026-06-27_20-04-55.png",
"20260627_201614_Screenshot_From_2026-06-27_20-04-11.png", "20260627_201614_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_201608_6_20260627_201343_image.png",
"20260627_201558_Screenshot_From_2026-06-27_19-59-43.png", "20260627_201558_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_201548_5_20260627_201343_image.png", "20260627_201548_5_20260627_201343_image.png",
"20260627_201525_4_20260627_201343_image.png",
"20260627_201518_image.png", "20260627_201518_image.png",
"20260627_201500_3_20260627_201343_image.png", "20260627_201500_3_20260627_201343_image.png",
"20260627_201439_2_20260627_201343_image.png", "20260627_201439_2_20260627_201343_image.png",
@@ -2244,16 +2395,10 @@
"_turntable/up_c8be3aa7/views/view_006_090deg.png", "_turntable/up_c8be3aa7/views/view_006_090deg.png",
"_turntable/up_c8be3aa7/views/view_005_075deg.png", "_turntable/up_c8be3aa7/views/view_005_075deg.png",
"_turntable/up_c8be3aa7/views/view_004_060deg.png", "_turntable/up_c8be3aa7/views/view_004_060deg.png",
"_turntable/up_c8be3aa7/views/view_003_045deg.png",
"_turntable/up_c8be3aa7/views/view_002_030deg.png",
"20260627_200801_12_20260627_200330_image.png",
"_turntable/up_c8be3aa7/views/view_001_015deg.png", "_turntable/up_c8be3aa7/views/view_001_015deg.png",
"20260627_200711_11_20260627_200330_image.png", "20260627_200711_11_20260627_200330_image.png",
"20260627_200632_9_20260627_200330_image.png", "20260627_200632_9_20260627_200330_image.png",
"20260627_200534_6_20260627_200330_image.png",
"20260627_200506_image.png", "20260627_200506_image.png",
"20260627_200458_4_20260627_200330_image.png",
"20260627_200440_3_20260627_200330_image.png",
"20260627_200422_2_20260627_200330_image.png", "20260627_200422_2_20260627_200330_image.png",
"20260627_200414_image.png", "20260627_200414_image.png",
"20260627_200405_1_20260627_200330_image.png", "20260627_200405_1_20260627_200330_image.png",
@@ -2454,31 +2599,17 @@
"_turntable/cg_e964fb19/views/view_002_030deg.png", "_turntable/cg_e964fb19/views/view_002_030deg.png",
"_turntable/cg_e964fb19/views/view_001_015deg.png", "_turntable/cg_e964fb19/views/view_001_015deg.png",
"_turntable/cg_e964fb19/views/view_000_000deg.png", "_turntable/cg_e964fb19/views/view_000_000deg.png",
"_turntable/cg_75340e8e/views/view_023_345deg.png",
"_turntable/cg_75340e8e/views/view_022_330deg.png", "_turntable/cg_75340e8e/views/view_022_330deg.png",
"_turntable/cg_75340e8e/views/view_021_315deg.png", "_turntable/cg_75340e8e/views/view_021_315deg.png",
"_turntable/cg_75340e8e/views/view_020_300deg.png", "_turntable/cg_75340e8e/views/view_020_300deg.png",
"_turntable/cg_75340e8e/views/view_019_285deg.png", "_turntable/cg_75340e8e/views/view_019_285deg.png",
"_turntable/cg_75340e8e/views/view_018_270deg.png", "_turntable/cg_75340e8e/views/view_018_270deg.png",
"_turntable/cg_75340e8e/views/view_017_255deg.png",
"_turntable/cg_75340e8e/views/view_016_240deg.png",
"_turntable/cg_75340e8e/views/view_015_225deg.png", "_turntable/cg_75340e8e/views/view_015_225deg.png",
"_turntable/cg_75340e8e/views/view_014_210deg.png",
"_turntable/cg_75340e8e/views/view_013_195deg.png",
"_turntable/cg_75340e8e/views/view_012_180deg.png",
"_turntable/cg_75340e8e/views/view_011_165deg.png",
"_turntable/cg_75340e8e/views/view_010_150deg.png",
"_turntable/cg_75340e8e/views/view_009_135deg.png",
"_turntable/cg_75340e8e/views/view_008_120deg.png",
"_turntable/cg_75340e8e/views/view_007_105deg.png",
"_turntable/cg_75340e8e/views/view_006_090deg.png", "_turntable/cg_75340e8e/views/view_006_090deg.png",
"_turntable/cg_75340e8e/views/view_005_075deg.png", "_turntable/cg_75340e8e/views/view_005_075deg.png",
"_turntable/cg_75340e8e/views/view_004_060deg.png", "_turntable/cg_75340e8e/views/view_004_060deg.png",
"_turntable/cg_75340e8e/views/view_003_045deg.png", "_turntable/cg_75340e8e/views/view_003_045deg.png",
"_turntable/cg_75340e8e/views/view_002_030deg.png", "_turntable/cg_75340e8e/views/view_002_030deg.png",
"_turntable/cg_75340e8e/views/view_001_015deg.png",
"_turntable/cg_75340e8e/views/view_000_000deg.png",
"_turntable/cg_f85e7ae1/views/view_023_345deg.png",
"_turntable/cg_f85e7ae1/views/view_022_330deg.png", "_turntable/cg_f85e7ae1/views/view_022_330deg.png",
"_turntable/cg_f85e7ae1/views/view_021_315deg.png", "_turntable/cg_f85e7ae1/views/view_021_315deg.png",
"_turntable/cg_f85e7ae1/views/view_020_300deg.png", "_turntable/cg_f85e7ae1/views/view_020_300deg.png",
@@ -2488,10 +2619,7 @@
"_turntable/cg_f85e7ae1/views/view_016_240deg.png", "_turntable/cg_f85e7ae1/views/view_016_240deg.png",
"_turntable/cg_f85e7ae1/views/view_015_225deg.png", "_turntable/cg_f85e7ae1/views/view_015_225deg.png",
"_turntable/cg_f85e7ae1/views/view_014_210deg.png", "_turntable/cg_f85e7ae1/views/view_014_210deg.png",
"_turntable/cg_f85e7ae1/views/view_013_195deg.png",
"_turntable/cg_f85e7ae1/views/view_012_180deg.png",
"_turntable/cg_f85e7ae1/views/view_011_165deg.png", "_turntable/cg_f85e7ae1/views/view_011_165deg.png",
"_turntable/cg_f85e7ae1/views/view_010_150deg.png",
"_turntable/cg_f85e7ae1/views/view_009_135deg.png", "_turntable/cg_f85e7ae1/views/view_009_135deg.png",
"_turntable/cg_f85e7ae1/views/view_008_120deg.png", "_turntable/cg_f85e7ae1/views/view_008_120deg.png",
"_turntable/cg_f85e7ae1/views/view_007_105deg.png", "_turntable/cg_f85e7ae1/views/view_007_105deg.png",
@@ -2500,8 +2628,6 @@
"_turntable/cg_f85e7ae1/views/view_004_060deg.png", "_turntable/cg_f85e7ae1/views/view_004_060deg.png",
"_turntable/cg_f85e7ae1/views/view_003_045deg.png", "_turntable/cg_f85e7ae1/views/view_003_045deg.png",
"_turntable/cg_f85e7ae1/views/view_002_030deg.png", "_turntable/cg_f85e7ae1/views/view_002_030deg.png",
"_turntable/cg_f85e7ae1/views/view_001_015deg.png",
"_turntable/cg_f85e7ae1/views/view_000_000deg.png",
"_turntable/up_c31bb439/views/view_023_345deg.png", "_turntable/up_c31bb439/views/view_023_345deg.png",
"_turntable/up_c31bb439/views/view_022_330deg.png", "_turntable/up_c31bb439/views/view_022_330deg.png",
"_turntable/up_c31bb439/views/view_021_315deg.png", "_turntable/up_c31bb439/views/view_021_315deg.png",
@@ -2550,12 +2676,6 @@
"_turntable/cg_4671b6c4/views/view_002_030deg.png", "_turntable/cg_4671b6c4/views/view_002_030deg.png",
"_turntable/cg_4671b6c4/views/view_001_015deg.png", "_turntable/cg_4671b6c4/views/view_001_015deg.png",
"_turntable/cg_4671b6c4/views/view_000_000deg.png", "_turntable/cg_4671b6c4/views/view_000_000deg.png",
"_turntable/cg_74544975/views/view_023_345deg.png",
"_turntable/cg_74544975/views/view_022_330deg.png",
"_turntable/cg_74544975/views/view_021_315deg.png",
"_turntable/cg_74544975/views/view_020_300deg.png",
"_turntable/cg_74544975/views/view_019_285deg.png",
"_turntable/cg_74544975/views/view_018_270deg.png",
"_turntable/cg_74544975/views/view_017_255deg.png", "_turntable/cg_74544975/views/view_017_255deg.png",
"_turntable/cg_74544975/views/view_016_240deg.png", "_turntable/cg_74544975/views/view_016_240deg.png",
"_turntable/cg_74544975/views/view_015_225deg.png", "_turntable/cg_74544975/views/view_015_225deg.png",
@@ -2569,11 +2689,8 @@
"_turntable/cg_74544975/views/view_007_105deg.png", "_turntable/cg_74544975/views/view_007_105deg.png",
"_turntable/cg_74544975/views/view_006_090deg.png", "_turntable/cg_74544975/views/view_006_090deg.png",
"_turntable/cg_74544975/views/view_005_075deg.png", "_turntable/cg_74544975/views/view_005_075deg.png",
"_turntable/cg_74544975/views/view_004_060deg.png",
"_turntable/cg_74544975/views/view_003_045deg.png", "_turntable/cg_74544975/views/view_003_045deg.png",
"_turntable/cg_74544975/views/view_002_030deg.png", "_turntable/cg_74544975/views/view_002_030deg.png",
"_turntable/cg_74544975/views/view_001_015deg.png",
"_turntable/cg_74544975/views/view_000_000deg.png",
"_turntable/cg_73e141fa/views/view_023_345deg.png", "_turntable/cg_73e141fa/views/view_023_345deg.png",
"_turntable/cg_73e141fa/views/view_022_330deg.png", "_turntable/cg_73e141fa/views/view_022_330deg.png",
"_turntable/cg_73e141fa/views/view_021_315deg.png", "_turntable/cg_73e141fa/views/view_021_315deg.png",
@@ -3616,7 +3733,6 @@
"_turntable/cg_58c0891c/views/view_001_015deg.png", "_turntable/cg_58c0891c/views/view_001_015deg.png",
"_turntable/cg_58c0891c/views/view_000_000deg.png", "_turntable/cg_58c0891c/views/view_000_000deg.png",
"_turntable/cg_5991f3f2/views/view_023_345deg.png", "_turntable/cg_5991f3f2/views/view_023_345deg.png",
"_turntable/cg_5991f3f2/views/view_022_330deg.png",
"_turntable/cg_5991f3f2/views/view_021_315deg.png", "_turntable/cg_5991f3f2/views/view_021_315deg.png",
"_turntable/cg_5991f3f2/views/view_020_300deg.png", "_turntable/cg_5991f3f2/views/view_020_300deg.png",
"_turntable/cg_5991f3f2/views/view_019_285deg.png", "_turntable/cg_5991f3f2/views/view_019_285deg.png",
@@ -3636,7 +3752,6 @@
"_turntable/cg_5991f3f2/views/view_005_075deg.png", "_turntable/cg_5991f3f2/views/view_005_075deg.png",
"_turntable/cg_5991f3f2/views/view_004_060deg.png", "_turntable/cg_5991f3f2/views/view_004_060deg.png",
"_turntable/cg_5991f3f2/views/view_003_045deg.png", "_turntable/cg_5991f3f2/views/view_003_045deg.png",
"_turntable/cg_5991f3f2/views/view_002_030deg.png",
"_turntable/cg_5991f3f2/views/view_001_015deg.png", "_turntable/cg_5991f3f2/views/view_001_015deg.png",
"_turntable/cg_5991f3f2/views/view_000_000deg.png", "_turntable/cg_5991f3f2/views/view_000_000deg.png",
"_turntable/out4.png/views/view_023_345deg.png", "_turntable/out4.png/views/view_023_345deg.png",
@@ -4032,9 +4147,7 @@
"_turntable/cg_2afca8fc/views/view_003_045deg.png", "_turntable/cg_2afca8fc/views/view_003_045deg.png",
"_turntable/cg_2afca8fc/views/view_002_030deg.png", "_turntable/cg_2afca8fc/views/view_002_030deg.png",
"_turntable/cg_2afca8fc/views/view_000_000deg.png", "_turntable/cg_2afca8fc/views/view_000_000deg.png",
"_turntable/cg_7c7b22c9/turntable.mp4",
"_turntable/cg_7c7b22c9/views/view_023_345deg.png", "_turntable/cg_7c7b22c9/views/view_023_345deg.png",
"_turntable/cg_7c7b22c9/views/view_022_330deg.png",
"_turntable/cg_7c7b22c9/views/view_021_315deg.png", "_turntable/cg_7c7b22c9/views/view_021_315deg.png",
"_turntable/cg_7c7b22c9/views/view_020_300deg.png", "_turntable/cg_7c7b22c9/views/view_020_300deg.png",
"_turntable/cg_7c7b22c9/views/view_019_285deg.png", "_turntable/cg_7c7b22c9/views/view_019_285deg.png",
@@ -4421,7 +4534,6 @@
"_turntable/cg_e79533a4/views/view_002_030deg.png", "_turntable/cg_e79533a4/views/view_002_030deg.png",
"_turntable/cg_e79533a4/views/view_001_015deg.png", "_turntable/cg_e79533a4/views/view_001_015deg.png",
"_turntable/cg_e79533a4/views/view_000_000deg.png", "_turntable/cg_e79533a4/views/view_000_000deg.png",
"_turntable/b1.png/turntable.mp4",
"_turntable/b1.png/views/view_023_345deg.png", "_turntable/b1.png/views/view_023_345deg.png",
"_turntable/b1.png/views/view_022_330deg.png", "_turntable/b1.png/views/view_022_330deg.png",
"_turntable/b1.png/views/view_021_315deg.png", "_turntable/b1.png/views/view_021_315deg.png",
@@ -4477,9 +4589,7 @@
"20260626_040655_sc_pad_20260626_034830_jb.nobg.png", "20260626_040655_sc_pad_20260626_034830_jb.nobg.png",
"20260626_040550_sc_pad_20260626_034830_jb.nobg.png", "20260626_040550_sc_pad_20260626_034830_jb.nobg.png",
"20260626_035131_pose_pad_20260626_034830_jb.nobg.png", "20260626_035131_pose_pad_20260626_034830_jb.nobg.png",
"cg_0ed9a15a_face.png",
"20260626_035101_pad_20260626_034830_jb.nobg.png", "20260626_035101_pad_20260626_034830_jb.nobg.png",
"20260626_034949_pose_jb.nobg.png",
"20260626_034830_jb.nobg.png", "20260626_034830_jb.nobg.png",
"20260626_034830_jb.png", "20260626_034830_jb.png",
"20260626_034708_jb.png", "20260626_034708_jb.png",
@@ -4488,7 +4598,6 @@
"20260626_031810_1_20260618_050846_img_4.nobg.png", "20260626_031810_1_20260618_050846_img_4.nobg.png",
"20260618_050923_2_20260618_050846_img_4.nobg.png", "20260618_050923_2_20260618_050846_img_4.nobg.png",
"20260626_030908_1_20260618_050846_img_4.nobg.png", "20260626_030908_1_20260618_050846_img_4.nobg.png",
"20260626_031833_1_20260618_050846_img_4.png",
"20260626_031821_1_20260618_050846_img_4.png", "20260626_031821_1_20260618_050846_img_4.png",
"20260626_031810_1_20260618_050846_img_4.png", "20260626_031810_1_20260618_050846_img_4.png",
"20260626_031759_jb1.png", "20260626_031759_jb1.png",
@@ -4858,7 +4967,6 @@
"20260624_160124_1_20260619_040135_image.png", "20260624_160124_1_20260619_040135_image.png",
"20260624_160113_1_20260619_040135_image.png", "20260624_160113_1_20260619_040135_image.png",
"20260624_160102_1_20260619_040135_image.png", "20260624_160102_1_20260619_040135_image.png",
"20260624_154905_img_72.png",
"20260624_154852_img_72.png", "20260624_154852_img_72.png",
"20260624_154840_img_72.png", "20260624_154840_img_72.png",
"20260624_154821_img_72.png", "20260624_154821_img_72.png",
@@ -4866,7 +4974,6 @@
"20260624_154746_img_72.png", "20260624_154746_img_72.png",
"20260624_154729_img_72.png", "20260624_154729_img_72.png",
"20260624_154712_img_72.png", "20260624_154712_img_72.png",
"20260624_154655_img_72.png",
"20260624_154639_img_72.png", "20260624_154639_img_72.png",
"20260624_154548_img_72.png", "20260624_154548_img_72.png",
"20260624_154536_img_72.png", "20260624_154536_img_72.png",
@@ -4879,13 +4986,10 @@
"cg_b7e71d34_face.png", "cg_b7e71d34_face.png",
"20260624_154236_img_72.png", "20260624_154236_img_72.png",
"20260624_154125_img_72.png", "20260624_154125_img_72.png",
"20260624_154040_img_72.png",
"20260624_153940_img_72.png", "20260624_153940_img_72.png",
"20260624_153831_img_72.png", "20260624_153831_img_72.png",
"20260624_153614_Screenshot_From_2026-06-17_07-41-27.png", "20260624_153614_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153433_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153417_Screenshot_From_2026-06-17_07-41-27.png", "20260624_153417_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153400_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153344_Screenshot_From_2026-06-17_07-41-27.png", "20260624_153344_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153311_Screenshot_From_2026-06-17_07-41-27.png", "20260624_153311_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153102_Screenshot_From_2026-06-17_07-41-27.png", "20260624_153102_Screenshot_From_2026-06-17_07-41-27.png",
@@ -4957,7 +5061,6 @@
"20260624_140813_Screenshot_From_2026-06-17_07-43-19.png", "20260624_140813_Screenshot_From_2026-06-17_07-43-19.png",
"20260624_140807_Screenshot_From_2026-06-17_07-41-27.png", "20260624_140807_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_140605_image.png", "20260624_140605_image.png",
"20260624_140549_image.png",
"20260624_140532_image.png", "20260624_140532_image.png",
"20260624_140221_image.png", "20260624_140221_image.png",
"20260624_140129_image.png", "20260624_140129_image.png",
@@ -5586,14 +5689,10 @@
"20260622_041306_image.png", "20260622_041306_image.png",
"20260622_041253_image.png", "20260622_041253_image.png",
"20260622_040911_b1.png", "20260622_040911_b1.png",
"20260622_040858_b1.png",
"20260622_040846_b1.png",
"20260622_040727_b1.png", "20260622_040727_b1.png",
"20260622_040702_b1.png", "20260622_040702_b1.png",
"20260622_040649_b1.png",
"20260622_040636_b1.png", "20260622_040636_b1.png",
"20260622_040347_b1.png", "20260622_040347_b1.png",
"20260622_040141_b1.png",
"20260622_035945_b1.png", "20260622_035945_b1.png",
"20260622_034529_b1.png", "20260622_034529_b1.png",
"20260622_033840_b1.png", "20260622_033840_b1.png",
@@ -5868,8 +5967,6 @@
"20260620_014646_image.png", "20260620_014646_image.png",
"20260620_014349_image.png", "20260620_014349_image.png",
"20260620_014239_img_77.png", "20260620_014239_img_77.png",
"20260627_145331_dup_20260618_011550_20260616_023209_img_51.png",
"20260627_145407_dup_20260618_011550_20260616_023209_img_51.png",
"20260620_003901_2_20260619_175210_image.png", "20260620_003901_2_20260619_175210_image.png",
"20260620_003844_2_20260619_175210_image.png", "20260620_003844_2_20260619_175210_image.png",
"20260620_003828_2_20260619_175210_image.png", "20260620_003828_2_20260619_175210_image.png",
@@ -5920,10 +6017,8 @@
"20260619_224737_img_14.png", "20260619_224737_img_14.png",
"20260619_224557_img_81.png", "20260619_224557_img_81.png",
"20260619_224542_img_35.png", "20260619_224542_img_35.png",
"20260619_224219_img_12.png",
"20260619_224133_img_87.png", "20260619_224133_img_87.png",
"20260619_224007_img_31.png", "20260619_224007_img_31.png",
"20260619_223940_img_75.png",
"20260619_223856_img_37.png", "20260619_223856_img_37.png",
"20260619_223812_img_57.png", "20260619_223812_img_57.png",
"20260619_223757_img_82.png", "20260619_223757_img_82.png",
@@ -6114,7 +6209,6 @@
"20260619_041555_1_20260619_040135_image.png", "20260619_041555_1_20260619_040135_image.png",
"20260619_041544_1_20260619_040135_image.png", "20260619_041544_1_20260619_040135_image.png",
"20260619_041533_1_20260619_040135_image.png", "20260619_041533_1_20260619_040135_image.png",
"20260619_041522_1_20260619_040135_image.png",
"20260619_041511_1_20260619_040135_image.png", "20260619_041511_1_20260619_040135_image.png",
"20260619_041500_1_20260619_040135_image.png", "20260619_041500_1_20260619_040135_image.png",
"20260619_041449_1_20260619_040135_image.png", "20260619_041449_1_20260619_040135_image.png",
@@ -6372,7 +6466,6 @@
"20260618_125809_1_20260618_125748_image.png", "20260618_125809_1_20260618_125748_image.png",
"20260618_125758_0_20260618_125748_image.png", "20260618_125758_0_20260618_125748_image.png",
"20260618_125748_image.png", "20260618_125748_image.png",
"20260618_125415_6_20260618_125217_image.png",
"20260618_125358_5_20260618_125217_image.png", "20260618_125358_5_20260618_125217_image.png",
"20260618_125340_4_20260618_125217_image.png", "20260618_125340_4_20260618_125217_image.png",
"20260618_125323_3_20260618_125217_image.png", "20260618_125323_3_20260618_125217_image.png",
@@ -6431,7 +6524,6 @@
"20260618_052548_1_20260618_052526_image.png", "20260618_052548_1_20260618_052526_image.png",
"20260618_052537_0_20260618_052526_image.png", "20260618_052537_0_20260618_052526_image.png",
"20260618_052526_image.png", "20260618_052526_image.png",
"20260618_051040_8_20260618_050846_img_4.png",
"20260618_051029_7_20260618_050846_img_4.png", "20260618_051029_7_20260618_050846_img_4.png",
"20260618_051006_5_20260618_050846_img_4.png", "20260618_051006_5_20260618_050846_img_4.png",
"20260618_050923_2_20260618_050846_img_4.png", "20260618_050923_2_20260618_050846_img_4.png",
@@ -6442,18 +6534,14 @@
"20260618_015156_20260618_010700_Pasted image (4).png", "20260618_015156_20260618_010700_Pasted image (4).png",
"20260618_015145_20260618_010627_jb3.png", "20260618_015145_20260618_010627_jb3.png",
"20260618_015135_20260618_011424_20260618_004356_bb_01.png", "20260618_015135_20260618_011424_20260618_004356_bb_01.png",
"20260618_015124_20260618_010617_20260615_153426_img_12.png",
"20260618_015113_20260618_004952_jb.png", "20260618_015113_20260618_004952_jb.png",
"20260618_015030_20260618_004858_p12.png", "20260618_015030_20260618_004858_p12.png",
"20260618_015019_20260618_010638_b1.png", "20260618_015019_20260618_010638_b1.png",
"20260618_015008_20260618_011445_20260618_004450_20260617_074413_img_73.png", "20260618_015008_20260618_011445_20260618_004450_20260617_074413_img_73.png",
"20260618_013512_Pasted image (9).png", "20260618_013512_Pasted image (9).png",
"20260618_013502_kk563t.png", "20260618_013502_kk563t.png",
"20260618_011633_t159zr-1.png",
"20260618_011612_20260616_003803_img_14.png", "20260618_011612_20260616_003803_img_14.png",
"20260618_011528_20260617_074613_img_75.png",
"20260618_011517_20260618_002014_20260616_020035_img_36.png", "20260618_011517_20260618_002014_20260616_020035_img_36.png",
"20260618_011507_20260617_134615_img_86.png",
"20260618_011456_20260618_004439_20260617_005512_img_60.png", "20260618_011456_20260618_004439_20260617_005512_img_60.png",
"20260618_011445_20260618_004450_20260617_074413_img_73.png", "20260618_011445_20260618_004450_20260617_074413_img_73.png",
"20260618_011434_20260618_004847_20260615_150812_img_19_2.png", "20260618_011434_20260618_004847_20260615_150812_img_19_2.png",
@@ -6462,7 +6550,6 @@
"20260618_010710_p12-2.png", "20260618_010710_p12-2.png",
"20260618_010700_Pasted image (4).png", "20260618_010700_Pasted image (4).png",
"20260618_010627_jb3.png", "20260618_010627_jb3.png",
"20260618_010617_20260615_153426_img_12.png",
"20260618_004952_jb.png", "20260618_004952_jb.png",
"20260618_004941_out7.png", "20260618_004941_out7.png",
"20260618_004930_20260617_134041_img_84.png", "20260618_004930_20260617_134041_img_84.png",
@@ -6498,7 +6585,6 @@
"20260617_133411_img_79.png", "20260617_133411_img_79.png",
"20260617_133154_img_78.png", "20260617_133154_img_78.png",
"20260617_133129_img_77.png", "20260617_133129_img_77.png",
"20260617_074613_img_75.png",
"20260617_074413_img_73.png", "20260617_074413_img_73.png",
"20260617_074223_img_72.png", "20260617_074223_img_72.png",
"20260617_005512_img_60.png", "20260617_005512_img_60.png",

View File

@@ -112,6 +112,7 @@ def migrate_schema():
"ALTER TABLE person ADD COLUMN IF NOT EXISTS faceswap_source_video TEXT", "ALTER TABLE person ADD COLUMN IF NOT EXISTS faceswap_source_video TEXT",
"ALTER TABLE person ADD COLUMN IF NOT EXISTS archived BOOLEAN DEFAULT FALSE", "ALTER TABLE person ADD COLUMN IF NOT EXISTS archived BOOLEAN DEFAULT FALSE",
"ALTER TABLE person ADD COLUMN IF NOT EXISTS face_embedding vector(512)", "ALTER TABLE person ADD COLUMN IF NOT EXISTS face_embedding vector(512)",
"ALTER TABLE person ADD COLUMN IF NOT EXISTS is_source BOOLEAN DEFAULT FALSE",
]: ]:
cur.execute(sql) cur.execute(sql)
conn.commit() conn.commit()
@@ -124,7 +125,7 @@ def upsert_person(filename, filepath=None, name=None, group_id=None, tags=None,
sort_order=None, group_name=None, hidden=None, sort_order=None, group_name=None, hidden=None,
has_background=None, source_refs=None, has_clothing=None, has_background=None, source_refs=None, has_clothing=None,
content_type=None, faceswap_source_video=None, archived=None, content_type=None, faceswap_source_video=None, archived=None,
face_embedding=None): face_embedding=None, is_source=None):
conn = get_db_connection() conn = get_db_connection()
cur = conn.cursor() cur = conn.cursor()
face_embedding_str = ("[" + ",".join(map(str, face_embedding)) + "]") if face_embedding is not None else None face_embedding_str = ("[" + ",".join(map(str, face_embedding)) + "]") if face_embedding is not None else None
@@ -133,8 +134,8 @@ def upsert_person(filename, filepath=None, name=None, group_id=None, tags=None,
INSERT INTO person (filename, filepath, name, group_id, tags, embedding, INSERT INTO person (filename, filepath, name, group_id, tags, embedding,
clip_description, prompt, pose, sort_order, group_name, hidden, clip_description, prompt, pose, sort_order, group_name, hidden,
has_background, source_refs, has_clothing, has_background, source_refs, has_clothing,
content_type, faceswap_source_video, archived, face_embedding) content_type, faceswap_source_video, archived, face_embedding, is_source)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
ON CONFLICT (filename) DO UPDATE ON CONFLICT (filename) DO UPDATE
SET filepath = COALESCE(EXCLUDED.filepath, person.filepath), SET filepath = COALESCE(EXCLUDED.filepath, person.filepath),
name = COALESCE(EXCLUDED.name, person.name), name = COALESCE(EXCLUDED.name, person.name),
@@ -153,12 +154,13 @@ def upsert_person(filename, filepath=None, name=None, group_id=None, tags=None,
content_type = COALESCE(EXCLUDED.content_type, person.content_type), content_type = COALESCE(EXCLUDED.content_type, person.content_type),
faceswap_source_video = COALESCE(EXCLUDED.faceswap_source_video, person.faceswap_source_video), faceswap_source_video = COALESCE(EXCLUDED.faceswap_source_video, person.faceswap_source_video),
archived = COALESCE(EXCLUDED.archived, person.archived), archived = COALESCE(EXCLUDED.archived, person.archived),
face_embedding = COALESCE(EXCLUDED.face_embedding, person.face_embedding); face_embedding = COALESCE(EXCLUDED.face_embedding, person.face_embedding),
is_source = COALESCE(EXCLUDED.is_source, person.is_source);
""", (filename, filepath, name, group_id, """, (filename, filepath, name, group_id,
json.dumps(tags) if tags else None, json.dumps(tags) if tags else None,
embedding, clip_description, prompt, pose, sort_order, group_name, hidden, embedding, clip_description, prompt, pose, sort_order, group_name, hidden,
has_background, source_refs, has_clothing, has_background, source_refs, has_clothing,
content_type, faceswap_source_video, archived, face_embedding_str)) content_type, faceswap_source_video, archived, face_embedding_str, is_source))
conn.commit() conn.commit()
finally: finally:
cur.close() cur.close()
@@ -206,7 +208,7 @@ def get_person(filename):
cur.execute(""" cur.execute("""
SELECT name, group_id, tags, embedding, clip_description, filepath, SELECT name, group_id, tags, embedding, clip_description, filepath,
prompt, pose, sort_order, group_name, hidden, has_background, source_refs, prompt, pose, sort_order, group_name, hidden, has_background, source_refs,
has_clothing has_clothing, is_source
FROM person WHERE filename = %s FROM person WHERE filename = %s
""", (filename,)) """, (filename,))
return cur.fetchone() return cur.fetchone()
@@ -222,7 +224,7 @@ def list_persons(include_archived=False):
cur.execute(f""" cur.execute(f"""
SELECT filename, name, group_id, clip_description, SELECT filename, name, group_id, clip_description,
prompt, pose, sort_order, group_name, hidden, has_background, source_refs, prompt, pose, sort_order, group_name, hidden, has_background, source_refs,
has_clothing, content_type, faceswap_source_video, archived has_clothing, content_type, faceswap_source_video, archived, is_source
FROM person FROM person
{where} {where}
""") """)

View File

@@ -210,13 +210,21 @@ def _run_consistency_check():
persons = database.list_persons(include_archived=True) persons = database.list_persons(include_archived=True)
missing_files = [] missing_files = []
archived_items = [] archived_items = []
missing_group = []
for p in persons: for p in persons:
filename = p[0] filename = p[0]
group_id = p[2]
if not group_id:
missing_group.append({
"filename": filename,
"name": p[1]
})
is_archived = bool(p[14]) if p[14] else False is_archived = bool(p[14]) if p[14] else False
if is_archived: if is_archived:
archived_items.append({ archived_items.append({
"filename": filename, "filename": filename,
"group_id": p[2], "group_id": group_id,
"name": p[1] "name": p[1]
}) })
@@ -224,7 +232,7 @@ def _run_consistency_check():
if not os.path.exists(fpath): if not os.path.exists(fpath):
missing_files.append({ missing_files.append({
"filename": filename, "filename": filename,
"group_id": p[2], "group_id": group_id,
"name": p[1] "name": p[1]
}) })
@@ -244,10 +252,11 @@ def _run_consistency_check():
"timestamp": time.time(), "timestamp": time.time(),
"missing_files": missing_files, "missing_files": missing_files,
"untracked_files": untracked_files, "untracked_files": untracked_files,
"archived_items": archived_items "archived_items": archived_items,
"missing_group": missing_group
} }
_write_json(os.path.join(data_dir, "inconsistencies.json"), report) _write_json(os.path.join(data_dir, "inconsistencies.json"), report)
print(f"[consistency] check complete: {len(missing_files)} missing, {len(untracked_files)} untracked, {len(archived_items)} archived") print(f"[consistency] check complete: {len(missing_files)} missing, {len(untracked_files)} untracked, {len(archived_items)} archived, {len(missing_group)} missing group")
return report return report
except Exception as e: except Exception as e:
print(f"[consistency] check failed: {e}") print(f"[consistency] check failed: {e}")
@@ -1305,6 +1314,7 @@ def _write_all_static() -> None:
"content_type": p[12] or "image", "content_type": p[12] or "image",
"faceswap_source_video": p[13], "faceswap_source_video": p[13],
"archived": is_archived, "archived": is_archived,
"is_source": bool(p[15]) if p[15] else False,
}) })
print(f"[static] write_all: {len(db_images)} total images, {archived_count} archived") print(f"[static] write_all: {len(db_images)} total images, {archived_count} archived")
try: try:
@@ -1674,8 +1684,9 @@ class GroupArchiveRequest(BaseModel):
filenames: list[str] filenames: list[str]
class RepairRequest(BaseModel): class RepairRequest(BaseModel):
action: str # "delete_record", "import_file", "restore", "delete_permanently" action: str # "delete_record", "import_file", "restore", "delete_permanently", "assign_group"
filename: str filename: str
group_id: str | None = None
class BatchRequest(BaseModel): class BatchRequest(BaseModel):
filenames: list[str] filenames: list[str]
@@ -2377,10 +2388,17 @@ def db_repair(req: RepairRequest):
if not os.path.exists(fpath): if not os.path.exists(fpath):
raise HTTPException(404, "File not found on disk") raise HTTPException(404, "File not found on disk")
# Basic import: just register it in DB # Basic import: just register it in DB
database.upsert_person(req.filename, filepath=fpath, group_id=naming.get_base_name(req.filename)) database.upsert_person(req.filename, filepath=fpath, group_id=naming.get_base_name(req.filename), is_source=True)
_invalidate_static() _invalidate_static()
_run_consistency_check() _run_consistency_check()
return {"status": "imported", "filename": req.filename} return {"status": "imported", "filename": req.filename}
elif req.action == "assign_group":
# Assign a group_id (default to base name if not provided)
gid = req.group_id or naming.get_base_name(req.filename)
database.upsert_person(req.filename, group_id=gid)
_invalidate_static()
_run_consistency_check()
return {"status": "assigned", "filename": req.filename, "group_id": gid}
elif req.action == "restore": elif req.action == "restore":
database.set_archived(req.filename, False) database.set_archived(req.filename, False)
_invalidate_static() _invalidate_static()
@@ -2516,6 +2534,7 @@ def _process_upload(file_path: str, filename: str, prompts: list[str], name: str
filename, filepath=file_path, name=auto_name, filename, filepath=file_path, name=auto_name,
clip_description=clip_desc, tags=tags, embedding=embedding, clip_description=clip_desc, tags=tags, embedding=embedding,
group_id=group_id, sort_order=0, has_clothing=has_clothing, group_id=group_id, sort_order=0, has_clothing=has_clothing,
is_source=True,
) )
# Surface the new group with its base image right away — the pose/base-prompt # Surface the new group with its base image right away — the pose/base-prompt
# generation below can take a while, and the user shouldn't wait for it to # generation below can take a while, and the user shouldn't wait for it to
@@ -2549,6 +2568,7 @@ def _process_upload(file_path: str, filename: str, prompts: list[str], name: str
clip_description=clip_desc, embedding=out_embedding, clip_description=clip_desc, embedding=out_embedding,
group_id=group_id, sort_order=next_order, group_id=group_id, sort_order=next_order,
prompt=prompt, pose=out_pose, prompt=prompt, pose=out_pose,
source_refs=json.dumps([filename]),
) )
except Exception as e: except Exception as e:
print(f"Error processing prompt '{prompt}' for {filename}: {e}") print(f"Error processing prompt '{prompt}' for {filename}: {e}")
@@ -2590,7 +2610,7 @@ def upload_image(
if group_id and skip_poses: if group_id and skip_poses:
sort_order = database.get_next_sort_order(group_id) sort_order = database.get_next_sort_order(group_id)
database.upsert_person(filename, filepath=file_path, group_id=group_id, database.upsert_person(filename, filepath=file_path, group_id=group_id,
sort_order=sort_order) sort_order=sort_order, is_source=True)
_invalidate_static() _invalidate_static()
return {"status": "added", "filename": filename, "group_id": group_id} return {"status": "added", "filename": filename, "group_id": group_id}
@@ -2677,7 +2697,11 @@ def set_image_preferred(filename: str):
raise HTTPException(404, "Image not found") raise HTTPException(404, "Image not found")
group_id = person[1] group_id = person[1]
if not group_id: if not group_id:
raise HTTPException(400, "Image has no group assigned") # Auto-assign group_id if missing (legacy/orphan)
group_id = naming.get_base_name(filename)
database.upsert_person(filename, group_id=group_id)
print(f"[fix] Auto-assigned group_id={group_id} to orphan {filename} during set-preferred")
rows = database.get_group_order(group_id) rows = database.get_group_order(group_id)
others = [r[0] for r in rows if r[0] != filename] others = [r[0] for r in rows if r[0] != filename]
database.set_group_order(group_id, [filename] + others) database.set_group_order(group_id, [filename] + others)
@@ -3440,7 +3464,8 @@ def remove_background_sam(filename: str):
# Register sidecar in DB so it appears in the same group # Register sidecar in DB so it appears in the same group
group_id = person[1] group_id = person[1]
database.upsert_person(nobg_filename, filepath=nobg_path, database.upsert_person(nobg_filename, filepath=nobg_path,
group_id=group_id, has_background=False) group_id=group_id, has_background=False,
source_refs=json.dumps([filename]))
used_sam2 = _sam2_predictor is not False and _sam2_predictor is not None used_sam2 = _sam2_predictor is not False and _sam2_predictor is not None
return { return {

View File

@@ -2,29 +2,39 @@ import torch
import open_clip import open_clip
from PIL import Image from PIL import Image
import os import os
import threading
_model = None _model = None
_preprocess = None _preprocess = None
_device = None _device = None
_lock = threading.Lock()
def get_model(): def get_model():
global _model, _preprocess, _device global _model, _preprocess, _device
if _model is None: if _model is None:
_device = "cuda" if torch.cuda.is_available() else "cpu" with _lock:
# ViT-H-14 is 1024-dim if _model is None:
_model, _, _preprocess = open_clip.create_model_and_transforms('ViT-H-14', pretrained='laion2b_s32b_b79k') dev = "cuda" if torch.cuda.is_available() else "cpu"
_model = _model.to(_device) # ViT-H-14 is 1024-dim
_model.eval() model, _, preprocess = open_clip.create_model_and_transforms('ViT-H-14', pretrained='laion2b_s32b_b79k')
model = model.to(dev)
model.eval()
# Set globals only when fully ready to avoid race conditions
_preprocess = preprocess
_device = dev
_model = model
return _model, _preprocess, _device return _model, _preprocess, _device
def generate_embedding(image_path): def generate_embedding(image_path):
model, preprocess, device = get_model() model, preprocess, device = get_model()
try: try:
image = preprocess(Image.open(image_path)).unsqueeze(0).to(device) with Image.open(image_path) as img:
with torch.no_grad(): image = preprocess(img.convert("RGB")).unsqueeze(0).to(device)
image_features = model.encode_image(image) with torch.no_grad():
image_features /= image_features.norm(dim=-1, keepdim=True) image_features = model.encode_image(image)
return image_features.cpu().numpy()[0].tolist() image_features /= image_features.norm(dim=-1, keepdim=True)
return image_features.cpu().numpy()[0].tolist()
except Exception as e: except Exception as e:
print(f"Error generating embedding for {image_path}: {e}") print(f"Error generating embedding for {image_path}: {e}")
return None return None

View File

@@ -1,8 +1,17 @@
# Upscale HQ # Upscale HQ
Masterpiece.
high quality. high quality.
detailed. detailed. detailed skin.
Anatomically precise, hyperrealistic, high detail, keep the characteristics of the reference image. Anatomically precise, photo realistic, high detail, keep the characteristics of the reference image.
# Upscale HQ (18)
Masterpiece.
high quality.
detailed. detailed skin.
teenage female.
Anatomically precise, photo realistic, high detail, keep the characteristics of the reference image.
# BG Remove # BG Remove
@@ -47,13 +56,18 @@ Keep full characteristics of reference image.
# Three-quarter (18) # Three-quarter (18)
You are in a black empty void. You are in a black empty void.
high quality, masterpiece, detailed, detailed skin, Head-on a full-body three-quarter detailed full-nude-body, female teenage portrait, realistic, transparent background. high quality, masterpiece, detailed, detailed skin.
Head-on a right-front detailed full-nude-body. Top-to-toe photo.
female teenage, photorealistic, sharp focus, transparent background.
Identical person from reference image.
Keep characteristics of reference image. Keep characteristics of reference image.
# Three-quarter # Three-quarter
You are in a black empty void. You are in a black empty void.
high quality, masterpiece, detailed, detailed skin, Head-on a full-body three-quarter detailed full-nude-body, female portrait, realistic, transparent background. high quality, masterpiece, detailed, detailed skin.
Head-on a right-front view. Top-to-toe.
detailed full-nude-body, female portrait, photorealistic, transparent background.
Keep characteristics of reference image. Keep characteristics of reference image.
# Head-on undress (18) # Head-on undress (18)
@@ -71,13 +85,13 @@ Keep characteristics of reference image.
# Head-on straight-on (18) # Head-on straight-on (18)
You are in a black empty void. You are in a black empty void.
Head-on straight-on full-body portrait, teenage female, realistic, black background. Head-on straight-on full-body portrait, teenage female, photo realistic, black background.
Keep characteristics of reference image. Keep characteristics of reference image.
# Head-on straight-on # Head-on straight-on
You are in a black empty void. You are in a black empty void.
Head-on straight-on full-body female portrait, realistic, black background. Head-on straight-on full-body female portrait, photo realistic, black background.
Keep characteristics of reference image. Keep characteristics of reference image.
# Looking viewer (18) # Looking viewer (18)
@@ -106,17 +120,26 @@ high quality, full-nude-body, female, masterpiece, realistic, photo, cinematic l
transparent background. transparent background.
Keep characteristics of reference image. Keep characteristics of reference image.
# Merge (18)x3
masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images.
detailed skin, detailed full-nude-body. teenage female.
Photo-realistic.
Anatomically precise, keep the posture and gesture from the base image.
# Merge (18) # Merge (18)
masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images. masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images.
detailed skin, detailed full-nude-body. teenage female. detailed skin, detailed full-nude-body. teenage female.
hyper realistic. keep the posture and gesture from the base image. hyper realistic.
Anatomically precise, keep the posture and gesture from the base image.
# Merge # Merge
masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images. masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images.
detailed skin, detailed full-nude-body. female. detailed skin, detailed full-nude-body. female.
hyper realistic. keep the posture and gesture from the base image. hyper realistic.
Anatomically precise, keep the posture and gesture from the base image.
# Jewelery # Jewelery

View File

@@ -80,6 +80,11 @@
<div id="archivedList">No archived items found.</div> <div id="archivedList">No archived items found.</div>
</div> </div>
<div class="section">
<h2>Missing Group IDs <span class="info">(Legacy or orphaned images with no group assigned)</span></h2>
<div id="orphansList">No images with missing groups found.</div>
</div>
<div class="section"> <div class="section">
<h2>Orphaned Records <span class="info">(In DB, but file missing on disk)</span></h2> <h2>Orphaned Records <span class="info">(In DB, but file missing on disk)</span></h2>
<div id="missingList">No orphaned records found.</div> <div id="missingList">No orphaned records found.</div>
@@ -118,6 +123,7 @@
else if (d.status === 'imported') msg = 'File imported'; else if (d.status === 'imported') msg = 'File imported';
else if (d.status === 'restored') msg = 'Item restored'; else if (d.status === 'restored') msg = 'Item restored';
else if (d.status === 'deleted_permanently') msg = 'Permanently deleted'; else if (d.status === 'deleted_permanently') msg = 'Permanently deleted';
else if (d.status === 'assigned') msg = 'Group assigned';
showToast(msg); showToast(msg);
loadInconsistencies(); loadInconsistencies();
@@ -137,6 +143,7 @@
renderArchived(d.archived_items || []); renderArchived(d.archived_items || []);
renderMissing(d.missing_files || []); renderMissing(d.missing_files || []);
renderUntracked(d.untracked_files || []); renderUntracked(d.untracked_files || []);
renderOrphans(d.missing_group || []);
if (d.timestamp) { if (d.timestamp) {
const date = new Date(d.timestamp * 1000); const date = new Date(d.timestamp * 1000);
@@ -150,6 +157,23 @@
} }
} }
function renderOrphans(files) {
const container = document.getElementById('orphansList');
if (files.length === 0) {
container.innerHTML = 'No images with missing groups found.';
return;
}
container.innerHTML = files.map(f => `
<div class="item">
<div>
<div class="filename">${f.filename}</div>
<div class="info">Name: ${f.name || 'none'}</div>
</div>
<button class="btn success" onclick="repair('${f.filename}', 'assign_group')">Auto-assign Group</button>
</div>
`).join('');
}
function renderArchived(files) { function renderArchived(files) {
const container = document.getElementById('archivedList'); const container = document.getElementById('archivedList');
if (files.length === 0) { if (files.length === 0) {

View File

@@ -189,7 +189,7 @@ def process_image(filename):
try: try:
embedding = embeddings.generate_embedding(output_path) embedding = embeddings.generate_embedding(output_path)
gid = filename gid = filename
database.upsert_person(output_filename, filepath=output_path, embedding=embedding, group_id=gid) database.upsert_person(output_filename, filepath=output_path, embedding=embedding, group_id=gid, is_source=True)
# Also trigger tagging to get auto-name and clip description # Also trigger tagging to get auto-name and clip description
tag_url = CONF["api_url"].replace("/edit", "/tag") tag_url = CONF["api_url"].replace("/edit", "/tag")