Commit ff4bad47 ff4bad47defb064f09a0157839d3865b43c21cb6 by 沈秋雨

fix

1 parent df390ea0
......@@ -27,6 +27,13 @@ python scripts/aliyun_dna/evaluate_aliyun_dna.py \
--queries composition_testset_20/queries.csv \
--out results/aliyun_dna_eval.csv \
--duplicate-threshold 0.8
# 测试翻唱库
python scripts/aliyun_dna/evaluate_aliyun_dna.py \
--queries downloads_db/queries.csv \
--out results/dna_eval.csv \
--db-id f08aee1806c14df782e03cc1ab93f1ea \
--concurrency 4
"""
import argparse
......
......@@ -54,6 +54,42 @@ logger = logging.getLogger(__name__)
DB_DSN = "postgresql://postgres:postgres@localhost:5432/embed_db"
# 正样本变体:对主版本做轻度变换,模拟不同编码/剪辑场景
# (variant_name, ffmpeg_extra_args_or_None)
POSITIVE_VARIANTS: list[tuple[str, list[str] | None]] = [
# 转码为 128kbps MP3,模拟不同平台压缩率
("mp3_128k", ["-codec:a", "libmp3lame", "-b:a", "128k"]),
# 重采样至 22050Hz,模拟不同采样率上传
("resample_22k", ["-ar", "22050", "-ac", "1"]),
# 去掉前后各 5%,模拟用户剪掉片头片尾
("trim_5pct", None),
]
def _make_variant(src: Path, dst: Path, ffmpeg_args: list[str] | None, duration: float | None = None) -> bool:
"""生成单个正样本变体,返回是否成功。"""
import subprocess
if ffmpeg_args is None:
# trim_5pct:需要先探测时长
if duration is None:
probe = subprocess.run(
["ffprobe", "-v", "error", "-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1", str(src)],
capture_output=True, text=True,
)
try:
duration = float(probe.stdout.strip())
except ValueError:
return False
ss = duration * 0.05
t = duration * 0.90
cmd = ["ffmpeg", "-y", "-i", str(src),
"-ss", f"{ss:.3f}", "-t", f"{t:.3f}", "-ac", "1", str(dst)]
else:
cmd = ["ffmpeg", "-y", "-i", str(src), *ffmpeg_args, "-ac", "1", str(dst)]
result = subprocess.run(cmd, capture_output=True)
return result.returncode == 0
# fetch_records 查询返回的列,也是 --export-csv / --from-csv 的 CSV 格式
RECORDS_FIELDS = [
"record_id", "song_id", "song_name", "original_singer",
......@@ -284,6 +320,8 @@ def main() -> None:
ap.add_argument("--timeout", type=int, default=60, help="单文件下载超时秒数(默认 60)")
ap.add_argument("--overwrite", action="store_true", help="覆盖已存在的文件")
ap.add_argument("--dsn", default=DB_DSN, help="PostgreSQL 连接串")
ap.add_argument("--no-positive-variants", action="store_true",
help="不生成正样本变体(mp3_128k/resample_22k/trim_5pct),只用 self 查询")
ap.add_argument(
"--export-csv", metavar="FILE",
help="只导出查询结果到 CSV 后退出,不执行下载(在本地机器上运行)",
......@@ -440,8 +478,11 @@ def main() -> None:
ok_results = [r for r in results if r.get("status") == "ok" and r.get("local_path")]
ref_rows, query_rows = [], []
variants_dir = output_dir / "variants"
for r in ok_results:
if int(r["is_main_version"]) == 1:
src = Path(r["local_path"])
ref_rows.append({
"song_id": r["song_id"],
"audio_path": r["local_path"],
......@@ -453,21 +494,39 @@ def main() -> None:
"genre": r["genre"],
"language_tag": r["language_tag"],
})
# 正样本:主版本自身查询(验证入库是否成功)
query_rows.append({
"song_id": r["song_id"],
"audio_path": r["local_path"],
"variant": "self",
"sample_class": "positive",
"expected_song_id": r["song_id"],
"expected": "duplicate",
"song_name": r["song_name"],
"original_singer": r["original_singer"],
"singer_name": r["original_singer"],
"platform_name": r["platform_name"],
"duration": r["duration"],
"is_main_version": r["is_main_version"],
})
def _query_row(path, variant):
return {
"song_id": r["song_id"],
"audio_path": str(path),
"variant": variant,
"sample_class": "positive",
"expected_song_id": r["song_id"],
"expected": "duplicate",
"song_name": r["song_name"],
"original_singer": r["original_singer"],
"singer_name": r["original_singer"],
"platform_name": r["platform_name"],
"duration": r["duration"],
"is_main_version": r["is_main_version"],
}
# self:原始文件直接作为查询(验证基本入库)
query_rows.append(_query_row(src, "self"))
# 轻度变体正样本
if not args.no_positive_variants:
variants_dir.mkdir(parents=True, exist_ok=True)
duration = float(r["duration"]) if r.get("duration") else None
for vname, ffargs in POSITIVE_VARIANTS:
ext = ".mp3" if vname == "mp3_128k" else src.suffix
dst = variants_dir / f"{r['song_id']}_{vname}{ext}"
if not dst.exists():
ok = _make_variant(src, dst, ffargs, duration)
if not ok:
logger.warning("变体生成失败,跳过: song_id=%s %s", r["song_id"], vname)
continue
query_rows.append(_query_row(dst, vname))
else:
# 负样本:翻唱/其他版本,不应匹配到 DNA 库中的主版本
platform = r["platform_name"] or "unknown"
......