Spaces:
Running on Zero
Running on Zero
| """受け取り方。ZIPでも音声ファイル単体でも、同じように扱えること。""" | |
| import struct | |
| import sys | |
| import wave | |
| import zipfile | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | |
| import pipeline as pl # noqa: E402 | |
| def make_wav(path: Path, seconds: float = 0.2) -> Path: | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| with wave.open(str(path), "wb") as f: | |
| f.setnchannels(1) | |
| f.setsampwidth(2) | |
| f.setframerate(16000) | |
| f.writeframes(b"".join( | |
| struct.pack("<h", (i % 100) * 50) for i in range(int(16000 * seconds)) | |
| )) | |
| return path | |
| def test_音声ファイルをそのまま受け取れる(tmp_path): | |
| src = make_wav(tmp_path / "受け取り" / "商談_A社.wav") | |
| found = pl.collect_audio([src], tmp_path / "audio") | |
| assert [name for name, _, _ in found] == ["商談_A社.wav"] | |
| assert found[0][1].exists() | |
| assert found[0][2] # 録音日時が入る | |
| def test_ZIPと音声ファイルを混ぜても良い(tmp_path): | |
| wav = make_wav(tmp_path / "受け取り" / "単体.wav") | |
| inner = make_wav(tmp_path / "元" / "ZIPの中.wav") | |
| zip_path = tmp_path / "受け取り" / "まとめ.zip" | |
| with zipfile.ZipFile(zip_path, "w") as zf: | |
| zf.write(inner, "ZIPの中.wav") | |
| found = pl.collect_audio([zip_path, wav], tmp_path / "audio") | |
| assert sorted(name for name, _, _ in found) == ["ZIPの中.wav", "単体.wav"] | |
| def test_同じ名前でも上書きしない(tmp_path): | |
| a = make_wav(tmp_path / "一つ目" / "同じ名前.wav") | |
| b = make_wav(tmp_path / "二つ目" / "同じ名前.wav") | |
| found = pl.collect_audio([a, b], tmp_path / "audio") | |
| paths = {path for _, path, _ in found} | |
| assert len(paths) == 2 # 別々のファイルとして残る | |
| def test_音声でないものは無視する(tmp_path): | |
| doc = tmp_path / "受け取り" / "資料.pdf" | |
| doc.parent.mkdir(parents=True, exist_ok=True) | |
| doc.write_bytes(b"%PDF-1.4") | |
| assert pl.collect_audio([doc], tmp_path / "audio") == [] | |
| def test_危ないファイル名は無害にする(): | |
| assert pl.safe_filename("../../etc/passwd") == "passwd" | |
| assert "/" not in pl.safe_filename("a/b/c.wav") | |
| assert pl.safe_filename("") == "音声" | |
| assert pl.safe_filename("a:b*c?.m4a").endswith(".m4a") | |
| def test_再生用の音声を作れる(tmp_path): | |
| """どのブラウザでも鳴らせるよう mp3 に揃える。""" | |
| src = make_wav(tmp_path / "元.wav", seconds=1.0) | |
| out = pl.to_playback(src, tmp_path / "再生用.mp3") | |
| assert out is not None and out.exists() | |
| assert out.stat().st_size > 0 | |
| head = out.read_bytes()[:3] | |
| assert head == b"ID3" or head[:2] in (b"\xff\xfb", b"\xff\xf3") # mp3の目印 | |
| def test_元の音質を落とさない(tmp_path): | |
| """聞き取りやすさを優先。周波数もチャンネル数も元のまま。""" | |
| src = make_wav(tmp_path / "元.wav", seconds=1.0) | |
| out = pl.to_playback(src, tmp_path / "再生用.mp3") | |
| assert out is not None | |
| assert abs(pl.probe_duration(out) - pl.probe_duration(src)) < 0.2 # 長さが変わらない | |
| def test_すでにmp3ならそのまま使う(tmp_path): | |
| """変換を重ねるほど音は悪くなるので、作り直さない。""" | |
| src = pl.to_playback(make_wav(tmp_path / "元.wav", seconds=1.0), tmp_path / "元.mp3") | |
| out = pl.to_playback(src, tmp_path / "再生用.mp3") | |
| assert out is not None | |
| assert out.read_bytes() == src.read_bytes() # 中身がそのまま | |