How GPT-SoVITS WebUI Implements Model Weight Selection and Checkpoint Switching
The GPT-SoVITS WebUI dynamically scans checkpoint directories, populates Gradio dropdown menus with discovered .pth and .ckpt files, and switches models via dedicated change handlers that resolve paths, detect versions, and load weights into global inference objects while yielding UI state updates.
The RVC-Boss/GPT-SoVITS repository provides a Gradio-based WebUI for voice synthesis that requires seamless switching between GPT and SoVITS checkpoints. Understanding how the WebUI implements model weight selection and checkpoint switching reveals a tightly coupled system of filesystem scanning, UI state management, and runtime model instantiation.
How Checkpoint Discovery Works
The foundation of model selection lies in config.py, which defines static maps for pre-trained models and the weight-root directories. The system maintains separate lists for SoVITS and GPT weights:
# config.py – definitions of the weight roots
SoVITS_weight_root = ["SoVITS_weights", "SoVITS_weights_v2", ...] # ← line 44‑49
GPT_weight_root = ["GPT_weights", "GPT_weights_v2", ...] # ← line 52‑58
The get_weights_names() function walks these directories to discover available checkpoints. It scans for files ending in .pth (SoVITS) or .ckpt (GPT), while also checking named entries in name2sovits_path and name2gpt_path:
def get_weights_names():
SoVITS_names = []
for key in name2sovits_path:
if os.path.exists(name2sovits_path[key]):
SoVITS_names.append(key) # ← line 88‑90
for path in SoVITS_weight_root:
if not os.path.exists(path):
continue
for name in os.listdir(path):
if name.endswith(".pth"):
SoVITS_names.append(f"{path}/{name}") # ← line 95‑97
# … same logic for GPT (lines 99‑108) …
SoVITS_names = sorted(SoVITS_names, key=custom_sort_key) # ← line 109‑110
return SoVITS_names, GPT_names # ← line 113‑114
This discovery mechanism ensures that both repository-provided models and user-added checkpoints in custom *_weights folders appear in the UI automatically.
Populating the Gradio Dropdown Menus
In webui.py, the inference tab constructs the GPT_dropdown and SoVITS_dropdown components using the sorted lists returned by config.get_weights_names():
# webui.py – inference tab (excerpt)
GPT_dropdown = gr.Dropdown(
label=i18n("GPT模型列表"),
choices=sorted(GPT_names, key=custom_sort_key), # ← line 1450‑1452
value=gpt_path,
interactive=True,
scale=14,
)
SoVITS_dropdown = gr.Dropdown(
label=i18n("SoVITS模型列表"),
choices=sorted(SoVITS_names, key=custom_sort_key), # ← line 1452‑1455
value=sovits_path,
interactive=True,
scale=14,
)
A Refresh button allows users to re-scan the filesystem at runtime without restarting the application:
refresh_button = gr.Button(i18n("刷新模型路径"), variant="primary", scale=14) # line 1459
refresh_button.click(fn=change_choices, inputs=[], outputs=[SoVITS_dropdown, GPT_dropdown]) # line 1460
The change_choices() function forwards the updated lists back to the dropdown components:
def change_choices():
SoVITS_names, GPT_names = get_weights_names() # ← line 116‑117
return {"choices": SoVITS_names, "__type__": "update"}, {"choices": GPT_names, "__type__": "update"}
Switching Between Checkpoints
When a user selects a new checkpoint from either dropdown, Gradio invokes dedicated change handlers that perform the actual model loading and UI synchronization.
Resolving Model Paths and Versions
Both change_sovits_weights() and change_gpt_weights() first resolve friendly display names (e.g., "v2底模!") into actual filesystem paths. The handlers check for special characters ! or ! in the selection to identify named entries:
if "!" in sovits_path or "!" in sovits_path:
sovits_path = name2sovits_path[sovits_path] # line 30‑31
For SoVITS checkpoints, the system must detect the model version to instantiate the correct class. The get_sovits_version_from_path_fast() function extracts version information (v1, v2, v3, v4) and LoRA flags directly from the filename:
version, model_version, if_lora_v3 = get_sovits_version_from_path_fast(sovits_path) # line 33‑34
Loading SoVITS Checkpoints
The change_sovits_weights() function in GPT_SoVITS/inference_webui.py implements the complete switching logic as a generator, yielding Gradio update dictionaries to refresh UI elements progressively without blocking the main thread:
def change_sovits_weights(sovits_path, prompt_language=None, text_language=None):
# ① Resolve named entries
if "!" in sovits_path or "!" in sovits_path:
sovits_path = name2sovits_path[sovits_path] # line 30‑31
# ② Determine version, model‑type and LoRA flag from the filename
version, model_version, if_lora_v3 = get_sovits_version_from_path_fast(sovits_path) # line 33‑34
# ③ Prepare UI state (language lists, visibility of sample‑steps, etc.) and **yield**
# a series of Gradio update dicts so the UI instantly reflects the new model.
# (lines 42‑78 – see the “yield (…)” block)
# ④ Load the checkpoint (weights + config) and build the model instance
dict_s2 = load_sovits_new(sovits_path) # line 81
hps = DictToAttrRecursive(dict_s2["config"]) # line 82‑84
# – adjust version flags, instantiate the appropriate Synthesizer class
# (v1/v2 vs. v3/v4) (lines 92‑110)
# ⑤ Move model to the selected device & precision
if is_half:
vq_model = vq_model.half().to(device) # line 117‑119
else:
vq_model = vq_model.to(device)
Key implementation details include:
- Path resolution allows readable UI labels while loading the correct file from
name2sovits_path - Version detection determines whether to instantiate
SynthesizerTrn(v1/v2) orSynthesizerTrnV3(v3/v4) - UI synchronization yields update dictionaries that adjust language selectors and reveal version-specific controls like
sample_stepsfor V3/V4 models - Device handling moves the loaded
vq_modelto the configured GPU/CPU and appliesfloat16precision whenis_halfis enabled
Loading GPT Checkpoints
The GPT switching logic follows a similar pattern but with less UI complexity. The change_gpt_weights() function updates the global gpt inference object:
def change_gpt_weights(gpt_path):
global gpt
# Resolve named entries (same as SoVITS)
if "!" in gpt_path or "!" in gpt_path:
gpt_path = name2gpt_path[gpt_path] # line 376‑377 (in inference_webui.py)
# Load the checkpoint (the implementation lives in process_ckpt)
gpt = load_gpt_new(gpt_path) # line 381
# Update UI (show loading indicator, enable inference button, etc.)
return (
{"__type__": "update", "value": i18n("模型加载中,请等待"), "interactive": False},
{"__type__": "update", "value": True, "interactive": True},
)
Once loaded, the global gpt variable ensures that subsequent calls to get_tts_wav() reference the currently selected checkpoint.
Programmatic Model Switching
You can trigger checkpoint switches programmatically by importing the change handlers directly from GPT_SoVITS/inference_webui.py:
from GPT_SoVITS.inference_webui import change_sovits_weights, change_gpt_weights
# Switch SoVITS checkpoint
list(change_sovits_weights("SoVITS_weights_v2/my_model.pth", prompt_language="中文", text_language="中文"))
# Switch GPT checkpoint
list(change_gpt_weights("GPT_weights_v2/my_gpt.ckpt"))
Each function returns a generator of Gradio update dictionaries; iterating over the generator forces the loading process to execute and apply UI updates.
Key Source Files and Architecture
The checkpoint switching mechanism spans several critical files in the RVC-Boss/GPT-SoVITS repository:
config.py– Containsget_weights_names(),SoVITS_weight_root, andGPT_weight_rootdefinitions for filesystem scanningwebui.py– Constructs theGPT_dropdownandSoVITS_dropdownGradio components and wires the refresh button tochange_choices()GPT_SoVITS/inference_webui.py– Implementschange_sovits_weights()andchange_gpt_weights()with version detection and model instantiationGPT_SoVITS/inference_webui_fast.py– Mirrors the switching logic for the low-latency inference pathprocess_ckpt.py– Providesload_sovits_new()andload_gpt_new()for low-level checkpoint deserialization
Summary
- Filesystem discovery via
config.get_weights_names()scansSoVITS_weight_rootandGPT_weight_rootfor.pthand.ckptfiles, merging results with named path mappings - Dynamic UI population uses
change_choices()to refresh Gradio dropdowns without requiring application restarts - Path resolution handles both direct file paths and friendly display names containing
!or!characters throughname2sovits_pathandname2gpt_pathlookups - Version-aware loading detects model architecture (v1/v2 vs. v3/v4) from filenames and instantiates the appropriate
SynthesizerTrnclass - Generator-based updates allow
change_sovits_weights()to yield progressive UI state changes while loading large models into the globalvq_modelandgptobjects
Frequently Asked Questions
How does the WebUI detect new checkpoints added after startup?
The Refresh button in the inference tab triggers change_choices(), which re-executes get_weights_names() to scan the filesystem again. This updates both dropdown menus with any new .pth or .ckpt files placed in the weight directories since the last scan, eliminating the need to restart the Gradio server.
What file extensions does GPT-SoVITS expect for model weights?
According to the source code in config.py, SoVITS checkpoints must use the .pth extension while GPT checkpoints use the .ckpt extension. The get_weights_names() function explicitly filters for these extensions when building the dropdown choices lists.
Why does change_sovits_weights() use a generator pattern?
The function yields multiple Gradio update dictionaries (with "__type__": "update") during execution rather than returning a single value. This allows the UI to display loading states, adjust language selectors, and toggle visibility of version-specific controls (like sample_steps for V3/V4) immediately, while the heavyweight model loading continues in the background without blocking the interface.
How does the system handle different model versions (v1, v2, v3, v4)?
The get_sovits_version_from_path_fast() function parses the selected filename to extract version strings. Based on this detection, change_sovits_weights() instantiates the appropriate synthesizer class—SynthesizerTrn for v1/v2 models or SynthesizerTrnV3 for v3/v4 models—and adjusts global configuration flags accordingly.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →