File size: 10,047 Bytes
c8be32d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
"""
This module contains the code for the "Manage models" tab.
"""

from typings.extra import DropdownValue

from functools import partial

import gradio as gr
import pandas as pd

from backend.manage_voice_models import (
    delete_all_models,
    delete_models,
    download_online_model,
    filter_public_models_table,
    get_current_models,
    load_public_model_tags,
    load_public_models_table,
    upload_local_model,
)

from frontend.common import (
    PROGRESS_BAR,
    confirm_box_js,
    confirmation_harness,
    exception_harness,
    identity,
    update_dropdowns,
)


def _update_model_lists(
    num_components: int, value: DropdownValue = None, value_indices: list[int] = []
) -> gr.Dropdown | tuple[gr.Dropdown, ...]:
    """
    Updates the choices of one or more dropdown
    components to the current set of voice models.

    Optionally updates the default value of one or more of these components.

    Parameters
    ----------
    num_components : int
        Number of dropdown components to update.
    value : DropdownValue, optional
        New value for dropdown components.
    value_indices : list[int], default=[]
        Indices of dropdown components to update the value for.

    Returns
    -------
    gr.Dropdown | tuple[gr.Dropdown, ...]
        Updated dropdown component or components.
    """
    return update_dropdowns(get_current_models, num_components, value, value_indices)


def _filter_public_models_table_harness(
    tags: list[str], query: str, progress_bar: gr.Progress
) -> gr.Dataframe:
    """
    Filter the public models table based on tags and search query.

    Parameters
    ----------
    tags : list[str]
        Tags to filter the table by.
    query : str
        Search query to filter the table by.
    progress_bar : gr.Progress
        Progress bar to display progress.

    Returns
    -------
    gr.Dataframe
        The filtered public models table rendered in a Gradio dataframe.
    """
    models_table = filter_public_models_table(tags, query, progress_bar)
    return gr.Dataframe(value=models_table)


def _pub_dl_autofill(
    pub_models: pd.DataFrame, event: gr.SelectData
) -> tuple[gr.Textbox, gr.Textbox]:
    """
    Autofill download link and model name based on selected row in public models table.

    Parameters
    ----------
    pub_models : pd.DataFrame
        Public models table.
    event : gr.SelectData
        Event containing the selected row.

    Returns
    -------
    download_link : gr.Textbox
        Autofilled download link.
    model_name : gr.Textbox
        Autofilled model name.
    """
    event_index = event.index[0]
    url_str = pub_models.loc[event_index, "URL"]
    model_str = pub_models.loc[event_index, "Model Name"]

    return gr.Textbox(value=url_str), gr.Textbox(value=model_str)


