diff --git a/README.KR.md b/README.KR.md index 0dacbcc..28dc662 100644 --- a/README.KR.md +++ b/README.KR.md @@ -70,6 +70,13 @@ Civitai 사이트의 모델 URL을 저장하여 나중에 참조하고 보관할 * CivitaiShortCutBackupUrl.json : Shortcut 등록시의 URL을 백업하는 파일 # Change Log +v 1.6.0 +* NSFW Filter 기능 추가 +* prompt recipe 리뉴얼 +* prompt recipe에 reference model을 등록 할수 있는 tab추가 +* prompt recipe 검색기능 보강 +* shortcut broswer의 검색창의 위치를 섬네일 목록의 상/하중 원하는 위치로 변경할 수 있도록 setting 에 추가. + v 1.5.8 * 모델 인포메이션에 personal note 항목을 추가, 검색에서 "@" 를 이용해서 검색가능 diff --git a/README.md b/README.md index d5837c8..5490188 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,13 @@ Four folders and five JSON files will be created, each serving the following rol * CivitaiShortCutBackupUrl.json : JSON file for backing up the URL during shortcut registration. # Change Log +v 1.6.0 +* Adding NSFW Filter function +* Revamping prompt recipe +* Adding a tab to register reference models in the prompt recipe +* Enhancing the search function for prompt recipes +* Added a setting in the shortcut browser to allow users to change the position of the search bar to their desired location, either above or below the thumbnail list. + v 1.5.8 * Add a 'Personal Note' section to the model information, and make it searchable using '@' in the search. diff --git a/img/card-no-preview.png b/img/card-no-preview.png new file mode 100644 index 0000000..e2beb26 Binary files /dev/null and b/img/card-no-preview.png differ diff --git a/img/nsfw-no-preview.png b/img/nsfw-no-preview.png new file mode 100644 index 0000000..092ba0e Binary files /dev/null and b/img/nsfw-no-preview.png differ diff --git a/scripts/civitai_manager_libs/civitai_gallery_action.py b/scripts/civitai_manager_libs/civitai_gallery_action.py index d0fad1f..fedc2ce 100644 --- a/scripts/civitai_manager_libs/civitai_gallery_action.py +++ b/scripts/civitai_manager_libs/civitai_gallery_action.py @@ -69,7 +69,8 @@ def on_ui(recipe_input): usergal_page_url = gr.Textbox(value=None) - # refresh_information = gr.Textbox() + refresh_information = gr.Textbox() + refresh_gallery = gr.Textbox() # 미리 다음페이지를 로딩한다. @@ -130,7 +131,23 @@ def on_ui(recipe_input): ], cancels=gallery ) - + + refresh_information.change( + fn=on_usergal_page_url_change, + inputs=[ + usergal_page_url, + paging_information + ], + outputs=[ + refresh_gallery, + usergal_images_url, + usergal_images_meta, + page_slider, + img_file_info, + ], + cancels=gallery + ) + # civitai user gallery information start selected_model_id.change( fn=on_selected_model_id_change, @@ -227,7 +244,7 @@ def on_ui(recipe_input): ] ) - return selected_model_id + return selected_model_id , refresh_information def on_send_to_recipe_click(img_file_info, img_index, usergal_images): try: @@ -503,6 +520,13 @@ def get_user_gallery(modelid, page_url, show_nsfw): img_url = image_info['url'] gallery_img_file = setting.get_image_url_to_gallery_file(image_info['url']) + + # NSFW filtering .... + if setting.NSFW_filtering_enable: + if not setting.NSFW_level[image_info["nsfwLevel"]]: + gallery_img_file = setting.nsfw_disable_image + meta_string = "" + if os.path.isfile(gallery_img_file): img_url = gallery_img_file diff --git a/scripts/civitai_manager_libs/civitai_shortcut_action.py b/scripts/civitai_manager_libs/civitai_shortcut_action.py index 2992105..dee44ce 100644 --- a/scripts/civitai_manager_libs/civitai_shortcut_action.py +++ b/scripts/civitai_manager_libs/civitai_shortcut_action.py @@ -10,12 +10,16 @@ from . import model_action from . import ishortcut_action from . import civitai_gallery_action -def on_ui(recipe_input): +def on_shortcut_input_change(shortcut_input): + return shortcut_input, gr.update(selected="Shortcut") + +def on_ui(recipe_input, shortcut_input, civitai_tabs): with gr.Row(visible=False): sc_modelid = gr.Textbox() update_informations = gr.Textbox() current_information_tabs = gr.State(0) + refresh_NSFW = gr.Textbox() with gr.Column(scale=setting.shortcut_browser_screen_split_ratio): with gr.Tabs() as civitai_shortcut_tabs: @@ -41,7 +45,13 @@ def on_ui(recipe_input): scan_new_version_btn = gr.Button(value="Scan new version model", variant="primary") sc_new_version_gallery = gr.Gallery(label="SC New Version Gallery", elem_id="sc_new_version_gallery", show_label=False).style(grid=[setting.shortcut_column], height="fit", object_fit=setting.gallery_thumbnail_image_style) gr.Markdown(value="The feature is to search for new versions of models on Civitai among the downloaded ones.", visible=True) - + with gr.TabItem("NSFW Filter"): + with gr.Row(): + with gr.Column(): + nsfw_filter_enable = gr.Dropdown(value='On', choices=['On','Off'], label='NSFW Filtering', interactive=True) + nsfw_level = gr.Dropdown(value=setting.get_NSFW_Level(), choices=setting.NSFW_level.keys(), label='NSFW Filtering Level', visible=True, interactive=True) + nsfw_save_btn = gr.Button(value="Save NSFW Setting", variant="primary", visible=True) + with gr.Column(scale=(setting.shortcut_browser_screen_split_ratio_max-setting.shortcut_browser_screen_split_ratio)): with gr.Tabs() as civitai_information_tabs: with gr.TabItem("Model Information" , id="civitai_info"): @@ -50,17 +60,67 @@ def on_ui(recipe_input): with gr.TabItem("User Gallery" , id="gallery_info"): with gr.Row(): - gallery_modelid = civitai_gallery_action.on_ui(recipe_input) + gallery_modelid, refresh_gallery_information = civitai_gallery_action.on_ui(recipe_input) with gr.TabItem("Downloaded Model Information" , id="download_info"): with gr.Row(): downloadinfo_modelid , refresh_download_information = model_action.on_ui() + + # NSFW Filter Setting Refresh + refresh_NSFW.change( + fn=on_refresh_NSFW_change, + inputs=None, + outputs=[ + nsfw_filter_enable, + nsfw_level + ] + ) + + nsfw_filter_enable.select( + fn=on_nsfw_filter, + inputs=[ + nsfw_filter_enable, + nsfw_level + ], + outputs=[ + nsfw_level, + refresh_civitai_information, + refresh_gallery_information + ] + ) + + nsfw_level.select( + fn=on_nsfw_filter, + inputs=[ + nsfw_filter_enable, + nsfw_level + ], + outputs=[ + nsfw_level, + refresh_civitai_information, + refresh_gallery_information + ] + ) + + nsfw_save_btn.click(fn=on_nsfw_save_btn_click) + + # shortcut information 에서 넘어올때는 새로운 레시피를 만든다. + shortcut_input.change( + fn=on_shortcut_input_change, + inputs=[ + shortcut_input + ], + outputs=[ + sc_modelid, + civitai_tabs, + ], show_progress=False + ) scan_new_version_btn.click(on_scan_new_version_btn,shortcut_new_version_type,sc_new_version_gallery) sc_gallery.select(on_sc_gallery_select, None, [sc_modelid], show_progress=False) sc_new_version_gallery.select(on_sc_gallery_select, None, [sc_modelid], show_progress=False) update_modelfolder_btn.click(on_update_modelfolder_btn_click,None,refresh_sc_browser) - civitai_shortcut_tabs.select(on_civitai_shortcut_tabs_select,None,refresh_sc_browser) + civitai_shortcut_tabs.select(on_civitai_shortcut_tabs_select,None,[refresh_sc_browser,refresh_NSFW],show_progress=False) update_informations.change( fn=on_sc_modelid_change, @@ -125,11 +185,29 @@ def on_ui(recipe_input): return refresh_sc_browser, refresh_civitai_information +def on_refresh_NSFW_change(): + if setting.NSFW_filtering_enable: + return gr.update(value="On") , gr.update(visible=True, value=setting.get_NSFW_Level()) + else: + return gr.update(value="Off") , gr.update(visible=False, value=setting.get_NSFW_Level()) + +def on_nsfw_filter(enable, level): + current_time = datetime.datetime.now() + setting.set_NSFW(True if enable == "On" else False , level) + + return gr.update(visible=True if enable == "On" else False, value=level), current_time, current_time + +def on_nsfw_save_btn_click(): + setting.save_NSFW() + def on_civitai_shortcut_tabs_select(evt: gr.SelectData): if evt.index == 1: current_time = datetime.datetime.now() - return current_time - return gr.update(visible=False) + return current_time,gr.update(visible=False) + elif evt.index == 3: + current_time = datetime.datetime.now() + return gr.update(visible=False), current_time + return gr.update(visible=False),gr.update(visible=False) def on_civitai_information_tabs_select(evt: gr.SelectData): current_time = datetime.datetime.now() diff --git a/scripts/civitai_manager_libs/ishortcut_action.py b/scripts/civitai_manager_libs/ishortcut_action.py index 256b2de..6cc6ef1 100644 --- a/scripts/civitai_manager_libs/ishortcut_action.py +++ b/scripts/civitai_manager_libs/ishortcut_action.py @@ -15,11 +15,14 @@ from . import downloader def on_ui(refresh_sc_browser:gr.Textbox(), recipe_input): with gr.Column(scale=3): - with gr.Accordion("#", open=True) as model_title_name: + with gr.Accordion("#", open=True) as model_title_name: + # with gr.Row(): + # nsfw_level = gr.Dropdown(label="NSFW LEVEL", choices=["None","Soft","Mature","X"], interactive=True, value="None") + # with gr.Row(): versions_list = gr.Dropdown(label="Model Version", choices=[setting.NORESULT], interactive=True, value=setting.NORESULT) with gr.Tabs(): - with gr.TabItem("Images" , id="Model_Images"): + with gr.TabItem("Images" , id="Model_Images"): saved_gallery = gr.Gallery(show_label=False, elem_id="saved_gallery").style(grid=[setting.gallery_column],height=setting.information_gallery_height, object_fit=setting.gallery_thumbnail_image_style) with gr.Row(): download_images = gr.Button(value="Download Images") @@ -877,10 +880,17 @@ def get_version_description_gallery(version_info): for ver in ver_images: description_img = setting.get_image_url_to_shortcut_file(modelid,versionid,ver['url']) meta_string = "" + + # NSFW filtering .... + if setting.NSFW_filtering_enable: + if not setting.NSFW_level[ver["nsfw"]]: + description_img = setting.nsfw_disable_image + meta_string = "" + if os.path.isfile(description_img): meta_string = util.convert_civitai_meta_to_stable_meta(ver['meta']) images_url.append(description_img) - images_meta.append(meta_string) + images_meta.append(meta_string) except: return None, None diff --git a/scripts/civitai_manager_libs/recipe.py b/scripts/civitai_manager_libs/recipe.py index 006c25f..7f9f524 100644 --- a/scripts/civitai_manager_libs/recipe.py +++ b/scripts/civitai_manager_libs/recipe.py @@ -4,6 +4,80 @@ import json from . import util from . import setting +def get_list(search=None, classification=None, shortcuts=None): + + RecipeCollection = load() + if not RecipeCollection: + return + + result_list = dict() + + keys, descs, notes = util.get_search_keyword(search) + + # filtering classification + for name, v in RecipeCollection.items(): + if classification: + if v['classification'] and classification == v['classification']: + result_list[name] = v + else: + result_list[name] = v + + # filtering shortcuts + if shortcuts: + shortcut_list = dict() + for name, v in result_list.items(): + if 'shortcuts' in v.keys(): + different_shortcuts = set(shortcuts) - set(v["shortcuts"]) + if not different_shortcuts: + shortcut_list[name]= v + + result_list = shortcut_list + + # filtering key + if keys: + key_list = dict() + for name, v in result_list.items(): + for key in keys: + if key in name.lower(): + key_list[name] = v + break + result_list = key_list + + # filtering descs + if descs: + desc_list = dict() + for name, v in result_list.items(): + if not v['description']: + continue + + for desc in descs: + if desc in v['description'].lower(): + desc_list[name] = v + break + result_list = desc_list + + # 필요한것으로 변환 + recipelist = list() + for name in result_list.keys(): + recipelist.append(name) + + return recipelist + +def get_reference_shortcuts(): + RecipeCollection = load() + reference_shortcuts = list() + + if not RecipeCollection: + return reference_shortcuts + + for v in RecipeCollection.values(): + if 'shortcuts' in v.keys(): + reference_shortcuts.extend(v['shortcuts']) + + reference_shortcuts = list(set(reference_shortcuts)) + + return reference_shortcuts + def get_classifications(): RecipeCollection = load() classifications = list() @@ -34,6 +108,17 @@ def is_classifications(classification): return False +def get_recipe_shortcuts(recipe): + if not recipe: + return None + + RecipeCollection = load() + if recipe in RecipeCollection: + if 'shortcuts' in RecipeCollection[recipe]: + return RecipeCollection[recipe]['shortcuts'] + + return None + def update_recipe_shortcuts(recipe, shortcuts:list): if not recipe: return @@ -119,31 +204,6 @@ def get_recipe(s_name): return None -# def get_list(): - -# RecipeCollection = load() - -# tmp_recipe_name = [] -# if RecipeCollection: -# tmp_recipe_name = [k for k in RecipeCollection.keys()] - -# return tmp_recipe_name - -def get_list(key=None): - - RecipeCollection = load() - - result = [] - if RecipeCollection: - for name, value in RecipeCollection.items(): - if key: - if value['classification'] and key == value['classification']: - result.append(name) - else: - result.append(name) - - return result - #================= raw =================================== def update_shortcuts(RecipeCollection:dict, recipe, shortcuts:list): diff --git a/scripts/civitai_manager_libs/recipe_action.py b/scripts/civitai_manager_libs/recipe_action.py index e4a5595..c4f8c2e 100644 --- a/scripts/civitai_manager_libs/recipe_action.py +++ b/scripts/civitai_manager_libs/recipe_action.py @@ -9,10 +9,14 @@ from . import setting from . import recipe from . import prompt # from . import prompt_ui +from . import sc_browser_page +from . import ishortcut + +from . import recipe_browser_page from PIL import Image - -def on_ui(recipe_input, civitai_tabs): + +def on_ui(recipe_input, shortcut_input, civitai_tabs): # data = '''Best quality, masterpiece, ultra high res, (photorealistic:1.4),girl, beautiful_face, detailed skin,upper body, # Negative prompt: ng_deepnegative_v1_75t, badhandv4 (worst quality:2), (low quality:2), (normal quality:2), lowres, bad anatomy, bad hands, normal quality, ((monochrome)), ((grayscale)), ng_deepnegative_v1_75t, badhandv4 (worst quality:2), (low quality:2), (normal quality:2), lowres, bad anatomy, bad hands, normal quality, ((monochrome)), ((grayscale)), @@ -23,14 +27,15 @@ def on_ui(recipe_input, civitai_tabs): with gr.Column(scale=setting.shortcut_browser_screen_split_ratio): with gr.Tabs(): with gr.TabItem("Prompt Recipe List"): - recipe_classification_list = gr.Dropdown(label="Prompt Recipe Classification", choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER, interactive=True, multiselect=False) - recipe_list = gr.Dropdown(label="Prompt Recipe List", choices=[setting.NEWRECIPE] + recipe.get_list(), value=setting.NEWRECIPE, interactive=True, multiselect=None) - recipe_drop_image = gr.Image(type="pil", label="Drop image").style(height='100%') + recipe_new_btn = gr.Button(value="New Recipe", variant="primary") + recipe_list, recipe_gallery, refresh_recipe_browser = recipe_browser_page.on_ui() + with gr.TabItem("Generate Prompt From Image"): + recipe_drop_image = gr.Image(type="pil", label="Drop image").style(height='100%') with gr.Column(scale=(setting.shortcut_browser_screen_split_ratio_max-setting.shortcut_browser_screen_split_ratio)): with gr.Accordion(label=setting.NEWRECIPE, open=True) as recipe_title_name: with gr.Row(): - with gr.Column(scale=5): + with gr.Column(scale=4): recipe_name = gr.Textbox(label="Name", value="", interactive=True, lines=1, placeholder="Please enter the prompt recipe name.").style(container=True) recipe_desc = gr.Textbox(label="Description", value="",interactive=True, lines=3, placeholder="Please enter the prompt recipe description.").style(container=True, show_copy_button=True) recipe_prompt = gr.Textbox(label="Prompt", placeholder="Prompt", value="", lines=3 ,interactive=True).style(container=True, show_copy_button=True) @@ -50,32 +55,76 @@ def on_ui(recipe_input, civitai_tabs): recipe_update_btn = gr.Button(value="Update", variant="primary", visible=False) with gr.Accordion("Delete Prompt Recipe", open=False): recipe_delete_btn = gr.Button(value="Delete", variant="primary") - with gr.Column(scale=2): + with gr.Column(scale=2): gr.Markdown("###") - recipe_image = gr.Image(type="pil", interactive=True, label="Prompt recipe image").style(height='100%') - gr.Markdown("This image does not influence the prompt on the left. You can choose any image that matches the created prompt.") - # recipe_image_info = gr.Textbox(label="Ganerate Infomation", lines=6, visible=True) + with gr.Tabs(): + with gr.TabItem("Reference Image"): + recipe_image = gr.Image(type="pil", interactive=True, label="Prompt recipe image").style(height='100%') + gr.Markdown("This image does not influence the prompt on the left. You can choose any image that matches the created prompt.") + # recipe_image_info = gr.Textbox(label="Ganerate Infomation", lines=6, visible=True) + with gr.TabItem("Reference Models"): + reference_gallery = gr.Gallery(elem_id="reference_gallery", show_label=False).style(grid=[2], height="full", object_fit=setting.gallery_thumbnail_image_style, preview=False) + reference_delete = gr.Checkbox(label="Delete from references when selecting a thumbnail.", value=False) + with gr.Accordion("Add Reference Shortcut Items", open=False): + reference_sc_gallery, refresh_reference_sc_browser, refresh_reference_sc_gallery = sc_browser_page.on_ui() with gr.Row(visible=False): - refresh_recipe = gr.Textbox() - recipe_generate_data = gr.Textbox() + selected_recipe_name = gr.Textbox() + refresh_recipe = gr.Textbox() + recipe_generate_data = gr.Textbox() + + reference_shortcuts = gr.State() + refresh_reference_gallery = gr.Textbox() try: modules.generation_parameters_copypaste.bind_buttons(send_to_buttons, recipe_image, recipe_output) except: pass + + # reference shortcuts + reference_gallery.select( + fn=on_reference_gallery_select, + inputs=[ + reference_shortcuts, + reference_delete + ], + outputs=[ + reference_shortcuts, + refresh_reference_gallery, + reference_gallery, + shortcut_input + ], + show_progress=False + ) + + refresh_reference_gallery.change( + fn=on_reference_gallery_loading, + inputs=[ + reference_shortcuts, + ], + outputs=[ + reference_gallery + ], + show_progress=False + ) + + reference_sc_gallery.select( + fn=on_reference_sc_gallery_select, + inputs=[ + reference_shortcuts + ], + outputs=[ + reference_shortcuts, + refresh_reference_gallery, + ], + show_progress=False + ) + # reference shortcuts recipe_prompt.blur(generate_prompt,[recipe_prompt,recipe_negative,recipe_option],recipe_output) recipe_negative.blur(generate_prompt,[recipe_prompt,recipe_negative,recipe_option],recipe_output) recipe_option.blur(generate_prompt,[recipe_prompt,recipe_negative,recipe_option],recipe_output) - recipe_classification_list.change( - fn=on_recipe_classification_list_change, - inputs=recipe_classification_list, - outputs=[ - recipe_list - ] - ) - + # 이렇게 합시다. # send to reciepe -> recipe_input : input drop image, reciep image, call recipe_generate_data(drop image) -> recipe_generate_data: img info 생성 ,분석, 갱신 # drop image -> recipe_drop_image.upload(drop image) : reciep image, call recipe_generate_data(drop image) -> recipe_generate_data: img info 생성 ,분석, 갱신 @@ -101,6 +150,8 @@ def on_ui(recipe_input, civitai_tabs): recipe_input ], outputs=[ + selected_recipe_name, + recipe_drop_image, recipe_image, recipe_generate_data, @@ -108,13 +159,14 @@ def on_ui(recipe_input, civitai_tabs): civitai_tabs, # 새 레시피 상태로 만든다. - recipe_list, recipe_name, recipe_desc, recipe_classification, recipe_title_name, recipe_create_btn, - recipe_update_btn + recipe_update_btn, + reference_shortcuts, + refresh_reference_gallery ], cancels=recipe_drop_image_upload ) @@ -134,32 +186,42 @@ def on_ui(recipe_input, civitai_tabs): refresh_recipe.change( fn=on_refresh_recipe_change, - inputs=[ - recipe_classification_list, - recipe_list - ], + inputs=None, outputs=[ - recipe_classification_list, - recipe_list, - # recipe_name, - # recipe_desc, - # recipe_prompt, - # recipe_negative, - # recipe_option, - # recipe_output, - # recipe_classification, - # recipe_title_name, - # recipe_image, - # recipe_create_btn, - # recipe_update_btn + refresh_reference_sc_browser, + refresh_recipe_browser ], show_progress=False ) - recipe_list.select( - fn=on_recipe_list_select, + # recipe_list.select( + # fn=on_recipe_list_select, + # inputs=None, + # outputs=[ + # selected_recipe_name, + # recipe_name, + # recipe_desc, + # recipe_prompt, + # recipe_negative, + # recipe_option, + # recipe_output, + # recipe_classification, + # recipe_title_name, + # recipe_image, + # recipe_drop_image, + # recipe_create_btn, + # recipe_update_btn, + # reference_shortcuts, + # refresh_reference_gallery + # ], + # cancels=recipe_drop_image_upload + # ) + + recipe_gallery.select( + fn=on_recipe_gallery_select, inputs=None, outputs=[ + selected_recipe_name, recipe_name, recipe_desc, recipe_prompt, @@ -171,67 +233,90 @@ def on_ui(recipe_input, civitai_tabs): recipe_image, recipe_drop_image, recipe_create_btn, - recipe_update_btn + recipe_update_btn, + reference_shortcuts, + refresh_reference_gallery ], cancels=recipe_drop_image_upload + ) + + recipe_new_btn.click( + fn=on_recipe_new_btn_click, + inputs=None, + outputs=[ + selected_recipe_name, + recipe_name, + recipe_desc, + recipe_prompt, + recipe_negative, + recipe_option, + recipe_output, + recipe_classification, + recipe_title_name, + recipe_image, + recipe_drop_image, + recipe_create_btn, + recipe_update_btn, + reference_shortcuts, + refresh_reference_gallery + ] ) - + recipe_create_btn.click( fn=on_recipe_create_btn_click, inputs=[ - recipe_classification_list, recipe_name, recipe_desc, recipe_prompt, recipe_negative, recipe_option, recipe_classification, - recipe_image + recipe_image, + reference_shortcuts ], outputs=[ - recipe_classification_list, - recipe_list, + selected_recipe_name, recipe_classification, recipe_title_name, recipe_create_btn, - recipe_update_btn + recipe_update_btn, + refresh_recipe_browser ] ) recipe_update_btn.click( fn=on_recipe_update_btn_click, inputs=[ - recipe_classification_list, - recipe_list, + selected_recipe_name, recipe_name, recipe_desc, recipe_prompt, recipe_negative, recipe_option, recipe_classification, - recipe_image + recipe_image, + reference_shortcuts ], outputs=[ - recipe_classification_list, - recipe_list, + selected_recipe_name, recipe_classification, - recipe_title_name, + recipe_title_name, + refresh_recipe_browser ] ) recipe_delete_btn.click( fn=on_recipe_delete_btn_click, inputs=[ - recipe_classification_list, - recipe_list, + selected_recipe_name ], - outputs=[ - recipe_classification_list, - recipe_list, + outputs=[ + selected_recipe_name, recipe_classification, recipe_title_name, recipe_create_btn, - recipe_update_btn + recipe_update_btn, + refresh_recipe_browser ] ) @@ -329,17 +414,19 @@ def get_recipe_information(select_name): return description, Prompt, negativePrompt, options, gen_string, classification, imagefile def on_recipe_input_change(recipe_input): - if recipe_input: - current_time = datetime.datetime.now() - return recipe_input, recipe_input, current_time, None, gr.update(selected="Recipe"),\ - gr.update(value=setting.NEWRECIPE), gr.update(value=""), gr.update(value=""), \ + current_time = datetime.datetime.now() + if recipe_input: + return gr.update(value=""), recipe_input, recipe_input, current_time, None, gr.update(selected="Recipe"),\ + gr.update(value=""), gr.update(value=""), \ gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER) ,gr.update(label=setting.NEWRECIPE),\ - gr.update(visible=True), gr.update(visible=False) + gr.update(visible=True), gr.update(visible=False),\ + None, current_time - return gr.update(visible=True),gr.update(visible=True),gr.update(visible=False),gr.update(visible=False),gr.update(selected="Recipe"),\ - gr.update(visible=True), gr.update(value=""), gr.update(value=""), \ + return gr.update(visible=False),gr.update(visible=True),gr.update(visible=True),gr.update(visible=False),gr.update(visible=False),gr.update(selected="Recipe"),\ + gr.update(value=""), gr.update(value=""), \ gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER), gr.update(label=setting.NEWRECIPE),\ - gr.update(visible=True), gr.update(visible=False) + gr.update(visible=True), gr.update(visible=False),\ + None, current_time def on_recipe_drop_image_upload(recipe_img): if recipe_img: @@ -359,42 +446,50 @@ def on_recipe_generate_data_change(recipe_img): return gr.update(value=positivePrompt), gr.update(value=negativePrompt), gr.update(value=options), gr.update(value=gen_string) return gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value="") -def on_recipe_classification_list_change(recipe_classification): - if recipe_classification and recipe_classification != setting.PLACEHOLDER: - return gr.update(choices=[setting.NEWRECIPE] + recipe.get_list(recipe_classification)) - return gr.update(choices=[setting.NEWRECIPE] + recipe.get_list()) +def on_refresh_recipe_change(): + current_time = datetime.datetime.now() + return current_time, current_time -def on_refresh_recipe_change(selected_classification, select_name): - return gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications()), gr.update(choices=[setting.NEWRECIPE] + recipe.get_list(selected_classification) if selected_classification != setting.PLACEHOLDER else recipe.get_list()) - -# def on_refresh_recipe_change(select_classification, select_name): -# if select_name != setting.NEWRECIPE: - -# description, Prompt, negativePrompt, options, gen_string, classification, imagefile = get_recipe_information(select_name) +# def on_recipe_list_select(evt: gr.SelectData): +# current_time = datetime.datetime.now() +# select_name = evt.value + +# description, Prompt, negativePrompt, options, gen_string, classification, imagefile = get_recipe_information(select_name) + +# if imagefile: # if not os.path.isfile(imagefile): # imagefile = None - -# return gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=select_classification), gr.update(choices=[setting.NEWRECIPE] + recipe.get_list(select_classification) if select_classification != setting.PLACEHOLDER else recipe.get_list(), value=select_name),gr.update(value=select_name), gr.update(value=description), gr.update(value=Prompt), gr.update(value=negativePrompt), gr.update(value=options), gr.update(value=gen_string), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=classification) ,gr.update(label=select_name),imagefile,\ -# gr.update(visible=False), gr.update(visible=True) -# return gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=select_classification), gr.update(choices=[setting.NEWRECIPE] + recipe.get_list(select_classification) if select_classification != setting.PLACEHOLDER else recipe.get_list(), value=setting.NEWRECIPE), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER), gr.update(label=setting.NEWRECIPE),None,\ -# gr.update(visible=True), gr.update(visible=False) + +# shortcuts = recipe.get_recipe_shortcuts(select_name) + +# return gr.update(value=select_name),gr.update(value=select_name),gr.update(value=description), gr.update(value=Prompt), gr.update(value=negativePrompt), gr.update(value=options), gr.update(value=gen_string), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=classification), gr.update(label=select_name),imagefile,None,\ +# gr.update(visible=False), gr.update(visible=True),\ +# shortcuts, current_time -def on_recipe_list_select(evt: gr.SelectData): - if evt.value != setting.NEWRECIPE: - select_name = evt.value +def on_recipe_gallery_select(evt: gr.SelectData): + current_time = datetime.datetime.now() + select_name = evt.value + + description, Prompt, negativePrompt, options, gen_string, classification, imagefile = get_recipe_information(select_name) + + if imagefile: + if not os.path.isfile(imagefile): + imagefile = None + + shortcuts = recipe.get_recipe_shortcuts(select_name) + + return gr.update(value=select_name),gr.update(value=select_name),gr.update(value=description), gr.update(value=Prompt), gr.update(value=negativePrompt), gr.update(value=options), gr.update(value=gen_string), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=classification), gr.update(label=select_name),imagefile,None,\ + gr.update(visible=False), gr.update(visible=True),\ + shortcuts, current_time + +def on_recipe_new_btn_click(): + current_time = datetime.datetime.now() + return gr.update(value=""),gr.update(value=""),gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER), gr.update(label=setting.NEWRECIPE), None, None,\ + gr.update(visible=True), gr.update(visible=False),\ + None, current_time - description, Prompt, negativePrompt, options, gen_string, classification, imagefile = get_recipe_information(select_name) - - if imagefile: - if not os.path.isfile(imagefile): - imagefile = None - - return gr.update(value=select_name),gr.update(value=description), gr.update(value=Prompt), gr.update(value=negativePrompt), gr.update(value=options), gr.update(value=gen_string), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=classification), gr.update(label=select_name),imagefile,None,\ - gr.update(visible=False), gr.update(visible=True) - return gr.update(value=""),gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(value=""), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER), gr.update(label=setting.NEWRECIPE), None, None,\ - gr.update(visible=True), gr.update(visible=False) - -def on_recipe_create_btn_click(selected_classification, recipe_name, recipe_desc, recipe_prompt, recipe_negative, recipe_option, recipe_classification, recipe_image=None): +def on_recipe_create_btn_click(recipe_name, recipe_desc, recipe_prompt, recipe_negative, recipe_option, recipe_classification, recipe_image=None, recipe_shortcuts=None): + current_time = datetime.datetime.now() s_classification = setting.PLACEHOLDER if recipe_name and len(recipe_name.strip()) > 0 and recipe_name != setting.NEWRECIPE: pmt = dict() @@ -421,20 +516,23 @@ def on_recipe_create_btn_click(selected_classification, recipe_name, recipe_desc recipe_imgfile = os.path.join(setting.shortcut_recipe_folder,unique_filename) recipe_image.save(recipe_imgfile) recipe.update_recipe_image(recipe_name,unique_filename) - - return gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications()), gr.update(choices=[setting.NEWRECIPE] + recipe.get_list(selected_classification) if selected_classification != setting.PLACEHOLDER else recipe.get_list(), value=recipe_name),\ + recipe.update_recipe_shortcuts(recipe_name, recipe_shortcuts) + + return gr.update(value=recipe_name),\ gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=s_classification), gr.update(label=recipe_name),\ - gr.update(visible=False),gr.update(visible=True) - return gr.update(visible=True), gr.update(visible=True), \ + gr.update(visible=False),gr.update(visible=True),\ + current_time + return gr.update(value=""),\ gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=s_classification), gr.update(label=setting.NEWRECIPE),\ - gr.update(visible=True),gr.update(visible=False) + gr.update(visible=True),gr.update(visible=False),\ + gr.update(visible=False) -def on_recipe_update_btn_click(selected_classification, recipe_list, recipe_name ,recipe_desc, recipe_prompt, recipe_negative, recipe_option, recipe_classification, recipe_image=None): +def on_recipe_update_btn_click(select_name, recipe_name ,recipe_desc, recipe_prompt, recipe_negative, recipe_option, recipe_classification, recipe_image=None, recipe_shortcuts=None): chg_name = setting.NEWRECIPE s_classification = setting.PLACEHOLDER - if recipe_list and recipe_list != setting.NEWRECIPE and recipe_name and recipe_name != setting.NEWRECIPE: + if select_name and select_name != setting.NEWRECIPE and recipe_name and recipe_name != setting.NEWRECIPE: pmt = dict() pmt['prompt'] = recipe_prompt @@ -452,7 +550,7 @@ def on_recipe_update_btn_click(selected_classification, recipe_list, recipe_name recipe_classification = recipe_classification.strip() s_classification = recipe_classification - if recipe.update_recipe(recipe_list, recipe_name, recipe_desc, pmt, recipe_classification): + if recipe.update_recipe(select_name, recipe_name, recipe_desc, pmt, recipe_classification): chg_name = recipe_name if recipe_image: if not os.path.exists(setting.shortcut_recipe_folder): @@ -464,24 +562,77 @@ def on_recipe_update_btn_click(selected_classification, recipe_list, recipe_name else: recipe.update_recipe_image(recipe_name,None) - if not recipe.is_classifications(selected_classification): - selected_classification = setting.PLACEHOLDER - - return gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=selected_classification), gr.update(choices=[setting.NEWRECIPE] + recipe.get_list(selected_classification) if selected_classification != setting.PLACEHOLDER else recipe.get_list(), value=chg_name), \ - gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=s_classification), gr.update(label=chg_name) + recipe.update_recipe_shortcuts(recipe_name, recipe_shortcuts) + + current_time = datetime.datetime.now() + return gr.update(value=chg_name), gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=s_classification), gr.update(label=chg_name), current_time -def on_recipe_delete_btn_click(selected_classification, select_name): - if select_name and select_name.strip() != setting.NEWRECIPE: +def on_recipe_delete_btn_click(select_name): + if select_name: recipe.delete_recipe(select_name) - - if not recipe.is_classifications(selected_classification): - selected_classification = setting.PLACEHOLDER - - return gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=selected_classification), gr.update(choices=[setting.NEWRECIPE] + recipe.get_list(selected_classification) if selected_classification != setting.PLACEHOLDER else recipe.get_list(), value=setting.NEWRECIPE), \ + + current_time = datetime.datetime.now() + return gr.update(value=""),\ gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER), gr.update(label=setting.NEWRECIPE),\ - gr.update(visible=True),gr.update(visible=False) - + gr.update(visible=True),gr.update(visible=False),\ + current_time + +# reference shortcuts +def on_reference_gallery_loading(shortcuts): + ISC = ishortcut.load() + if not ISC: + return None + shotcutlist = list() + + if shortcuts: + result_list = list() + for mid in shortcuts: + mid = str(mid) + if mid in ISC: + result_list.append(ISC[mid]) + + for v in result_list: + if v: + if ishortcut.is_sc_image(v['id']): + shotcutlist.append((os.path.join(setting.shortcut_thumbnail_folder,f"{v['id']}{setting.preview_image_ext}"),setting.set_shortcutname(v['name'],v['id']))) + else: + shotcutlist.append((setting.no_card_preview_image,setting.set_shortcutname(v['name'],v['id']))) + + return shotcutlist + +def on_reference_sc_gallery_select(evt: gr.SelectData, shortcuts): + clf = None + current_time = datetime.datetime.now() + + if evt.value: + + shortcut = evt.value + sc_model_id = setting.get_modelid_from_shortcutname(shortcut) + if not shortcuts: + shortcuts = list() + + if sc_model_id not in shortcuts: + shortcuts.append(sc_model_id) + + return shortcuts, current_time + return shortcuts, None + +def on_reference_gallery_select(evt: gr.SelectData, shortcuts, delete_opt=True): + if evt.value: + shortcut = evt.value + sc_model_id = setting.get_modelid_from_shortcutname(shortcut) + current_time = datetime.datetime.now() + + if not shortcuts: + shortcuts = list() + + if sc_model_id in shortcuts: + if delete_opt: + shortcuts.remove(sc_model_id) + + return shortcuts, current_time, None, gr.update(visible=False) if delete_opt else sc_model_id + return shortcuts, None, None, gr.update(visible=False) \ No newline at end of file diff --git a/scripts/civitai_manager_libs/recipe_browser_page.py b/scripts/civitai_manager_libs/recipe_browser_page.py new file mode 100644 index 0000000..604a29c --- /dev/null +++ b/scripts/civitai_manager_libs/recipe_browser_page.py @@ -0,0 +1,355 @@ +import gradio as gr +import math +import os +import datetime + +from . import util +from . import setting +from . import recipe +from . import ishortcut + +from PIL import Image + +def on_ui(): + + recipe_thumb_list, thumb_list , thumb_totals, thumb_max_page = get_recipe_list(None,None,None,1) + reference_list, reference_totals, reference_max_page = get_recipe_reference_list(1) + + recipe_list = gr.Dropdown(label="Recipe List", choices=recipe_thumb_list, interactive=True, multiselect=None, visible=False) + recipe_gallery_page = gr.Slider(minimum=1, maximum=thumb_max_page, value=1, step=1, label=f"Total {thumb_max_page} Pages", interactive=True, visible=True) + recipe_gallery = gr.Gallery(value=thumb_list, show_label=False).style(grid=[setting.shortcut_column], height="full", object_fit=setting.gallery_thumbnail_image_style, preview=False) + + with gr.Accordion(label="Search Recipe", open=True): + recipe_search = gr.Textbox(label="Search", value="", placeholder="Search name, #description ....",interactive=True, lines=1) + recipe_classification_list = gr.Dropdown(label="Filter Recipe Classification", choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=setting.PLACEHOLDER, interactive=True, multiselect=False) + + with gr.Accordion(label="Filter Reference Shortcut Items", open=False): + recipe_reference_select_gallery = gr.Gallery(elem_id="recipe_select_reference_gallery", label="Filter Reference Models").style(grid=[setting.shortcut_column], height="full", object_fit=setting.gallery_thumbnail_image_style, preview=False) + recipe_reference_gallery_page = gr.Slider(minimum=1, maximum=reference_max_page, value=1, step=1, label=f"Total {reference_max_page} Pages", interactive=True, visible=True) + recipe_reference_gallery = gr.Gallery(value=reference_list, show_label=False).style(grid=[setting.shortcut_column], height="full", object_fit=setting.gallery_thumbnail_image_style, preview=False) + + with gr.Row(visible=False): + # recipe_browser 갱신 트리거 + refresh_recipe_browser = gr.Textbox() + + # 강제 검색 트리거 + refresh_recipe_search = gr.Textbox() + + # recipe_reference_gallery 갱신 트리거 + refresh_recipe_reference_select_gallery = gr.Textbox() + + # 현재 선택된 리퍼런스를 저장하는 곳 + recipe_reference_select = gr.State() + + # recipe_reference_select_shortcuts_gallery 에서 선택할때 작용 + recipe_reference_select_gallery.select( + fn=on_recipe_reference_select_gallery_select, + inputs=[ + recipe_reference_select + ], + outputs=[ + recipe_reference_select, + recipe_reference_select_gallery, + refresh_recipe_reference_select_gallery, + ], + show_progress=False + ) + + # recipe_reference_select_gallery를 recipe_reference_select 값에서 갱신 + refresh_recipe_reference_select_gallery.change( + fn=on_recipe_reference_select_gallery_loading, + inputs=[ + recipe_reference_select, + ], + outputs=[ + recipe_reference_select_gallery, + refresh_recipe_search + ], + show_progress=False + ) + + # recipe_reference_shortcuts_gallery를 선택할때 작용 + recipe_reference_gallery.select( + fn=on_recipe_reference_gallery_select, + inputs=[ + recipe_reference_select + ], + outputs=[ + recipe_reference_select, + refresh_recipe_reference_select_gallery, + ], + show_progress=False + ) + + recipe_reference_gallery_page.release( + fn = on_recipe_reference_gallery_page, + inputs = [ + recipe_reference_gallery_page + ], + outputs=[ + recipe_reference_gallery, + refresh_recipe_reference_select_gallery + ] + ) + + #============================== + + recipe_gallery_page.release( + fn = on_recipe_gallery_page, + inputs = [ + recipe_search, + recipe_classification_list, + recipe_reference_select, + recipe_gallery_page + ], + outputs=[ + recipe_gallery + ] + ) + + refresh_recipe_search.change( + fn=on_recipe_list_search, + inputs=[ + recipe_search, + recipe_classification_list, + recipe_reference_select + ], + outputs=[ + recipe_list, + recipe_gallery + ] + ) + + refresh_recipe_browser.change( + fn=on_refresh_recipe_browser_change, + inputs= [ + recipe_search, + recipe_classification_list, + recipe_reference_select, + recipe_gallery_page, + + recipe_reference_gallery_page + ], + outputs=[ + recipe_classification_list, + recipe_list, + recipe_gallery, + recipe_gallery_page, + + recipe_reference_gallery, + recipe_reference_gallery_page + ], + show_progress=False + ) + + recipe_search.submit( + fn=on_recipe_list_search, + inputs=[ + recipe_search, + recipe_classification_list, + recipe_reference_select + ], + outputs=[ + recipe_list, + recipe_gallery + ] + ) + + recipe_classification_list.change( + fn=on_recipe_list_search, + inputs=[ + recipe_search, + recipe_classification_list, + recipe_reference_select + ], + outputs=[ + recipe_list, + recipe_gallery + ] + ) + + return recipe_list, recipe_gallery, refresh_recipe_browser + +def on_recipe_reference_gallery_page(page): + reference_list, reference_totals, reference_max_page = get_recipe_reference_list(page) + return gr.update(value=reference_list), reference_list + +def on_recipe_gallery_page(search, classification, shortcut, page = 0): + recipe_thumb_list, thumb_list , thumb_totals, thumb_max_page = get_recipe_list(search, classification, shortcut,page) + return gr.update(value=thumb_list) + +def get_recipe_reference_list(page = 0): + + total = 0 + max_page = 1 + shortlist = None + result = None + + reference_list = recipe.get_reference_shortcuts() + + if not reference_list: + return None, total, max_page + + if reference_list: + total = len(reference_list) + shortlist = reference_list + + if total > 0: + # page 즉 페이징이 아닌 전체가 필요할때도 총페이지 수를 구할때도 있으므로.. + # page == 0 은 전체 리스트를 반환한다 + if setting.shortcut_count_per_page > 0: + max_page = math.ceil(total / setting.shortcut_count_per_page) + + if page > 0 and setting.shortcut_count_per_page > 0: + item_start = setting.shortcut_count_per_page * (page - 1) + item_end = (setting.shortcut_count_per_page * page) + if total < item_end: + item_end = total + + shortlist = reference_list[item_start:item_end] + + if shortlist: + result = list() + for shortcut in shortlist: + v = ishortcut.get_shortcut_model(str(shortcut)) + if v: + if ishortcut.is_sc_image(v['id']): + result.append((os.path.join(setting.shortcut_thumbnail_folder,f"{v['id']}{setting.preview_image_ext}"), setting.set_shortcutname(v['name'],v['id']))) + else: + result.append((setting.no_card_preview_image,setting.set_shortcutname(v['name'],v['id']))) + + return result, total, max_page + +def get_recipe_list(search=None, classification=None, shortcut=None, page = 0): + + total = 0 + max_page = 1 + shortlist = None + result = None + txtlist = list() + + if classification == setting.PLACEHOLDER: + classification = None + + recipe_list = recipe.get_list(search, classification, shortcut) + + if not recipe_list: + return txtlist, None, total, max_page + + if recipe_list: + total = len(recipe_list) + shortlist = recipe_list + + if total > 0: + # page 즉 페이징이 아닌 전체가 필요할때도 총페이지 수를 구할때도 있으므로.. + # page == 0 은 전체 리스트를 반환한다 + if setting.shortcut_count_per_page > 0: + max_page = math.ceil(total / setting.shortcut_count_per_page) + + if page > 0 and setting.shortcut_count_per_page > 0: + item_start = setting.shortcut_count_per_page * (page - 1) + item_end = (setting.shortcut_count_per_page * page) + if total < item_end: + item_end = total + shortlist = recipe_list[item_start:item_end] + + if shortlist: + result = list() + txtlist = list() + for shortcut in shortlist: + re = recipe.get_recipe(shortcut) + if re: + if re["image"]: + dpimage = os.path.join(setting.shortcut_recipe_folder,f"{re['image']}") + + if os.path.isfile(dpimage): + result.append((dpimage,shortcut)) + else: + result.append((setting.no_card_preview_image,shortcut)) + else: + result.append((setting.no_card_preview_image,shortcut)) + txtlist.append(shortcut) + + return txtlist, result, total, max_page + +def on_recipe_list_search(search, classification, shortcut): + thumb_list = None + thumb_totals = 0 + thumb_max_page = 1 + + recipe_thumb_list, thumb_list , thumb_totals, thumb_max_page = get_recipe_list(search, classification, shortcut,1) + + return gr.update(choices=recipe_thumb_list), gr.update(value=thumb_list) + +def on_refresh_recipe_browser_change(search, classification, shortcut, sc_page, rs_page): + thumb_list = None + thumb_totals = 0 + thumb_max_page = 1 + + recipe_thumb_list, thumb_list , thumb_totals, thumb_max_page = get_recipe_list(search, classification, shortcut, sc_page) + + if not recipe.is_classifications(classification): + classification = setting.PLACEHOLDER + + reference_list, reference_totals, reference_max_page = get_recipe_reference_list(rs_page) + return gr.update(choices=[setting.PLACEHOLDER] + recipe.get_classifications(), value=classification), gr.update(choices=recipe_thumb_list), gr.update(value=thumb_list), gr.update(minimum=1, maximum=thumb_max_page, value=sc_page, step=1, label=f"Total {thumb_max_page} Pages"), \ + reference_list, gr.update(minimum=1, maximum=reference_max_page, value=rs_page, step=1, label=f"Total {reference_max_page} Pages") + +def on_recipe_reference_select_gallery_select(evt: gr.SelectData, shortcuts): + if evt.value: + shortcut = evt.value + sc_model_id = setting.get_modelid_from_shortcutname(shortcut) + current_time = datetime.datetime.now() + + if not shortcuts: + shortcuts = list() + + if sc_model_id in shortcuts: + shortcuts.remove(sc_model_id) + + return shortcuts, None, current_time + return shortcuts, None, None + +def on_recipe_reference_select_gallery_loading(shortcuts): + ISC = ishortcut.load() + if not ISC: + return None, gr.update(visible=False) + + shotcutlist = list() + + if shortcuts: + result_list = list() + for mid in shortcuts: + mid = str(mid) + if mid in ISC: + result_list.append(ISC[mid]) + + for v in result_list: + if v: + if ishortcut.is_sc_image(v['id']): + shotcutlist.append((os.path.join(setting.shortcut_thumbnail_folder,f"{v['id']}{setting.preview_image_ext}"),setting.set_shortcutname(v['name'],v['id']))) + else: + shotcutlist.append((setting.no_card_preview_image,setting.set_shortcutname(v['name'],v['id']))) + + current_time = datetime.datetime.now() + + return shotcutlist, current_time + +def on_recipe_reference_gallery_select(evt: gr.SelectData, shortcuts): + clf = None + current_time = datetime.datetime.now() + + if evt.value: + + shortcut = evt.value + sc_model_id = setting.get_modelid_from_shortcutname(shortcut) + + if not shortcuts: + shortcuts = list() + + if sc_model_id not in shortcuts: + shortcuts.append(str(sc_model_id)) + + return shortcuts, current_time + return shortcuts, None + diff --git a/scripts/civitai_manager_libs/sc_browser_page.py b/scripts/civitai_manager_libs/sc_browser_page.py index 879d725..9288976 100644 --- a/scripts/civitai_manager_libs/sc_browser_page.py +++ b/scripts/civitai_manager_libs/sc_browser_page.py @@ -96,18 +96,32 @@ def on_sc_gallery_page(sc_types, sc_search, sc_basemodels, sc_classifications, s def on_ui(): thumb_list , thumb_totals, thumb_max_page = get_thumbnail_list(None,False,None,None,None,1) - - with gr.Accordion("Search", open=True): - shortcut_type = gr.Dropdown(label='Filter Model Type', multiselect=True, choices=[k for k in setting.ui_typenames], interactive=True) - sc_search = gr.Textbox(label="Search", value="", placeholder="Search name, #tags, @personal note ....",interactive=True, lines=1) - sc_classification_list = gr.Dropdown(label='Classification',info="The selection options of classification are subject to the AND operation.", multiselect=True, choices=classification.get_list(), interactive=True) - shortcut_basemodel = gr.Dropdown(label='Filter Model BaseModel', multiselect=True, choices=[k for k in setting.model_basemodels], interactive=True) - show_downloaded_sc = gr.Checkbox(label="Show downloaded model's shortcut only", value=False) - # show_downloaded_sc = gr.Dropdown(label='Filter Downloaded Model View', multiselect=False, choices=[ALL_DOWNLOADED_MODEL,DOWNLOADED_MODEL,NOT_DOWNLOADED_MODEL], value=ALL_DOWNLOADED_MODEL, interactive=True) + + if setting.shortcut_browser_search_up: + with gr.Accordion("Search", open=True): + shortcut_type = gr.Dropdown(label='Filter Model Type', multiselect=True, choices=[k for k in setting.ui_typenames], interactive=True) + sc_search = gr.Textbox(label="Search", value="", placeholder="Search name, #tags, @personal note ....",interactive=True, lines=1) + sc_classification_list = gr.Dropdown(label='Classification',info="The selection options of classification are subject to the AND operation.", multiselect=True, choices=classification.get_list(), interactive=True) + shortcut_basemodel = gr.Dropdown(label='Filter Model BaseModel', multiselect=True, choices=[k for k in setting.model_basemodels], interactive=True) + show_downloaded_sc = gr.Checkbox(label="Show downloaded model's shortcut only", value=False) + # show_downloaded_sc = gr.Dropdown(label='Filter Downloaded Model View', multiselect=False, choices=[ALL_DOWNLOADED_MODEL,DOWNLOADED_MODEL,NOT_DOWNLOADED_MODEL], value=ALL_DOWNLOADED_MODEL, interactive=True) + + sc_gallery_page = gr.Slider(minimum=1, maximum=thumb_max_page, value=1, step=1, label=f"Total {thumb_max_page} Pages", interactive=True, visible=True if setting.shortcut_count_per_page > 0 else False) + # elem_id 를 안써줘야 옆의 인포와 연동이 안된다. 인포쪽에는 써줘야 할것.... + sc_gallery = gr.Gallery(show_label=False, value=thumb_list).style(grid=[setting.shortcut_column], height=["fit" if setting.shortcut_count_per_page != 0 else "auto"], object_fit=setting.gallery_thumbnail_image_style) + else: + sc_gallery_page = gr.Slider(minimum=1, maximum=thumb_max_page, value=1, step=1, label=f"Total {thumb_max_page} Pages", interactive=True, visible=True if setting.shortcut_count_per_page > 0 else False) + # elem_id 를 안써줘야 옆의 인포와 연동이 안된다. 인포쪽에는 써줘야 할것.... + sc_gallery = gr.Gallery(show_label=False, value=thumb_list).style(grid=[setting.shortcut_column], height=["fit" if setting.shortcut_count_per_page != 0 else "auto"], object_fit=setting.gallery_thumbnail_image_style) - sc_gallery_page = gr.Slider(minimum=1, maximum=thumb_max_page, value=1, step=1, label=f"Total {thumb_max_page} Pages", interactive=True, visible=True if setting.shortcut_count_per_page > 0 else False) - # elem_id 를 안써줘야 옆의 인포와 연동이 안된다. 인포쪽에는 써줘야 할것.... - sc_gallery = gr.Gallery(show_label=False, value=thumb_list).style(grid=[setting.shortcut_column], height=["fit" if setting.shortcut_count_per_page != 0 else "auto"], object_fit=setting.gallery_thumbnail_image_style) + with gr.Accordion("Search", open=True): + shortcut_type = gr.Dropdown(label='Filter Model Type', multiselect=True, choices=[k for k in setting.ui_typenames], interactive=True) + sc_search = gr.Textbox(label="Search", value="", placeholder="Search name, #tags, @personal note ....",interactive=True, lines=1) + sc_classification_list = gr.Dropdown(label='Classification',info="The selection options of classification are subject to the AND operation.", multiselect=True, choices=classification.get_list(), interactive=True) + shortcut_basemodel = gr.Dropdown(label='Filter Model BaseModel', multiselect=True, choices=[k for k in setting.model_basemodels], interactive=True) + show_downloaded_sc = gr.Checkbox(label="Show downloaded model's shortcut only", value=False) + # show_downloaded_sc = gr.Dropdown(label='Filter Downloaded Model View', multiselect=False, choices=[ALL_DOWNLOADED_MODEL,DOWNLOADED_MODEL,NOT_DOWNLOADED_MODEL], value=ALL_DOWNLOADED_MODEL, interactive=True) + with gr.Row(visible=False): refresh_sc_browser = gr.Textbox() diff --git a/scripts/civitai_manager_libs/setting.py b/scripts/civitai_manager_libs/setting.py index e25d36c..005e949 100644 --- a/scripts/civitai_manager_libs/setting.py +++ b/scripts/civitai_manager_libs/setting.py @@ -12,7 +12,7 @@ extension_base = scripts.basedir() headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.68'} Extensions_Name = "Civitai Shortcut" -Extensions_Version = "v 1.5.8" +Extensions_Version = "v 1.6.0" PLACEHOLDER = "[No Select]" NORESULT = "[No Result]" @@ -24,7 +24,7 @@ CREATE_MODEL_FOLDER = "Create a model folder to download the model" model_exts = (".bin", ".pt", ".safetensors", ".ckpt") -model_basemodels = ("SD 1.4", "SD 1.5", "SD 2.0", "SD 2.0 768", "SD 2.1", "SD 2.1 768", "SD 2.1 Unclip", "SDXL 0.9", "Other") +model_basemodels = ("SD 1.4", "SD 1.5", "SD 2.0", "SD 2.0 768", "SD 2.1", "SD 2.1 768", "SD 2.1 Unclip", "SDXL 0.9", "SDXL 1.0", "Other") # civitai model type -> folder path model_folders = { @@ -101,6 +101,8 @@ information_gallery_height = "auto" # auto , fit shortcut_browser_screen_split_ratio = 3 shortcut_browser_screen_split_ratio_max = 10 +shortcut_browser_search_up = False + # 갤러리 ui설정 gallery_column = 7 shortcut_column = 5 @@ -135,9 +137,65 @@ shortcut_info_folder = "sc_infos" shortcut_gallery_folder = "sc_gallery" no_card_preview_image = os.path.join(root_path,"html","card-no-preview.png") +nsfw_disable_image = os.path.join(extension_base,"img","nsfw-no-preview.png") + +NSFW_filtering_enable = True +NSFW_level = { "None":True, "Soft":False, "Mature":False, "X":False } # None, Soft, Mature, X shortcut_env = dict() +def set_NSFW(enable, level="None"): + global NSFW_filtering_enable + global NSFW_level + + NSFW_filtering_enable = enable + + if level == "Soft": + NSFW_level["None"] = True + NSFW_level["Soft"] = True + NSFW_level["Mature"] = False + NSFW_level["X"] = False + elif level == "Mature": + NSFW_level["None"] = True + NSFW_level["Soft"] = True + NSFW_level["Mature"] = True + NSFW_level["X"] = False + elif level == "X": + NSFW_level["None"] = True + NSFW_level["Soft"] = True + NSFW_level["Mature"] = True + NSFW_level["X"] = True + else: + # level == 1 + NSFW_level["None"] = True + NSFW_level["Soft"] = False + NSFW_level["Mature"] = False + NSFW_level["X"] = False + +def get_NSFW_Level(): + prev = "None" + for level, v in NSFW_level.items(): + if not v: + return prev + else: + prev = level + + return prev + +def save_NSFW(): + global NSFW_filtering_enable + + environment = load() + if not environment: + environment = dict() + + nsfw_filter = dict() + nsfw_filter['nsfw_filter_enable'] = NSFW_filtering_enable + nsfw_filter['nsfw_level'] = get_NSFW_Level() + environment['NSFW_filter'] = nsfw_filter + + save(environment) + def init(): global extension_base @@ -162,7 +220,7 @@ def init(): shortcut_recipe_folder = os.path.join(extension_base,shortcut_recipe_folder) shortcut_info_folder = os.path.join(extension_base,shortcut_info_folder) shortcut_gallery_folder = os.path.join(extension_base,shortcut_gallery_folder) - + load_data() def load_data(): @@ -176,7 +234,8 @@ def load_data(): global usergallery_images_page_limit global shortcut_max_download_image_per_version global gallery_thumbnail_image_style - + global shortcut_browser_search_up + global download_images_folder global shortcut_browser_screen_split_ratio global information_gallery_height @@ -198,7 +257,15 @@ def load_data(): environment = load() if environment: + if "NSFW_filter" in environment.keys(): + nsfw_filter = environment['NSFW_filter'] + filtering_enable = True + if 'nsfw_filter_enable' in nsfw_filter.keys(): + filtering_enable = bool(nsfw_filter['nsfw_filter_enable']) + if 'nsfw_level' in nsfw_filter.keys(): + set_NSFW(filtering_enable, nsfw_filter['nsfw_level']) + if "application_allow" in environment.keys(): application_allow = environment['application_allow'] @@ -217,6 +284,8 @@ def load_data(): information_gallery_height = screen_style['information_gallery_height'] if "gallery_thumbnail_image_style" in screen_style.keys(): gallery_thumbnail_image_style = screen_style['gallery_thumbnail_image_style'] + if "shortcut_browser_search_up" in screen_style.keys(): + shortcut_browser_search_up = bool(screen_style['shortcut_browser_search_up']) if "image_style" in environment.keys(): image_style = environment['image_style'] diff --git a/scripts/civitai_manager_libs/setting_action.py b/scripts/civitai_manager_libs/setting_action.py index 7c12d08..2f873ad 100644 --- a/scripts/civitai_manager_libs/setting_action.py +++ b/scripts/civitai_manager_libs/setting_action.py @@ -9,7 +9,6 @@ from . import setting from modules import scripts, script_callbacks, shared def on_setting_ui(): - with gr.Column(): with gr.Row(): with gr.Accordion("Option", open=False): @@ -25,7 +24,8 @@ def on_setting_ui(): with gr.Row(): info_gallery_height = gr.Dropdown(choices=["auto","fit"], value=setting.information_gallery_height, allow_custom_value=True, interactive=True, info="You can also specify a specific size other than 'auto' or 'fit'" , label="Information Gallery Height") gallery_thumbnail_image_style = gr.Dropdown(choices=["scale-down","cover","contain","fill","none"], value=setting.gallery_thumbnail_image_style, interactive=True, info="This specifies the shape of the displayed thumbnail." , label="Gallery Thumbnail Image Style") - + shortcut_browser_search_up = gr.Dropdown(choices=["Up","Down"], value="Up" if setting.shortcut_browser_search_up else "Down", interactive=True, label="Set the position of the search bar in the shortcut browser.", info="If you select 'Up', the search bar will be placed above the thumbnail pane.") + with gr.Row(): with gr.Accordion("Shortcut Browser and Information Images", open=False): with gr.Row(): @@ -79,6 +79,7 @@ def on_setting_ui(): usergallery_images_page_limit, shortcut_max_download_image_per_version, gallery_thumbnail_image_style, + shortcut_browser_search_up, extension_locon_folder, extension_wildcards_folder, extension_controlnet_folder, @@ -86,7 +87,7 @@ def on_setting_ui(): extension_poses_folder, extension_other_folder, download_images_folder, - classification_preview_mode_disable + classification_preview_mode_disable ], show_progress=False ) @@ -120,6 +121,7 @@ def on_setting_ui(): usergallery_images_page_limit, shortcut_max_download_image_per_version, gallery_thumbnail_image_style, + shortcut_browser_search_up, extension_locon_folder, extension_wildcards_folder, extension_controlnet_folder, @@ -140,6 +142,7 @@ def on_save_btn_click(shortcut_update_when_start, gallery_column, classification_gallery_column, usergallery_images_column, usergallery_images_page_limit, shortcut_max_download_image_per_version, gallery_thumbnail_image_style, + shortcut_browser_search_up, locon,wildcards,controlnet,aestheticgradient,poses,other,download_images_folder, classification_preview_mode_disable ): @@ -150,6 +153,7 @@ def on_save_btn_click(shortcut_update_when_start, gallery_column, classification_gallery_column, usergallery_images_column, usergallery_images_page_limit, shortcut_max_download_image_per_version, gallery_thumbnail_image_style, + shortcut_browser_search_up, locon,wildcards,controlnet,aestheticgradient,poses,other,download_images_folder, classification_preview_mode_disable ) @@ -160,12 +164,15 @@ def save_setting(shortcut_update_when_start, gallery_column, classification_gallery_column, usergallery_images_column, usergallery_images_page_limit, shortcut_max_download_image_per_version, gallery_thumbnail_image_style, + shortcut_browser_search_up, locon,wildcards,controlnet,aestheticgradient,poses,other,download_images_folder, classification_preview_mode_disable ): - environment = dict() - + environment = setting.load() + if not environment: + environment = dict() + application_allow = dict() application_allow['shortcut_update_when_start'] = shortcut_update_when_start application_allow['shortcut_max_download_image_per_version'] = shortcut_max_download_image_per_version @@ -175,6 +182,7 @@ def save_setting(shortcut_update_when_start, screen_style['shortcut_browser_screen_split_ratio'] = scbrowser_screen_split_ratio screen_style['information_gallery_height'] = info_gallery_height screen_style['gallery_thumbnail_image_style'] = gallery_thumbnail_image_style + screen_style['shortcut_browser_search_up'] = True if shortcut_browser_search_up == "Up" else False environment['screen_style'] = screen_style image_style = dict() @@ -256,6 +264,7 @@ def on_refresh_setting_change(): setting.usergallery_images_page_limit,\ setting.shortcut_max_download_image_per_version,\ setting.gallery_thumbnail_image_style,\ + "Up" if setting.shortcut_browser_search_up else "Down",\ setting.model_folders['LoCon'],\ setting.model_folders['Wildcards'],\ setting.model_folders['Controlnet'],\ diff --git a/scripts/civitai_shortcut.py b/scripts/civitai_shortcut.py index d7a4583..66decd0 100644 --- a/scripts/civitai_shortcut.py +++ b/scripts/civitai_shortcut.py @@ -43,13 +43,15 @@ def civitai_shortcut_ui(): with gr.Tabs(elem_id="civitai_shortcut_tabs_container") as civitai_tabs: with gr.Row(visible=False): recipe_input = gr.Textbox() + shortcut_input = gr.Textbox() + with gr.TabItem("Civitai Shortcut" , id="Shortcut"): with gr.Row(): - refresh_civitai_sc_browser, refresh_civitai_information = civitai_shortcut_action.on_ui(recipe_input) + refresh_civitai_sc_browser, refresh_civitai_information = civitai_shortcut_action.on_ui(recipe_input, shortcut_input, civitai_tabs) with gr.TabItem("Prompt Recipe" , id="Recipe"): with gr.Row(): - refresh_recipe = recipe_action.on_ui(recipe_input, civitai_tabs) + refresh_recipe = recipe_action.on_ui(recipe_input, shortcut_input, civitai_tabs) with gr.TabItem("Assistance" , id="Assistance"): with gr.Tabs() as civitai_assistance_tabs: