John6666 commited on
Commit
9c86d59
·
verified ·
1 Parent(s): 13ea36e

Upload 5 files

Browse files
Files changed (5) hide show
  1. README.md +166 -165
  2. app.py +81 -80
  3. env.py +2 -0
  4. modutils.py +119 -35
  5. requirements.txt +23 -22
README.md CHANGED
@@ -1,165 +1,166 @@
1
- ---
2
- title: 🧩 DiffuseCraft Mod (SDXL/SD1.5 Models Text-to-Image)
3
- emoji: 🧩🖼️📦
4
- colorFrom: red
5
- colorTo: pink
6
- sdk: gradio
7
- sdk_version: 5.45.0
8
- app_file: app.py
9
- pinned: true
10
- header: mini
11
- license: mit
12
- duplicated_from: r3gm/DiffuseCraft
13
- short_description: Stunning images using stable diffusion.
14
- preload_from_hub:
15
- - madebyollin/sdxl-vae-fp16-fix config.json,diffusion_pytorch_model.safetensors
16
- ---
17
-
18
- ## Using this Space programmatically
19
-
20
- You can call this Space from Python (via `gradio_client`) or from plain `curl`.
21
-
22
- > ⚠️ Note: This README may lag behind the actual API definition shown in the Space’s “View API” page.
23
- > If something does not work, always double-check the latest argument list and endpoint names there.
24
-
25
- Assumptions:
26
-
27
- - Space ID: `John6666/DiffuseCraftMod`
28
- - You have a valid Hugging Face access token: `hf_xxx...` (read access is enough)
29
- - Replace `hf_xxx...` with your own token
30
-
31
- ---
32
-
33
- ### 1. Python examples (`gradio_client`)
34
-
35
- Install:
36
-
37
- ```bash
38
- pip install gradio_client
39
- ````
40
-
41
- #### 1.1 Synchronous API – `generate_image`
42
-
43
- ```python
44
- from gradio_client import Client
45
-
46
- client = Client("John6666/DiffuseCraftMod", hf_token="hf_xxx...")
47
-
48
- status, images, info = client.predict(
49
- # Core text controls
50
- prompt="Hello!!",
51
- negative_prompt=(
52
- "lowres, bad anatomy, bad hands, missing fingers, extra digit, "
53
- "fewer digits, worst quality, low quality"
54
- ),
55
-
56
- # Basic generation controls
57
- num_images=1,
58
- num_inference_steps=28,
59
- guidance_scale=7.0,
60
- clip_skip=0,
61
- seed=-1,
62
-
63
- # Canvas / model / task (optional, server has defaults)
64
- height=1024,
65
- width=1024,
66
- model_name="votepurchase/animagine-xl-3.1",
67
- vae_model="None",
68
- task="txt2img",
69
-
70
- # All other arguments are optional; defaults match the UI
71
- api_name="/generate_image",
72
- )
73
-
74
- print(status) # e.g. "COMPLETE"
75
- print(images) # list of image paths / URLs
76
- print(info) # generation metadata (seed, model, etc.)
77
- ```
78
-
79
- #### 1.2 Streaming API – `generate_image_stream`
80
-
81
- ```python
82
- from gradio_client import Client
83
-
84
- client = Client("John6666/DiffuseCraftMod", hf_token="hf_xxx...")
85
-
86
- job = client.submit(
87
- prompt="Hello!!",
88
- negative_prompt=(
89
- "lowres, bad anatomy, bad hands, missing fingers, extra digit, "
90
- "fewer digits, worst quality, low quality"
91
- ),
92
- num_images=1,
93
- num_inference_steps=28,
94
- guidance_scale=7.0,
95
- clip_skip=0,
96
- seed=-1,
97
- height=1024,
98
- width=1024,
99
- model_name="votepurchase/animagine-xl-3.1",
100
- vae_model="None",
101
- task="txt2img",
102
- api_name="/generate_image_stream",
103
- )
104
-
105
- for status, images, info in job:
106
- # You will see progress messages, intermediate previews, and the final result.
107
- print(status, images, info)
108
- ```
109
-
110
- You can stop iterating once you see a `"COMPLETE"` status if you only care about the final output.
111
-
112
- ---
113
-
114
- ### 2. `curl` examples
115
-
116
- When calling from `curl`, include your HF token; anonymous calls may be rate-limited or rejected.
117
-
118
- ```bash
119
- export HF_TOKEN="hf_xxx..." # your Hugging Face access token
120
- ```
121
-
122
- The `data` field is a positional array. The order must match the function signature.
123
- For simplicity, the examples below only send the first few arguments and rely on server defaults for the rest.
124
-
125
- #### 2.1 Synchronous API – `generate_image`
126
-
127
- ```bash
128
- curl -X POST "https://john6666-diffusecraftmod.hf.space/call/generate_image" \
129
- -H "Authorization: Bearer $HF_TOKEN" \
130
- -H "Content-Type: application/json" \
131
- -d '{
132
- "data": [
133
- "Hello!!", // prompt
134
- "lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality", // negative_prompt
135
- 1, // num_images
136
- 28, // num_inference_steps
137
- 7.0, // guidance_scale
138
- 0, // clip_skip
139
- -1 // seed
140
- // All subsequent parameters will use their default values
141
- ]
142
- }'
143
- ```
144
-
145
- #### 2.2 Streaming API – `generate_image_stream`
146
-
147
- ```bash
148
- curl -X POST "https://john6666-diffusecraftmod.hf.space/call/generate_image_stream" \
149
- -H "Authorization: Bearer $HF_TOKEN" \
150
- -H "Content-Type: application/json" \
151
- -d '{
152
- "data": [
153
- "Hello!!",
154
- "lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality",
155
- 1,
156
- 28,
157
- 7.0,
158
- 0,
159
- -1
160
- ]
161
- }'
162
- ```
163
-
164
- For full parameter coverage (all advanced options such as LoRAs, ControlNet, IP-Adapter, etc.),
165
- refer to the Space’s “View API” page and adapt the examples above accordingly.
 
 
1
+ ---
2
+ title: 🧩 DiffuseCraft Mod (SDXL/SD1.5 Models Text-to-Image)
3
+ emoji: 🧩🖼️📦
4
+ colorFrom: red
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: 6.17.3
8
+ python_version: "3.12"
9
+ app_file: app.py
10
+ pinned: true
11
+ header: mini
12
+ license: mit
13
+ duplicated_from: r3gm/DiffuseCraft
14
+ short_description: Stunning images using stable diffusion.
15
+ preload_from_hub:
16
+ - madebyollin/sdxl-vae-fp16-fix config.json,diffusion_pytorch_model.safetensors
17
+ ---
18
+
19
+ ## Using this Space programmatically
20
+
21
+ You can call this Space from Python (via `gradio_client`) or from plain `curl`.
22
+
23
+ > ⚠️ Note: This README may lag behind the actual API definition shown in the Space’s “View API” page.
24
+ > If something does not work, always double-check the latest argument list and endpoint names there.
25
+
26
+ Assumptions:
27
+
28
+ - Space ID: `John6666/DiffuseCraftMod`
29
+ - You have a valid Hugging Face access token: `hf_xxx...` (read access is enough)
30
+ - Replace `hf_xxx...` with your own token
31
+
32
+ ---
33
+
34
+ ### 1. Python examples (`gradio_client`)
35
+
36
+ Install:
37
+
38
+ ```bash
39
+ pip install gradio_client
40
+ ````
41
+
42
+ #### 1.1 Synchronous API – `generate_image`
43
+
44
+ ```python
45
+ from gradio_client import Client
46
+
47
+ client = Client("John6666/DiffuseCraftMod", hf_token="hf_xxx...")
48
+
49
+ status, images, info = client.predict(
50
+ # Core text controls
51
+ prompt="Hello!!",
52
+ negative_prompt=(
53
+ "lowres, bad anatomy, bad hands, missing fingers, extra digit, "
54
+ "fewer digits, worst quality, low quality"
55
+ ),
56
+
57
+ # Basic generation controls
58
+ num_images=1,
59
+ num_inference_steps=28,
60
+ guidance_scale=7.0,
61
+ clip_skip=0,
62
+ seed=-1,
63
+
64
+ # Canvas / model / task (optional, server has defaults)
65
+ height=1024,
66
+ width=1024,
67
+ model_name="votepurchase/animagine-xl-3.1",
68
+ vae_model="None",
69
+ task="txt2img",
70
+
71
+ # All other arguments are optional; defaults match the UI
72
+ api_name="/generate_image",
73
+ )
74
+
75
+ print(status) # e.g. "COMPLETE"
76
+ print(images) # list of image paths / URLs
77
+ print(info) # generation metadata (seed, model, etc.)
78
+ ```
79
+
80
+ #### 1.2 Streaming API – `generate_image_stream`
81
+
82
+ ```python
83
+ from gradio_client import Client
84
+
85
+ client = Client("John6666/DiffuseCraftMod", hf_token="hf_xxx...")
86
+
87
+ job = client.submit(
88
+ prompt="Hello!!",
89
+ negative_prompt=(
90
+ "lowres, bad anatomy, bad hands, missing fingers, extra digit, "
91
+ "fewer digits, worst quality, low quality"
92
+ ),
93
+ num_images=1,
94
+ num_inference_steps=28,
95
+ guidance_scale=7.0,
96
+ clip_skip=0,
97
+ seed=-1,
98
+ height=1024,
99
+ width=1024,
100
+ model_name="votepurchase/animagine-xl-3.1",
101
+ vae_model="None",
102
+ task="txt2img",
103
+ api_name="/generate_image_stream",
104
+ )
105
+
106
+ for status, images, info in job:
107
+ # You will see progress messages, intermediate previews, and the final result.
108
+ print(status, images, info)
109
+ ```
110
+
111
+ You can stop iterating once you see a `"COMPLETE"` status if you only care about the final output.
112
+
113
+ ---
114
+
115
+ ### 2. `curl` examples
116
+
117
+ When calling from `curl`, include your HF token; anonymous calls may be rate-limited or rejected.
118
+
119
+ ```bash
120
+ export HF_TOKEN="hf_xxx..." # your Hugging Face access token
121
+ ```
122
+
123
+ The `data` field is a positional array. The order must match the function signature.
124
+ For simplicity, the examples below only send the first few arguments and rely on server defaults for the rest.
125
+
126
+ #### 2.1 Synchronous API – `generate_image`
127
+
128
+ ```bash
129
+ curl -X POST "https://john6666-diffusecraftmod.hf.space/call/generate_image" \
130
+ -H "Authorization: Bearer $HF_TOKEN" \
131
+ -H "Content-Type: application/json" \
132
+ -d '{
133
+ "data": [
134
+ "Hello!!", // prompt
135
+ "lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality", // negative_prompt
136
+ 1, // num_images
137
+ 28, // num_inference_steps
138
+ 7.0, // guidance_scale
139
+ 0, // clip_skip
140
+ -1 // seed
141
+ // All subsequent parameters will use their default values
142
+ ]
143
+ }'
144
+ ```
145
+
146
+ #### 2.2 Streaming API – `generate_image_stream`
147
+
148
+ ```bash
149
+ curl -X POST "https://john6666-diffusecraftmod.hf.space/call/generate_image_stream" \
150
+ -H "Authorization: Bearer $HF_TOKEN" \
151
+ -H "Content-Type: application/json" \
152
+ -d '{
153
+ "data": [
154
+ "Hello!!",
155
+ "lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality",
156
+ 1,
157
+ 28,
158
+ 7.0,
159
+ 0,
160
+ -1
161
+ ]
162
+ }'
163
+ ```
164
+
165
+ For full parameter coverage (all advanced options such as LoRAs, ControlNet, IP-Adapter, etc.),
166
+ refer to the Space’s “View API” page and adapt the examples above accordingly.
app.py CHANGED
@@ -878,7 +878,7 @@ CSS ="""
878
  .desc [src$='#float'] { float: right; margin: 20px; }
879
  """
880
 
881
- with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=False, css=CSS) as app:
882
  gr.Markdown("# 🧩 DiffuseCraft Mod", elem_classes="title")
883
  gr.Markdown("This space is a modification of [r3gm's DiffuseCraft](https://huggingface.co/spaces/r3gm/DiffuseCraft).", elem_classes="info")
884
  with gr.Column():
@@ -923,9 +923,9 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
923
  keep_tags_gui = gr.Radio(label="Remove tags leaving only the following", choices=["body", "dress", "all"], value="all")
924
  image_algorithms = gr.CheckboxGroup(["Use WD Tagger"], label="Algorithms", value=["Use WD Tagger"], visible=False)
925
  generate_from_image_btn_gui = gr.Button(value="GENERATE TAGS FROM IMAGE")
926
- prompt_gui = gr.Textbox(lines=6, placeholder="1girl, solo, ...", label="Prompt", show_copy_button=True)
927
  with gr.Accordion("Negative prompt, etc.", open=False) as menu_negative:
928
- neg_prompt_gui = gr.Textbox(lines=3, placeholder="Enter Neg prompt", label="Negative prompt", value="lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality, very displeasing, (bad)", show_copy_button=True)
929
  translate_prompt_button = gr.Button(value="Translate prompt to English", size="sm", variant="secondary")
930
  with gr.Row():
931
  insert_prompt_gui = gr.Radio(label="Insert reccomended positive / negative prompt", choices=["None", "Auto", "Animagine", "Pony"], value="Auto", interactive=True)
@@ -955,7 +955,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
955
  update_task_options,
956
  [model_name_gui, task_gui],
957
  [task_gui],
958
- show_api=False,
959
  )
960
 
961
  load_model_gui = gr.HTML(elem_id="load_model", elem_classes="contain")
@@ -972,8 +972,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
972
  # height="auto",
973
  interactive=False,
974
  preview=False,
975
- show_share_button=False,
976
- show_download_button=True,
977
  selected_index=50,
978
  format="png",
979
  )
@@ -984,9 +983,9 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
984
 
985
  with gr.Accordion("History", open=False):
986
  history_files = gr.Files(interactive=False, visible=False)
987
- history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", format="png", interactive=False, show_share_button=False, show_download_button=True)
988
  history_clear_button = gr.Button(value="Clear History", variant="secondary")
989
- history_clear_button.click(lambda: ([], []), None, [history_gallery, history_files], queue=False, show_api=False)
990
 
991
  with gr.Row(equal_height=False, variant="default"):
992
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=20, show_label=False, container=False, info="GPU time duration (seconds)")
@@ -1166,7 +1165,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1166
  return gr.Slider(minimum=-val_lora, maximum=val_lora, step=0.01, value=1.0, label=label, visible=visible)
1167
 
1168
  def lora_textbox(label):
1169
- return gr.Textbox(label=label, info="Example of prompt:", value="None", show_copy_button=True, interactive=False, visible=False)
1170
 
1171
  with gr.Row():
1172
  with gr.Column():
@@ -1237,7 +1236,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1237
  search_civitai_button_lora = gr.Button("Search on Civitai")
1238
  search_civitai_desc_lora = gr.Markdown(value="", visible=False, elem_classes="desc")
1239
  with gr.Accordion("Select from Gallery", open=False):
1240
- search_civitai_gallery_lora = gr.Gallery([], label="Results", allow_preview=False, columns=5, show_share_button=False, interactive=False)
1241
  search_civitai_result_lora = gr.Dropdown(label="Search Results", choices=[("", "")], value="", allow_custom_value=True, visible=False)
1242
  with gr.Row():
1243
  text_lora = gr.Textbox(label="LoRA's download URL", placeholder="https://civitai.com/api/download/models/28907", info="It has to be .safetensors files, and you can also download them from Hugging Face.", lines=1, scale=4)
@@ -1321,8 +1320,8 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1321
  use_textual_inversion_gui = gr.CheckboxGroup(choices=get_embed_list(get_model_pipeline(model_name_gui.value)) if active_textual_inversion_gui.value else [], value=None, label="Use Textual Invertion in prompt")
1322
  def update_textual_inversion_gui(active_textual_inversion_gui, model_name_gui):
1323
  return gr.update(choices=get_embed_list(get_model_pipeline(model_name_gui)) if active_textual_inversion_gui else [])
1324
- active_textual_inversion_gui.change(update_textual_inversion_gui, [active_textual_inversion_gui, model_name_gui], [use_textual_inversion_gui], show_api=False)
1325
- model_name_gui.change(update_textual_inversion_gui, [active_textual_inversion_gui, model_name_gui], [use_textual_inversion_gui], show_api=False)
1326
 
1327
  with gr.Accordion("ControlNet / Img2img / Inpaint", open=False, visible=True) as menu_i2i:
1328
  with gr.Row():
@@ -1360,7 +1359,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1360
  change_preprocessor_choices,
1361
  [task_gui],
1362
  [preprocessor_name_gui],
1363
- show_api=False,
1364
  )
1365
 
1366
  with gr.Row():
@@ -1420,7 +1419,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1420
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1421
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1422
 
1423
- style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui], show_api=False)
1424
 
1425
  with gr.Accordion("Other settings", open=False, visible=True) as menu_other:
1426
  with gr.Row():
@@ -1542,7 +1541,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1542
 
1543
  def change_visibility_canvas():
1544
  return gr.update(visible=True, interactive=True), gr.update(visible=False)
1545
- show_canvas.click(change_visibility_canvas, [], [image_base, show_canvas], show_api=False)
1546
 
1547
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1548
  btn = gr.Button("Create mask")
@@ -1556,7 +1555,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1556
 
