欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python實現(xiàn)音頻去廣告和字幕提取

 更新時間:2025年02月06日 09:27:12   作者:敖天羽  
這篇文章主要為大家詳細介紹了如何使用Python實現(xiàn)音頻去廣告和字幕提取功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

之前下了一些音頻課,但是存在一些音頻中間插入廣告,更萬惡的是,它根本不分是不是整句,只要時間差不多了就插入。

要去掉廣告我們分為以下步驟依次執(zhí)行:

  • 分析規(guī)律(就是前面找規(guī)律)
  • 廣告提取
  • 識別廣告
  • 重新拼接

對于字幕提取,之前其實我們在 AI 相關(guān)的文章中也介紹過對應模型,直接轉(zhuǎn)換并處理就可以了,后面再介紹。

分析規(guī)律

和寫爬蟲一樣,第一點就是要找規(guī)律:用一張草稿紙記錄每個廣告的起始時間和結(jié)束時間,再分析它和整段音頻的關(guān)系。

遺憾的是,在插入時或許是為了避免裁剪,逐秒計算(也叫做)后,我得出了一個結(jié)論:它是在固定時間(end_time - 3min) + random_offset 值,因為了 offset 值的介入,整個就變的玄學了起來。

還好很快我又有了一些新的想法:利用一些識別的手段把廣告詞裁掉就可以了。

還好廣告詞是固定的,而要處理的音頻卻多,這樣計算下來 ROI 還是劃算的。

廣告提取

這一步是所有步驟里最耗費時間的,對于整句來說,切割分離是一個高敏感性的操作,稍微多留白幾百毫秒,你聽起來可能就很難受。只有原始數(shù)據(jù)切割的恰到好處,才能達到完美還原。

因此我們需要更精細化,精細到毫秒的裁剪手段。

Windows 下也不知道用啥,搜了下就選了 Audacity:

以毫秒控制選區(qū),然后切割后如果聽感是無縫的,那么就相當于抽離了,如果覺得怪怪的就再調(diào)整毫秒重新裁,如此反復直到無縫銜接。

依賴列表

下文完整的 import依賴(因為懶得在文末貼完整代碼了):

import glob
import os
from concurrent.futures import ThreadPoolExecutor, as_completed

import numpy as np
import librosa
import torch
import whisper
from pydub import AudioSegment
import soundfile as sf
import torch.nn.functional as F
import shutil

識別廣告

接下來我們得到了兩個片段,一個是完整版的音頻,另一個是純廣告音頻,將對應波形的相似度進行比對,找到相似的段,再進行切割。

當然,由于整段二三十分鐘,相對的來說計算量會很大,由于我們知道了總是在一個音頻快結(jié)束了插入廣告,因此可以先裁剪縮小對比規(guī)模,然后再進行比對,減少計算量。

其中有一些非常抽象的音頻和數(shù)學知識,只能說謝謝 GPT 老師(我也沒學會)

# 已知的廣告片段文件
AD_SNIPPET_FILE  = "./testcase/test2.wav"

# 待處理的音頻文件目錄
audio_dir = "./testcase"
TAIL_SECONDS = 300  # 只截取最后5分鐘處理
SIMILARITY_THRESHOLD = 0.8  # 相似度閾值(0~1之間, 需根據(jù)實際情況調(diào)整)
SUCCESS_DIR = "./success"
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

def load_audio_segment(file_path, sr=16000, tail_seconds=None):
info = sf.info(file_path)
total_duration = info.duration
if tail_seconds is not None and tail_seconds < total_duration:
    start_time = total_duration - tail_seconds
    audio, _ = librosa.load(file_path, sr=sr, mono=True, offset=start_time, duration=tail_seconds)
    return audio, start_time

else:
    audio, _ = librosa.load(file_path, sr=sr, mono=True)
    return audio, 0.0

def find_audio_snippet(main_audio_path, snippet_audio, snippet_norm, sr=16000, tail_seconds=300):
"""
在 main_audio_path 中尋找 snippet_audio 音頻片段的出現(xiàn)位置。
snippet_audio 為事先加載好的 numpy 數(shù)組,snippet_norm 為 snippet 的二范數(shù),用于相似度計算。
返回 (ad_start_time, ad_end_time, similarity)
若未找到則返回 (None, None, None)
"""
main_audio, main_start = load_audio_segment(main_audio_path, sr=sr, tail_seconds=tail_seconds)
if len(snippet_audio) > len(main_audio):
    return None, None, None
# 轉(zhuǎn)換到 GPU 張量
main_audio_t = torch.from_numpy(main_audio).float().to(device).unsqueeze(0).unsqueeze(0)  # [1,1,M]
snippet_audio_t = torch.from_numpy(snippet_audio).float().to(device).unsqueeze(0).unsqueeze(0)  # [1,1,S]
# 使用 conv1d 來進行類似相似度搜索 (無 snippet 翻轉(zhuǎn))
correlation = F.conv1d(main_audio_t, snippet_audio_t)
correlation = correlation[0, 0].cpu().numpy()
best_index = np.argmax(correlation)
best_value = correlation[best_index]
# 相似度計算:歸一化
similarity = best_value / snippet_norm if snippet_norm > 0 else 0
ad_start_time = main_start + best_index / sr
ad_end_time = ad_start_time + len(snippet_audio) / s

return ad_start_time, ad_end_time, similarity

重新拼接

找到廣告后我們將廣告段落減去,然后再重新拼接生成新的音頻文件即可。

def process_file(filename, snippet_audio, snippet_norm, sr=16000, tail_seconds=300, similarity_threshold=0.8):
"""
處理單個文件,找到廣告并移除。
"""
ad_start, ad_end, similarity = find_audio_snippet(filename, snippet_audio, snippet_norm, sr=sr,
                                                  tail_seconds=tail_seconds)

if ad_start is not None and similarity > similarity_threshold:
    # 去除廣告段落
    audio = AudioSegment.from_file(filename)
    part1 = audio[:ad_start * 1000]
    part2 = audio[ad_end * 1000:]
    cleaned = part1 + part2
    cleaned_file = f"output/{os.path.basename(filename)}"
    cleaned.export(cleaned_file, format="mp3")
    shutil.move(filename, SUCCESS_DIR)
    return f"{filename} 已移除廣告,生成 {cleaned_file},相似度:{similarity}"
else:
    return f"{filename} 中未高相似度檢測到廣告或相似度過低({similarity})"


def remove_ads():
sr = 16000
# 預先加載廣告片段
snippet_audio, _ = librosa.load(AD_SNIPPET_FILE , sr=sr, mono=True)
# 計算snippet的范數(shù),用于相似度歸一化
snippet_norm = np.dot(snippet_audio, snippet_audio)

file_list = [os.path.join(audio_dir, f) for f in os.listdir(audio_dir) if
             f.endswith(".mp3")]

# 使用多線程加速處理
# 線程數(shù)可根據(jù)您的機器資源調(diào)整
max_workers = 20
results = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
    futures = {
        executor.submit(process_file, file, snippet_audio, snippet_norm, sr, TAIL_SECONDS,
                        SIMILARITY_THRESHOLD): file
        for file in file_list
    }

    for future in as_completed(futures):
        file = futures[future]
        try:
            res = future.result()
            print(res)
        except Exception as e:
            print(f"{file} 處理時出錯: {e}")

字幕提取

下一個問題是,音頻是提取好了,但是音頻的字幕和總結(jié)能力其實也是一個亮點,這個也是我們想要有的能力,而好多都是付費的,百度網(wǎng)盤雖然會員免費,但是實際聽音頻的過程中遇到了 Bug,讓我不得不另謀高就。

要使用這個能力,核心還是使用 whisper這個模型的能力。

我考慮用 Emby 來當音頻播放器,字幕可以和歌詞字幕一樣,因此就需要生成 lrc 格式的標準文件。

也就是:

  • 提取字幕
  • 給每段字幕和時間軸進行格式轉(zhuǎn)換,轉(zhuǎn)為 lrc 標準格式

而跑 AI 模型的時候,務必保證 GPU 加速(否則你會卡的痛不欲生)。

模型請根據(jù)自己的內(nèi)存和實際情況決定,不一定是越大越好的,可以先跑一段音頻試試效果。

如果本地沒有找到對應的模型,whisper 先嘗試下載,也可以使用本地準備好的模型。

def format_lrc_timestamp(seconds: float) -> str:
"""將秒數(shù)轉(zhuǎn)換為 LRC 格式時間戳 [mm:ss.xx]"""
total_seconds = int(seconds)
m = total_seconds // 60
s = total_seconds % 60
# 毫秒取兩位小數(shù)
ms = (seconds - total_seconds) * 100
return f"[{m:02d}:{s:02d}.{int(ms):02d}]"

def trans_files():
# 請將此路徑替換為你的音頻目錄路徑
audio_directory = "./audio_files"
# 可根據(jù)需要選擇模型大小,如 "small"、"medium"、"large"
trans_text(audio_directory, model_name="medium", language="zh")

def transcribe_to_lrc(audio_path: str, lrc_path: str, model, language: str = "zh"):
"""
使用已加載的 whisper model 對 audio_path 進行轉(zhuǎn)錄,
并將結(jié)果保存為 lrc_path 文件。
"""
result = model.transcribe(audio_path, language=language)
segments = result.get("segments", [])

with open(lrc_path, "w", encoding="utf-8") as f:
    # 可根據(jù)需要添加標簽信息,如標題、歌手、專輯
    f.write("[ti:未知標題]\n")
    f.write("[ar:未知作者]\n")
    f.write("[al:未知專輯]\n\n")

    for seg in segments:
        start_time = format_lrc_timestamp(seg['start'])
        text = seg['text'].strip()
        f.write(f"{start_time}{text}\n")


