README.md 5.29 KB

Lyric Duplicate Checker

第一版用于“新增歌词查重”:先用已有 .lrc / .txt 歌词建立索引,再把新增歌词拿来查询,返回 duplicatereviewnew

建立索引

假设已有曲库在 data/library/

python -m lyric_dedup.cli build-index \
  --lyrics-dir data/library \
  --index outputs/indexes/lyrics.pkl

检查单个新增歌词

python -m lyric_dedup.cli check-file \
  --index outputs/indexes/lyrics.pkl \
  --file data/incoming/new_song.lrc

批量检查新增目录

python -m lyric_dedup.cli batch-check \
  --index outputs/indexes/lyrics.pkl \
  --lyrics-dir data/incoming \
  --out outputs/results/incoming_check.csv

CSV 里重点看这些列:

  • decision: 总判断。
  • best_candidate_id: 最像的已有歌词。
  • best_candidate_jaccard: n-gram 字面相似度。
  • best_candidate_line_coverage: 行级覆盖率。
  • matched_unique_lines: 命中的规范化歌词行。
  • best_candidate_reason: 中文判定原因,说明为什么判重、复核或判新。

生产判断建议:duplicate 可自动拦截;review 进人工池;new 入库前仍可抽样检查。

原文 + 中文翻译歌词的防护规则

当前会把歌词拆成三类行:

  • primary_lines: 原文行,自动判重主要依赖这部分。
  • translation_lines: 中文翻译行,只用于召回和复核解释。
  • unknown_lines: 无法稳定判断的行。

高置信拆分包括:

  • 同一个时间戳下出现外文行和中文行。
  • 多组稳定的外文行 + 中文行交替。

中置信拆分包括:

  • 同一行内明显的外文 / 中文翻译,例如 I miss you / 今晚我想你

低置信拆分包括:

  • 先整段外文,再整段中文翻译。

判定策略:

  • 原文高度一致,即使新增歌词多了中文翻译,也可以 duplicate
  • 只有翻译行相似,原文相似不足,只能 review,不自动判重。
  • 疑似整段翻译结构属于低置信拆分,即使原文 hash 一致,也先 review
  • 普通中文歌没有检测到翻译结构时,全部有效行按原文处理。

由于索引里会保存拆分后的原文/翻译特征,修改拆分规则后需要重建索引。

用标注 CSV 评估正确率

可以先从已有曲库自动生成一批评估样本:

python -m lyric_dedup.cli generate-eval-set \
  --library-dir data/library \
  --lyrics-dir data/generated_eval/incoming \
  --csv data/generated_eval/eval_50000.csv \
  --index outputs/indexes/lyrics.pkl \
  --eval-index data/generated_eval/eval_50000.csv.index.pkl \
  --size 50000 \
  --positive-ratio 0.3

生成器的业务口径:

  • 先扫描整个曲库,按有效歌词行数、语言类型、文件来源前缀做分层采样,不再按排序前缀取样。
  • 应去重 样本只生成全曲歌词的样式变化,例如时间戳、标点、平台噪声、空行、重复副歌次数变化、附加中文翻译。
  • 不应去重 样本以真实 holdout 完整歌词为主,也包含片段歌词、重复副歌碰撞、仅翻译相似、同主题新歌词、短歌词/占位边界样本。
  • 片段歌词即使命中已有歌曲的一部分,也不应该输出 duplicate;最多进入 review
  • 生成器会额外写出 --eval-index,这个索引排除了 holdout 歌,评估生成 CSV 时应使用它。
  • 同时会生成 *.manifest.json,记录 seed、曲库规模、holdout 数、样本类型分布、语言/来源分桶和样本来源覆盖数。

先准备一个 CSV,例如 data/eval/eval.csv

id,file,expected
case-001,incoming/song_a.lrc,应去重
case-002,incoming/song_b.txt,不应去重

也可以不用文件路径,直接把歌词放在 lyrics 列:

id,lyrics,expected
case-003,"我爱你在每个夜里\n听风说话也听见你",duplicate
case-004,"南方的雨穿过街心\n你把故事说给云听",new

expected 支持这些写法:

  • 应去重:应去重重复duplicate1trueyes
  • 不应去重:不应去重不重复new0falseno

运行评估:

python -m lyric_dedup.cli evaluate-csv \
  --index outputs/indexes/lyrics.pkl \
  --csv data/eval/eval.csv \
  --base-dir data \
  --out outputs/results/eval_result.csv

默认只有系统输出 duplicate 才算“预测应去重”。这适合评估自动拦截的准确率,误杀会更明显。

如果你想评估“可疑样本召回率”,也就是 duplicatereview 都算命中:

python -m lyric_dedup.cli evaluate-csv \
  --index outputs/indexes/lyrics.pkl \
  --csv data/eval/eval.csv \
  --base-dir data \
  --positive-decisions duplicate,review \
  --out outputs/results/eval_result_review_as_positive.csv

会生成两个文件:

  • outputs/results/eval_result.csv: 每条样本的预测、候选、原因和是否正确。
  • outputs/results/eval_result.csv.summary.json: 总体指标。

summary 里重点看:

  • accuracy: 总正确率。
  • precision: 预测应去重的样本里,有多少是真的应去重。自动拦截优先看这个。
  • recall: 真实应去重的样本里,有多少被系统抓到。
  • f1: precision 和 recall 的综合指标。
  • false_positive: 不应去重但被判为应去重,属于误杀。
  • false_negative: 应去重但没抓到,属于漏召。