GPT-SoVITS/tools/list_metadata.py
XucroYuri e1720e7e5a feat: 兼容 proplus-hc-dev 训练数据 + 新增「情绪/括注」字段
兼容 proplus-hc-dev 分支基于 6 列 .list 训练的模型,并按主分支自身流程
增加 emotion 字段(标注/推理 UI 单输入框「情绪/括注」,存 emotion 列,
保留 remark 列以兼容 proplus 6 列结构)。emotion/remark 不参与训练。

核心兼容性修复(消除 3 处硬编码拒绝 proplus 的 6 列 .list):
- 新增 tools/list_metadata.py: 6 列 .list 解析/格式化器 (parse/format_list_line)
- 1-get-text.py:129  line.split("|") 严格 4 列解包 -> parse_list_line
                   (proplus 同款修复,只取训练所需前 4 列,emotion/remark 静默忽略)
- subfix_webui b_load_list: 仅接受 len==4 -> 改用 parse_list_line (>=4 列)
- subfix_webui b_save_list: 写 4 列 -> 写 6 列 (保留 emotion/remark,向前向后兼容)

标注 UI (tools/subfix_webui.py):
- 每条音频新增「情绪/括注」Text 输入框 (g_emotion_list)
- b_change_index/reload_data/b_submit_change 贯通 emotion 读写
- 8 个分页事件输出列表统一追加 *g_emotion_list

推理 WebUI (inference_webui.py):
- _read_emotion_map_for_webui: 读 output/asr_opt/<exp>/*.list 的 emotion 列
- 训练样本下拉标签附加【emotion】(有则显示)
- 选中样本时同步刷新「情绪/括注」只读文本框; 应用样本一并填入
- 无 emotion 数据则文本框留空 (符合「无数据不显示」)

API (api_v2.py):
- GET /models/{name}/samples 响应增加 emotion 字段 (来自同源 .list)

向后兼容: 主分支原生 4 列 .list 全程正常; 训练 pipeline 不感知 emotion。
list_metadata/parse/emotion/round-trip 单元自测通过; py_compile 全通过。
2026-07-07 11:44:02 +08:00

62 lines
1.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from dataclasses import dataclass
@dataclass(frozen=True)
class ListLine:
"""一条 `.list` 标注行(兼容 4/5/6 列)。
列定义: wav_path|speaker_name|language|text[|emotion|remark]
训练只用前 4 列training_fieldsemotion / remark 为元数据,
不参与模型训练,用于标注与参考音频展示。
"""
wav_path: str
speaker_name: str
language: str
text: str
emotion: str = ""
remark: str = ""
@property
def training_fields(self):
return [self.wav_path, self.speaker_name, self.language, self.text]
def _clean(value):
return str(value or "").strip()
def parse_list_line(line):
"""解析一行 `.list`。列数 < 4 返回 Noneemotion/remark 缺省为空串。"""
parts = str(line or "").rstrip("\r\n").split("|")
if len(parts) < 4:
return None
return ListLine(
wav_path=_clean(parts[0]),
speaker_name=_clean(parts[1]),
language=_clean(parts[2]),
text=_clean(parts[3]),
emotion=_clean(parts[4]) if len(parts) >= 5 else "",
remark=_clean(parts[5]) if len(parts) >= 6 else "",
)
def format_list_line(item):
"""把 ListLine 格式化为 6 列 `.list` 行emotion/remark 为空也保留分隔符)。
注意:写出 6 列以保证与 proplus-hc-dev 分支互操作,主分支训练侧
1-get-text.py已用 parse_list_line 只消费前 4 列,多余列不影响训练。
"""
return "|".join(
[
str(item.wav_path or ""),
str(item.speaker_name or ""),
str(item.language or ""),
str(item.text or ""),
str(item.emotion or ""),
str(item.remark or ""),
]
)