def trans_text(audio_dir: str, model_name: str = "medium", language: str = "zh"):
# 嘗試使用 GPU
device = "cuda:0" if torch.cuda.is_available() else "cpu"
print(f"使用設(shè)備: {device}")

# 加載模型到指定設(shè)備
# 模型大小可根據(jù)資源調(diào)整,如:tiny, base, small, medium, large
print(f"加載 Whisper 模型 ({model_name}),請稍候...")
model = whisper.load_model(model_name, device=device)
print("模型加載完成。")

# 遍歷指定目錄下所有 mp3
audio_files = glob.glob(os.path.join(audio_dir, "*.mp3"))
if not audio_files:
    print("指定目錄中未找到 MP3 文件。")
    return

for audio_path in audio_files:
    base_name = os.path.splitext(audio_path)[0]
    lrc_path = base_name + ".lrc"

    print(f"處理文件: {audio_path} -> {lrc_path}")
    transcribe_to_lrc(audio_path, lrc_path, model=model, language=language)
    print(f"完成: {lrc_path}")

print("所有文件處理完成!")

def trans_files():
# 請將此路徑替換為你的音頻目錄路徑
audio_directory = "./audio_files"
# 可根據(jù)需要選擇模型大小,如 "small"、"medium"、"large"
trans_text(audio_directory, model_name="medium", language="zh")

目前我還沒有做總結(jié)功能(主要是普通播放器也沒地方顯示總結(jié)),但是有了全量文本,相信對于各位來說并不是難事。

總結(jié)

本文的所有代碼均由 AI 編寫,可以說過去讓它寫的代碼更多的是提效用,我姑且還算一知半解,但是涉及到音頻和數(shù)學知識的本功能我是真的一無所知,但它卻能幫我做出一個非常完美的效果,真的是科技改變生活了。

以上就是Python實現(xiàn)音頻去廣告和字幕提取的詳細內(nèi)容,更多關(guān)于Python音頻去廣告和字幕提取的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • gethostbyaddr在Python3中引發(fā)UnicodeDecodeError

    gethostbyaddr在Python3中引發(fā)UnicodeDecodeError

    本文介紹了gethostbyaddr()在Python?3中引發(fā)UnicodeDecodeError的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧
    2022-05-05
  • Python中逗號轉(zhuǎn)為空格的三種方法

    Python中逗號轉(zhuǎn)為空格的三種方法

    本文介紹了Python中將逗號轉(zhuǎn)換為空格的三種方法,包含使用replace函數(shù)、使用split函數(shù)、使用正則表達式,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • Python實現(xiàn)批量合并多個txt文件并生成Excel文件

    Python實現(xiàn)批量合并多個txt文件并生成Excel文件

    在數(shù)據(jù)處理中,有時會面臨合并多個文本文件的任務,本文將詳細介紹如何使用Python批量合并多個txt文件,并將其生成為一個Excel文件,需要的可以參考下
    2023-12-12
  • Python+PyQT5的子線程更新UI界面的實例

    Python+PyQT5的子線程更新UI界面的實例

    今天小編就為大家分享一篇Python+PyQT5的子線程更新UI界面的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • Python?Pipeline處理數(shù)據(jù)工作原理探究

    Python?Pipeline處理數(shù)據(jù)工作原理探究

    如果你是一個Python開發(fā)者,你可能聽過"pipeline"這個術(shù)語,但?pipeline?到底是什么,它又有什么用呢?在這篇文章中,我們將探討?Python?中的?pipeline?概念,它們是如何工作的,以及它們?nèi)绾螏椭憔帉懜逦?、更高效的代碼
    2024-01-01
  • Django values()和value_list()的使用

    Django values()和value_list()的使用

    這篇文章主要介紹了Django values()和value_list()的使用,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Tensorflow?2.1完成對MPG回歸預測詳解

    Tensorflow?2.1完成對MPG回歸預測詳解

    這篇文章主要為大家介紹了Tensorflow?2.1完成對MPG回歸預測詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • python3使用urllib模塊制作網(wǎng)絡爬蟲

    python3使用urllib模塊制作網(wǎng)絡爬蟲

    本文給大家介紹的是利用urllib模塊通過指定的URL抓取網(wǎng)頁內(nèi)容 所謂網(wǎng)頁抓取,就是把URL地址中指定的網(wǎng)絡資源從網(wǎng)絡流中讀取出來,保存到本地,有需要的小伙伴可以參考下
    2016-04-04
  • Python中字符串List按照長度排序

    Python中字符串List按照長度排序

    這篇文章主要介紹了字符串List按照長度排序(python)的實現(xiàn)方法啊,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • python?open函數(shù)中newline參數(shù)實例詳解

    python?open函數(shù)中newline參數(shù)實例詳解

    newLine()方法可用于輸出一個換行字符"/n",下面這篇文章主要給大家介紹了關(guān)于python?open函數(shù)中newline參數(shù)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-06-06

最新評論