1557
  def send_img(img_source, img_result):
1558
  return img_source, img_result
1559
- btn_send.click(send_img, [img_source, img_result], [image_control, image_mask_gui], show_api=False)
1560
 
1561
  with gr.Tab("PNG Info"):
1562
  with gr.Row():
@@ -1564,7 +1563,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1564
  image_metadata = gr.Image(label="Image with metadata", type="pil", sources=["upload"])
1565
 
1566
  with gr.Column():
1567
- result_metadata = gr.Textbox(label="Metadata", show_label=True, show_copy_button=True, interactive=False, container=True, max_lines=99)
1568
 
1569
  image_metadata.change(
1570
  fn=extract_exif_data,
@@ -1602,11 +1601,11 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1602
  [menu_model, menu_from_image, menu_negative, menu_gen, menu_hires, menu_lora, menu_advanced,
1603
  menu_example, task_gui, quick_speed_gui],
1604
  queue=False,
1605
- show_api=False,
1606
  )
1607
- model_name_gui.change(get_t2i_model_info, [model_name_gui], [model_info_gui], queue=False, show_api=False)
1608
- translate_prompt_gui.click(translate_to_en, [prompt_gui], [prompt_gui], queue=False, show_api=False)\
1609
- .then(translate_to_en, [neg_prompt_gui], [neg_prompt_gui], queue=False, show_api=False)
1610
 
1611
  gr.on(
1612
  triggers=[quick_model_type_gui.change, quick_genre_gui.change, quick_speed_gui.change, quick_aspect_gui.change],
@@ -1615,7 +1614,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1615
  outputs=[quality_selector_gui, style_selector_gui, sampler_selector_gui, optimization_gui, insert_prompt_gui],
1616
  queue=False,
1617
  trigger_mode="once",
1618
- show_api=False,
1619
  )
1620
  gr.on(
1621
  triggers=[quality_selector_gui.change, style_selector_gui.change, insert_prompt_gui.change],
@@ -1624,7 +1623,7 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1624
  outputs=[prompt_gui, neg_prompt_gui, quick_model_type_gui],
1625
  queue=False,
1626
  trigger_mode="once",
1627
- show_api=False,
1628
  )
1629
  sampler_selector_gui.change(set_sampler_settings, [sampler_selector_gui], [sampler_gui, steps_gui, cfg_gui, clip_skip_gui, img_width_gui, img_height_gui, optimization_gui], queue=False)
1630
  optimization_gui.change(set_optimization, [optimization_gui, steps_gui, cfg_gui, sampler_gui, clip_skip_gui, lora5_gui, lora_scale_5_gui], [steps_gui, cfg_gui, sampler_gui, clip_skip_gui, lora5_gui, lora_scale_5_gui], queue=False)
@@ -1647,15 +1646,15 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1647
  lora7_gui, lora_scale_7_gui, lora7_info_gui, lora7_copy_gui, lora7_desc_gui],
1648
  queue=False,
1649
  trigger_mode="once",
1650
- show_api=False,
1651
  )
1652
- lora1_copy_gui.click(apply_lora_prompt, [prompt_gui, lora1_info_gui], [prompt_gui], queue=False, show_api=False)
1653
- lora2_copy_gui.click(apply_lora_prompt, [prompt_gui, lora2_info_gui], [prompt_gui], queue=False, show_api=False)
1654
- lora3_copy_gui.click(apply_lora_prompt, [prompt_gui, lora3_info_gui], [prompt_gui], queue=False, show_api=False)
1655
- lora4_copy_gui.click(apply_lora_prompt, [prompt_gui, lora4_info_gui], [prompt_gui], queue=False, show_api=False)
1656
- lora5_copy_gui.click(apply_lora_prompt, [prompt_gui, lora5_info_gui], [prompt_gui], queue=False, show_api=False)
1657
- lora6_copy_gui.click(apply_lora_prompt, [prompt_gui, lora6_info_gui], [prompt_gui], queue=False, show_api=False)
1658
- lora7_copy_gui.click(apply_lora_prompt, [prompt_gui, lora7_info_gui], [prompt_gui], queue=False, show_api=False)
1659
  gr.on(
1660
  triggers=[search_civitai_button_lora.click, search_civitai_query_lora.submit],
1661
  fn=search_civitai_lora,
@@ -1664,54 +1663,54 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1664
  outputs=[search_civitai_result_lora, search_civitai_desc_lora, search_civitai_button_lora, search_civitai_query_lora, search_civitai_gallery_lora],
1665
  queue=True,
1666
  scroll_to_output=True,
1667
- show_api=False,
1668
  )
1669
- search_civitai_result_lora.change(select_civitai_lora, [search_civitai_result_lora], [text_lora, search_civitai_desc_lora], queue=False, scroll_to_output=True, show_api=False)
1670
- search_civitai_gallery_lora.select(update_civitai_selection, None, [search_civitai_result_lora], queue=False, show_api=False)
1671
- button_lora.click(get_my_lora, [text_lora, romanize_text], [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui, lora6_gui, lora7_gui, new_lora_status], scroll_to_output=True, show_api=False)
1672
- upload_button_lora.upload(upload_file_lora, [upload_button_lora], [file_output_lora, upload_button_lora], show_api=False).success(
1673
- move_file_lora, [file_output_lora], [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui, lora6_gui, lora7_gui], scroll_to_output=True, show_api=False)
1674
 
1675
- use_textual_inversion_gui.change(set_textual_inversion_prompt, [use_textual_inversion_gui, prompt_gui, neg_prompt_gui, prompt_syntax_gui], [prompt_gui, neg_prompt_gui], show_api=False)
1676
 
1677
  generate_from_image_btn_gui.click(
1678
- lambda: ("", "", ""), None, [series_dbt, character_dbt, prompt_gui], queue=False, show_api=False,
1679
  ).success(
1680
  predict_tags_wd,
1681
  [input_image_gui, prompt_gui, image_algorithms, general_threshold_gui, character_threshold_gui],
1682
  [series_dbt, character_dbt, prompt_gui, copy_button_dbt],
1683
- show_api=False,
1684
  ).success(
1685
- compose_prompt_to_copy, [character_dbt, series_dbt, prompt_gui], [prompt_gui], queue=False, show_api=False,
1686
  ).success(
1687
- remove_specific_prompt, [prompt_gui, keep_tags_gui], [prompt_gui], queue=False, show_api=False,
1688
  ).success(
1689
- convert_danbooru_to_e621_prompt, [prompt_gui, tag_type_gui], [prompt_gui], queue=False, show_api=False,
1690
  ).success(
1691
- insert_recom_prompt, [prompt_gui, neg_prompt_gui, recom_prompt_gui], [prompt_gui, neg_prompt_gui], queue=False, show_api=False,
1692
  )
1693
 
1694
- prompt_type_button.click(convert_danbooru_to_e621_prompt, [prompt_gui, prompt_type_gui], [prompt_gui], queue=False, show_api=False)
1695
- random_character_gui.click(select_random_character, [series_dbt, character_dbt], [series_dbt, character_dbt], queue=False, show_api=False)
1696
  generate_db_random_button.click(
1697
  v2_random_prompt,
1698
  [prompt_gui, series_dbt, character_dbt,
1699
  rating_dbt, aspect_ratio_dbt, length_dbt, identity_dbt, ban_tags_dbt, model_name_dbt],
1700
  [prompt_gui, series_dbt, character_dbt],
1701
- show_api=False,
1702
  ).success(
1703
- convert_danbooru_to_e621_prompt, [prompt_gui, tag_type_gui], [prompt_gui], queue=False, show_api=False,
1704
  )
1705
 
1706
- translate_prompt_button.click(translate_prompt, [prompt_gui], [prompt_gui], queue=False, show_api=False)
1707
- translate_prompt_button.click(translate_prompt, [character_dbt], [character_dbt], queue=False, show_api=False)
1708
- translate_prompt_button.click(translate_prompt, [series_dbt], [series_dbt], queue=False, show_api=False)
1709
 
1710
  generate_button.click(
1711
  fn=insert_model_recom_prompt,
1712
  inputs=[prompt_gui, neg_prompt_gui, model_name_gui, recom_prompt_gui],
1713
  outputs=[prompt_gui, neg_prompt_gui],
1714
- api_name=False,
1715
  queue=False,
1716
  ).success(
1717
  fn=sd_gen.load_new_model,
@@ -1854,8 +1853,8 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1854
  api_name="sd_gen_generate_pipeline",
1855
  queue=True,
1856
  show_progress="full",
1857
- ).success(save_gallery_images, [result_images, model_name_gui], [result_images, result_images_files], queue=False, show_api=False)\
1858
- .success(save_gallery_history, [result_images, result_images_files, history_gallery, history_files], [history_gallery, history_files], queue=False, show_api=False)
1859
 
1860
  with gr.Tab("Danbooru Tags Transformer with WD Tagger", render=True):
1861
  with gr.Column(scale=2):
@@ -1894,60 +1893,60 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
1894
  generate_btn = gr.Button(value="GENERATE TAGS", size="lg", variant="primary")
1895
  with gr.Row():
1896
  with gr.Group():
1897
- output_text = gr.TextArea(label="Output tags", interactive=False, show_copy_button=True)
1898
  with gr.Row():
1899
  copy_btn = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
1900
  copy_prompt_btn = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
1901
  with gr.Group():
1902
- output_text_pony = gr.TextArea(label="Output tags (Pony e621 style)", interactive=False, show_copy_button=True)
1903
  with gr.Row():
1904
  copy_btn_pony = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
1905
  copy_prompt_btn_pony = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
1906
  description_ui()
1907
 
1908
- translate_input_prompt_button.click(translate_prompt, inputs=[input_general], outputs=[input_general], queue=False, show_api=False)
1909
- translate_input_prompt_button.click(translate_prompt, inputs=[input_character], outputs=[input_character], queue=False, show_api=False)
1910
- translate_input_prompt_button.click(translate_prompt, inputs=[input_copyright], outputs=[input_copyright], queue=False, show_api=False)
1911
 
1912
  generate_from_image_btn.click(
1913
- lambda: ("", "", ""), None, [input_copyright, input_character, input_general], queue=False, show_api=False,
1914
  ).success(
1915
  predict_tags_wd,
1916
  [input_image, input_general, image_algorithms, general_threshold, character_threshold],
1917
  [input_copyright, input_character, input_general, copy_input_btn],
1918
- show_api=False,
1919
  ).success(
1920
- remove_specific_prompt, inputs=[input_general, keep_tags], outputs=[input_general], queue=False, show_api=False,
1921
  ).success(
1922
- convert_danbooru_to_e621_prompt, inputs=[input_general, input_tag_type], outputs=[input_general], queue=False, show_api=False,
1923
  ).success(
1924
- insert_recom_prompt, inputs=[input_general, dummy_np, recom_prompt], outputs=[input_general, dummy_np], queue=False, show_api=False,
1925
  ).success(lambda: gr.update(interactive=True), None, [copy_prompt_btn_input], queue=False)
1926
- copy_input_btn.click(compose_prompt_to_copy, inputs=[input_character, input_copyright, input_general], outputs=[input_tags_to_copy], show_api=False)\
1927
- .success(gradio_copy_text, inputs=[input_tags_to_copy], js=COPY_ACTION_JS, show_api=False)
1928
- copy_prompt_btn_input.click(compose_prompt_to_copy, inputs=[input_character, input_copyright, input_general], outputs=[input_tags_to_copy], show_api=False)\
1929
- .success(gradio_copy_prompt, inputs=[input_tags_to_copy], outputs=[prompt_gui], show_api=False)
1930
 
1931
- pick_random_character.click(select_random_character, [input_copyright, input_character], [input_copyright, input_character], show_api=False)
1932
 
1933
  generate_btn.click(
1934
  v2_upsampling_prompt,
1935
  [model_name, input_copyright, input_character, input_general,
1936
  input_rating, input_aspect_ratio, input_length, input_identity, input_ban_tags],
1937
  [output_text],
1938
- show_api=False,
1939
  ).success(
1940
- convert_danbooru_to_e621_prompt, inputs=[output_text, tag_type], outputs=[output_text_pony], queue=False, show_api=False,
1941
  ).success(
1942
- insert_recom_prompt, inputs=[output_text, dummy_np, recom_animagine], outputs=[output_text, dummy_np], queue=False, show_api=False,
1943
  ).success(
1944
- insert_recom_prompt, inputs=[output_text_pony, dummy_np, recom_pony], outputs=[output_text_pony, dummy_np], queue=False, show_api=False,
1945
  ).success(lambda: (gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)),
1946
- None, [copy_btn, copy_btn_pony, copy_prompt_btn, copy_prompt_btn_pony], queue=False, show_api=False)
1947
- copy_btn.click(gradio_copy_text, inputs=[output_text], js=COPY_ACTION_JS, show_api=False)
1948
- copy_btn_pony.click(gradio_copy_text, inputs=[output_text_pony], js=COPY_ACTION_JS, show_api=False)
1949
- copy_prompt_btn.click(gradio_copy_prompt, inputs=[output_text], outputs=[prompt_gui], show_api=False)
1950
- copy_prompt_btn_pony.click(gradio_copy_prompt, inputs=[output_text_pony], outputs=[prompt_gui], show_api=False)
1951
 
1952
  from typing import Any, Dict, List, Optional, Tuple, Generator
1953
  # 1) Helper: model loader (keeps existing behavior)
@@ -2285,8 +2284,8 @@ with gr.Blocks(theme=args.theme, elem_id="main", fill_width=True, fill_height=Fa
2285
  yield from _generate_image(argv)
2286
 
2287
  # 5) Register two APIs with explicit signatures
2288
- gr.api(generate_image, api_name="generate_image", show_api=True, queue=True, concurrency_id="gpu")
2289
- gr.api(generate_image_stream, api_name="generate_image_stream", show_api=True, queue=True, concurrency_id="gpu")
2290
 
2291
  gr.DuplicateButton(value="Duplicate Space for private use (This demo does not work on CPU. Requires GPU Space)")
2292
 
@@ -2300,5 +2299,7 @@ if __name__ == "__main__":
2300
  ssr_mode=args.ssr,
2301
  mcp_server=False,
2302
  allowed_paths=[allowed_path],
 
 
2303
  )
2304
  ## END MOD
 
878
  .desc [src$='#float'] { float: right; margin: 20px; }