def render(
    dummy_deletion_checkbox: gr.Checkbox,
    delete_confirmation: gr.State,
    rvc_models_to_delete: gr.Dropdown,
    rvc_model_1click: gr.Dropdown,
    rvc_model_multi: gr.Dropdown,
) -> None:
    """
    Render "Manage models" tab.

    Parameters
    ----------
    dummy_deletion_checkbox : gr.Checkbox
        Dummy component needed for deletion confirmation in the
        "Manage audio" tab and the "Manage models" tab.
    delete_confirmation : gr.State
        Component storing deletion confirmation status in the
        "Manage audio" tab and the "Manage models" tab.
    rvc_models_to_delete : gr.Dropdown
        Dropdown for selecting models to delete in the
        "Manage models" tab.
    rvc_model_1click : gr.Dropdown
        Dropdown for selecting models in the "One-click generation" tab.
    rvc_model_multi : gr.Dropdown
        Dropdown for selecting models in the "Multi-step generation" tab.
    """

    # Download tab
    with gr.Tab("Download model"):

        with gr.Accordion("View public models table", open=False):

            gr.Markdown("")
            gr.Markdown("HOW TO USE")
            gr.Markdown("- Filter models using tags or search bar")
            gr.Markdown("- Select a row to autofill the download link and model name")

            filter_tags = gr.CheckboxGroup(
                value=[],
                label="Show voice models with tags",
                choices=load_public_model_tags(),
            )
            search_query = gr.Textbox(label="Search")

            public_models_table = gr.DataFrame(
                value=load_public_models_table([]),
                headers=["Model Name", "Description", "Tags", "Credit", "Added", "URL"],
                label="Available Public Models",
                interactive=False,
            )

        with gr.Row():
            model_zip_link = gr.Textbox(
                label="Download link to model",
                info=(
                    "Should point to a zip file containing a .pth model file and an"
                    " optional .index file."
                ),
            )
            model_name = gr.Textbox(
                label="Model name", info="Enter a unique name for the model."
            )

        with gr.Row():
            download_btn = gr.Button("Download 🌐", variant="primary", scale=19)
            dl_output_message = gr.Textbox(
                label="Output message", interactive=False, scale=20
            )

        download_button_click = download_btn.click(
            partial(
                exception_harness(download_online_model), progress_bar=PROGRESS_BAR
            ),
            inputs=[model_zip_link, model_name],
            outputs=dl_output_message,
        )

        public_models_table.select(
            _pub_dl_autofill,
            inputs=public_models_table,
            outputs=[model_zip_link, model_name],
            show_progress="hidden",
        )
        search_query.change(
            partial(
                exception_harness(_filter_public_models_table_harness),
                progress_bar=PROGRESS_BAR,
            ),
            inputs=[filter_tags, search_query],
            outputs=public_models_table,
            show_progress="hidden",
        )
        filter_tags.select(
            partial(
                exception_harness(_filter_public_models_table_harness),
                progress_bar=PROGRESS_BAR,
            ),
            inputs=[filter_tags, search_query],
            outputs=public_models_table,
            show_progress="hidden",
        )

    # Upload tab
    with gr.Tab("Upload model"):
        with gr.Accordion("HOW TO USE"):
            gr.Markdown(
                "- Find locally trained RVC v2 model file (weights folder) and optional"
                " index file (logs/[name] folder)"
            )
            gr.Markdown(
                "- Upload model file and optional index file directly or compress into"
                " a zip file and upload that"
            )
            gr.Markdown("- Enter a unique name for the model")
            gr.Markdown("- Click 'Upload model'")

        with gr.Row():
            with gr.Column():
                model_files = gr.File(label="Files", file_count="multiple")

            local_model_name = gr.Textbox(label="Model name")

        with gr.Row():
            model_upload_button = gr.Button("Upload model", variant="primary", scale=19)
            local_upload_output_message = gr.Textbox(
                label="Output message", interactive=False, scale=20
            )
            model_upload_button_click = model_upload_button.click(
                partial(
                    exception_harness(upload_local_model), progress_bar=PROGRESS_BAR
                ),
                inputs=[model_files, local_model_name],
                outputs=local_upload_output_message,
            )

    with gr.Tab("Delete models"):
        with gr.Row():
            with gr.Column():
                rvc_models_to_delete.render()
            with gr.Column():
                rvc_models_deleted_message = gr.Textbox(
                    label="Output message", interactive=False
                )

        with gr.Row():
            with gr.Column():
                delete_models_button = gr.Button(
                    "Delete selected models", variant="secondary"
                )
                delete_all_models_button = gr.Button(
                    "Delete all models", variant="primary"
                )
            with gr.Column():
                pass
        delete_models_button_click = delete_models_button.click(
            # NOTE not sure why, but in order for subsequent event listener
            # to trigger, changes coming from the js code
            # have to be routed through an identity function which takes as
            # input some dummy component of type bool.
            identity,
            inputs=dummy_deletion_checkbox,
            outputs=delete_confirmation,
            js=confirm_box_js("Are you sure you want to delete the selected models?"),
            show_progress="hidden",
        ).then(
            partial(confirmation_harness(delete_models), progress_bar=PROGRESS_BAR),
            inputs=[delete_confirmation, rvc_models_to_delete],
            outputs=rvc_models_deleted_message,
        )

        delete_all_models_btn_click = delete_all_models_button.click(
            identity,
            inputs=dummy_deletion_checkbox,
            outputs=delete_confirmation,
            js=confirm_box_js("Are you sure you want to delete all models?"),
            show_progress="hidden",
        ).then(
            partial(confirmation_harness(delete_all_models), progress_bar=PROGRESS_BAR),
            inputs=delete_confirmation,
            outputs=rvc_models_deleted_message,
        )

    for click_event in [
        download_button_click,
        model_upload_button_click,
        delete_models_button_click,
        delete_all_models_btn_click,
    ]:
        click_event.success(
            partial(_update_model_lists, 3, [], [2]),
            outputs=[rvc_model_1click, rvc_model_multi, rvc_models_to_delete],
            show_progress="hidden",
        )