DPM1987 commited on
Commit
df83e9f
·
verified ·
1 Parent(s): c384670

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +50 -0
  2. .gitignore +95 -0
  3. .gradio/certificate.pem +31 -0
  4. ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2.jpeg +3 -0
  5. ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2_999-icecream.jpeg +3 -0
  6. ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2_999.jpeg +3 -0
  7. README.md +3 -9
  8. complete_fixed_flux_script copy.py +725 -0
  9. complete_fixed_flux_script.py +791 -0
  10. data/training_images/Stocksy_comp_1503760_G1G3.jpg +3 -0
  11. data/training_images/Stocksy_comp_2058141_G1G3.jpg +3 -0
  12. data/training_images/Stocksy_comp_2511302_G1G2G4.jpg +3 -0
  13. data/training_images/Stocksy_comp_2604801_G1G2G3G4.jpg +3 -0
  14. data/training_images/Stocksy_comp_3177699_G1G3.jpg +3 -0
  15. data/training_images/Stocksy_comp_3414632_NO GLOW.jpg +3 -0
  16. data/training_images/Stocksy_comp_3737382_G1G2G3G4.jpg +3 -0
  17. data/training_images/Stocksy_comp_3890544_G2G4.jpg +3 -0
  18. data/training_images/Stocksy_comp_3942209._G1G2G3G4jpg.jpg +3 -0
  19. data/training_images/Stocksy_comp_4003550_G2G3G4.jpg +3 -0
  20. data/training_images/Stocksy_comp_4103954_G1G3.jpg +3 -0
  21. data/training_images/Stocksy_comp_4165779_G1G2G3G4.jpg +3 -0
  22. data/training_images/Stocksy_comp_634618_G2G3G4.jpg +3 -0
  23. data/training_images/photocase_3841861_G1G2G3G4.jpg +3 -0
  24. data/training_images/photocase_3992910_G1G2G3G4.jpg +3 -0
  25. data/training_images/photocase_4173298_G2G34.jpg +3 -0
  26. data/training_images/photocase_4190225_G1G2G3G4.jpg +3 -0
  27. data/training_images/photocase_4202421_G1G2G34.jpg +3 -0
  28. data/training_images/photocase_4363114_G1G2G3G4.jpg +3 -0
  29. data/training_images/photocase_4687971_G1G2G3G4.jpg +3 -0
  30. data/training_images/processed/Stocksy_comp_1503760_G1G3.jpg +0 -0
  31. data/training_images/processed/Stocksy_comp_2058141_G1G3.jpg +0 -0
  32. data/training_images/processed/Stocksy_comp_2511302_G1G2G4.jpg +0 -0
  33. data/training_images/processed/Stocksy_comp_2604801_G1G2G3G4.jpg +0 -0
  34. data/training_images/processed/Stocksy_comp_3177699_G1G3.jpg +0 -0
  35. data/training_images/processed/Stocksy_comp_3414632_NO GLOW.jpg +0 -0
  36. data/training_images/processed/Stocksy_comp_3737382_G1G2G3G4.jpg +0 -0
  37. data/training_images/processed/Stocksy_comp_3890544_G2G4.jpg +0 -0
  38. data/training_images/processed/Stocksy_comp_3942209._G1G2G3G4jpg.jpg +0 -0
  39. data/training_images/processed/Stocksy_comp_4003550_G2G3G4.jpg +0 -0
  40. data/training_images/processed/Stocksy_comp_4103954_G1G3.jpg +0 -0
  41. data/training_images/processed/Stocksy_comp_4165779_G1G2G3G4.jpg +0 -0
  42. data/training_images/processed/Stocksy_comp_634618_G2G3G4.jpg +0 -0
  43. data/training_images/processed/photocase_3841861_G1G2G3G4.jpg +0 -0
  44. data/training_images/processed/photocase_3992910_G1G2G3G4.jpg +0 -0
  45. data/training_images/processed/photocase_4173298_G2G34.jpg +0 -0
  46. data/training_images/processed/photocase_4190225_G1G2G3G4.jpg +0 -0
  47. data/training_images/processed/photocase_4202421_G1G2G34.jpg +0 -0
  48. data/training_images/processed/photocase_4363114_G1G2G3G4.jpg +0 -0
  49. data/training_images/processed/photocase_4687971_G1G2G3G4.jpg +0 -0
  50. flux_dev_oddtopersonmark2.jpeg +3 -0
.gitattributes CHANGED
@@ -33,3 +33,53 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2.jpeg filter=lfs diff=lfs merge=lfs -text
37
+ ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2_999-icecream.jpeg filter=lfs diff=lfs merge=lfs -text
38
+ ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2_999.jpeg filter=lfs diff=lfs merge=lfs -text
39
+ data/training_images/Stocksy_comp_1503760_G1G3.jpg filter=lfs diff=lfs merge=lfs -text
40
+ data/training_images/Stocksy_comp_2058141_G1G3.jpg filter=lfs diff=lfs merge=lfs -text
41
+ data/training_images/Stocksy_comp_2511302_G1G2G4.jpg filter=lfs diff=lfs merge=lfs -text
42
+ data/training_images/Stocksy_comp_2604801_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
43
+ data/training_images/Stocksy_comp_3177699_G1G3.jpg filter=lfs diff=lfs merge=lfs -text
44
+ data/training_images/Stocksy_comp_3414632_NO[[:space:]]GLOW.jpg filter=lfs diff=lfs merge=lfs -text
45
+ data/training_images/Stocksy_comp_3737382_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
46
+ data/training_images/Stocksy_comp_3890544_G2G4.jpg filter=lfs diff=lfs merge=lfs -text
47
+ data/training_images/Stocksy_comp_3942209._G1G2G3G4jpg.jpg filter=lfs diff=lfs merge=lfs -text
48
+ data/training_images/Stocksy_comp_4003550_G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
49
+ data/training_images/Stocksy_comp_4103954_G1G3.jpg filter=lfs diff=lfs merge=lfs -text
50
+ data/training_images/Stocksy_comp_4165779_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
51
+ data/training_images/Stocksy_comp_634618_G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
52
+ data/training_images/photocase_3841861_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
53
+ data/training_images/photocase_3992910_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
54
+ data/training_images/photocase_4173298_G2G34.jpg filter=lfs diff=lfs merge=lfs -text
55
+ data/training_images/photocase_4190225_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
56
+ data/training_images/photocase_4202421_G1G2G34.jpg filter=lfs diff=lfs merge=lfs -text
57
+ data/training_images/photocase_4363114_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
58
+ data/training_images/photocase_4687971_G1G2G3G4.jpg filter=lfs diff=lfs merge=lfs -text
59
+ flux_dev_oddtopersonmark2.jpeg filter=lfs diff=lfs merge=lfs -text
60
+ flux_dev_oddtopersonmark2_99.png filter=lfs diff=lfs merge=lfs -text
61
+ flux_dev_oddtopersonmark2_999-icecream.jpeg filter=lfs diff=lfs merge=lfs -text
62
+ flux_dev_oddtopersonmark2_999.jpeg filter=lfs diff=lfs merge=lfs -text
63
+ models/Flux/hf_cache/models--black-forest-labs--FLUX.1-dev/blobs/f5b59a26851551b67ae1fe58d32e76486e1e812def4696a4bea97f16604d40a3 filter=lfs diff=lfs merge=lfs -text
64
+ outputs/complete_local_flux/flux_dev_oddtopersonmark2_999.png filter=lfs diff=lfs merge=lfs -text
65
+ outputs/flux_dev_MWTfEJZVDWOaLY6cdoWfb_pytorch_lora_weights_42.png filter=lfs diff=lfs merge=lfs -text
66
+ outputs/flux_dev_MWTfEJZVDWOaLY6cdoWfb_pytorch_lora_weights_999.png filter=lfs diff=lfs merge=lfs -text
67
+ outputs/flux_dev_oddtoperson_42.png filter=lfs diff=lfs merge=lfs -text
68
+ outputs/flux_dev_oddtoperson_99.png filter=lfs diff=lfs merge=lfs -text
69
+ outputs/flux_dev_oddtopersonmark2.jpeg filter=lfs diff=lfs merge=lfs -text
70
+ outputs/flux_dev_oddtopersonmark2_123[[:space:]]copy.png filter=lfs diff=lfs merge=lfs -text
71
+ outputs/flux_dev_oddtopersonmark2_123.png filter=lfs diff=lfs merge=lfs -text
72
+ outputs/flux_dev_oddtopersonmark2_42.png filter=lfs diff=lfs merge=lfs -text
73
+ outputs/flux_dev_oddtopersonmark2_777.png filter=lfs diff=lfs merge=lfs -text
74
+ outputs/flux_dev_oddtopersonmark2_99.png filter=lfs diff=lfs merge=lfs -text
75
+ outputs/flux_dev_oddtopersonmark2_992.png filter=lfs diff=lfs merge=lfs -text
76
+ outputs/flux_dev_oddtopersonmark2_999[[:space:]]copy[[:space:]]2.png filter=lfs diff=lfs merge=lfs -text
77
+ outputs/flux_dev_oddtopersonmark2_999[[:space:]]copy[[:space:]]3.png filter=lfs diff=lfs merge=lfs -text
78
+ outputs/flux_dev_oddtopersonmark2_999[[:space:]]copy.png filter=lfs diff=lfs merge=lfs -text
79
+ outputs/flux_dev_oddtopersonmark2_999.png filter=lfs diff=lfs merge=lfs -text
80
+ outputs/flux_dev_wJavqTDrJzyC9ound57AP_pytorch_lora_weights_42.png filter=lfs diff=lfs merge=lfs -text
81
+ outputs/flux_schnell_MWTfEJZVDWOaLY6cdoWfb_pytorch_lora_weights_42.png filter=lfs diff=lfs merge=lfs -text
82
+ outputs/flux_schnell_oddtopersonmark2_2024.png filter=lfs diff=lfs merge=lfs -text
83
+ outputs/flux_schnell_oddtopersonmark2_42.png filter=lfs diff=lfs merge=lfs -text
84
+ outputs/flux_schnell_oddtopersonmark2_999.png filter=lfs diff=lfs merge=lfs -text
85
+ outputs/flux_schnell_wJavqTDrJzyC9ound57AP_pytorch_lora_weights_42.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.zip
2
+ *.tar.gz
3
+ *.tar.bz2
4
+ *.7z
5
+ *.rar
6
+
7
+ # Model files (often very large)
8
+ *.safetensors
9
+ *.ckpt
10
+ *.bin
11
+ *.pt
12
+ *.pth
13
+ *.h5
14
+ *.pickle
15
+ *.pkl
16
+
17
+ # Python cache and temporary files
18
+ __pycache__/
19
+ *.py[cod]
20
+ *$py.class
21
+ *.so
22
+ *.egg
23
+ *.egg-info/
24
+ dist/
25
+ build/
26
+ .pytest_cache/
27
+
28
+ # Temporary files
29
+ *.tmp
30
+ *.temp
31
+ *~
32
+ .DS_Store
33
+ Thumbs.db
34
+
35
+ # Large image formats (consider using compressed versions)
36
+ *.tiff
37
+ *.tif
38
+ *.bmp
39
+ *.raw
40
+
41
+ # Video files (typically large)
42
+ *.mp4
43
+ *.avi
44
+ *.mov
45
+ *.mkv
46
+ *.flv
47
+
48
+ # Audio files
49
+ *.wav
50
+ *.flac
51
+ *.aiff
52
+
53
+ # Large data files
54
+ *.csv
55
+ *.json
56
+ *.xml
57
+ *.sql
58
+
59
+ # IDE and editor files
60
+ .vscode/
61
+ .idea/
62
+ *.swp
63
+ *.swo
64
+ *~
65
+
66
+ # OS generated files
67
+ .DS_Store
68
+ .DS_Store?
69
+ ._*
70
+ .Spotlight-V100
71
+ .Trashes
72
+ ehthumbs.db
73
+ Thumbs.db
74
+
75
+ # Git LFS temporary files
76
+ .git/lfs/tmp/
77
+
78
+ # Jupyter Notebook checkpoints
79
+ .ipynb_checkpoints/
80
+
81
+ # Environment variables
82
+ .env
83
+ .env.local
84
+ .env.*.local
85
+
86
+ # Log files
87
+ *.log
88
+ logs/
89
+
90
+ # Large image directories (adjust as needed)
91
+ # ACT-ODIDO-IMAGES/
92
+ # **/large_images/
93
+ # **/generated_images/
94
+ `
95
+ }
.gradio/certificate.pem ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
3
+ TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
4
+ cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
5
+ WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
6
+ ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
7
+ MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
8
+ h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
9
+ 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
10
+ A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
11
+ T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
12
+ B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
13
+ B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
14
+ KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
15
+ OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
16
+ jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
17
+ qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
18
+ rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
19
+ HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
20
+ hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
21
+ ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
22
+ 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
23
+ NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
24
+ ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
25
+ TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
26
+ jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
27
+ oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
28
+ 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
29
+ mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
30
+ emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
31
+ -----END CERTIFICATE-----
ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2.jpeg ADDED

Git LFS Details

  • SHA256: b3e1e4f3ad6f46035e80a9c07f24906d99a55f09edce9ae750021cedda20eb75
  • Pointer size: 131 Bytes
  • Size of remote file: 544 kB
ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2_999-icecream.jpeg ADDED

Git LFS Details

  • SHA256: 1f28db5994481acedbe82f91883d8664e10ce5fdd3fd71b63f8cb88e3e0ef01a
  • Pointer size: 131 Bytes
  • Size of remote file: 448 kB
ACT-ODIDO-IMAGES/flux_dev_oddtopersonmark2_999.jpeg ADDED

Git LFS Details

  • SHA256: fa1d8d9717c7019170c7dbb5ea632f6066ecc9bd464654b9f61c29c7d0b4b559
  • Pointer size: 131 Bytes
  • Size of remote file: 578 kB
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: ACT Images
3
- emoji: 📊
4
- colorFrom: yellow
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 5.33.0
8
- app_file: app.py
9
- pinned: false
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: ACT-images
3
+ app_file: complete_fixed_flux_script.py
 
 
4
  sdk: gradio
5
+ sdk_version: 5.20.0
 
 
6
  ---
 
 
complete_fixed_flux_script copy.py ADDED
@@ -0,0 +1,725 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ from diffusers import FluxPipeline
4
+ from transformers import CLIPTextModel, T5EncoderModel, CLIPTokenizer, T5Tokenizer
5
+ from safetensors.torch import load_file
6
+ import os
7
+ import socket
8
+ from PIL import Image
9
+ import base64
10
+ import io
11
+ import requests
12
+ import json
13
+
14
+ def find_free_port(start_port=7860):
15
+ """Find a free port"""
16
+ for port in range(start_port, start_port + 20):
17
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
18
+ try:
19
+ s.bind(('localhost', port))
20
+ return port
21
+ except OSError:
22
+ continue
23
+ return None
24
+
25
+ class CompleteLocalFlux:
26
+ def __init__(self):
27
+ # Set up Groq API key (you'll need to set this)
28
+ self.groq_api_key = os.getenv("GROQ_API_KEY")
29
+ if not self.groq_api_key:
30
+ print("⚠️ GROQ_API_KEY not found in environment variables")
31
+ print(" Set it with: export GROQ_API_KEY='your_api_key_here'")
32
+ else:
33
+ print("✅ Groq API key found")
34
+
35
+ if torch.backends.mps.is_available():
36
+ self.device = torch.device("mps")
37
+ print("🚀 Using Apple M2 Max with MPS")
38
+ else:
39
+ self.device = torch.device("cpu")
40
+
41
+ # Find your models
42
+ self.flux_models = {}
43
+ self.local_t5_path = None
44
+
45
+ # Check for Flux models
46
+ possible_flux_files = [
47
+ ("Flux Dev", "./models/Flux/flux-dev.safetensors"),
48
+ ("Flux Schnell", "./models/Flux/flux1-schnell.safetensors"),
49
+ ("Flux Kontex", "./models/Flux/flux-kontex.safetensors"),
50
+ ("Flux Dev Alt", "./flux-dev.safetensors"),
51
+ ("Flux Schnell Alt", "./flux1-schnell.safetensors"),
52
+ ("Flux Kontex Alt", "./flux-kontex.safetensors")
53
+ ]
54
+
55
+ for name, path in possible_flux_files:
56
+ if os.path.exists(path):
57
+ size_gb = os.path.getsize(path) / (1024*1024*1024)
58
+ self.flux_models[name] = {"path": path, "size": size_gb}
59
+ print(f"✅ Found {name}: {path} ({size_gb:.1f} GB)")
60
+
61
+ # Check for local T5 model
62
+ possible_t5_paths = [
63
+ "./models/Flux/google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors",
64
+ "./google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors",
65
+ "./models/google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors"
66
+ ]
67
+
68
+ for path in possible_t5_paths:
69
+ if os.path.exists(path):
70
+ size_gb = os.path.getsize(path) / (1024*1024*1024)
71
+ self.local_t5_path = path
72
+ print(f"✅ Found T5 model: {path} ({size_gb:.1f} GB)")
73
+ break
74
+
75
+ # Check for local VAE model (including downloaded cache)
76
+ self.local_vae_path = None
77
+ self.cached_vae_path = "./models/Flux/vae_cache" # Cache directory for downloaded VAE
78
+
79
+ possible_vae_paths = [
80
+ "./models/Flux/ae.safetensors",
81
+ "./ae.safetensors",
82
+ "./models/ae.safetensors",
83
+ "./models/Flux/vae.safetensors",
84
+ "./vae.safetensors",
85
+ self.cached_vae_path # Check for cached downloaded VAE
86
+ ]
87
+
88
+ for path in possible_vae_paths:
89
+ if os.path.exists(path):
90
+ if os.path.isdir(path): # Cached VAE directory
91
+ self.local_vae_path = path
92
+ print(f"✅ Found cached VAE: {path}")
93
+ else: # Single VAE file
94
+ size_gb = os.path.getsize(path) / (1024*1024*1024)
95
+ self.local_vae_path = path
96
+ print(f"✅ Found VAE model: {path} ({size_gb:.1f} GB)")
97
+ break
98
+
99
+ # Find LoRA files - simple and working approach
100
+ self.lora_files = []
101
+
102
+ # Check multiple directories for LoRA files
103
+ lora_search_paths = [
104
+ "./models/lora", # Main LoRA directory
105
+ ".", # Current directory
106
+ "./models",
107
+ "./lora",
108
+ "./LoRA"
109
+ ]
110
+
111
+ for search_path in lora_search_paths:
112
+ if os.path.exists(search_path):
113
+ try:
114
+ files = [f for f in os.listdir(search_path) if f.endswith(".safetensors")]
115
+ # Add full path for files not in current directory
116
+ if search_path != ".":
117
+ files = [os.path.join(search_path, f) for f in files]
118
+ self.lora_files.extend(files)
119
+ except PermissionError:
120
+ continue
121
+
122
+ # Also specifically look for your LoRA files
123
+ specific_lora_files = [
124
+ "./models/lora/act_person_trained.safetensors",
125
+ "./models/lora/oddtoperson.safetensors",
126
+ "./models/lora/oddtopersonmark2.safetensors",
127
+
128
+ ]
129
+
130
+ for lora_file in specific_lora_files:
131
+ if os.path.exists(lora_file) and lora_file not in self.lora_files:
132
+ self.lora_files.append(lora_file)
133
+
134
+ # Remove duplicates while preserving order
135
+ seen = set()
136
+ unique_lora_files = []
137
+ for f in self.lora_files:
138
+ if f not in seen:
139
+ seen.add(f)
140
+ unique_lora_files.append(f)
141
+ self.lora_files = unique_lora_files
142
+
143
+ self.pipeline = None
144
+ self.current_model = None
145
+ self.lora_loaded = False
146
+ self.encoders_loaded = False
147
+
148
+ print(f"✅ Found {len(self.lora_files)} LoRA files")
149
+ for f in self.lora_files:
150
+ print(f" - {f}")
151
+
152
+ def cleanup_memory(self):
153
+ """Clean up GPU/MPS memory"""
154
+ if hasattr(self, 'pipeline') and self.pipeline is not None:
155
+ del self.pipeline
156
+ self.pipeline = None
157
+
158
+ if torch.cuda.is_available():
159
+ torch.cuda.empty_cache()
160
+ elif self.device.type == "mps":
161
+ torch.mps.empty_cache()
162
+
163
+ print("🧹 Memory cleaned up")
164
+
165
+ def load_local_text_encoders(self):
166
+ """Load text encoders using local and remote models"""
167
+ try:
168
+ print("🔄 Loading text encoders...")
169
+
170
+ # Use consistent dtype for MPS compatibility
171
+ dtype = torch.float32 # Use float32 for better MPS compatibility
172
+
173
+ # Load CLIP text encoder (download - small ~1GB)
174
+ print(" Loading CLIP text encoder (downloading ~1GB)...")
175
+ self.clip_text_encoder = CLIPTextModel.from_pretrained(
176
+ "openai/clip-vit-large-patch14",
177
+ torch_dtype=dtype
178
+ )
179
+ self.clip_tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")
180
+
181
+ # Load T5 encoder - fix the tokenizer warning and local loading
182
+ if self.local_t5_path:
183
+ print(f" Loading T5 from local file: {self.local_t5_path}")
184
+
185
+ # Load tokenizer with legacy=False to suppress warning
186
+ print(" Loading T5 tokenizer...")
187
+ self.t5_tokenizer = T5Tokenizer.from_pretrained(
188
+ "google/t5-v1_1-xxl",
189
+ legacy=False # This fixes the warning
190
+ )
191
+
192
+ print(" Loading local T5 weights...")
193
+ # Load the model architecture first
194
+ self.t5_text_encoder = T5EncoderModel.from_pretrained(
195
+ "google/t5-v1_1-xxl",
196
+ torch_dtype=dtype
197
+ )
198
+
199
+ # Try to load and apply your local weights
200
+ try:
201
+ print(" Attempting to load local T5 safetensors...")
202
+ local_t5_weights = load_file(self.local_t5_path)
203
+
204
+ # Filter weights to only include those that match the model structure
205
+ model_state_dict = self.t5_text_encoder.state_dict()
206
+ filtered_weights = {}
207
+
208
+ for key, value in local_t5_weights.items():
209
+ if key in model_state_dict:
210
+ if model_state_dict[key].shape == value.shape:
211
+ filtered_weights[key] = value
212
+ else:
213
+ print(f"⚠️ Skipping {key}: shape mismatch {model_state_dict[key].shape} vs {value.shape}")
214
+ else:
215
+ print(f"⚠️ Skipping {key}: not found in model")
216
+
217
+ # Load the filtered weights
218
+ missing_keys, unexpected_keys = self.t5_text_encoder.load_state_dict(filtered_weights, strict=False)
219
+
220
+ if missing_keys:
221
+ print(f"⚠️ Missing keys: {len(missing_keys)} (this is often normal)")
222
+ if unexpected_keys:
223
+ print(f"⚠️ Unexpected keys: {len(unexpected_keys)}")
224
+
225
+ print("✅ Local T5 weights loaded successfully!")
226
+
227
+ except Exception as e:
228
+ print(f"❌ Error loading local T5 weights: {e}")
229
+ print(" Your T5 file may be corrupted or incomplete.")
230
+ print(" Falling back to downloaded weights (model architecture already loaded)...")
231
+ # Keep the downloaded model architecture - don't try to reload
232
+
233
+ else:
234
+ print(" No local T5 found, downloading...")
235
+ self.t5_tokenizer = T5Tokenizer.from_pretrained(
236
+ "google/t5-v1_1-xxl",
237
+ legacy=False # This fixes the warning
238
+ )
239
+ self.t5_text_encoder = T5EncoderModel.from_pretrained(
240
+ "google/t5-v1_1-xxl",
241
+ torch_dtype=dtype
242
+ )
243
+
244
+ # Move to device
245
+ self.clip_text_encoder = self.clip_text_encoder.to(self.device)
246
+ self.t5_text_encoder = self.t5_text_encoder.to(self.device)
247
+
248
+ self.encoders_loaded = True
249
+ print("✅ All text encoders loaded successfully!")
250
+ return True
251
+
252
+ except Exception as e:
253
+ print(f"❌ Error loading text encoders: {e}")
254
+ import traceback
255
+ traceback.print_exc() # This will help debug the exact issue
256
+ return False
257
+
258
+ def load_flux_complete(self, model_choice, lora_choice):
259
+ """Load complete Flux setup with better memory management"""
260
+ try:
261
+ # Clean up previous model if switching
262
+ if self.current_model and self.current_model != model_choice:
263
+ print("🧹 Cleaning up previous model...")
264
+ self.cleanup_memory()
265
+
266
+ # Load encoders if needed
267
+ if not self.encoders_loaded:
268
+ if not self.load_local_text_encoders():
269
+ return "❌ Failed to load text encoders"
270
+
271
+ if model_choice not in self.flux_models:
272
+ return f"❌ Model {model_choice} not found"
273
+
274
+ model_path = self.flux_models[model_choice]["path"]
275
+ print(f"🔄 Loading {model_choice} with complete setup...")
276
+
277
+ # Load VAE separately (required for Flux)
278
+ print(" Loading VAE...")
279
+ from diffusers import AutoencoderKL
280
+
281
+ # Check if we have a cached VAE first
282
+ if self.local_vae_path and os.path.isdir(self.local_vae_path):
283
+ print(f" Using cached VAE from: {self.local_vae_path}")
284
+ try:
285
+ vae = AutoencoderKL.from_pretrained(
286
+ self.local_vae_path,
287
+ torch_dtype=torch.float32
288
+ )
289
+ # Ensure all VAE weights are float32 for MPS compatibility
290
+ vae = vae.to(torch.float32)
291
+ print("✅ Cached VAE loaded successfully!")
292
+ except Exception as e:
293
+ print(f"❌ Cached VAE failed: {e}")
294
+ vae = None
295
+ else:
296
+ vae = None
297
+
298
+ # Download and cache VAE if no local version works
299
+ if vae is None:
300
+ print(" Downloading VAE from HuggingFace...")
301
+ try:
302
+ # Create cache directory
303
+ os.makedirs(os.path.dirname(self.cached_vae_path), exist_ok=True)
304
+
305
+ # Download and save to cache
306
+ vae = AutoencoderKL.from_pretrained(
307
+ "black-forest-labs/FLUX.1-dev",
308
+ subfolder="vae",
309
+ torch_dtype=torch.float32,
310
+ cache_dir="./models/Flux/hf_cache" # Local cache for HuggingFace downloads
311
+ )
312
+
313
+ # Ensure all VAE weights are float32 for MPS compatibility
314
+ vae = vae.to(torch.float32)
315
+
316
+ # Save the VAE locally for next time
317
+ print(f" Caching VAE to: {self.cached_vae_path}")
318
+ vae.save_pretrained(self.cached_vae_path)
319
+ self.local_vae_path = self.cached_vae_path # Update for future runs
320
+
321
+ print("✅ VAE downloaded and cached locally!")
322
+
323
+ except Exception as e:
324
+ print(f"❌ Failed to download VAE: {e}")
325
+ return f"❌ Could not load VAE: {e}"
326
+ vae = AutoencoderKL.from_pretrained(
327
+ "black-forest-labs/FLUX.1-dev",
328
+ subfolder="vae",
329
+ torch_dtype=torch.bfloat16 if self.device.type == "mps" else torch.float32
330
+ )
331
+
332
+ # Load Flux with all components including VAE
333
+ self.pipeline = FluxPipeline.from_single_file(
334
+ model_path,
335
+ text_encoder=self.clip_text_encoder,
336
+ text_encoder_2=self.t5_text_encoder,
337
+ tokenizer=self.clip_tokenizer,
338
+ tokenizer_2=self.t5_tokenizer,
339
+ vae=vae, # Add the VAE component
340
+ torch_dtype=torch.float32, # Use float32 for MPS compatibility
341
+ )
342
+
343
+ self.current_model = model_choice
344
+ print(f"✅ {model_choice} loaded completely!")
345
+
346
+ # Load LoRA
347
+ self.lora_loaded = False
348
+ if lora_choice != "None" and lora_choice in self.lora_files:
349
+ try:
350
+ print(f"🔄 Loading LoRA: {lora_choice}")
351
+
352
+ # Load LoRA with better error handling and warnings suppression
353
+ import warnings
354
+ with warnings.catch_warnings():
355
+ warnings.filterwarnings("ignore", message="No LoRA keys associated to CLIPTextModel found")
356
+ warnings.filterwarnings("ignore", message="You can also try specifying")
357
+
358
+ self.pipeline.load_lora_weights(".", weight_name=lora_choice)
359
+
360
+ self.lora_loaded = True
361
+ print("✅ LoRA loaded successfully!")
362
+
363
+ except Exception as e:
364
+ print(f"❌ LoRA loading failed: {e}")
365
+ # Continue without LoRA if it fails
366
+ self.lora_loaded = False
367
+
368
+ # Move pipeline to device (MPS for Apple Silicon)
369
+ self.pipeline = self.pipeline.to(self.device)
370
+
371
+ # Ensure all pipeline components are float32 for MPS compatibility
372
+ if self.device.type == "mps":
373
+ print(" Converting all components to float32 for MPS...")
374
+ self.pipeline.vae = self.pipeline.vae.to(torch.float32)
375
+ self.pipeline.text_encoder = self.pipeline.text_encoder.to(torch.float32)
376
+ self.pipeline.text_encoder_2 = self.pipeline.text_encoder_2.to(torch.float32)
377
+
378
+ # Enable MPS-specific optimizations
379
+ self.pipeline.enable_attention_slicing()
380
+ print("✅ Enabled MPS optimizations and float32 conversion")
381
+
382
+ status = f"✅ {model_choice} ready"
383
+ if self.local_t5_path:
384
+ status += " (using local T5)"
385
+ if self.lora_loaded:
386
+ status += f" + LoRA ({lora_choice})"
387
+
388
+ return status
389
+
390
+ except Exception as e:
391
+ print(f"❌ Error in load_flux_complete: {e}")
392
+ import traceback
393
+ traceback.print_exc()
394
+ return f"❌ Error: {e}"
395
+
396
+ def generate_image(self, prompt, model_choice, lora_choice, steps, guidance, seed):
397
+ """Generate with complete local setup - YOUR SETTINGS ARE RESPECTED"""
398
+
399
+ # Convert clean LoRA name back to full path if needed
400
+ actual_lora_choice = lora_choice
401
+ if hasattr(self, 'lora_path_mapping') and lora_choice in self.lora_path_mapping:
402
+ actual_lora_choice = self.lora_path_mapping[lora_choice]
403
+
404
+ # Load if needed
405
+ if self.pipeline is None or self.current_model != model_choice:
406
+ print(f"🔄 Need to load model: {model_choice}")
407
+ load_status = self.load_flux_complete(model_choice, actual_lora_choice)
408
+ if "❌" in load_status:
409
+ print(f"❌ Model loading failed: {load_status}")
410
+ return None, load_status
411
+
412
+ if not prompt.strip():
413
+ return None, "❌ Please enter a prompt"
414
+
415
+ try:
416
+ print(f"🎨 Starting generation...")
417
+ print(f" Prompt: {prompt[:60]}...")
418
+ print(f" Model: {model_choice}")
419
+ print(f" LoRA: {lora_choice}")
420
+ print(f" Steps: {steps}, Guidance: {guidance}, Seed: {seed}")
421
+
422
+ torch.manual_seed(int(seed))
423
+
424
+ # USE YOUR EXACT SETTINGS - NO OVERRIDES!
425
+ print(f" Using your exact settings: {steps} steps, guidance: {guidance}")
426
+
427
+ print("🔄 Running pipeline...")
428
+ with torch.inference_mode():
429
+ result = self.pipeline(
430
+ prompt=prompt,
431
+ num_inference_steps=int(steps),
432
+ guidance_scale=guidance,
433
+ width=1024,
434
+ height=1024,
435
+ generator=torch.Generator(device=self.device).manual_seed(int(seed))
436
+ )
437
+
438
+ if hasattr(result, 'images') and len(result.images) > 0:
439
+ image = result.images[0]
440
+ print("✅ Image generated successfully!")
441
+ else:
442
+ print("❌ No images in pipeline result")
443
+ return None, "❌ Pipeline returned no images"
444
+
445
+ if self.device.type == "mps":
446
+ torch.mps.empty_cache()
447
+
448
+ # Save with clean filename
449
+ os.makedirs("outputs/complete_local_flux", exist_ok=True)
450
+ model_name = model_choice.replace(" ", "_").lower()
451
+
452
+ # Clean LoRA name for filename
453
+ if lora_choice != "None":
454
+ lora_name = os.path.basename(lora_choice).replace(".safetensors", "")
455
+ lora_name = lora_name.replace("/", "_").replace("\\", "_").replace(" ", "_")
456
+ else:
457
+ lora_name = "no_lora"
458
+ filename = f"{model_name}_{lora_name}_{seed}.png"
459
+ filepath = os.path.join("outputs/complete_local_flux", filename)
460
+
461
+ print(f"💾 Saving to: {filepath}")
462
+ image.save(filepath, optimize=True)
463
+
464
+ status = f"✅ Generated with {model_choice}"
465
+ if self.lora_loaded:
466
+ status += f" + LoRA"
467
+ if self.local_t5_path:
468
+ status += " (local T5)"
469
+ status += f"\n📐 1024x1024 • {steps} steps • Guidance: {guidance} • Seed: {seed}"
470
+ status += f"\n💾 {filepath}"
471
+
472
+ print("🎉 Generation complete!")
473
+ return image, status
474
+
475
+ except Exception as e:
476
+ error_msg = f"❌ Generation failed: {str(e)}"
477
+ print(error_msg)
478
+ import traceback
479
+ traceback.print_exc()
480
+ return None, error_msg
481
+
482
+ def image_to_base64(self, image):
483
+ """Convert PIL Image to base64 string"""
484
+ try:
485
+ # Resize image if too large (Groq has size limits)
486
+ max_size = 1024
487
+ if image.width > max_size or image.height > max_size:
488
+ image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
489
+
490
+ # Convert to RGB if needed
491
+ if image.mode != 'RGB':
492
+ image = image.convert('RGB')
493
+
494
+ # Convert to base64
495
+ buffered = io.BytesIO()
496
+ image.save(buffered, format="JPEG", quality=85)
497
+ img_str = base64.b64encode(buffered.getvalue()).decode()
498
+ return img_str
499
+ except Exception as e:
500
+ print(f"❌ Error converting image to base64: {e}")
501
+ return None
502
+
503
+ def analyze_image_with_groq(self, image):
504
+ """Analyze image using Groq Vision API and return description"""
505
+ if not self.groq_api_key:
506
+ return "❌ Groq API key not configured. Set GROQ_API_KEY environment variable."
507
+
508
+ try:
509
+ print("🔍 Analyzing image with Groq Vision...")
510
+
511
+ # Convert image to base64
512
+ base64_image = self.image_to_base64(image)
513
+ if not base64_image:
514
+ return "❌ Failed to convert image to base64"
515
+
516
+ # Prepare the API request
517
+ headers = {
518
+ "Authorization": f"Bearer {self.groq_api_key}",
519
+ "Content-Type": "application/json"
520
+ }
521
+
522
+ payload = {
523
+ "model": "meta-llama/llama-4-scout-17b-16e-instruct",
524
+ "messages": [
525
+ {
526
+ "role": "user",
527
+ "content": [
528
+ {
529
+ "type": "text",
530
+ "text": "Describe this image in detail for an AI image generation prompt. Focus on visual elements, style, composition, lighting, colors, mood, and artistic techniques. Be descriptive but concise. Format it as a prompt that could be used to recreate a similar image."
531
+ },
532
+ {
533
+ "type": "image_url",
534
+ "image_url": {
535
+ "url": f"data:image/jpeg;base64,{base64_image}"
536
+ }
537
+ }
538
+ ]
539
+ }
540
+ ],
541
+ "max_tokens": 300,
542
+ "temperature": 0.3
543
+ }
544
+
545
+ # Make the API call
546
+ response = requests.post(
547
+ "https://api.groq.com/openai/v1/chat/completions",
548
+ headers=headers,
549
+ json=payload,
550
+ timeout=30
551
+ )
552
+
553
+ if response.status_code == 200:
554
+ result = response.json()
555
+ description = result['choices'][0]['message']['content'].strip()
556
+ print("✅ Image analysis complete!")
557
+ return description
558
+ else:
559
+ error_msg = f"Groq API error: {response.status_code} - {response.text}"
560
+ print(f"❌ {error_msg}")
561
+ return f"❌ {error_msg}"
562
+
563
+ except Exception as e:
564
+ error_msg = f"Error analyzing image: {str(e)}"
565
+ print(f"❌ {error_msg}")
566
+ return f"❌ {error_msg}"
567
+
568
+ def create_interface(self):
569
+ """Create complete interface"""
570
+
571
+ model_choices = list(self.flux_models.keys())
572
+ if not model_choices:
573
+ model_choices = ["No models found"]
574
+
575
+ # Clean up LoRA choices - show only the filename
576
+ clean_lora_choices = ["None"]
577
+ for lora_path in self.lora_files:
578
+ filename = os.path.basename(lora_path) # Get just the filename
579
+ clean_lora_choices.append(filename)
580
+
581
+ # Create a mapping from clean names to full paths
582
+ self.lora_path_mapping = {"None": "None"}
583
+ for lora_path in self.lora_files:
584
+ filename = os.path.basename(lora_path)
585
+ self.lora_path_mapping[filename] = lora_path
586
+
587
+ with gr.Blocks(title="Complete Local Flux Studio", theme=gr.themes.Soft()) as interface:
588
+
589
+ gr.Markdown("# 🏠 Complete Local Flux Studio")
590
+ gr.Markdown("*Using your local Flux models + T5 + LoRA - maximum efficiency!*")
591
+
592
+ # Show what's available locally
593
+ if self.flux_models:
594
+ gr.Markdown("## 📁 Your Local Setup:")
595
+ for name, info in self.flux_models.items():
596
+ gr.Markdown(f"- **{name}**: {info['size']:.1f} GB")
597
+ if self.local_t5_path:
598
+ t5_size = os.path.getsize(self.local_t5_path) / (1024*1024*1024)
599
+ gr.Markdown(f"- **T5 Encoder**: {t5_size:.1f} GB (local)")
600
+ if self.local_vae_path:
601
+ if os.path.isdir(self.local_vae_path):
602
+ gr.Markdown(f"- **VAE**: cached (local)")
603
+ else:
604
+ vae_size = os.path.getsize(self.local_vae_path) / (1024*1024*1024)
605
+ gr.Markdown(f"- **VAE**: {vae_size:.1f} GB (local)")
606
+ gr.Markdown(f"- **LoRA Models**: {len(self.lora_files)} found")
607
+
608
+ # IMAGE ANALYSIS SECTION - MOVED TO TOP LEVEL
609
+ gr.Markdown("## 🔍 Image Analysis with Groq Vision")
610
+ gr.Markdown("*Upload an image to automatically generate a prompt description*")
611
+
612
+ input_image = gr.Image(
613
+ label="📤 Upload Image to Analyze",
614
+ type="pil",
615
+ height=200
616
+ )
617
+
618
+ analyze_btn = gr.Button(
619
+ "🔍 Analyze Image with Groq Vision",
620
+ variant="primary",
621
+ size="lg"
622
+ )
623
+
624
+ with gr.Row():
625
+ with gr.Column(scale=1):
626
+ gr.Markdown("## 🎨 Generate")
627
+
628
+ model_choice = gr.Dropdown(
629
+ choices=model_choices,
630
+ value=model_choices[0] if model_choices[0] != "No models found" else None,
631
+ label="Flux Model"
632
+ )
633
+
634
+ lora_choice = gr.Dropdown(
635
+ choices=clean_lora_choices,
636
+ value=clean_lora_choices[1] if len(clean_lora_choices) > 1 else "None",
637
+ label="Your LoRA"
638
+ )
639
+
640
+ prompt = gr.Textbox(
641
+ label="Prompt",
642
+ value="artistic lifestyle portrait, person wearing vibrant orange bucket hat, expressive face, golden hour lighting, street style photography, film aesthetic",
643
+ lines=6,
644
+ placeholder="Enter your prompt here, or upload an image above and click 'Analyze' to auto-generate..."
645
+ )
646
+
647
+ with gr.Row():
648
+ steps = gr.Slider(4, 50, value=20, label="Steps")
649
+ guidance = gr.Slider(0.0, 10.0, value=3.5, label="Guidance")
650
+ seed = gr.Number(value=42, label="Seed")
651
+
652
+ generate_btn = gr.Button("🏠 Generate Locally", variant="primary", size="lg")
653
+
654
+ with gr.Column(scale=1):
655
+ output_image = gr.Image(label="Generated Image", height=600)
656
+ status = gr.Textbox(label="Status", interactive=False, lines=4)
657
+
658
+ # Quick prompts for your artistic style
659
+ gr.Markdown("## 🎨 Your Artistic Style")
660
+ with gr.Row():
661
+ portrait_btn = gr.Button("🎭 Portrait")
662
+ vibrant_btn = gr.Button("🌈 Vibrant")
663
+ street_btn = gr.Button("📸 Street")
664
+
665
+ # Event handlers
666
+ analyze_btn.click(
667
+ fn=self.analyze_image_with_groq,
668
+ inputs=[input_image],
669
+ outputs=[prompt]
670
+ )
671
+
672
+ portrait_btn.click(
673
+ lambda: "artistic lifestyle portrait, person with expressive face, vibrant clothing, golden hour lighting",
674
+ outputs=[prompt]
675
+ )
676
+
677
+ vibrant_btn.click(
678
+ lambda: "person in colorful streetwear, vibrant orange bucket hat, street photography, film aesthetic",
679
+ outputs=[prompt]
680
+ )
681
+
682
+ street_btn.click(
683
+ lambda: "urban street style portrait, candid expression, natural lighting, contemporary photography",
684
+ outputs=[prompt]
685
+ )
686
+
687
+ generate_btn.click(
688
+ fn=self.generate_image,
689
+ inputs=[prompt, model_choice, lora_choice, steps, guidance, seed],
690
+ outputs=[output_image, status]
691
+ )
692
+
693
+ return interface
694
+
695
+ def launch(self):
696
+ """Launch complete interface"""
697
+ interface = self.create_interface()
698
+
699
+ port = find_free_port()
700
+ print("🏠 Launching Complete Local Flux Studio...")
701
+ print(f"📱 Interface: http://localhost:{port}")
702
+ print("🚀 Using maximum local resources!")
703
+
704
+ try:
705
+ interface.launch(
706
+ server_port=port,
707
+ share=True,
708
+ inbrowser=True
709
+
710
+ )
711
+ except Exception as e:
712
+ print(f"❌ Launch failed: {e}")
713
+
714
+ if __name__ == "__main__":
715
+ # Check if sentencepiece is installed
716
+ try:
717
+ import sentencepiece
718
+ print("✅ SentencePiece found")
719
+ except ImportError:
720
+ print("❌ SentencePiece not found")
721
+ print("🔧 Install with: pip install sentencepiece protobuf")
722
+ exit(1)
723
+
724
+ interface = CompleteLocalFlux()
725
+ interface.launch()
complete_fixed_flux_script.py ADDED
@@ -0,0 +1,791 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ from diffusers import FluxPipeline
4
+ from transformers import CLIPTextModel, T5EncoderModel, CLIPTokenizer, T5Tokenizer
5
+ from safetensors.torch import load_file
6
+ import os
7
+ import socket
8
+ from PIL import Image
9
+ import base64
10
+ import io
11
+ import requests
12
+ import json
13
+
14
+ def find_free_port(start_port=7860):
15
+ """Find a free port"""
16
+ for port in range(start_port, start_port + 20):
17
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
18
+ try:
19
+ s.bind(('localhost', port))
20
+ return port
21
+ except OSError:
22
+ continue
23
+ return None
24
+
25
+ class CompleteLocalFlux:
26
+ def __init__(self):
27
+ # Set up Groq API key (you'll need to set this)
28
+ self.groq_api_key = os.getenv("GROQ_API_KEY")
29
+ if not self.groq_api_key:
30
+ print("⚠️ GROQ_API_KEY not found in environment variables")
31
+ print(" Set it with: export GROQ_API_KEY='your_api_key_here'")
32
+ else:
33
+ print("✅ Groq API key found")
34
+
35
+ if torch.backends.mps.is_available():
36
+ self.device = torch.device("mps")
37
+ print("🚀 Using Apple M2 Max with MPS")
38
+ else:
39
+ self.device = torch.device("cpu")
40
+
41
+ # Find your models
42
+ self.flux_models = {}
43
+ self.local_t5_path = None
44
+
45
+ # Check for Flux models
46
+ possible_flux_files = [
47
+ ("Flux Dev", "./models/Flux/flux-dev.safetensors"),
48
+ ("Flux Schnell", "./models/Flux/flux1-schnell.safetensors"),
49
+ ("Flux Kontex", "./models/Flux/flux-kontex.safetensors"),
50
+ ("Flux Dev Alt", "./flux-dev.safetensors"),
51
+ ("Flux Schnell Alt", "./flux1-schnell.safetensors"),
52
+ ("Flux Kontex Alt", "./flux-kontex.safetensors")
53
+ ]
54
+
55
+ for name, path in possible_flux_files:
56
+ if os.path.exists(path):
57
+ size_gb = os.path.getsize(path) / (1024*1024*1024)
58
+ self.flux_models[name] = {"path": path, "size": size_gb}
59
+ print(f"✅ Found {name}: {path} ({size_gb:.1f} GB)")
60
+
61
+ # Check for local T5 model
62
+ possible_t5_paths = [
63
+ "./models/Flux/google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors",
64
+ "./google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors",
65
+ "./models/google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors"
66
+ ]
67
+
68
+ for path in possible_t5_paths:
69
+ if os.path.exists(path):
70
+ size_gb = os.path.getsize(path) / (1024*1024*1024)
71
+ self.local_t5_path = path
72
+ print(f"✅ Found T5 model: {path} ({size_gb:.1f} GB)")
73
+ break
74
+
75
+ # Check for local CLIP model
76
+ self.local_clip_path = None
77
+ possible_clip_paths = [
78
+ "./models/clip",
79
+ "./models/CLIP/clip-vit-large-patch14",
80
+ "./clip-vit-large-patch14"
81
+ ]
82
+
83
+ for path in possible_clip_paths:
84
+ if os.path.exists(path) and os.path.exists(os.path.join(path, "config.json")):
85
+ self.local_clip_path = path
86
+ print(f"✅ Found local CLIP model: {path}")
87
+ break
88
+
89
+ if not self.local_clip_path:
90
+ print("⚠️ No local CLIP model found - will download on first use")
91
+
92
+ # Check for local VAE model (including downloaded cache)
93
+ self.local_vae_path = None
94
+ self.cached_vae_path = "./models/Flux/vae_cache" # Cache directory for downloaded VAE
95
+
96
+ possible_vae_paths = [
97
+ "./models/Flux/vae_local", # New local VAE location
98
+ "./models/Flux/ae.safetensors",
99
+ "./ae.safetensors",
100
+ "./models/ae.safetensors",
101
+ "./models/Flux/vae.safetensors",
102
+ "./vae.safetensors",
103
+ self.cached_vae_path # Check for cached downloaded VAE
104
+ ]
105
+
106
+ for path in possible_vae_paths:
107
+ if os.path.exists(path):
108
+ if os.path.isdir(path): # Cached VAE directory
109
+ self.local_vae_path = path
110
+ print(f"✅ Found cached VAE: {path}")
111
+ else: # Single VAE file
112
+ size_gb = os.path.getsize(path) / (1024*1024*1024)
113
+ self.local_vae_path = path
114
+ print(f"✅ Found VAE model: {path} ({size_gb:.1f} GB)")
115
+ break
116
+
117
+ # Find LoRA files - simple and working approach
118
+ self.lora_files = []
119
+
120
+ # Check multiple directories for LoRA files
121
+ lora_search_paths = [
122
+ "./models/lora", # Main LoRA directory
123
+ ".", # Current directory
124
+ "./models",
125
+ "./lora",
126
+ "./LoRA"
127
+ ]
128
+
129
+ for search_path in lora_search_paths:
130
+ if os.path.exists(search_path):
131
+ try:
132
+ files = [f for f in os.listdir(search_path) if f.endswith(".safetensors")]
133
+ # Add full path for files not in current directory
134
+ if search_path != ".":
135
+ files = [os.path.join(search_path, f) for f in files]
136
+ self.lora_files.extend(files)
137
+ except PermissionError:
138
+ continue
139
+
140
+ # Also specifically look for your LoRA files
141
+ specific_lora_files = [
142
+ "./models/lora/act_person_trained.safetensors",
143
+ "./models/lora/oddtoperson.safetensors",
144
+ "./models/lora/oddtopersonmark2.safetensors",
145
+
146
+ ]
147
+
148
+ for lora_file in specific_lora_files:
149
+ if os.path.exists(lora_file) and lora_file not in self.lora_files:
150
+ self.lora_files.append(lora_file)
151
+
152
+ # Remove duplicates while preserving order
153
+ seen = set()
154
+ unique_lora_files = []
155
+ for f in self.lora_files:
156
+ if f not in seen:
157
+ seen.add(f)
158
+ unique_lora_files.append(f)
159
+ self.lora_files = unique_lora_files
160
+
161
+ self.pipeline = None
162
+ self.current_model = None
163
+ self.lora_loaded = False
164
+ self.encoders_loaded = False
165
+
166
+ print(f"✅ Found {len(self.lora_files)} LoRA files")
167
+ for f in self.lora_files:
168
+ print(f" - {f}")
169
+
170
+ def cleanup_memory(self):
171
+ """Clean up GPU/MPS memory"""
172
+ if hasattr(self, 'pipeline') and self.pipeline is not None:
173
+ del self.pipeline
174
+ self.pipeline = None
175
+
176
+ if torch.cuda.is_available():
177
+ torch.cuda.empty_cache()
178
+ elif self.device.type == "mps":
179
+ torch.mps.empty_cache()
180
+
181
+ print("🧹 Memory cleaned up")
182
+
183
+ def load_local_text_encoders(self):
184
+ """Load text encoders using local and remote models"""
185
+ try:
186
+ print("🔄 Loading text encoders...")
187
+
188
+ # Use consistent dtype for MPS compatibility
189
+ dtype = torch.float32 # Use float32 for better MPS compatibility
190
+
191
+ # Load CLIP text encoder from local folder if available
192
+ if self.local_clip_path:
193
+ print(f" Loading CLIP from local folder: {self.local_clip_path}")
194
+ try:
195
+ self.clip_text_encoder = CLIPTextModel.from_pretrained(
196
+ self.local_clip_path,
197
+ torch_dtype=dtype,
198
+ local_files_only=True # Force local only
199
+ )
200
+ self.clip_tokenizer = CLIPTokenizer.from_pretrained(
201
+ self.local_clip_path,
202
+ local_files_only=True # Force local only
203
+ )
204
+ print("✅ Local CLIP model loaded successfully!")
205
+ except Exception as e:
206
+ print(f"❌ Error loading local CLIP folder: {e}")
207
+ print(" Falling back to download...")
208
+ # Fallback to download if local fails
209
+ self.clip_text_encoder = CLIPTextModel.from_pretrained(
210
+ "openai/clip-vit-large-patch14",
211
+ torch_dtype=dtype
212
+ )
213
+ self.clip_tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")
214
+ else:
215
+ print(" Loading CLIP text encoder (downloading ~1GB)...")
216
+ self.clip_text_encoder = CLIPTextModel.from_pretrained(
217
+ "openai/clip-vit-large-patch14",
218
+ torch_dtype=dtype
219
+ )
220
+ self.clip_tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")
221
+
222
+ # Load T5 encoder - fix the tokenizer warning and local loading
223
+ if self.local_t5_path:
224
+ print(f" Loading T5 from local file: {self.local_t5_path}")
225
+
226
+ # Load tokenizer with legacy=False to suppress warning
227
+ print(" Loading T5 tokenizer...")
228
+ self.t5_tokenizer = T5Tokenizer.from_pretrained(
229
+ "google/t5-v1_1-xxl",
230
+ legacy=False # This fixes the warning
231
+ )
232
+
233
+ print(" Loading local T5 weights...")
234
+ # Load the model architecture first
235
+ self.t5_text_encoder = T5EncoderModel.from_pretrained(
236
+ "google/t5-v1_1-xxl",
237
+ torch_dtype=dtype
238
+ )
239
+
240
+ # Try to load and apply your local weights
241
+ try:
242
+ print(" Attempting to load local T5 safetensors...")
243
+ local_t5_weights = load_file(self.local_t5_path)
244
+
245
+ # Filter weights to only include those that match the model structure
246
+ model_state_dict = self.t5_text_encoder.state_dict()
247
+ filtered_weights = {}
248
+
249
+ for key, value in local_t5_weights.items():
250
+ if key in model_state_dict:
251
+ if model_state_dict[key].shape == value.shape:
252
+ filtered_weights[key] = value
253
+ else:
254
+ print(f"⚠️ Skipping {key}: shape mismatch {model_state_dict[key].shape} vs {value.shape}")
255
+ else:
256
+ print(f"⚠️ Skipping {key}: not found in model")
257
+
258
+ # Load the filtered weights
259
+ missing_keys, unexpected_keys = self.t5_text_encoder.load_state_dict(filtered_weights, strict=False)
260
+
261
+ if missing_keys:
262
+ print(f"⚠️ Missing keys: {len(missing_keys)} (this is often normal)")
263
+ if unexpected_keys:
264
+ print(f"⚠️ Unexpected keys: {len(unexpected_keys)}")
265
+
266
+ print("✅ Local T5 weights loaded successfully!")
267
+
268
+ except Exception as e:
269
+ print(f"❌ Error loading local T5 weights: {e}")
270
+ print(" Your T5 file may be corrupted or incomplete.")
271
+ print(" Falling back to downloaded weights (model architecture already loaded)...")
272
+ # Keep the downloaded model architecture - don't try to reload
273
+
274
+ else:
275
+ print(" No local T5 found, downloading...")
276
+ self.t5_tokenizer = T5Tokenizer.from_pretrained(
277
+ "google/t5-v1_1-xxl",
278
+ legacy=False # This fixes the warning
279
+ )
280
+ self.t5_text_encoder = T5EncoderModel.from_pretrained(
281
+ "google/t5-v1_1-xxl",
282
+ torch_dtype=dtype
283
+ )
284
+
285
+ # Move to device
286
+ self.clip_text_encoder = self.clip_text_encoder.to(self.device)
287
+ self.t5_text_encoder = self.t5_text_encoder.to(self.device)
288
+
289
+ self.encoders_loaded = True
290
+ print("✅ All text encoders loaded successfully!")
291
+ return True
292
+
293
+ except Exception as e:
294
+ print(f"❌ Error loading text encoders: {e}")
295
+ import traceback
296
+ traceback.print_exc() # This will help debug the exact issue
297
+ return False
298
+
299
+ def load_flux_complete(self, model_choice, lora_choice):
300
+ """Load complete Flux setup with better memory management"""
301
+ try:
302
+ # Clean up previous model if switching
303
+ if self.current_model and self.current_model != model_choice:
304
+ print("🧹 Cleaning up previous model...")
305
+ self.cleanup_memory()
306
+
307
+ # Load encoders if needed
308
+ if not self.encoders_loaded:
309
+ if not self.load_local_text_encoders():
310
+ return "❌ Failed to load text encoders"
311
+
312
+ if model_choice not in self.flux_models:
313
+ return f"❌ Model {model_choice} not found"
314
+
315
+ model_path = self.flux_models[model_choice]["path"]
316
+ print(f"🔄 Loading {model_choice} with complete setup...")
317
+
318
+ # Load VAE separately (required for Flux)
319
+ print(" Loading VAE...")
320
+ from diffusers import AutoencoderKL
321
+
322
+ # Check if we have a local VAE first
323
+ if self.local_vae_path:
324
+ print(f" Using local VAE from: {self.local_vae_path}")
325
+ try:
326
+ if os.path.isdir(self.local_vae_path):
327
+ # Local VAE folder
328
+ vae = AutoencoderKL.from_pretrained(
329
+ self.local_vae_path,
330
+ torch_dtype=torch.float32,
331
+ local_files_only=True # Force local only
332
+ )
333
+ else:
334
+ # Single VAE file - load the base model and apply weights
335
+ vae = AutoencoderKL.from_pretrained(
336
+ "black-forest-labs/FLUX.1-dev",
337
+ subfolder="vae",
338
+ torch_dtype=torch.float32
339
+ )
340
+ # Load local weights if it's a safetensors file
341
+ if self.local_vae_path.endswith('.safetensors'):
342
+ from safetensors.torch import load_file
343
+ vae_weights = load_file(self.local_vae_path)
344
+ vae.load_state_dict(vae_weights, strict=False)
345
+
346
+ # Ensure all VAE weights are float32 for MPS compatibility
347
+ vae = vae.to(torch.float32)
348
+ print("✅ Local VAE loaded successfully!")
349
+
350
+ except Exception as e:
351
+ print(f"❌ Local VAE failed: {e}")
352
+ print(" Falling back to download...")
353
+ vae = None
354
+ else:
355
+ vae = None
356
+
357
+ # Download and cache VAE if no local version works
358
+ if vae is None:
359
+ print(" ⚠️ No local VAE found - downloading from HuggingFace...")
360
+ print(" Consider running download_vae.py for 100% local operation")
361
+ try:
362
+ # Create cache directory
363
+ os.makedirs(os.path.dirname(self.cached_vae_path), exist_ok=True)
364
+
365
+ # Download and save to cache
366
+ vae = AutoencoderKL.from_pretrained(
367
+ "black-forest-labs/FLUX.1-dev",
368
+ subfolder="vae",
369
+ torch_dtype=torch.float32,
370
+ cache_dir="./models/Flux/hf_cache" # Local cache for HuggingFace downloads
371
+ )
372
+
373
+ # Ensure all VAE weights are float32 for MPS compatibility
374
+ vae = vae.to(torch.float32)
375
+
376
+ # Save the VAE locally for next time
377
+ print(f" Caching VAE to: {self.cached_vae_path}")
378
+ vae.save_pretrained(self.cached_vae_path)
379
+ self.local_vae_path = self.cached_vae_path # Update for future runs
380
+
381
+ print("✅ VAE downloaded and cached locally!")
382
+
383
+ except Exception as e:
384
+ print(f"❌ Failed to download VAE: {e}")
385
+ return f"❌ Could not load VAE: {e}"
386
+
387
+ # Load Flux with all components including VAE
388
+ self.pipeline = FluxPipeline.from_single_file(
389
+ model_path,
390
+ text_encoder=self.clip_text_encoder,
391
+ text_encoder_2=self.t5_text_encoder,
392
+ tokenizer=self.clip_tokenizer,
393
+ tokenizer_2=self.t5_tokenizer,
394
+ vae=vae, # Add the VAE component
395
+ torch_dtype=torch.float32, # Use float32 for MPS compatibility
396
+ )
397
+
398
+ self.current_model = model_choice
399
+ print(f"✅ {model_choice} loaded completely!")
400
+
401
+ # Load LoRA
402
+ self.lora_loaded = False
403
+ if lora_choice != "None" and lora_choice in self.lora_files:
404
+ try:
405
+ print(f"🔄 Loading LoRA: {lora_choice}")
406
+
407
+ # Load LoRA with better error handling and warnings suppression
408
+ import warnings
409
+ with warnings.catch_warnings():
410
+ warnings.filterwarnings("ignore", message="No LoRA keys associated to CLIPTextModel found")
411
+ warnings.filterwarnings("ignore", message="You can also try specifying")
412
+
413
+ self.pipeline.load_lora_weights(".", weight_name=lora_choice)
414
+
415
+ self.lora_loaded = True
416
+ print("✅ LoRA loaded successfully!")
417
+
418
+ except Exception as e:
419
+ print(f"❌ LoRA loading failed: {e}")
420
+ # Continue without LoRA if it fails
421
+ self.lora_loaded = False
422
+
423
+ # Move pipeline to device (MPS for Apple Silicon)
424
+ self.pipeline = self.pipeline.to(self.device)
425
+
426
+ # Ensure all pipeline components are float32 for MPS compatibility
427
+ if self.device.type == "mps":
428
+ print(" Converting all components to float32 for MPS...")
429
+ self.pipeline.vae = self.pipeline.vae.to(torch.float32)
430
+ self.pipeline.text_encoder = self.pipeline.text_encoder.to(torch.float32)
431
+ self.pipeline.text_encoder_2 = self.pipeline.text_encoder_2.to(torch.float32)
432
+
433
+ # Enable MPS-specific optimizations
434
+ self.pipeline.enable_attention_slicing()
435
+ print("✅ Enabled MPS optimizations and float32 conversion")
436
+
437
+ status = f"✅ {model_choice} ready"
438
+ if self.local_t5_path:
439
+ status += " (local T5)"
440
+ if self.local_clip_path:
441
+ status += " (local CLIP)"
442
+ if self.local_vae_path:
443
+ status += " (local VAE)"
444
+ if self.lora_loaded:
445
+ status += f" + LoRA ({lora_choice})"
446
+
447
+ return status
448
+
449
+ except Exception as e:
450
+ print(f"❌ Error in load_flux_complete: {e}")
451
+ import traceback
452
+ traceback.print_exc()
453
+ return f"❌ Error: {e}"
454
+
455
+ def generate_image(self, prompt, model_choice, lora_choice, steps, guidance, seed):
456
+ """Generate with complete local setup - YOUR SETTINGS ARE RESPECTED"""
457
+
458
+ # Convert clean LoRA name back to full path if needed
459
+ actual_lora_choice = lora_choice
460
+ if hasattr(self, 'lora_path_mapping') and lora_choice in self.lora_path_mapping:
461
+ actual_lora_choice = self.lora_path_mapping[lora_choice]
462
+
463
+ # Load if needed
464
+ if self.pipeline is None or self.current_model != model_choice:
465
+ print(f"🔄 Need to load model: {model_choice}")
466
+ load_status = self.load_flux_complete(model_choice, actual_lora_choice)
467
+ if "❌" in load_status:
468
+ print(f"❌ Model loading failed: {load_status}")
469
+ return None, load_status
470
+
471
+ if not prompt.strip():
472
+ return None, "❌ Please enter a prompt"
473
+
474
+ try:
475
+ print(f"🎨 Starting generation...")
476
+ print(f" Prompt: {prompt[:60]}...")
477
+ print(f" Model: {model_choice}")
478
+ print(f" LoRA: {lora_choice}")
479
+ print(f" Steps: {steps}, Guidance: {guidance}, Seed: {seed}")
480
+
481
+ torch.manual_seed(int(seed))
482
+
483
+ # USE YOUR EXACT SETTINGS - NO OVERRIDES!
484
+ print(f" Using your exact settings: {steps} steps, guidance: {guidance}")
485
+
486
+ print("🔄 Running pipeline...")
487
+ with torch.inference_mode():
488
+ result = self.pipeline(
489
+ prompt=prompt,
490
+ num_inference_steps=int(steps),
491
+ guidance_scale=guidance,
492
+ width=1024,
493
+ height=1024,
494
+ generator=torch.Generator(device=self.device).manual_seed(int(seed))
495
+ )
496
+
497
+ if hasattr(result, 'images') and len(result.images) > 0:
498
+ image = result.images[0]
499
+ print("✅ Image generated successfully!")
500
+ else:
501
+ print("❌ No images in pipeline result")
502
+ return None, "❌ Pipeline returned no images"
503
+
504
+ if self.device.type == "mps":
505
+ torch.mps.empty_cache()
506
+
507
+ # Save with clean filename
508
+ os.makedirs("outputs/complete_local_flux", exist_ok=True)
509
+ model_name = model_choice.replace(" ", "_").lower()
510
+
511
+ # Clean LoRA name for filename
512
+ if lora_choice != "None":
513
+ lora_name = os.path.basename(lora_choice).replace(".safetensors", "")
514
+ lora_name = lora_name.replace("/", "_").replace("\\", "_").replace(" ", "_")
515
+ else:
516
+ lora_name = "no_lora"
517
+ filename = f"{model_name}_{lora_name}_{seed}.png"
518
+ filepath = os.path.join("outputs/complete_local_flux", filename)
519
+
520
+ print(f"💾 Saving to: {filepath}")
521
+ image.save(filepath, optimize=True)
522
+
523
+ status = f"✅ Generated with {model_choice}"
524
+ if self.lora_loaded:
525
+ status += f" + LoRA"
526
+ if self.local_t5_path:
527
+ status += " (local T5)"
528
+ status += f"\n📐 1024x1024 • {steps} steps • Guidance: {guidance} • Seed: {seed}"
529
+ status += f"\n💾 {filepath}"
530
+
531
+ print("🎉 Generation complete!")
532
+ return image, status
533
+
534
+ except Exception as e:
535
+ error_msg = f"❌ Generation failed: {str(e)}"
536
+ print(error_msg)
537
+ import traceback
538
+ traceback.print_exc()
539
+ return None, error_msg
540
+
541
+ def image_to_base64(self, image):
542
+ """Convert PIL Image to base64 string"""
543
+ try:
544
+ # Resize image if too large (Groq has size limits)
545
+ max_size = 1024
546
+ if image.width > max_size or image.height > max_size:
547
+ image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
548
+
549
+ # Convert to RGB if needed
550
+ if image.mode != 'RGB':
551
+ image = image.convert('RGB')
552
+
553
+ # Convert to base64
554
+ buffered = io.BytesIO()
555
+ image.save(buffered, format="JPEG", quality=85)
556
+ img_str = base64.b64encode(buffered.getvalue()).decode()
557
+ return img_str
558
+ except Exception as e:
559
+ print(f"❌ Error converting image to base64: {e}")
560
+ return None
561
+
562
+ def analyze_image_with_groq(self, image):
563
+ """Analyze image using Groq Vision API and return description"""
564
+ if not self.groq_api_key:
565
+ return "❌ Groq API key not configured. Set GROQ_API_KEY environment variable."
566
+
567
+ try:
568
+ print("🔍 Analyzing image with Groq Vision...")
569
+
570
+ # Convert image to base64
571
+ base64_image = self.image_to_base64(image)
572
+ if not base64_image:
573
+ return "❌ Failed to convert image to base64"
574
+
575
+ # Prepare the API request
576
+ headers = {
577
+ "Authorization": f"Bearer {self.groq_api_key}",
578
+ "Content-Type": "application/json"
579
+ }
580
+
581
+ payload = {
582
+ "model": "meta-llama/llama-4-scout-17b-16e-instruct",
583
+ "messages": [
584
+ {
585
+ "role": "user",
586
+ "content": [
587
+ {
588
+ "type": "text",
589
+ "text": "Describe this image in detail for an AI image generation prompt. Focus on visual elements, style, composition, lighting, colors, mood, and artistic techniques. Be descriptive but concise. Format it as a prompt that could be used to recreate a similar image."
590
+ },
591
+ {
592
+ "type": "image_url",
593
+ "image_url": {
594
+ "url": f"data:image/jpeg;base64,{base64_image}"
595
+ }
596
+ }
597
+ ]
598
+ }
599
+ ],
600
+ "max_tokens": 300,
601
+ "temperature": 0.3
602
+ }
603
+
604
+ # Make the API call
605
+ response = requests.post(
606
+ "https://api.groq.com/openai/v1/chat/completions",
607
+ headers=headers,
608
+ json=payload,
609
+ timeout=30
610
+ )
611
+
612
+ if response.status_code == 200:
613
+ result = response.json()
614
+ description = result['choices'][0]['message']['content'].strip()
615
+ print("✅ Image analysis complete!")
616
+ return description
617
+ else:
618
+ error_msg = f"Groq API error: {response.status_code} - {response.text}"
619
+ print(f"❌ {error_msg}")
620
+ return f"❌ {error_msg}"
621
+
622
+ except Exception as e:
623
+ error_msg = f"Error analyzing image: {str(e)}"
624
+ print(f"❌ {error_msg}")
625
+ return f"❌ {error_msg}"
626
+
627
+ def create_interface(self):
628
+ """Create complete interface"""
629
+
630
+ model_choices = list(self.flux_models.keys())
631
+ if not model_choices:
632
+ model_choices = ["No models found"]
633
+
634
+ # Clean up LoRA choices - show only the filename
635
+ clean_lora_choices = ["None"]
636
+ for lora_path in self.lora_files:
637
+ filename = os.path.basename(lora_path) # Get just the filename
638
+ clean_lora_choices.append(filename)
639
+
640
+ # Create a mapping from clean names to full paths
641
+ self.lora_path_mapping = {"None": "None"}
642
+ for lora_path in self.lora_files:
643
+ filename = os.path.basename(lora_path)
644
+ self.lora_path_mapping[filename] = lora_path
645
+
646
+ with gr.Blocks(title="Complete Local Flux Studio", theme=gr.themes.Soft()) as interface:
647
+
648
+ gr.Markdown("# 🏠 Complete Local Flux Studio")
649
+ gr.Markdown("*Using your local Flux models + T5 + LoRA - maximum efficiency!*")
650
+
651
+ # Show what's available locally
652
+ if self.flux_models:
653
+ gr.Markdown("## 📁 Your Local Setup:")
654
+ for name, info in self.flux_models.items():
655
+ gr.Markdown(f"- **{name}**: {info['size']:.1f} GB")
656
+ if self.local_t5_path:
657
+ t5_size = os.path.getsize(self.local_t5_path) / (1024*1024*1024)
658
+ gr.Markdown(f"- **T5 Encoder**: {t5_size:.1f} GB (local)")
659
+ if self.local_clip_path:
660
+ clip_file = os.path.join(self.local_clip_path, "model.safetensors")
661
+ if os.path.exists(clip_file):
662
+ clip_size = os.path.getsize(clip_file) / (1024*1024*1024)
663
+ gr.Markdown(f"- **CLIP Encoder**: {clip_size:.1f} GB (local)")
664
+ else:
665
+ gr.Markdown(f"- **CLIP Encoder**: local folder found")
666
+ if self.local_vae_path:
667
+ if os.path.isdir(self.local_vae_path):
668
+ gr.Markdown(f"- **VAE**: cached (local)")
669
+ else:
670
+ vae_size = os.path.getsize(self.local_vae_path) / (1024*1024*1024)
671
+ gr.Markdown(f"- **VAE**: {vae_size:.1f} GB (local)")
672
+ gr.Markdown(f"- **LoRA Models**: {len(self.lora_files)} found")
673
+
674
+ # IMAGE ANALYSIS SECTION - MOVED TO TOP LEVEL
675
+ gr.Markdown("## 🔍 Image Analysis with Groq Vision")
676
+ gr.Markdown("*Upload an image to automatically generate a prompt description*")
677
+
678
+ input_image = gr.Image(
679
+ label="📤 Upload Image to Analyze",
680
+ type="pil",
681
+ height=200
682
+ )
683
+
684
+ analyze_btn = gr.Button(
685
+ "🔍 Analyze Image with Groq Vision",
686
+ variant="primary",
687
+ size="lg"
688
+ )
689
+
690
+ with gr.Row():
691
+ with gr.Column(scale=1):
692
+ gr.Markdown("## 🎨 Generate")
693
+
694
+ model_choice = gr.Dropdown(
695
+ choices=model_choices,
696
+ value=model_choices[0] if model_choices[0] != "No models found" else None,
697
+ label="Flux Model"
698
+ )
699
+
700
+ lora_choice = gr.Dropdown(
701
+ choices=clean_lora_choices,
702
+ value=clean_lora_choices[1] if len(clean_lora_choices) > 1 else "None",
703
+ label="Your LoRA"
704
+ )
705
+
706
+ prompt = gr.Textbox(
707
+ label="Prompt",
708
+ value="artistic lifestyle portrait, person wearing vibrant orange bucket hat, expressive face, golden hour lighting, street style photography, film aesthetic",
709
+ lines=6,
710
+ placeholder="Enter your prompt here, or upload an image above and click 'Analyze' to auto-generate..."
711
+ )
712
+
713
+ with gr.Row():
714
+ steps = gr.Slider(4, 50, value=20, label="Steps")
715
+ guidance = gr.Slider(0.0, 10.0, value=3.5, label="Guidance")
716
+ seed = gr.Number(value=42, label="Seed")
717
+
718
+ generate_btn = gr.Button("🏠 Generate Locally", variant="primary", size="lg")
719
+
720
+ with gr.Column(scale=1):
721
+ output_image = gr.Image(label="Generated Image", height=600)
722
+ status = gr.Textbox(label="Status", interactive=False, lines=4)
723
+
724
+ # Quick prompts for your artistic style
725
+ gr.Markdown("## 🎨 Your Artistic Style")
726
+ with gr.Row():
727
+ portrait_btn = gr.Button("🎭 Portrait")
728
+ vibrant_btn = gr.Button("🌈 Vibrant")
729
+ street_btn = gr.Button("📸 Street")
730
+
731
+ # Event handlers
732
+ analyze_btn.click(
733
+ fn=self.analyze_image_with_groq,
734
+ inputs=[input_image],
735
+ outputs=[prompt]
736
+ )
737
+
738
+ portrait_btn.click(
739
+ lambda: "artistic lifestyle portrait, person with expressive face, vibrant clothing, golden hour lighting",
740
+ outputs=[prompt]
741
+ )
742
+
743
+ vibrant_btn.click(
744
+ lambda: "person in colorful streetwear, vibrant orange bucket hat, street photography, film aesthetic",
745
+ outputs=[prompt]
746
+ )
747
+
748
+ street_btn.click(
749
+ lambda: "urban street style portrait, candid expression, natural lighting, contemporary photography",
750
+ outputs=[prompt]
751
+ )
752
+
753
+ generate_btn.click(
754
+ fn=self.generate_image,
755
+ inputs=[prompt, model_choice, lora_choice, steps, guidance, seed],
756
+ outputs=[output_image, status]
757
+ )
758
+
759
+ return interface
760
+
761
+ def launch(self):
762
+ """Launch complete interface"""
763
+ interface = self.create_interface()
764
+
765
+ port = find_free_port()
766
+ print("🏠 Launching Complete Local Flux Studio...")
767
+ print(f"📱 Interface: http://localhost:{port}")
768
+ print("🚀 Using maximum local resources!")
769
+
770
+ try:
771
+ interface.launch(
772
+ server_port=port,
773
+ share=True,
774
+ inbrowser=True
775
+
776
+ )
777
+ except Exception as e:
778
+ print(f"❌ Launch failed: {e}")
779
+
780
+ if __name__ == "__main__":
781
+ # Check if sentencepiece is installed
782
+ try:
783
+ import sentencepiece
784
+ print("✅ SentencePiece found")
785
+ except ImportError:
786
+ print("❌ SentencePiece not found")
787
+ print("🔧 Install with: pip install sentencepiece protobuf")
788
+ exit(1)
789
+
790
+ interface = CompleteLocalFlux()
791
+ interface.launch()
data/training_images/Stocksy_comp_1503760_G1G3.jpg ADDED

Git LFS Details

  • SHA256: d7d1788e1e273ced08e1f7141e967d27a4897d89b913fa7e69d378de29e3de0c
  • Pointer size: 133 Bytes
  • Size of remote file: 10.2 MB
data/training_images/Stocksy_comp_2058141_G1G3.jpg ADDED

Git LFS Details

  • SHA256: aecf4199a054c729fd83b429bda694393e676a03879415ba588a808e4bb99556
  • Pointer size: 133 Bytes
  • Size of remote file: 23 MB
data/training_images/Stocksy_comp_2511302_G1G2G4.jpg ADDED

Git LFS Details

  • SHA256: fd4f583fd6cb6d7f529cfd73fda871b541e6c2b8bfc70bdd0d068b413c289167
  • Pointer size: 132 Bytes
  • Size of remote file: 9.98 MB
data/training_images/Stocksy_comp_2604801_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 041de4a11f492949263a69e365366a63e9e52ebc9fce60135640ac53f9bc4c03
  • Pointer size: 132 Bytes
  • Size of remote file: 9.59 MB
data/training_images/Stocksy_comp_3177699_G1G3.jpg ADDED

Git LFS Details

  • SHA256: 14b0238319364f791e1429d03b308b3b557169739fc89a4fe1ff63578131882c
  • Pointer size: 133 Bytes
  • Size of remote file: 14.6 MB
data/training_images/Stocksy_comp_3414632_NO GLOW.jpg ADDED

Git LFS Details

  • SHA256: f24396f3f21c11398b6a9009837d872fd6efd1f483b1c98a768a9ea65671f124
  • Pointer size: 133 Bytes
  • Size of remote file: 15.1 MB
data/training_images/Stocksy_comp_3737382_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 22bd226e7cedc380209b47417c4a52cbeea41e101e4a4166c996658224e6a36d
  • Pointer size: 132 Bytes
  • Size of remote file: 8.38 MB
data/training_images/Stocksy_comp_3890544_G2G4.jpg ADDED

Git LFS Details

  • SHA256: 011b918402ed99fd0cf35b2664e5e10ca32c4b1e4af6e247d91168cffc392849
  • Pointer size: 132 Bytes
  • Size of remote file: 8.94 MB
data/training_images/Stocksy_comp_3942209._G1G2G3G4jpg.jpg ADDED

Git LFS Details

  • SHA256: bd16d3e76ba7eb58c09ba8b5df09d49ed2edc4d57e50aab007324da67031d1e7
  • Pointer size: 133 Bytes
  • Size of remote file: 12 MB
data/training_images/Stocksy_comp_4003550_G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: f20632954dec6535fb107674f5aaf5375b4bd89d6ed339e9494dc91e117c7e23
  • Pointer size: 133 Bytes
  • Size of remote file: 16.6 MB
data/training_images/Stocksy_comp_4103954_G1G3.jpg ADDED

Git LFS Details

  • SHA256: b90cc8a37638cc5443fdd600c1f7dee5c385a334f3ce213b82b9bee8df90264b
  • Pointer size: 133 Bytes
  • Size of remote file: 17.3 MB
data/training_images/Stocksy_comp_4165779_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 207193aa50b0158c3ca2c7d0e7259b9185bce3e693bdafc921fe34d4c5b4998e
  • Pointer size: 133 Bytes
  • Size of remote file: 13.8 MB
data/training_images/Stocksy_comp_634618_G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 59f27aa87dd076ab3d3feea46836a76c91555bb8a4c32e25b060e0bfd09649d5
  • Pointer size: 133 Bytes
  • Size of remote file: 12.9 MB
data/training_images/photocase_3841861_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 09f6e14eeb24e7810f10be266ca03dce093dc0001e7f67f4b981bfa714bf4844
  • Pointer size: 133 Bytes
  • Size of remote file: 23.3 MB
data/training_images/photocase_3992910_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 2bf9760da28f2b2b2c02cb61a5e494262f7953d3dd9109f6637790d26bab5ae7
  • Pointer size: 132 Bytes
  • Size of remote file: 7.67 MB
data/training_images/photocase_4173298_G2G34.jpg ADDED

Git LFS Details

  • SHA256: cf10de9b08fa0cb192eeb2f75319d96b8b9d5695179c347e8e6246b21ddf2f2e
  • Pointer size: 132 Bytes
  • Size of remote file: 8.73 MB
data/training_images/photocase_4190225_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 3d78df0a22ad074cabf9a013bbfd4b0008e5cf95d7495069e475ffdc3d1e2a73
  • Pointer size: 133 Bytes
  • Size of remote file: 10.1 MB
data/training_images/photocase_4202421_G1G2G34.jpg ADDED

Git LFS Details

  • SHA256: 9b3784fc21731be605f9f00a67b4f8727909de68acf5d13ba6c54ab8db85d2e6
  • Pointer size: 133 Bytes
  • Size of remote file: 12.6 MB
data/training_images/photocase_4363114_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 948e7f7bb7a5f210fc3d7399e3c50469ddb498a2feba8eb705db51df0f8a2a16
  • Pointer size: 132 Bytes
  • Size of remote file: 7.61 MB
data/training_images/photocase_4687971_G1G2G3G4.jpg ADDED

Git LFS Details

  • SHA256: 973a907f322bec7d0d0bc10bfeebaa8cd03b9e71c9222abd455224d154b17527
  • Pointer size: 132 Bytes
  • Size of remote file: 6.18 MB
data/training_images/processed/Stocksy_comp_1503760_G1G3.jpg ADDED
data/training_images/processed/Stocksy_comp_2058141_G1G3.jpg ADDED
data/training_images/processed/Stocksy_comp_2511302_G1G2G4.jpg ADDED
data/training_images/processed/Stocksy_comp_2604801_G1G2G3G4.jpg ADDED
data/training_images/processed/Stocksy_comp_3177699_G1G3.jpg ADDED
data/training_images/processed/Stocksy_comp_3414632_NO GLOW.jpg ADDED
data/training_images/processed/Stocksy_comp_3737382_G1G2G3G4.jpg ADDED
data/training_images/processed/Stocksy_comp_3890544_G2G4.jpg ADDED
data/training_images/processed/Stocksy_comp_3942209._G1G2G3G4jpg.jpg ADDED
data/training_images/processed/Stocksy_comp_4003550_G2G3G4.jpg ADDED
data/training_images/processed/Stocksy_comp_4103954_G1G3.jpg ADDED
data/training_images/processed/Stocksy_comp_4165779_G1G2G3G4.jpg ADDED
data/training_images/processed/Stocksy_comp_634618_G2G3G4.jpg ADDED
data/training_images/processed/photocase_3841861_G1G2G3G4.jpg ADDED
data/training_images/processed/photocase_3992910_G1G2G3G4.jpg ADDED
data/training_images/processed/photocase_4173298_G2G34.jpg ADDED
data/training_images/processed/photocase_4190225_G1G2G3G4.jpg ADDED
data/training_images/processed/photocase_4202421_G1G2G34.jpg ADDED
data/training_images/processed/photocase_4363114_G1G2G3G4.jpg ADDED
data/training_images/processed/photocase_4687971_G1G2G3G4.jpg ADDED
flux_dev_oddtopersonmark2.jpeg ADDED

Git LFS Details

  • SHA256: b3e1e4f3ad6f46035e80a9c07f24906d99a55f09edce9ae750021cedda20eb75
  • Pointer size: 131 Bytes
  • Size of remote file: 544 kB