iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
自我挑戰組

與 AI 共舞:打造更高效的日常系列 第 11

AI 驅動的 Podcast 摘要系統(2)

  • 分享至 

  • xImage
  •  

備註: 雖然這個系列的主題圍繞 AI,但今天的內容中 AI 元素稍顯不足,還請大家見諒。

引言

在前一篇文章中,我提到我選擇了 n8n 平台來設計這個自動化流程。起初的構想是這樣的:將 Podcast 音檔上傳到 S3,再利用 Whisper AI 進行語音轉文字。但在實作過程中,我突然發現一個意外驚喜 —— Podcast 的 RSS 鏈接其實已經公開了音檔的 URL,這讓我要上傳的麻煩程序瞬間化為烏有。

這個發現讓我深刻體會到流程簡化的重要性,也為接下來的開發指明了方向。我決定直接利用 RSS 提供的音檔 URL,省去繁瑣的上傳步驟,專注於轉檔和摘要的生成,目標就是要以最簡單、高效的方式完成這個系統。

工具選擇與挑戰

一開始,我打算繼續挑戰 n8n 和 Divy.ai 這兩套自動化流程工具。我的想法是先從 Podcast 平台(例如 Apple Podcast 或 Spotify for Podcasters)抓取音檔的 URL,最後我選了 Spotify for Podcasters,因為它的原始碼裡面就有 Podcast 的 RSS 資訊,比較好分析處理。

不過,這些資訊藏在 <script> 標籤裡面,要解析出來有點麻煩。為了處理這個問題,我花了些時間寫了一個 Python 腳本來解決。

import requests
from bs4 import BeautifulSoup
import re
import json


def extract_audio_url(podcast_url):
    """
    從 Spotify for Podcasters 的特定集數網頁中提取音頻 URL。
    
    Parameters:
        podcast_url: Spotify Podcast 集數的網址。
    
    Returns:
        str or None: 提取到的音頻 URL,若未找到則返回 None。
    """
    try:
        response = requests.get(podcast_url)
        response.raise_for_status()
    except requests.RequestException as e:
        print(f"Error fetching the URL: {e}")
        return None
    
    # 查找包含 `window.__STATE__` 的 <script> 標籤
    soup = BeautifulSoup(response.text, 'html.parser')
    script_tag = None
    for script in soup.find_all('script'):
        if script.string and 'window.__STATE__' in script.string:
            script_tag = script.string
            break
    
    if not script_tag:
        print("Couldn't find the script tag containing 'window.__STATE__'.")
        return None
    
    # 使用 RegEx 提取 JSON 字串
    match = re.search(r'window\.__STATE__\s*=\s*({.*?});', script_tag, re.DOTALL)
    if not match:
        print("Couldn't extract JSON data from 'window.__STATE__'.")
        return None
    
    json_str = match.group(1)
    try:
        state = json.loads(json_str)
    except json.JSONDecodeError as e:
        print(f"Error decoding JSON: {e}")
        return None
    
    # 根據提供的 HTML 結構,提取 `episodeEnclosureUrl`
    try:
        episode_enclosure_url = state['episodePreview']['episodeEnclosureUrl']
    except KeyError:
        print("Couldn't find 'episodeEnclosureUrl' in the JSON data.")
        return None
    
    decoded_url = bytes(episode_enclosure_url, "utf-8").decode("unicode_escape")
    return decoded_url


if __name__ == "__main__":
    # 範例網址:台灣通勤第一品牌 —— EP144 此處應有本
    podcast_episode_url = "https://podcasters.spotify.com/pod/show/taiwanfirstcommuter/episodes/EP144-e18ghfi"
    
    audio_url = extract_audio_url(podcast_episode_url)
    
    if audio_url:
        print(f"Extracted Audio URL: {audio_url}")
    else:
        print("Failed to extract the audio URL.")

遭遇的困難與解決

