John6666 commited on
Commit
c4860b7
·
verified ·
1 Parent(s): 46d591b

Upload 30 files

Browse files
Files changed (5) hide show
  1. README.md +2 -2
  2. app.py +89 -90
  3. env.py +2 -0
  4. modutils.py +119 -35
  5. requirements.txt +5 -6
README.md CHANGED
@@ -4,8 +4,8 @@ emoji: 🖼🖼️📦
4
  colorFrom: purple
5
  colorTo: red
6
  sdk: gradio
7
- sdk_version: 5.45.0
8
- python_version: "3.10"
9
  app_file: app.py
10
  license: mit
11
  short_description: Text-to-Image
 
4
  colorFrom: purple
5
  colorTo: red
6
  sdk: gradio
7
+ sdk_version: 6.17.3
8
+ python_version: "3.12"
9
  app_file: app.py
10
  license: mit
11
  short_description: Text-to-Image
app.py CHANGED
@@ -54,7 +54,7 @@ css = """
54
  .image { margin: 0px auto; object-fit: contain; }
55
  """
56
 
57
- with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
58
  gr.Markdown("# Votepurchase Multiple Model", elem_classes="title")
59
  state = gr.State(value={})
60
  with gr.Tab("Image Generator"):
@@ -68,20 +68,19 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
68
  auto_trans = gr.Checkbox(label="Auto translate to English", value=False, scale=2)
69
 
70
  result = gr.Image(label="Result", elem_id="result", format="png", type="filepath", show_label=False, interactive=False,
71
- show_download_button=True, show_share_button=False, container=True)
72
 
73
  with gr.Accordion("History", open=False):
74
  history_files = gr.Files(interactive=False, visible=False)
75
- history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", format="png", interactive=False, show_share_button=False,
76
- show_download_button=True)
77
  history_clear_button = gr.Button(value="Clear History", variant="secondary")
78
- history_clear_button.click(lambda: ([], []), None, [history_gallery, history_files], queue=False, show_api=False)
79
 
80
  with gr.Accordion("Advanced Settings", open=True):
81
  task = gr.Dropdown(label="Task", choices=SDXL_TASK, value=TASK_MODEL_LIST[0])
82
  with gr.Tab("Generation Settings"):
83
  with gr.Row():
84
- negative_prompt = gr.Text(label="Negative prompt", lines=1, max_lines=6, placeholder="Enter a negative prompt", show_copy_button=True,
85
  value="(low quality, worst quality:1.2), very displeasing, watermark, signature, ugly")
86
  with gr.Accordion("Prompt Settings", open=False):
87
  with gr.Row():
@@ -131,7 +130,7 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
131
  return gr.Slider(minimum=-val_lora, maximum=val_lora, step=0.01, value=1.0, label=label, visible=visible)
132
 
133
  def lora_textbox():
134
- return gr.Textbox(label="", info="Example of prompt:", value="", show_copy_button=True, interactive=False, visible=False)
135
 
136
  with gr.Row():
137
  with gr.Column():
@@ -204,7 +203,7 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
204
  lora_search_civitai_json = gr.JSON(value={}, visible=False)
205
  lora_search_civitai_desc = gr.Markdown(value="", visible=False, elem_classes="desc")
206
  with gr.Accordion("Select from Gallery", open=False):
207
- lora_search_civitai_gallery = gr.Gallery([], label="Results", allow_preview=False, columns=5, show_share_button=False, interactive=False)
208
  lora_search_civitai_result = gr.Dropdown(label="Search Results", choices=[("", "")], value="", allow_custom_value=True, visible=False)
209
  lora_download_url = 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)
210
  lora_download = gr.Button("Get and set LoRA and apply to prompt")
@@ -215,10 +214,10 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
215
  with gr.Column():
216
  #image_control = gr.Image(label="Image ControlNet / Inpaint / Img2img", type="filepath", height=384, sources=["upload", "clipboard", "webcam"], show_share_button=False)
217
  image_control = gr.ImageEditor(label="Image ControlNet / Inpaint / Img2img", type="filepath", sources=["upload", "clipboard", "webcam"], image_mode='RGB',
218
- show_share_button=False, show_fullscreen_button=False, layers=False, canvas_size=(384, 384), width=384, height=512,
219
  brush=gr.Brush(colors=["#FFFFFF"], color_mode="fixed", default_size=32), eraser=gr.Eraser(default_size="32"), elem_classes="image")
220
  result_to_ic_button = gr.Button("Get image from generated result")
221
- image_mask = gr.Image(label="Image Mask", type="filepath", height=384, sources=["upload", "clipboard"], show_share_button=False, elem_classes="image")
222
  with gr.Row():
223
  strength = gr.Slider(minimum=0.01, maximum=1.0, step=0.01, value=0.55, label="Strength",
224
  info="This option adjusts the level of changes for img2img, repaint and inpaint.")
@@ -248,10 +247,10 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
248
  with gr.Column():
249
  #image_ip1 = gr.Image(label="IP Image", type="filepath", height=384, sources=["upload", "clipboard"], show_share_button=False)
250
  image_ip1 = gr.ImageEditor(label="IP Image", type="filepath", sources=["upload", "clipboard", "webcam"], image_mode='RGB',
251
- show_share_button=False, show_fullscreen_button=False, layers=False, canvas_size=(384, 384), width=384, height=512,
252
  brush=gr.Brush(colors=["#FFFFFF"], color_mode="fixed", default_size=32), eraser=gr.Eraser(default_size="32"), elem_classes="image")
253
  result_to_ip1_button = gr.Button("Get image from generated result")
254
- mask_ip1 = gr.Image(label="IP Mask (optional)", type="filepath", height=384, sources=["upload", "clipboard"], show_share_button=False, elem_classes="image")
255
  with gr.Row():
256
  model_ip1 = gr.Dropdown(value="plus_face", label="Model", choices=IP_MODELS)