879
  """
880
 
881
+ with gr.Blocks(elem_id="main", fill_width=True, fill_height=False) as app:
882
  gr.Markdown("# 🧩 DiffuseCraft Mod", elem_classes="title")
883
  gr.Markdown("This space is a modification of [r3gm's DiffuseCraft](https://huggingface.co/spaces/r3gm/DiffuseCraft).", elem_classes="info")
884
  with gr.Column():
 
923
  keep_tags_gui = gr.Radio(label="Remove tags leaving only the following", choices=["body", "dress", "all"], value="all")
924
  image_algorithms = gr.CheckboxGroup(["Use WD Tagger"], label="Algorithms", value=["Use WD Tagger"], visible=False)
925
  generate_from_image_btn_gui = gr.Button(value="GENERATE TAGS FROM IMAGE")
926
+ prompt_gui = gr.Textbox(lines=6, placeholder="1girl, solo, ...", label="Prompt", buttons=["copy"])
927
  with gr.Accordion("Negative prompt, etc.", open=False) as menu_negative:
928
+ neg_prompt_gui = gr.Textbox(lines=3, placeholder="Enter Neg prompt", label="Negative prompt", value="lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality, very displeasing, (bad)", buttons=["copy"])
929
  translate_prompt_button = gr.Button(value="Translate prompt to English", size="sm", variant="secondary")
930
  with gr.Row():
931
  insert_prompt_gui = gr.Radio(label="Insert reccomended positive / negative prompt", choices=["None", "Auto", "Animagine", "Pony"], value="Auto", interactive=True)
 
955
  update_task_options,
956
  [model_name_gui, task_gui],
957
  [task_gui],
958
+ api_visibility="undocumented",
959
  )
960
 
961
  load_model_gui = gr.HTML(elem_id="load_model", elem_classes="contain")
 
972
  # height="auto",
973
  interactive=False,
974
  preview=False,
975
+ buttons=["download", "fullscreen"],
 
976
  selected_index=50,
977
  format="png",
978
  )
 
983
 
984
  with gr.Accordion("History", open=False):
985
  history_files = gr.Files(interactive=False, visible=False)
986
+ history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", format="png", interactive=False, buttons=["download", "fullscreen"])
987
  history_clear_button = gr.Button(value="Clear History", variant="secondary")
988
+ history_clear_button.click(lambda: ([], []), None, [history_gallery, history_files], queue=False, api_visibility="undocumented")
989
 
990
  with gr.Row(equal_height=False, variant="default"):
991
  gpu_duration_gui = gr.Number(minimum=5, maximum=240, value=20, show_label=False, container=False, info="GPU time duration (seconds)")
 
1165
  return gr.Slider(minimum=-val_lora, maximum=val_lora, step=0.01, value=1.0, label=label, visible=visible)
1166
 
1167
  def lora_textbox(label):
1168
+ return gr.Textbox(label=label, info="Example of prompt:", value="None", buttons=["copy"], interactive=False, visible=False)
1169
 
1170
  with gr.Row():
1171
  with gr.Column():
 
1236
  search_civitai_button_lora = gr.Button("Search on Civitai")
1237
  search_civitai_desc_lora = gr.Markdown(value="", visible=False, elem_classes="desc")
1238
  with gr.Accordion("Select from Gallery", open=False):
1239
+ search_civitai_gallery_lora = gr.Gallery([], label="Results", allow_preview=False, columns=5, buttons=["download", "fullscreen"], interactive=False)
1240
  search_civitai_result_lora = gr.Dropdown(label="Search Results", choices=[("", "")], value="", allow_custom_value=True, visible=False)
1241
  with gr.Row():
1242
  text_lora = gr.Textbox(label="LoRA's download URL", placeholder="https://civitai.com/api/download/models/28907", info="It has to be .safetensors files, and you can also download them from Hugging Face.", lines=1, scale=4)
 
1320
  use_textual_inversion_gui = gr.CheckboxGroup(choices=get_embed_list(get_model_pipeline(model_name_gui.value)) if active_textual_inversion_gui.value else [], value=None, label="Use Textual Invertion in prompt")
1321
  def update_textual_inversion_gui(active_textual_inversion_gui, model_name_gui):
1322
  return gr.update(choices=get_embed_list(get_model_pipeline(model_name_gui)) if active_textual_inversion_gui else [])
1323
+ active_textual_inversion_gui.change(update_textual_inversion_gui, [active_textual_inversion_gui, model_name_gui], [use_textual_inversion_gui], api_visibility="undocumented")
1324
+ model_name_gui.change(update_textual_inversion_gui, [active_textual_inversion_gui, model_name_gui], [use_textual_inversion_gui], api_visibility="undocumented")
1325
 
1326
  with gr.Accordion("ControlNet / Img2img / Inpaint", open=False, visible=True) as menu_i2i:
1327
  with gr.Row():
 
1359
  change_preprocessor_choices,
1360
  [task_gui],
1361
  [preprocessor_name_gui],
1362
+ api_visibility="undocumented",
1363
  )
1364
 
1365
  with gr.Row():
 
1419
  gr.Info(f"{len(sd_gen.model.STYLE_NAMES)} styles loaded")
1420
  return gr.update(value=None, choices=sd_gen.model.STYLE_NAMES)
1421
 
1422
+ style_button.click(load_json_style_file, [style_json_gui], [style_prompt_gui], api_visibility="undocumented")
1423
 
1424
  with gr.Accordion("Other settings", open=False, visible=True) as menu_other:
1425
  with gr.Row():
 
1541
 
1542
  def change_visibility_canvas():
1543
  return gr.update(visible=True, interactive=True), gr.update(visible=False)
1544
+ show_canvas.click(change_visibility_canvas, [], [image_base, show_canvas], api_visibility="undocumented")
1545
 
1546
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
1547
  btn = gr.Button("Create mask")
 
1555
 
1556
  def send_img(img_source, img_result):
1557
  return img_source, img_result
1558
+ btn_send.click(send_img, [img_source, img_result], [image_control, image_mask_gui], api_visibility="undocumented")
1559
 
1560
  with gr.Tab("PNG Info"):
1561
  with gr.Row():
 
1563
  image_metadata = gr.Image(label="Image with metadata", type="pil", sources=["upload"])
1564
 
1565
  with gr.Column():
1566
+ result_metadata = gr.Textbox(label="Metadata", show_label=True, buttons=["copy"], interactive=False, container=True, max_lines=99)
1567
 
1568
  image_metadata.change(
1569
  fn=extract_exif_data,
 
1601
  [menu_model, menu_from_image, menu_negative, menu_gen, menu_hires, menu_lora, menu_advanced,
1602
  menu_example, task_gui, quick_speed_gui],
1603
  queue=False,
1604
+ api_visibility="undocumented",
1605
  )
1606
+ model_name_gui.change(get_t2i_model_info, [model_name_gui], [model_info_gui], queue=False, api_visibility="undocumented")
1607
+ translate_prompt_gui.click(translate_to_en, [prompt_gui], [prompt_gui], queue=False, api_visibility="undocumented")\
1608
+ .then(translate_to_en, [neg_prompt_gui], [neg_prompt_gui], queue=False, api_visibility="undocumented")
1609
 
1610
  gr.on(
1611
  triggers=[quick_model_type_gui.change, quick_genre_gui.change, quick_speed_gui.change, quick_aspect_gui.change],
 
1614
  outputs=[quality_selector_gui, style_selector_gui, sampler_selector_gui, optimization_gui, insert_prompt_gui],
1615
  queue=False,
1616
  trigger_mode="once",
1617
+ api_visibility="undocumented",
1618
  )
1619
  gr.on(
1620
  triggers=[quality_selector_gui.change, style_selector_gui.change, insert_prompt_gui.change],
 
1623
  outputs=[prompt_gui, neg_prompt_gui, quick_model_type_gui],
1624
  queue=False,
1625
  trigger_mode="once",
1626
+ api_visibility="undocumented",
1627
  )
1628
  sampler_selector_gui.change(set_sampler_settings, [sampler_selector_gui], [sampler_gui, steps_gui, cfg_gui, clip_skip_gui, img_width_gui, img_height_gui, optimization_gui], queue=False)
1629
  optimization_gui.change(set_optimization, [optimization_gui, steps_gui, cfg_gui, sampler_gui, clip_skip_gui, lora5_gui, lora_scale_5_gui], [steps_gui, cfg_gui, sampler_gui, clip_skip_gui, lora5_gui, lora_scale_5_gui], queue=False)
 
1646
  lora7_gui, lora_scale_7_gui, lora7_info_gui, lora7_copy_gui, lora7_desc_gui],
1647
  queue=False,
1648
  trigger_mode="once",
1649
+ api_visibility="undocumented",
1650
  )
1651
+ lora1_copy_gui.click(apply_lora_prompt, [prompt_gui, lora1_info_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1652
+ lora2_copy_gui.click(apply_lora_prompt, [prompt_gui, lora2_info_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1653
+ lora3_copy_gui.click(apply_lora_prompt, [prompt_gui, lora3_info_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1654
+ lora4_copy_gui.click(apply_lora_prompt, [prompt_gui, lora4_info_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1655
+ lora5_copy_gui.click(apply_lora_prompt, [prompt_gui, lora5_info_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1656
+ lora6_copy_gui.click(apply_lora_prompt, [prompt_gui, lora6_info_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1657
+ lora7_copy_gui.click(apply_lora_prompt, [prompt_gui, lora7_info_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1658
  gr.on(
1659
  triggers=[search_civitai_button_lora.click, search_civitai_query_lora.submit],
1660
  fn=search_civitai_lora,
 
1663
  outputs=[search_civitai_result_lora, search_civitai_desc_lora, search_civitai_button_lora, search_civitai_query_lora, search_civitai_gallery_lora],
1664
  queue=True,
1665
  scroll_to_output=True,
1666
+ api_visibility="undocumented",
1667
  )
1668
+ search_civitai_result_lora.change(select_civitai_lora, [search_civitai_result_lora], [text_lora, search_civitai_desc_lora], queue=False, scroll_to_output=True, api_visibility="undocumented")
1669
+ search_civitai_gallery_lora.select(update_civitai_selection, None, [search_civitai_result_lora], queue=False, api_visibility="undocumented")
1670
+ button_lora.click(get_my_lora, [text_lora, romanize_text], [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui, lora6_gui, lora7_gui, new_lora_status], scroll_to_output=True, api_visibility="undocumented")
1671
+ upload_button_lora.upload(upload_file_lora, [upload_button_lora], [file_output_lora, upload_button_lora], api_visibility="undocumented").success(
1672
+ move_file_lora, [file_output_lora], [lora1_gui, lora2_gui, lora3_gui, lora4_gui, lora5_gui, lora6_gui, lora7_gui], scroll_to_output=True, api_visibility="undocumented")
1673
 
1674
+ use_textual_inversion_gui.change(set_textual_inversion_prompt, [use_textual_inversion_gui, prompt_gui, neg_prompt_gui, prompt_syntax_gui], [prompt_gui, neg_prompt_gui], api_visibility="undocumented")
1675
 
1676
  generate_from_image_btn_gui.click(
1677
+ lambda: ("", "", ""), None, [series_dbt, character_dbt, prompt_gui], queue=False, api_visibility="undocumented",
1678
  ).success(
1679
  predict_tags_wd,
1680
  [input_image_gui, prompt_gui, image_algorithms, general_threshold_gui, character_threshold_gui],
1681
  [series_dbt, character_dbt, prompt_gui, copy_button_dbt],
1682
+ api_visibility="undocumented",
1683
  ).success(
1684
+ compose_prompt_to_copy, [character_dbt, series_dbt, prompt_gui], [prompt_gui], queue=False, api_visibility="undocumented",
1685
  ).success(
1686
+ remove_specific_prompt, [prompt_gui, keep_tags_gui], [prompt_gui], queue=False, api_visibility="undocumented",
1687
  ).success(
1688
+ convert_danbooru_to_e621_prompt, [prompt_gui, tag_type_gui], [prompt_gui], queue=False, api_visibility="undocumented",
1689
  ).success(
1690
+ insert_recom_prompt, [prompt_gui, neg_prompt_gui, recom_prompt_gui], [prompt_gui, neg_prompt_gui], queue=False, api_visibility="undocumented",
1691
  )
1692
 
1693
+ prompt_type_button.click(convert_danbooru_to_e621_prompt, [prompt_gui, prompt_type_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1694
+ random_character_gui.click(select_random_character, [series_dbt, character_dbt], [series_dbt, character_dbt], queue=False, api_visibility="undocumented")
1695
  generate_db_random_button.click(
1696
  v2_random_prompt,
1697
  [prompt_gui, series_dbt, character_dbt,
1698
  rating_dbt, aspect_ratio_dbt, length_dbt, identity_dbt, ban_tags_dbt, model_name_dbt],
1699
  [prompt_gui, series_dbt, character_dbt],
1700
+ api_visibility="undocumented",
1701
  ).success(
1702
+ convert_danbooru_to_e621_prompt, [prompt_gui, tag_type_gui], [prompt_gui], queue=False, api_visibility="undocumented",
1703
  )
1704
 
1705
+ translate_prompt_button.click(translate_prompt, [prompt_gui], [prompt_gui], queue=False, api_visibility="undocumented")
1706
+ translate_prompt_button.click(translate_prompt, [character_dbt], [character_dbt], queue=False, api_visibility="undocumented")
1707
+ translate_prompt_button.click(translate_prompt, [series_dbt], [series_dbt], queue=False, api_visibility="undocumented")
1708
 
1709
  generate_button.click(
1710
  fn=insert_model_recom_prompt,
1711
  inputs=[prompt_gui, neg_prompt_gui, model_name_gui, recom_prompt_gui],
1712
  outputs=[prompt_gui, neg_prompt_gui],
1713
+ api_visibility="private",
1714
  queue=False,
1715
  ).success(
1716
  fn=sd_gen.load_new_model,
 
1853
  api_name="sd_gen_generate_pipeline",
1854
  queue=True,
1855
  show_progress="full",
1856
+ ).success(save_gallery_images, [result_images, model_name_gui], [result_images, result_images_files], queue=False, api_visibility="undocumented")\
1857
+ .success(save_gallery_history, [result_images, result_images_files, history_gallery, history_files], [history_gallery, history_files], queue=False, api_visibility="undocumented")
1858
 
1859
  with gr.Tab("Danbooru Tags Transformer with WD Tagger", render=True):
1860
  with gr.Column(scale=2):
 
1893
  generate_btn = gr.Button(value="GENERATE TAGS", size="lg", variant="primary")
1894
  with gr.Row():
1895
  with gr.Group():
1896
+ output_text = gr.TextArea(label="Output tags", interactive=False, buttons=["copy"])
1897
  with gr.Row():
1898
  copy_btn = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
1899
  copy_prompt_btn = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
1900
  with gr.Group():
1901
+ output_text_pony = gr.TextArea(label="Output tags (Pony e621 style)", interactive=False, buttons=["copy"])
1902
  with gr.Row():
1903
  copy_btn_pony = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
1904
  copy_prompt_btn_pony = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
1905
  description_ui()
1906
 
1907
+ translate_input_prompt_button.click(translate_prompt, inputs=[input_general], outputs=[input_general], queue=False, api_visibility="undocumented")
1908
+ translate_input_prompt_button.click(translate_prompt, inputs=[input_character], outputs=[input_character], queue=False, api_visibility="undocumented")
1909
+ translate_input_prompt_button.click(translate_prompt, inputs=[input_copyright], outputs=[input_copyright], queue=False, api_visibility="undocumented")
1910
 
1911
  generate_from_image_btn.click(
1912
+ lambda: ("", "", ""), None, [input_copyright, input_character, input_general], queue=False, api_visibility="undocumented",
1913
  ).success(
1914
  predict_tags_wd,
1915
  [input_image, input_general, image_algorithms, general_threshold, character_threshold],
1916
  [input_copyright, input_character, input_general, copy_input_btn],
1917
+ api_visibility="undocumented",
1918
  ).success(
1919
+ remove_specific_prompt, inputs=[input_general, keep_tags], outputs=[input_general], queue=False, api_visibility="undocumented",
1920
  ).success(
1921
+ convert_danbooru_to_e621_prompt, inputs=[input_general, input_tag_type], outputs=[input_general], queue=False, api_visibility="undocumented",
1922
  ).success(
1923
+ insert_recom_prompt, inputs=[input_general, dummy_np, recom_prompt], outputs=[input_general, dummy_np], queue=False, api_visibility="undocumented",
1924
  ).success(lambda: gr.update(interactive=True), None, [copy_prompt_btn_input], queue=False)
1925
+ copy_input_btn.click(compose_prompt_to_copy, inputs=[input_character, input_copyright, input_general], outputs=[input_tags_to_copy], api_visibility="undocumented")\
1926
+ .success(gradio_copy_text, inputs=[input_tags_to_copy], js=COPY_ACTION_JS, api_visibility="undocumented")
1927
+ copy_prompt_btn_input.click(compose_prompt_to_copy, inputs=[input_character, input_copyright, input_general], outputs=[input_tags_to_copy], api_visibility="undocumented")\
1928
+ .success(gradio_copy_prompt, inputs=[input_tags_to_copy], outputs=[prompt_gui], api_visibility="undocumented")
1929
 
1930
+ pick_random_character.click(select_random_character, [input_copyright, input_character], [input_copyright, input_character], api_visibility="undocumented")
1931
 
1932
  generate_btn.click(
1933
  v2_upsampling_prompt,
1934
  [model_name, input_copyright, input_character, input_general,
1935
  input_rating, input_aspect_ratio, input_length, input_identity, input_ban_tags],
1936
  [output_text],
1937
+ api_visibility="undocumented",
1938
  ).success(
1939
+ convert_danbooru_to_e621_prompt, inputs=[output_text, tag_type], outputs=[output_text_pony], queue=False, api_visibility="undocumented",
1940
  ).success(
1941
+ insert_recom_prompt, inputs=[output_text, dummy_np, recom_animagine], outputs=[output_text, dummy_np], queue=False, api_visibility="undocumented",
1942
  ).success(
1943
+ insert_recom_prompt, inputs=[output_text_pony, dummy_np, recom_pony], outputs=[output_text_pony, dummy_np], queue=False, api_visibility="undocumented",
1944
  ).success(lambda: (gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)),
1945
+ None, [copy_btn, copy_btn_pony, copy_prompt_btn, copy_prompt_btn_pony], queue=False, api_visibility="undocumented")
1946
+ copy_btn.click(gradio_copy_text, inputs=[output_text], js=COPY_ACTION_JS, api_visibility="undocumented")
1947
+ copy_btn_pony.click(gradio_copy_text, inputs=[output_text_pony], js=COPY_ACTION_JS, api_visibility="undocumented")
1948
+ copy_prompt_btn.click(gradio_copy_prompt, inputs=[output_text], outputs=[prompt_gui], api_visibility="undocumented")
1949
+ copy_prompt_btn_pony.click(gradio_copy_prompt, inputs=[output_text_pony], outputs=[prompt_gui], api_visibility="undocumented")
1950
 
1951
  from typing import Any, Dict, List, Optional, Tuple, Generator
1952
  # 1) Helper: model loader (keeps existing behavior)
 
2284
  yield from _generate_image(argv)
2285
 
2286
  # 5) Register two APIs with explicit signatures
2287
+ gr.api(generate_image, api_name="generate_image", api_visibility="public", queue=True, concurrency_id="gpu")
2288
+ gr.api(generate_image_stream, api_name="generate_image_stream", api_visibility="public", queue=True, concurrency_id="gpu")
2289
 
2290
  gr.DuplicateButton(value="Duplicate Space for private use (This demo does not work on CPU. Requires GPU Space)")
2291
 
 
2299
  ssr_mode=args.ssr,
2300
  mcp_server=False,
2301
  allowed_paths=[allowed_path],
2302
+ theme=args.theme,
2303
+ css=CSS,
2304
  )
2305
  ## END MOD
env.py CHANGED
@@ -50,6 +50,8 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
50
  'Raelina/Raehoshi-illust-XL-8.1',
51
  'Raelina/Raehoshi-illust-XL-9',
52
  'Raelina/Raehoshi-illust-XL-9.1',
 
 
53
  'Raelina/Raehoshi-illust-vpred',
54
  'camenduru/FLUX.1-dev-diffusers',
55
  'black-forest-labs/FLUX.1-schnell',
 
50
  'Raelina/Raehoshi-illust-XL-8.1',
51
  'Raelina/Raehoshi-illust-XL-9',
52
  'Raelina/Raehoshi-illust-XL-9.1',
53
+ 'Raelina/Raehoshi-illust-XL-10',
54
+ 'Raelina/Raehoshi-illust-XL-11',
55
  'Raelina/Raehoshi-illust-vpred',
56
  'camenduru/FLUX.1-dev-diffusers',
57
  'black-forest-labs/FLUX.1-schnell',
modutils.py CHANGED
@@ -218,6 +218,8 @@ CIVITAI_RESOLVE_NEGATIVE_CACHE: dict[str, str] = {}
218
  CIVITAI_VERSION_JSON_CACHE: dict[str, dict] = {}
219
  CIVITAI_VERSION_NEGATIVE_CACHE: dict[str, str] = {}
220
  CIVITAI_WGET_FRESH_RETRY_LIMIT = 1
 
 
221
  CIVITAI_API_PROBE_TIMEOUT = (3.0, 8.0)
222
  CIVITAI_API_RETRYABLE_STATUSES = frozenset([404, 405, 429, 500, 502, 503, 504])
223
  CIVITAI_ACTIVE_API_ORIGIN = ""
@@ -492,6 +494,20 @@ def extract_civitai_model_version_id(url: str):
492
  return ""
493
  return ""
494
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  def get_civitai_query_filters(url: str):
496
  try:
497
  parts = get_civitai_url_parts(url)
@@ -706,6 +722,16 @@ def pick_civitai_file_from_version_json(json_data, source_url: str = ""):
706
  files = json_data.get("files", []) if isinstance(json_data, dict) else []
707
  if not isinstance(files, list) or not files:
708
  return {}
 
 
 
 
 
 
 
 
 
 
709
  version_id = str((json_data or {}).get("id") or "")
710
  filters = get_civitai_query_filters(source_url)
711
  candidates = []
@@ -786,41 +812,61 @@ def request_json_data(url, api_key: str = ""):
786
  return None
787
 
788
  endpoint_path = f"/model-versions/{model_version_id}"
789
- headers = get_civitai_headers(effective_api_key)
790
- session = create_retry_session()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
791
 
792
- try:
793
- json_data, endpoint_url, result = request_civitai_api_json(
794
- endpoint_path,
795
- headers=headers,
796
- timeout=CIVITAI_METADATA_TIMEOUT,
797
- api_key=effective_api_key,
798
- session=session,
799
- stream=True,
800
- allow_not_found=True,
801
- )
802
- if result.status_code == 404:
803
- print(f"Civitai metadata lookup status=404: {endpoint_url}")
804
- cache_put(CIVITAI_VERSION_NEGATIVE_CACHE, model_version_id, "status=404")
805
- return None
806
- if not json_data:
807
- print(f"Civitai metadata lookup returned empty JSON: {endpoint_url}")
808
- cache_put(CIVITAI_VERSION_NEGATIVE_CACHE, model_version_id, "empty_json")
809
- return None
810
- cache_put(CIVITAI_VERSION_JSON_CACHE, model_version_id, copy.deepcopy(json_data))
811
- if normalized_url and normalized_url != raw_url:
812
- cache_put(CIVITAI_RESOLVE_CACHE, raw_url, normalized_url)
813
- return json_data
814
- except Exception as e:
815
- print(f"Civitai metadata lookup failed: {endpoint_url} {type(e).__name__}: {sanitize_sensitive_log_text(e)}")
816
- return None
817
 
818
  class ModelInformation:
819
  def __init__(self, json_data, source_url: str = ""):
820
  selected_file = pick_civitai_file_from_version_json(json_data, source_url=source_url)
 
821
  self.model_version_id = json_data.get("id", "")
822
  self.model_id = json_data.get("modelId", "")
823
- self.download_url = selected_file.get("downloadUrl", "") or json_data.get("downloadUrl", "")
824
  self.model_url = f"{get_civitai_canonical_web_origin()}/models/{self.model_id}?modelVersionId={self.model_version_id}"
825
  self.filename_url = selected_file.get("name", "") or ""
826
  self.description = json_data.get("description", "")
@@ -1005,7 +1051,41 @@ def guess_downloaded_file_path(directory, before_files, expected_filename=""):
1005
 
1006
  return None
1007
 
1008
- def get_existing_completed_download_path(directory, expected_filename=""):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1009
  expected_name = str(expected_filename or "").strip()
1010
  if not expected_name:
1011
  return ""
@@ -1021,7 +1101,7 @@ def get_existing_completed_download_path(directory, expected_filename=""):
1021
  candidate_paths.append(legacy_nested_path)
1022
 
1023
  for candidate_path in candidate_paths:
1024
- if candidate_path.exists() and candidate_path.is_file():
1025
  return str(candidate_path)
1026
 
1027
  return ""
@@ -1064,6 +1144,7 @@ def download_things(directory, url, hf_token="", civitai_api_key="", romanize=Fa
1064
  if normalized_url != url:
1065
  print(f"Civitai download URL normalized: {sanitize_url_for_log(url)} -> {sanitize_url_for_log(normalized_url)}")
1066
  model_profile = retrieve_model_info(normalized_url, api_key=civitai_api_key)
 
1067
  if model_profile and model_profile.download_url:
1068
  url = model_profile.download_url
1069
  filename = model_profile.filename_url or ""
@@ -1087,7 +1168,7 @@ def download_things(directory, url, hf_token="", civitai_api_key="", romanize=Fa
1087
  print(f"Filename: {filename}")
1088
  print(f"[civitai] resolved signed host={signed_host or '-'} url={sanitize_url_for_log(url)}")
1089
 
1090
- existing_completed_path = get_existing_completed_download_path(directory, expected_filename=filename)
1091
  if existing_completed_path:
1092
  print(f"[civitai] using existing completed file path={existing_completed_path}")
1093
  downloaded_file_path = existing_completed_path
@@ -1139,10 +1220,14 @@ def download_things(directory, url, hf_token="", civitai_api_key="", romanize=Fa
1139
  if download_status != 0:
1140
  log_download_error("civitai", "command_failed", url=url, status=download_status)
1141
 
 
 
 
 
 
 
1142
  if not downloaded_file_path:
1143
- downloaded_file_path = guess_downloaded_file_path(directory, before_files, expected_filename=filename)
1144
- if not downloaded_file_path:
1145
- existing_completed_path = get_existing_completed_download_path(directory, expected_filename=filename)
1146
  if existing_completed_path:
1147
  print(f"[civitai] using existing completed file path={existing_completed_path}")
1148
  downloaded_file_path = existing_completed_path
@@ -1773,7 +1858,6 @@ def get_lora_info(lora_path: str):
1773
  label = ""
1774
  md = "None"
1775
  if not lora_path or lora_path == "None":
1776
- print("LoRA file not found.")
1777
  return is_valid, label, tag, md
1778
  path = Path(lora_path)
1779
  new_path = Path(f'{path.parent.name}/{escape_lora_basename(path.stem)}{path.suffix}')
 
218
  CIVITAI_VERSION_JSON_CACHE: dict[str, dict] = {}
219
  CIVITAI_VERSION_NEGATIVE_CACHE: dict[str, str] = {}
220
  CIVITAI_WGET_FRESH_RETRY_LIMIT = 1
221
+ CIVITAI_METADATA_RECONNECT_ATTEMPTS = 3
222
+ CIVITAI_METADATA_RECONNECT_BACKOFF = 0.8
223
  CIVITAI_API_PROBE_TIMEOUT = (3.0, 8.0)
224
  CIVITAI_API_RETRYABLE_STATUSES = frozenset([404, 405, 429, 500, 502, 503, 504])
225
  CIVITAI_ACTIVE_API_ORIGIN = ""
 
494
  return ""
495
  return ""
496
 
497
+ def extract_civitai_file_id(url: str):
498
+ try:
499
+ parts = get_civitai_url_parts(url)
500
+ qs = urllib.parse.parse_qs(parts.query)
501
+ for key, values in qs.items():
502
+ if str(key).casefold() != "fileid" or not values:
503
+ continue
504
+ value = str(values[0] or "").strip()
505
+ if value.isdigit():
506
+ return value
507
+ except Exception:
508
+ return ""
509
+ return ""
510
+
511
  def get_civitai_query_filters(url: str):
512
  try:
513
  parts = get_civitai_url_parts(url)
 
722
  files = json_data.get("files", []) if isinstance(json_data, dict) else []
723
  if not isinstance(files, list) or not files:
724
  return {}
725
+ explicit_file_id = extract_civitai_file_id(source_url)
726
+ if explicit_file_id:
727
+ for file_info in files:
728
+ if not isinstance(file_info, dict):
729
+ continue
730
+ candidate_id = str(file_info.get("id") or file_info.get("fileId") or "").strip()
731
+ if candidate_id == explicit_file_id:
732
+ return dict(file_info)
733
+ print(f"[civitai] explicit fileId={explicit_file_id} not present in model version metadata")
734
+ return {}
735
  version_id = str((json_data or {}).get("id") or "")
736
  filters = get_civitai_query_filters(source_url)
737
  candidates = []
 
812
  return None
813
 
814
  endpoint_path = f"/model-versions/{model_version_id}"
815
+ last_error = None
816
+ for attempt in range(1, CIVITAI_METADATA_RECONNECT_ATTEMPTS + 1):
817
+ session = create_retry_session()
818
+ headers = get_civitai_headers(effective_api_key)
819
+ if attempt > 1:
820
+ headers["Connection"] = "close"
821
+ endpoint_url = ""
822
+ try:
823
+ json_data, endpoint_url, result = request_civitai_api_json(
824
+ endpoint_path,
825
+ headers=headers,
826
+ timeout=CIVITAI_METADATA_TIMEOUT,
827
+ api_key=effective_api_key,
828
+ session=session,
829
+ stream=True,
830
+ allow_not_found=True,
831
+ )
832
+ if result.status_code == 404:
833
+ print(f"Civitai metadata lookup status=404: {endpoint_url}")
834
+ cache_put(CIVITAI_VERSION_NEGATIVE_CACHE, model_version_id, "status=404")
835
+ return None
836
+ if not json_data:
837
+ print(f"Civitai metadata lookup returned empty JSON: {endpoint_url}")
838
+ cache_put(CIVITAI_VERSION_NEGATIVE_CACHE, model_version_id, "empty_json")
839
+ return None
840
+ cache_put(CIVITAI_VERSION_JSON_CACHE, model_version_id, copy.deepcopy(json_data))
841
+ if normalized_url and normalized_url != raw_url:
842
+ cache_put(CIVITAI_RESOLVE_CACHE, raw_url, normalized_url)
843
+ return json_data
844
+ except Exception as e:
845
+ last_error = e
846
+ print(
847
+ f"[civitai] metadata reconnect attempt={attempt}/{CIVITAI_METADATA_RECONNECT_ATTEMPTS} "
848
+ f"url={sanitize_url_for_log(endpoint_url or endpoint_path)} "
849
+ f"error={type(e).__name__}: {sanitize_sensitive_log_text(e)}"
850
+ )
851
+ finally:
852
+ try:
853
+ session.close()
854
+ except Exception:
855
+ pass
856
+ if attempt < CIVITAI_METADATA_RECONNECT_ATTEMPTS:
857
+ time.sleep(min(2.5, CIVITAI_METADATA_RECONNECT_BACKOFF * attempt))
858
 
859
+ if last_error is not None:
860
+ print(f"Civitai metadata lookup failed after reconnects: {type(last_error).__name__}: {sanitize_sensitive_log_text(last_error)}")
861
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
862
 
863
  class ModelInformation:
864
  def __init__(self, json_data, source_url: str = ""):
865
  selected_file = pick_civitai_file_from_version_json(json_data, source_url=source_url)
866
+ explicit_file_id = extract_civitai_file_id(source_url)
867
  self.model_version_id = json_data.get("id", "")
868
  self.model_id = json_data.get("modelId", "")
869
+ self.download_url = selected_file.get("downloadUrl", "") or ("" if explicit_file_id else json_data.get("downloadUrl", ""))
870
  self.model_url = f"{get_civitai_canonical_web_origin()}/models/{self.model_id}?modelVersionId={self.model_version_id}"
871
  self.filename_url = selected_file.get("name", "") or ""
872
  self.description = json_data.get("description", "")
 
1051
 
1052
  return None
1053
 
1054
+ def get_civitai_expected_size_bytes(file_info):
1055
+ if not isinstance(file_info, dict):
1056
+ return 0
1057
+ raw_size_kb = file_info.get("sizeKB")
1058
+ if raw_size_kb is None:
1059
+ raw_size_kb = file_info.get("sizeKb")
1060
+ try:
1061
+ size_kb = float(raw_size_kb)
1062
+ except (TypeError, ValueError):
1063
+ return 0
1064
+ if size_kb <= 0:
1065
+ return 0
1066
+ return max(1, int(round(size_kb * 1024.0)))
1067
+
1068
+ def is_civitai_file_complete(path, file_info=None, *, log_mismatch=False):
1069
+ candidate = Path(path)
1070
+ if not candidate.exists() or not candidate.is_file():
1071
+ return False
1072
+ expected_size = get_civitai_expected_size_bytes(file_info)
1073
+ if expected_size <= 0:
1074
+ return True
1075
+ try:
1076
+ actual_size = int(candidate.stat().st_size)
1077
+ except OSError:
1078
+ return False
1079
+ tolerance = 4096
1080
+ complete = abs(actual_size - expected_size) <= tolerance
1081
+ if not complete and log_mismatch:
1082
+ print(
1083
+ f"[civitai] existing file size mismatch; treating as incomplete "
1084
+ f"path={candidate} actual={actual_size} expected={expected_size}"
1085
+ )
1086
+ return complete
1087
+
1088
+ def get_existing_completed_download_path(directory, expected_filename="", file_info=None):
1089
  expected_name = str(expected_filename or "").strip()
1090
  if not expected_name:
1091
  return ""
 
1101
  candidate_paths.append(legacy_nested_path)
1102
 
1103
  for candidate_path in candidate_paths:
1104
+ if is_civitai_file_complete(candidate_path, file_info=file_info, log_mismatch=True):
1105
  return str(candidate_path)
1106
 
1107
  return ""
 
1144
  if normalized_url != url:
1145
  print(f"Civitai download URL normalized: {sanitize_url_for_log(url)} -> {sanitize_url_for_log(normalized_url)}")
1146
  model_profile = retrieve_model_info(normalized_url, api_key=civitai_api_key)
1147
+ selected_file = model_profile.selected_file if model_profile else {}
1148
  if model_profile and model_profile.download_url:
1149
  url = model_profile.download_url
1150
  filename = model_profile.filename_url or ""
 
1168
  print(f"Filename: {filename}")
1169
  print(f"[civitai] resolved signed host={signed_host or '-'} url={sanitize_url_for_log(url)}")
1170
 
1171
+ existing_completed_path = get_existing_completed_download_path(directory, expected_filename=filename, file_info=selected_file)
1172
  if existing_completed_path:
1173
  print(f"[civitai] using existing completed file path={existing_completed_path}")
1174
  downloaded_file_path = existing_completed_path
 
1220
  if download_status != 0:
1221
  log_download_error("civitai", "command_failed", url=url, status=download_status)
1222
 
1223
+ if not downloaded_file_path and download_status == 0:
1224
+ candidate_path = guess_downloaded_file_path(directory, before_files, expected_filename=filename)
1225
+ if candidate_path and is_civitai_file_complete(candidate_path, file_info=selected_file, log_mismatch=True):
1226
+ downloaded_file_path = candidate_path
1227
+ elif candidate_path:
1228
+ log_download_error("civitai", "size_mismatch", url=url, detail=f"path={candidate_path}")
1229
  if not downloaded_file_path:
1230
+ existing_completed_path = get_existing_completed_download_path(directory, expected_filename=filename, file_info=selected_file)
 
 
1231
  if existing_completed_path:
1232
  print(f"[civitai] using existing completed file path={existing_completed_path}")
1233
  downloaded_file_path = existing_completed_path
 
1858
  label = ""
1859
  md = "None"
1860
  if not lora_path or lora_path == "None":
 
1861
  return is_valid, label, tag, md
1862
  path = Path(lora_path)
1863
  new_path = Path(f'{path.parent.name}/{escape_lora_basename(path.stem)}{path.suffix}')
requirements.txt CHANGED
@@ -1,22 +1,23 @@
1
- stablepy==0.6.5
2
- diffusers
3
- transformers
4
- accelerate
5
- huggingface_hub
6
- spaces
7
- torch==2.8.0
8
- numpy<2
9
- gdown
10
- opencv-python
11
- optimum[onnxruntime]
12
- #dartrs
13
- git+https://github.com/John6666cat/dartrs
14
- translatepy
15
- timm
16
- rapidfuzz
17
- sentencepiece
18
- unidecode
19
- matplotlib-inline
20
- mediapipe==0.10.5
21
- einops
22
- # pydantic==2.10.6
 
 
1
+ stablepy==0.6.5
2
+ diffusers
3
+ transformers>=4.47.1,<5,!=4.57.0
4
+ accelerate
5
+ huggingface_hub
6
+ spaces
7
+ torch==2.8.0
8
+ numpy<2
9
+ gdown
10
+ opencv-python
11
+ #dartrs
12
+ git+https://github.com/John6666cat/dartrs
13
+ translatepy
14
+ timm
15
+ rapidfuzz
16
+ pandas
17
+ safetensors
18
+ sentencepiece
19
+ unidecode
20
+ matplotlib-inline
21
+ mediapipe==0.10.13
22
+ einops
23
+ # pydantic==2.10.6