意外發現,不管是 n8n 還是 Divy.ai,它們提供的 Python 執行環境都不支援外部套件。這表示我只能用 Python 3 內建的標準函式庫,我嘗試改寫使用 urllib 加上正則表達式來抓取和解析 HTML 內容。而且,這兩個平台也沒辦法直接呼叫 Web API 來抓外部資料,只能先用它們的 HTTPS 功能模板取得 HTML,再把資料傳給 Python 功能模組處理。

更麻煩的是,Divy.ai 對 HTTP 回應內容的大小有限制,超過 1MB 就沒辦法處理。因為 Spotify for Podcasters 由於把整個 RSS 內容都放在 meta data 裡面,網頁內容很容易就超過 1MB,所以 Divy.ai 在這個階段就被我淘汰了,畢竟之後轉出來的逐字稿應該也很容易超過 1MB。

https://ithelp.ithome.com.tw/upload/images/20240921/201682886bzGEOrl88.png

n8n 的限制與挫折

後來,我在 n8n 上試著做一些處理的時候,嘗試將 HTTP 功能模組抓取到的資料傳遞到 Python 能模組,卻一直碰壁。而且,n8n 的除錯工具功能陽春,說明文件寫得也不夠詳細,讓我在探索 n8n 的 Python 執行環境上浪費了不少時間,最後只好放棄使用它。

最佳解決方案:Serverless

經過多次嘗試和調整,我最終決定採用 Serverless 的方式來解決這些問題。我將腳本部署在 DigitalOcean 的 Function 上,這樣不僅可以自由使用像 RequestsBeautifulSoup 這樣的外部套件來解析 HTML,還能利用 DigitalOcean 每月的免費額度來滿足需求。

這次的經驗讓我深刻理解到,像 n8n 擅長的是流程控制,且內建了許多功能模組;Divy.ai 則擅長打造 AI workflow 或 RAG 應用。然而當這些自動化流程缺乏你所需的功能時,以我目前的使用體驗來看,強烈不建議在它們上面執行 Python 程式碼,這只會浪費時間

轉向 Serverless 方案,不僅能夠更靈活地運用各種外部套件,還能提升整體效率。若 Low-code 平台無法滿足需求,強烈建議直接轉向 Serverless 方案,避免在半殘的運行環境上寫 Python 程式碼浪費寶貴時間。

自動化遇阻?Serverless 是王道!
自動化遇阻?Serverless 是王道!
自動化遇阻?Serverless 是王道!

很重要所以要講三次

https://ithelp.ithome.com.tw/upload/images/20240921/20168288MOa6r10MhC.png

實作進展與未來計畫

目前,我已經完成 Podcast 節目 URL 到逐字稿的整套流程。我的 Webhook 可以接收 Podcast 節目的 URL,透過 DigitalOcean 的 Function 擷取音檔的實際 URL,然後加上一些參數,將音檔的 URL傳遞到 Replicate 的 Whisper API 進行語音轉文字的處理。由於這是一個非同步的過程,我額外加上了一組 if-else 迴圈,每隔五分鐘呼叫 GET API,檢查任務是否完成。任務完成後,我就能取得轉好的逐字稿。

https://ithelp.ithome.com.tw/upload/images/20240921/20168288GApa0ZOBLN.png

實際測試的效果相當不錯,從 Podcast 節目 URL 中提取音檔並順利轉譯成文字的流程已經運作良好。接下來,我將開始進行 AI 摘要的生成,這也是我計畫明天要完成的工作。讓我們拭目以待,期待明天的成果吧!

總結

在打造自動化系統的過程中,選擇適合的工具和方法非常重要。Low-code 平台如 n8n 和 Divy.ai,雖然在某些領域有優勢,但遇到特殊需求時反而可能綁手綁腳。這時候不妨考慮把這部分工作交給 Serverless 方案,這樣一來,不只能更彈性地運用各種外部套件,還能大幅提升整體效率。希望我的經驗分享,能給正在尋找自動化解決方案的您一些幫助!


上一篇
AI 驅動的 Podcast 摘要系統(1.5)
下一篇
AI 驅動的 Podcast 摘要系統(3)
系列文
與 AI 共舞:打造更高效的日常30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言