257
  mode_ip1 = gr.Dropdown(value="original", label="Mode", choices=MODE_IP_OPTIONS)
@@ -261,10 +260,10 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
261
  with gr.Column():
262
  #image_ip2 = gr.Image(label="IP Image", type="filepath", height=384, sources=["upload", "clipboard"], show_share_button=False)
263
  image_ip2 = gr.ImageEditor(label="IP Image", type="filepath", sources=["upload", "clipboard", "webcam"], image_mode='RGB',
264
- show_share_button=False, show_fullscreen_button=False, layers=False, canvas_size=(384, 384), width=384, height=512,
265
  brush=gr.Brush(colors=["#FFFFFF"], color_mode="fixed", default_size=32), eraser=gr.Eraser(default_size="32"), elem_classes="image")
266
  result_to_ip2_button = gr.Button("Get image from generated result")
267
- mask_ip2 = gr.Image(label="IP Mask (optional)", type="filepath", height=384, sources=["upload", "clipboard"], show_share_button=False, elem_classes="image")
268
  with gr.Row():
269
  model_ip2 = gr.Dropdown(value="base", label="Model", choices=IP_MODELS)
270
  mode_ip2 = gr.Dropdown(value="style", label="Mode", choices=MODE_IP_OPTIONS)
@@ -275,24 +274,24 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
275
  with gr.Column():
276
  image_base = gr.ImageEditor(sources=["upload", "clipboard", "webcam"],
277
  brush=gr.Brush(default_size="32", color_mode="fixed", colors=["rgba(0, 0, 0, 1)", "rgba(0, 0, 0, 0.1)", "rgba(255, 255, 255, 0.1)"]),
278
- eraser=gr.Eraser(default_size="32"), show_share_button=False, show_fullscreen_button=False,
279
  canvas_size=(384, 384), width=384, height=512, elem_classes="image")
280
  result_to_cm_button = gr.Button("Get image from generated result")
281
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
282
  cm_btn = gr.Button("Create mask")
283
  with gr.Column():
284
- img_source = gr.Image(interactive=False, height=384, show_share_button=False, elem_classes="image")
285
- img_result = gr.Image(label="Mask image", show_label=True, interactive=False, height=384, show_share_button=False, elem_classes="image")
286
  cm_btn_send = gr.Button("Send to ControlNet / Img2img / Inpaint")
287
  with gr.Row():
288
  cm_btn_send_ip1 = gr.Button("Send to IP-Adapter 1")
289
  cm_btn_send_ip2 = gr.Button("Send to IP-Adapter 2")
290
- cm_btn.click(create_mask_now, [image_base, invert_mask], [img_source, img_result], show_api=False)
291
  def send_img(img_source, img_result):
292
  return img_source, img_result
293
- cm_btn_send.click(send_img, [img_source, img_result], [image_control, image_mask], queue=False, show_api=False)
294
- cm_btn_send_ip1.click(send_img, [img_source, img_result], [image_ip1, mask_ip1], queue=False, show_api=False)
295
- cm_btn_send_ip2.click(send_img, [img_source, img_result], [image_ip2, mask_ip2], queue=False, show_api=False)
296
 
297
  with gr.Tab("Hires fix / Detailfix / Face restoration"):
298
  with gr.Accordion("Hires fix", open=True):
@@ -355,7 +354,7 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
355
  face_restoration_weight = gr.Slider(minimum=0., maximum=1., step=0.001, value=.5, label="Weight", info="(0 = maximum effect, 1 = minimum effect)")
356
 
357
  with gr.Tab("Translation Settings"):
358
- chatbot = gr.Chatbot(type="messages", render_markdown=False, visible=False) # component for auto-translation
359
  chat_model = gr.Dropdown(choices=get_dolphin_models(), value=get_dolphin_models()[0], allow_custom_value=True, label="Model")
360
  chat_model_info = gr.Markdown(value=get_dolphin_model_info(get_dolphin_models()[0]), label="Model info")
361
  chat_format = gr.Dropdown(choices=get_llm_formats(), value=get_dolphin_model_format(get_dolphin_models()[0]), label="Message format")
@@ -382,18 +381,18 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
382
  cache_examples=False,
383
  )
384
 
385
- model_name.change(update_task_options, [model_name, task], [task], queue=False, show_api=False)\
386
- .success(update_task_options, [model_name, task_sel], [task_sel], queue=False, show_api=False)\
387
- .success(update_textual_inversion, [active_textual_inversion, model_name], [use_textual_inversion], queue=False, show_api=False)
388
- task_sel.select(lambda x: x, [task_sel], [task], queue=False, show_api=False)
389
- task.change(change_preprocessor_choices, [task], [preprocessor_name], queue=False, show_api=False)\
390
- .success(lambda x: x, [task], [task_sel], queue=False, show_api=False)
391
- active_textual_inversion.change(update_textual_inversion, [active_textual_inversion, model_name], [use_textual_inversion], queue=False, show_api=False)
392
  use_textual_inversion.change(set_textual_inversion_prompt, [use_textual_inversion, prompt, negative_prompt, prompt_syntax], [prompt, negative_prompt])
393
- result_to_cm_button.click(lambda x: x, [result], [image_base], queue=False, show_api=False)
394
- result_to_ic_button.click(lambda x: x, [result], [image_control], queue=False, show_api=False)
395
- result_to_ip1_button.click(lambda x: x, [result], [image_ip1], queue=False, show_api=False)
396
- result_to_ip2_button.click(lambda x: x, [result], [image_ip2], queue=False, show_api=False)
397
 
398
  gr.on( #lambda x: None, inputs=None, outputs=result).then(
399
  triggers=[run_button.click, prompt.submit],
@@ -420,7 +419,7 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
420
  outputs=[result],
421
  queue=True,
422
  show_progress="full",
423
- show_api=True,
424
  )
425
 
426
  gr.on( #lambda x: None, inputs=None, outputs=result).then(
@@ -447,7 +446,7 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
447
  active_textual_inversion, face_restoration_model, face_restoration_visibility, face_restoration_weight, gpu_duration, auto_trans, recom_prompt],
448
  outputs=[result],
449
  queue=False,
450
- show_api=True,
451
  api_name="infer_translate",
452
  ).success(
453
  fn=dolphin_respond_auto,
@@ -455,13 +454,13 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
455
  outputs=[chatbot, result, prompt],
456
  queue=True,
457
  show_progress="full",
458
- show_api=False,
459
  ).success(
460
  fn=dolphin_parse_simple,
461
  inputs=[prompt, chatbot, state],
462
  outputs=[prompt],
463
  queue=False,
464
- show_api=False,
465
  ).success(
466
  fn=infer,
467
  inputs=[prompt, negative_prompt, seed, randomize_seed, width, height,
@@ -486,11 +485,11 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
486
  outputs=[result],
487
  queue=True,
488
  show_progress="full",
489
- show_api=False,
490
- ).success(lambda: None, None, chatbot, queue=False, show_api=False)\
491
- .success(pass_result, [result], [result], queue=False, show_api=False) # dummy fn for api
492
 
493
- result.change(save_image_history, [result, history_gallery, history_files, model_name], [history_gallery, history_files], queue=False, show_api=False)
494
 
495
  gr.on(
496
  triggers=[lora1.change, lora1_wt.change, lora2.change, lora2_wt.change, lora3.change, lora3_wt.change,
@@ -503,15 +502,15 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
503
  lora6, lora6_wt, lora6_info, lora6_copy, lora6_md, lora7, lora7_wt, lora7_info, lora7_copy, lora7_md],
504
  queue=False,
505
  trigger_mode="once",
506
- show_api=False,
507
  )
508
- lora1_copy.click(apply_lora_prompt, [prompt, lora1_info], [prompt], queue=False, show_api=False)
509
- lora2_copy.click(apply_lora_prompt, [prompt, lora2_info], [prompt], queue=False, show_api=False)
510
- lora3_copy.click(apply_lora_prompt, [prompt, lora3_info], [prompt], queue=False, show_api=False)
511
- lora4_copy.click(apply_lora_prompt, [prompt, lora4_info], [prompt], queue=False, show_api=False)
512
- lora5_copy.click(apply_lora_prompt, [prompt, lora5_info], [prompt], queue=False, show_api=False)
513
- lora6_copy.click(apply_lora_prompt, [prompt, lora6_info], [prompt], queue=False, show_api=False)
514
- lora7_copy.click(apply_lora_prompt, [prompt, lora7_info], [prompt], queue=False, show_api=False)
515
 
516
  gr.on(
517
  triggers=[lora_search_civitai_submit.click, lora_search_civitai_query.submit],
@@ -520,10 +519,10 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
520
  outputs=[lora_search_civitai_result, lora_search_civitai_desc, lora_search_civitai_submit, lora_search_civitai_query, lora_search_civitai_gallery],
521
  scroll_to_output=True,
522
  queue=True,
523
- show_api=False,
524
  )
525
- lora_search_civitai_json.change(search_civitai_lora_json, [lora_search_civitai_query, lora_search_civitai_basemodel], [lora_search_civitai_json], queue=True, show_api=True) # fn for api
526
- lora_search_civitai_result.change(select_civitai_lora, [lora_search_civitai_result], [lora_download_url, lora_search_civitai_desc], scroll_to_output=True, queue=False, show_api=False)
527
  gr.on(
528
  triggers=[lora_download.click, lora_download_url.submit],
529
  fn=download_my_lora,
@@ -531,9 +530,9 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
531
  outputs=[lora1, lora2, lora3, lora4, lora5, lora6, lora7],
532
  scroll_to_output=True,
533
  queue=True,
534
- show_api=False,
535
  )
536
- lora_search_civitai_gallery.select(update_civitai_selection, None, [lora_search_civitai_result], queue=False, show_api=False)
537
 
538
  #recom_prompt.change(enable_model_recom_prompt, [recom_prompt], [recom_prompt], queue=False, show_api=False)
539
  gr.on(
@@ -543,18 +542,18 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
543
  outputs=[prompt, negative_prompt],
544
  queue=False,
545
  trigger_mode="once",
546
- show_api=False,
547
  )
548
 
549
- model_detail.change(enable_diffusers_model_detail, [model_detail, model_name, state], [model_detail, model_name, state], queue=False, show_api=False)
550
- model_name.change(get_t2i_model_info, [model_name], [model_info], queue=False, show_api=False)
551
 
552
- chat_model.change(select_dolphin_model, [chat_model, state], [chat_model, chat_format, chat_model_info, state], queue=True, show_progress="full", show_api=False)\
553
- .success(lambda: None, None, chatbot, queue=False, show_api=False)
554
- chat_format.change(select_dolphin_format, [chat_format, state], [chat_format, state], queue=False, show_api=False)\
555
- .success(lambda: None, None, chatbot, queue=False, show_api=False)
556
  chat_lora.change(select_dolphin_lora, [chat_lora, state], [chat_lora, state], queue=True, show_progress="full")\
557
- .success(lambda: None, None, chatbot, queue=False, show_api=False)
558
 
559
  # Tagger
560
  with gr.Tab("Tags Transformer with Tagger"):
@@ -594,61 +593,61 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
594
  generate_btn = gr.Button(value="GENERATE TAGS", size="lg", variant="primary")
595
  with gr.Row():
596
  with gr.Group():
597
- output_text = gr.TextArea(label="Output tags", interactive=False, show_copy_button=True)
598
  with gr.Row():
599
  copy_btn = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
600
  copy_prompt_btn = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
601
  with gr.Group():
602
- output_text_pony = gr.TextArea(label="Output tags (Pony e621 style)", interactive=False, show_copy_button=True)
603
  with gr.Row():
604
  copy_btn_pony = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
605
  copy_prompt_btn_pony = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
606
 
607
- random_character.click(select_random_character, [input_copyright, input_character], [input_copyright, input_character], queue=False, show_api=False)
608
 
609
- translate_input_prompt_button.click(translate_prompt, [input_general], [input_general], queue=False, show_api=False)
610
- translate_input_prompt_button.click(translate_prompt, [input_character], [input_character], queue=False, show_api=False)
611
- translate_input_prompt_button.click(translate_prompt, [input_copyright], [input_copyright], queue=False, show_api=False)
612
 
613
  generate_from_image_btn.click(
614
- lambda: ("", "", ""), None, [input_copyright, input_character, input_general], queue=False, show_api=False,
615
  ).success(
616
  predict_tags_wd,
617
  [input_image, input_general, image_algorithms, general_threshold, character_threshold],
618
  [input_copyright, input_character, input_general, copy_input_btn],
619
- show_api=False,
620
  ).success(
621
- predict_tags_fl2_sd3, [input_image, input_general, image_algorithms], [input_general], show_api=False,
622
  ).success(
623
- remove_specific_prompt, [input_general, keep_tags], [input_general], queue=False, show_api=False,
624
  ).success(
625
- convert_danbooru_to_e621_prompt, [input_general, input_tag_type], [input_general], queue=False, show_api=False,
626
  ).success(
627
- insert_recom_prompt, [input_general, dummy_np, recom_prompt], [input_general, dummy_np], queue=False, show_api=False,
628
- ).success(lambda: gr.update(interactive=True), None, [copy_prompt_btn_input], queue=False, show_api=False)
629
- copy_input_btn.click(compose_prompt_to_copy, [input_character, input_copyright, input_general], [input_tags_to_copy], show_api=False)\
630
- .success(gradio_copy_text, [input_tags_to_copy], js=COPY_ACTION_JS, show_api=False)
631
- copy_prompt_btn_input.click(compose_prompt_to_copy, inputs=[input_character, input_copyright, input_general], outputs=[input_tags_to_copy], show_api=False)\
632
- .success(gradio_copy_prompt, inputs=[input_tags_to_copy], outputs=[prompt], show_api=False)
633
 
634
  generate_btn.click(
635
  v2_upsampling_prompt,
636
  [model_name, input_copyright, input_character, input_general,
637
  input_rating, input_aspect_ratio, input_length, input_identity, input_ban_tags],
638
  [output_text],
639
- show_api=False,
640
  ).success(
641
- convert_danbooru_to_e621_prompt, [output_text, tag_type], [output_text_pony], queue=False, show_api=False,
642
  ).success(
643
- insert_recom_prompt, [output_text, dummy_np, recom_animagine], [output_text, dummy_np], queue=False, show_api=False,
644
  ).success(
645
- insert_recom_prompt, [output_text_pony, dummy_np, recom_pony], [output_text_pony, dummy_np], queue=False, show_api=False,
646
  ).success(lambda: (gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)),
647
- None, [copy_btn, copy_btn_pony, copy_prompt_btn, copy_prompt_btn_pony], queue=False, show_api=False)
648
- copy_btn.click(gradio_copy_text, [output_text], js=COPY_ACTION_JS, show_api=False)
649
- copy_btn_pony.click(gradio_copy_text, [output_text_pony], js=COPY_ACTION_JS, show_api=False)
650
- copy_prompt_btn.click(gradio_copy_prompt, inputs=[output_text], outputs=[prompt], show_api=False)
651
- copy_prompt_btn_pony.click(gradio_copy_prompt, inputs=[output_text_pony], outputs=[prompt], show_api=False)
652
 
653
  with gr.Tab("PNG Info"):
654
  with gr.Row():
@@ -656,7 +655,7 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
656
  image_metadata = gr.Image(label="Image with metadata", type="pil", sources=["upload"])
657
 
658
  with gr.Column():
659
- result_metadata = gr.Textbox(label="Metadata", show_label=True, show_copy_button=True, interactive=False, container=True, max_lines=99)
660
 
661
  image_metadata.change(
662
  fn=extract_exif_data,
@@ -687,4 +686,4 @@ with gr.Blocks(fill_width=True, elem_id="container", css=css) as demo:
687
 
688
  if __name__ == "__main__":
689
  demo.queue()
690
- demo.launch(show_error=True, share=False, debug=True, ssr_mode=False, mcp_server=False)
 
54
  .image { margin: 0px auto; object-fit: contain; }
55
  """
56
 
57
+ with gr.Blocks(fill_width=True, elem_id="container") as demo:
58
  gr.Markdown("# Votepurchase Multiple Model", elem_classes="title")
59
  state = gr.State(value={})
60
  with gr.Tab("Image Generator"):
 
68
  auto_trans = gr.Checkbox(label="Auto translate to English", value=False, scale=2)
69
 
70
  result = gr.Image(label="Result", elem_id="result", format="png", type="filepath", show_label=False, interactive=False,
71
+ buttons=["download", "fullscreen"], container=True)
72
 
73
  with gr.Accordion("History", open=False):
74
  history_files = gr.Files(interactive=False, visible=False)
75
+ history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", format="png", interactive=False, buttons=["download", "fullscreen"])
 
76
  history_clear_button = gr.Button(value="Clear History", variant="secondary")
77
+ history_clear_button.click(lambda: ([], []), None, [history_gallery, history_files], queue=False, api_visibility="undocumented")
78
 
79
  with gr.Accordion("Advanced Settings", open=True):
80
  task = gr.Dropdown(label="Task", choices=SDXL_TASK, value=TASK_MODEL_LIST[0])
81
  with gr.Tab("Generation Settings"):
82
  with gr.Row():
83
+ negative_prompt = gr.Text(label="Negative prompt", lines=1, max_lines=6, placeholder="Enter a negative prompt", buttons=["copy"],
84
  value="(low quality, worst quality:1.2), very displeasing, watermark, signature, ugly")
85
  with gr.Accordion("Prompt Settings", open=False):
86
  with gr.Row():
 
130
  return gr.Slider(minimum=-val_lora, maximum=val_lora, step=0.01, value=1.0, label=label, visible=visible)
131
 
132
  def lora_textbox():
133
+ return gr.Textbox(label="", info="Example of prompt:", value="", buttons=["copy"], interactive=False, visible=False)
134
 
135
  with gr.Row():
136
  with gr.Column():
 
203
  lora_search_civitai_json = gr.JSON(value={}, visible=False)
204
  lora_search_civitai_desc = gr.Markdown(value="", visible=False, elem_classes="desc")
205
  with gr.Accordion("Select from Gallery", open=False):
206
+ lora_search_civitai_gallery = gr.Gallery([], label="Results", allow_preview=False, columns=5, buttons=["download", "fullscreen"], interactive=False)
207
  lora_search_civitai_result = gr.Dropdown(label="Search Results", choices=[("", "")], value="", allow_custom_value=True, visible=False)
208
  lora_download_url = 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)
209
  lora_download = gr.Button("Get and set LoRA and apply to prompt")
 
214
  with gr.Column():
215
  #image_control = gr.Image(label="Image ControlNet / Inpaint / Img2img", type="filepath", height=384, sources=["upload", "clipboard", "webcam"], show_share_button=False)
216
  image_control = gr.ImageEditor(label="Image ControlNet / Inpaint / Img2img", type="filepath", sources=["upload", "clipboard", "webcam"], image_mode='RGB',
217
+ buttons=["download"], layers=False, canvas_size=(384, 384), width=384, height=512,
218
  brush=gr.Brush(colors=["#FFFFFF"], color_mode="fixed", default_size=32), eraser=gr.Eraser(default_size="32"), elem_classes="image")
219
  result_to_ic_button = gr.Button("Get image from generated result")
220
+ image_mask = gr.Image(label="Image Mask", type="filepath", height=384, sources=["upload", "clipboard"], buttons=["download", "fullscreen"], elem_classes="image")
221
  with gr.Row():
222
  strength = gr.Slider(minimum=0.01, maximum=1.0, step=0.01, value=0.55, label="Strength",
223
  info="This option adjusts the level of changes for img2img, repaint and inpaint.")
 
247
  with gr.Column():
248
  #image_ip1 = gr.Image(label="IP Image", type="filepath", height=384, sources=["upload", "clipboard"], show_share_button=False)
249
  image_ip1 = gr.ImageEditor(label="IP Image", type="filepath", sources=["upload", "clipboard", "webcam"], image_mode='RGB',
250
+ buttons=["download"], layers=False, canvas_size=(384, 384), width=384, height=512,
251
  brush=gr.Brush(colors=["#FFFFFF"], color_mode="fixed", default_size=32), eraser=gr.Eraser(default_size="32"), elem_classes="image")
252
  result_to_ip1_button = gr.Button("Get image from generated result")
253
+ mask_ip1 = gr.Image(label="IP Mask (optional)", type="filepath", height=384, sources=["upload", "clipboard"], buttons=["download", "fullscreen"], elem_classes="image")
254
  with gr.Row():
255
  model_ip1 = gr.Dropdown(value="plus_face", label="Model", choices=IP_MODELS)
256
  mode_ip1 = gr.Dropdown(value="original", label="Mode", choices=MODE_IP_OPTIONS)
 
260
  with gr.Column():
261
  #image_ip2 = gr.Image(label="IP Image", type="filepath", height=384, sources=["upload", "clipboard"], show_share_button=False)
262
  image_ip2 = gr.ImageEditor(label="IP Image", type="filepath", sources=["upload", "clipboard", "webcam"], image_mode='RGB',
263
+ buttons=["download"], layers=False, canvas_size=(384, 384), width=384, height=512,
264
  brush=gr.Brush(colors=["#FFFFFF"], color_mode="fixed", default_size=32), eraser=gr.Eraser(default_size="32"), elem_classes="image")
265
  result_to_ip2_button = gr.Button("Get image from generated result")
266
+ mask_ip2 = gr.Image(label="IP Mask (optional)", type="filepath", height=384, sources=["upload", "clipboard"], buttons=["download", "fullscreen"], elem_classes="image")
267
  with gr.Row():
268
  model_ip2 = gr.Dropdown(value="base", label="Model", choices=IP_MODELS)
269
  mode_ip2 = gr.Dropdown(value="style", label="Mode", choices=MODE_IP_OPTIONS)
 
274
  with gr.Column():
275
  image_base = gr.ImageEditor(sources=["upload", "clipboard", "webcam"],
276
  brush=gr.Brush(default_size="32", color_mode="fixed", colors=["rgba(0, 0, 0, 1)", "rgba(0, 0, 0, 0.1)", "rgba(255, 255, 255, 0.1)"]),
277
+ eraser=gr.Eraser(default_size="32"), buttons=["download"],
278
  canvas_size=(384, 384), width=384, height=512, elem_classes="image")
279
  result_to_cm_button = gr.Button("Get image from generated result")
280
  invert_mask = gr.Checkbox(value=False, label="Invert mask")
281
  cm_btn = gr.Button("Create mask")
282
  with gr.Column():
283
+ img_source = gr.Image(interactive=False, height=384, buttons=["download", "fullscreen"], elem_classes="image")
284
+ img_result = gr.Image(label="Mask image", show_label=True, interactive=False, height=384, buttons=["download", "fullscreen"], elem_classes="image")
285
  cm_btn_send = gr.Button("Send to ControlNet / Img2img / Inpaint")
286
  with gr.Row():
287
  cm_btn_send_ip1 = gr.Button("Send to IP-Adapter 1")
288
  cm_btn_send_ip2 = gr.Button("Send to IP-Adapter 2")
289
+ cm_btn.click(create_mask_now, [image_base, invert_mask], [img_source, img_result], api_visibility="undocumented")
290
  def send_img(img_source, img_result):
291
  return img_source, img_result
292
+ cm_btn_send.click(send_img, [img_source, img_result], [image_control, image_mask], queue=False, api_visibility="undocumented")
293
+ cm_btn_send_ip1.click(send_img, [img_source, img_result], [image_ip1, mask_ip1], queue=False, api_visibility="undocumented")
294
+ cm_btn_send_ip2.click(send_img, [img_source, img_result], [image_ip2, mask_ip2], queue=False, api_visibility="undocumented")
295
 
296
  with gr.Tab("Hires fix / Detailfix / Face restoration"):
297
  with gr.Accordion("Hires fix", open=True):
 
354
  face_restoration_weight = gr.Slider(minimum=0., maximum=1., step=0.001, value=.5, label="Weight", info="(0 = maximum effect, 1 = minimum effect)")
355
 
356
  with gr.Tab("Translation Settings"):
357
+ chatbot = gr.Chatbot(render_markdown=False, visible=False) # component for auto-translation
358
  chat_model = gr.Dropdown(choices=get_dolphin_models(), value=get_dolphin_models()[0], allow_custom_value=True, label="Model")
359
  chat_model_info = gr.Markdown(value=get_dolphin_model_info(get_dolphin_models()[0]), label="Model info")
360
  chat_format = gr.Dropdown(choices=get_llm_formats(), value=get_dolphin_model_format(get_dolphin_models()[0]), label="Message format")
 
381
  cache_examples=False,
382
  )
383
 
384
+ model_name.change(update_task_options, [model_name, task], [task], queue=False, api_visibility="undocumented")\
385
+ .success(update_task_options, [model_name, task_sel], [task_sel], queue=False, api_visibility="undocumented")\
386
+ .success(update_textual_inversion, [active_textual_inversion, model_name], [use_textual_inversion], queue=False, api_visibility="undocumented")
387
+ task_sel.select(lambda x: x, [task_sel], [task], queue=False, api_visibility="undocumented")
388
+ task.change(change_preprocessor_choices, [task], [preprocessor_name], queue=False, api_visibility="undocumented")\
389
+ .success(lambda x: x, [task], [task_sel], queue=False, api_visibility="undocumented")
390
+ active_textual_inversion.change(update_textual_inversion, [active_textual_inversion, model_name], [use_textual_inversion], queue=False, api_visibility="undocumented")
391
  use_textual_inversion.change(set_textual_inversion_prompt, [use_textual_inversion, prompt, negative_prompt, prompt_syntax], [prompt, negative_prompt])
392
+ result_to_cm_button.click(lambda x: x, [result], [image_base], queue=False, api_visibility="undocumented")
393
+ result_to_ic_button.click(lambda x: x, [result], [image_control], queue=False, api_visibility="undocumented")
394
+ result_to_ip1_button.click(lambda x: x, [result], [image_ip1], queue=False, api_visibility="undocumented")
395
+ result_to_ip2_button.click(lambda x: x, [result], [image_ip2], queue=False, api_visibility="undocumented")
396
 
397
  gr.on( #lambda x: None, inputs=None, outputs=result).then(
398
  triggers=[run_button.click, prompt.submit],
 
419
  outputs=[result],
420
  queue=True,
421
  show_progress="full",
422
+ api_visibility="public",
423
  )
424
 
425
  gr.on( #lambda x: None, inputs=None, outputs=result).then(
 
446
  active_textual_inversion, face_restoration_model, face_restoration_visibility, face_restoration_weight, gpu_duration, auto_trans, recom_prompt],
447
  outputs=[result],
448
  queue=False,
449
+ api_visibility="public",
450
  api_name="infer_translate",
451
  ).success(
452
  fn=dolphin_respond_auto,
 
454
  outputs=[chatbot, result, prompt],
455
  queue=True,
456
  show_progress="full",
457
+ api_visibility="undocumented",
458
  ).success(
459
  fn=dolphin_parse_simple,
460
  inputs=[prompt, chatbot, state],
461
  outputs=[prompt],
462
  queue=False,
463
+ api_visibility="undocumented",
464
  ).success(
465
  fn=infer,
466
  inputs=[prompt, negative_prompt, seed, randomize_seed, width, height,
 
485
  outputs=[result],
486
  queue=True,
487
  show_progress="full",
488
+ api_visibility="undocumented",
489
+ ).success(lambda: None, None, chatbot, queue=False, api_visibility="undocumented")\
490
+ .success(pass_result, [result], [result], queue=False, api_visibility="undocumented") # dummy fn for api
491
 
492
+ result.change(save_image_history, [result, history_gallery, history_files, model_name], [history_gallery, history_files], queue=False, api_visibility="undocumented")
493
 
494
  gr.on(
495
  triggers=[lora1.change, lora1_wt.change, lora2.change, lora2_wt.change, lora3.change, lora3_wt.change,
 
502
  lora6, lora6_wt, lora6_info, lora6_copy, lora6_md, lora7, lora7_wt, lora7_info, lora7_copy, lora7_md],
503
  queue=False,
504
  trigger_mode="once",
505
+ api_visibility="undocumented",
506
  )
507
+ lora1_copy.click(apply_lora_prompt, [prompt, lora1_info], [prompt], queue=False, api_visibility="undocumented")
508
+ lora2_copy.click(apply_lora_prompt, [prompt, lora2_info], [prompt], queue=False, api_visibility="undocumented")
509
+ lora3_copy.click(apply_lora_prompt, [prompt, lora3_info], [prompt], queue=False, api_visibility="undocumented")
510
+ lora4_copy.click(apply_lora_prompt, [prompt, lora4_info], [prompt], queue=False, api_visibility="undocumented")
511
+ lora5_copy.click(apply_lora_prompt, [prompt, lora5_info], [prompt], queue=False, api_visibility="undocumented")
512
+ lora6_copy.click(apply_lora_prompt, [prompt, lora6_info], [prompt], queue=False, api_visibility="undocumented")
513
+ lora7_copy.click(apply_lora_prompt, [prompt, lora7_info], [prompt], queue=False, api_visibility="undocumented")
514
 
515
  gr.on(
516
  triggers=[lora_search_civitai_submit.click, lora_search_civitai_query.submit],
 
519
  outputs=[lora_search_civitai_result, lora_search_civitai_desc, lora_search_civitai_submit, lora_search_civitai_query, lora_search_civitai_gallery],
520
  scroll_to_output=True,
521
  queue=True,
522
+ api_visibility="undocumented",
523
  )
524
+ lora_search_civitai_json.change(search_civitai_lora_json, [lora_search_civitai_query, lora_search_civitai_basemodel], [lora_search_civitai_json], queue=True, api_visibility="public") # fn for api
525
+ lora_search_civitai_result.change(select_civitai_lora, [lora_search_civitai_result], [lora_download_url, lora_search_civitai_desc], scroll_to_output=True, queue=False, api_visibility="undocumented")
526
  gr.on(
527
  triggers=[lora_download.click, lora_download_url.submit],
528
  fn=download_my_lora,
 
530
  outputs=[lora1, lora2, lora3, lora4, lora5, lora6, lora7],
531
  scroll_to_output=True,
532
  queue=True,
533
+ api_visibility="undocumented",
534
  )
535
+ lora_search_civitai_gallery.select(update_civitai_selection, None, [lora_search_civitai_result], queue=False, api_visibility="undocumented")
536
 
537
  #recom_prompt.change(enable_model_recom_prompt, [recom_prompt], [recom_prompt], queue=False, show_api=False)
538
  gr.on(
 
542
  outputs=[prompt, negative_prompt],
543
  queue=False,
544
  trigger_mode="once",
545
+ api_visibility="undocumented",
546
  )
547
 
548
+ model_detail.change(enable_diffusers_model_detail, [model_detail, model_name, state], [model_detail, model_name, state], queue=False, api_visibility="undocumented")
549
+ model_name.change(get_t2i_model_info, [model_name], [model_info], queue=False, api_visibility="undocumented")
550
 
551
+ chat_model.change(select_dolphin_model, [chat_model, state], [chat_model, chat_format, chat_model_info, state], queue=True, show_progress="full", api_visibility="undocumented")\
552
+ .success(lambda: None, None, chatbot, queue=False, api_visibility="undocumented")
553
+ chat_format.change(select_dolphin_format, [chat_format, state], [chat_format, state], queue=False, api_visibility="undocumented")\
554
+ .success(lambda: None, None, chatbot, queue=False, api_visibility="undocumented")
555
  chat_lora.change(select_dolphin_lora, [chat_lora, state], [chat_lora, state], queue=True, show_progress="full")\
556
+ .success(lambda: None, None, chatbot, queue=False, api_visibility="undocumented")
557
 
558
  # Tagger
559
  with gr.Tab("Tags Transformer with Tagger"):
 
593
  generate_btn = gr.Button(value="GENERATE TAGS", size="lg", variant="primary")
594
  with gr.Row():
595
  with gr.Group():
596
+ output_text = gr.TextArea(label="Output tags", interactive=False, buttons=["copy"])
597
  with gr.Row():
598
  copy_btn = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
599
  copy_prompt_btn = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
600
  with gr.Group():
601
+ output_text_pony = gr.TextArea(label="Output tags (Pony e621 style)", interactive=False, buttons=["copy"])
602
  with gr.Row():
603
  copy_btn_pony = gr.Button(value="Copy to clipboard", size="sm", interactive=False)
604
  copy_prompt_btn_pony = gr.Button(value="Copy to primary prompt", size="sm", interactive=False)
605
 
606
+ random_character.click(select_random_character, [input_copyright, input_character], [input_copyright, input_character], queue=False, api_visibility="undocumented")
607
 
608
+ translate_input_prompt_button.click(translate_prompt, [input_general], [input_general], queue=False, api_visibility="undocumented")
609
+ translate_input_prompt_button.click(translate_prompt, [input_character], [input_character], queue=False, api_visibility="undocumented")
610
+ translate_input_prompt_button.click(translate_prompt, [input_copyright], [input_copyright], queue=False, api_visibility="undocumented")
611
 
612
  generate_from_image_btn.click(
613
+ lambda: ("", "", ""), None, [input_copyright, input_character, input_general], queue=False, api_visibility="undocumented",
614
  ).success(
615
  predict_tags_wd,
616
  [input_image, input_general, image_algorithms, general_threshold, character_threshold],
617
  [input_copyright, input_character, input_general, copy_input_btn],
618
+ api_visibility="undocumented",
619
  ).success(
620
+ predict_tags_fl2_sd3, [input_image, input_general, image_algorithms], [input_general], api_visibility="undocumented",
621
  ).success(
622
+ remove_specific_prompt, [input_general, keep_tags], [input_general], queue=False, api_visibility="undocumented",
623
  ).success(
624
+ convert_danbooru_to_e621_prompt, [input_general, input_tag_type], [input_general], queue=False, api_visibility="undocumented",
625
  ).success(
626
+ insert_recom_prompt, [input_general, dummy_np, recom_prompt], [input_general, dummy_np], queue=False, api_visibility="undocumented",
627
+ ).success(lambda: gr.update(interactive=True), None, [copy_prompt_btn_input], queue=False, api_visibility="undocumented")
628
+ copy_input_btn.click(compose_prompt_to_copy, [input_character, input_copyright, input_general], [input_tags_to_copy], api_visibility="undocumented")\
629
+ .success(gradio_copy_text, [input_tags_to_copy], js=COPY_ACTION_JS, api_visibility="undocumented")
630
+ copy_prompt_btn_input.click(compose_prompt_to_copy, inputs=[input_character, input_copyright, input_general], outputs=[input_tags_to_copy], api_visibility="undocumented")\
631
+ .success(gradio_copy_prompt, inputs=[input_tags_to_copy], outputs=[prompt], api_visibility="undocumented")
632
 
633
  generate_btn.click(
634
  v2_upsampling_prompt,
635
  [model_name, input_copyright, input_character, input_general,
636
  input_rating, input_aspect_ratio, input_length, input_identity, input_ban_tags],
637
  [output_text],
638
+ api_visibility="undocumented",
639
  ).success(
640
+ convert_danbooru_to_e621_prompt, [output_text, tag_type], [output_text_pony], queue=False, api_visibility="undocumented",
641
  ).success(
642
+ insert_recom_prompt, [output_text, dummy_np, recom_animagine], [output_text, dummy_np], queue=False, api_visibility="undocumented",
643
  ).success(
644
+ insert_recom_prompt, [output_text_pony, dummy_np, recom_pony], [output_text_pony, dummy_np], queue=False, api_visibility="undocumented",
645
  ).success(lambda: (gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)),
646
+ None, [copy_btn, copy_btn_pony, copy_prompt_btn, copy_prompt_btn_pony], queue=False, api_visibility="undocumented")
647
+ copy_btn.click(gradio_copy_text, [output_text], js=COPY_ACTION_JS, api_visibility="undocumented")
648
+ copy_btn_pony.click(gradio_copy_text, [output_text_pony], js=COPY_ACTION_JS, api_visibility="undocumented")
649
+ copy_prompt_btn.click(gradio_copy_prompt, inputs=[output_text], outputs=[prompt], api_visibility="undocumented")
650
+ copy_prompt_btn_pony.click(gradio_copy_prompt, inputs=[output_text_pony], outputs=[prompt], api_visibility="undocumented")
651
 
652
  with gr.Tab("PNG Info"):
653
  with gr.Row():
 
655
  image_metadata = gr.Image(label="Image with metadata", type="pil", sources=["upload"])
656
 
657
  with gr.Column():
658
+ result_metadata = gr.Textbox(label="Metadata", show_label=True, buttons=["copy"], interactive=False, container=True, max_lines=99)
659
 
660
  image_metadata.change(
661
  fn=extract_exif_data,
 
686
 
687
  if __name__ == "__main__":
688
  demo.queue()
689
+ demo.launch(show_error=True, share=False, debug=True, ssr_mode=False, mcp_server=False, css=css)
env.py CHANGED
@@ -80,6 +80,8 @@ LOAD_DIFFUSERS_FORMAT_MODEL = [
80
  'Raelina/Raehoshi-illust-XL-8.1',
81
  'Raelina/Raehoshi-illust-XL-9',
82
  'Raelina/Raehoshi-illust-XL-9.1',
 
 
83
  'Raelina/Raehoshi-illust-vpred',
84
  'camenduru/FLUX.1-dev-diffusers',
85
  'black-forest-labs/FLUX.1-schnell',
 
80
  'Raelina/Raehoshi-illust-XL-8.1',
81
  'Raelina/Raehoshi-illust-XL-9',
82
  'Raelina/Raehoshi-illust-XL-9.1',
83
+ 'Raelina/Raehoshi-illust-XL-10',
84
+ 'Raelina/Raehoshi-illust-XL-11',
85
  'Raelina/Raehoshi-illust-vpred',
86
  'camenduru/FLUX.1-dev-diffusers',
87
  '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,6 +1,6 @@
1
  stablepy==0.6.5
2
  diffusers
3
- transformers
4
  accelerate
5
  torch==2.8.0
6
  numpy<2
@@ -8,12 +8,11 @@ gdown
8
  opencv-python
9
  huggingface_hub
10
  spaces
11
- scikit-build-core
12
- https://github.com/John6666cat/llama-cpp-python/releases/download/v0.3.35-cu128-Basic-linux-20260412/llama_cpp_python-0.3.35+cu128.basic-cp310-cp310-linux_x86_64.whl
13
  git+https://github.com/John6666cat/llama-cpp-agent
14
- pybind11>=2.12
15
  rapidfuzz
16
- optimum[onnxruntime]
 
17
  #dartrs
18
  git+https://github.com/John6666cat/dartrs
19
  translatepy
@@ -22,6 +21,6 @@ wrapt-timeout-decorator
22
  sentencepiece
23
  unidecode
24
  matplotlib-inline
25
- mediapipe==0.10.5
26
  einops
27
  # pydantic==2.10.6
 
1
  stablepy==0.6.5
2
  diffusers
3
+ transformers>=4.47.1,<5,!=4.57.0
4
  accelerate
5
  torch==2.8.0
6
  numpy<2
 
8
  opencv-python
9
  huggingface_hub
10
  spaces
11
+ https://github.com/JamePeng/llama-cpp-python/releases/download/v0.3.46-cu128-linux-20260808/llama_cpp_python-0.3.46+cu128-cp312-cp312-linux_x86_64.whl
 
12
  git+https://github.com/John6666cat/llama-cpp-agent
 
13
  rapidfuzz
14
+ pandas
15
+ safetensors
16
  #dartrs
17
  git+https://github.com/John6666cat/dartrs
18
  translatepy
 
21
  sentencepiece
22
  unidecode
23
  matplotlib-inline
24
+ mediapipe==0.10.13
25
  einops
26
  # pydantic==2.10.6