import os
import re
import glob
import openai
import numpy as np
import whisper
# 指定 ffmpeg 的執行檔路徑
os.environ["PATH"] += os.pathsep + "/opt/homebrew/bin"
# 設定 OpenAI API 金鑰(請確認環境變數或直接指定)
openai.api_key ="xxx"
#############################################
# A. 透過 OpenAI Whisper 轉錄影片與 MP3 檔案
#############################################
def get_movie_transcript(video_file):
"""
使用 OpenAI Whisper 模型對 MP4 影片進行語音轉錄,
返回電影逐字稿(整個文字字串)。
"""
print(f"開始轉錄影片:{video_file} ...")
model = whisper.load_model("base")
result = model.transcribe(video_file)
transcript = result["text"].strip()
print("影片轉錄完成。")
return transcript
def extract_number(filename):
"""
從檔名中提取數字部分,用於排序。
假設檔名格式為 segment_1.mp3, segment_2.mp3, ...
"""
base = os.path.basename(filename)
m = re.search(r'(\d+)', base)
if m:
return int(m.group(1))
return 0
def get_script_text_from_folder(folder):
"""
從指定資料夾中讀取所有 MP3 檔案,
按照檔名中數字部分排序後,分別使用 Whisper 模型轉錄,
將所有轉錄結果合併成一個大字串(以換行分隔)。
"""
mp3_files = sorted(glob.glob(os.path.join(folder, "*.mp3")), key=extract_number)
if not mp3_files:
print("指定資料夾中找不到 MP3 檔案!")
return ""
print(f"共找到 {len(mp3_files)} 個 MP3 檔案,開始轉錄...")
model = whisper.load_model("base")
all_text = []
for mp3_file in mp3_files:
print(f"轉錄 {mp3_file} ...")
result = model.transcribe(mp3_file)
text = result["text"].strip()
all_text.append(text)
script_text = "\n".join(all_text)
print("所有 MP3 檔案轉錄完成。")
return script_text
#############################################
# B. 文本拆分與匹配(參考之前的範例)
#############################################
def split_text(text):
"""
利用正則表達式以中文、英文逗號、句號以及換行符拆分文本,
並去除空白字串。
"""
segments = re.split(r'[,,。.\n]', text)
segments = [seg.strip() for seg in segments if seg.strip()]
return segments
#############################################
# 2. 批次取得 OpenAI 嵌入向量(更新後)
#############################################
def get_embeddings_batch(texts, model="text-embedding-ada-002"):
"""
使用 OpenAI API 的新版本接口一次取得多個文本的嵌入向量,
返回一個 numpy array 列表。
"""
response = openai.embeddings.create(input=texts, model=model)
embeddings = [np.array(item.embedding) for item in response.data]
return embeddings
#############################################
# 3. 計算 Cosine 相似度
#############################################
def cosine_similarity(vec1, vec2):
"""
計算兩個向量之間的 cosine 相似度。
"""
return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2) + 1e-8)
#############################################
# 4. 對應講稿段落與電影逐字稿段落
#############################################
def match_script_to_movie(script_segments, movie_segments, script_embeddings, movie_embeddings):
"""
對每個講稿段落找出電影逐字稿中最相關的段落,
返回一個列表,每項包含講稿段落、最佳匹配的電影段落、相似度分數及電影段落索引。
"""
mapping = []
for i, script_emb in enumerate(script_embeddings):
best_score = -1
best_index = None
for j, movie_emb in enumerate(movie_embeddings):
score = cosine_similarity(script_emb, movie_emb)
if score > best_score:
best_score = score
best_index = j
mapping.append({
"script": script_segments[i],
"movie": movie_segments[best_index],
"score": best_score,
"movie_index": best_index
})
return mapping
#############################################
# C. 主程式:取得影片逐字稿與講稿、拆分並匹配
#############################################
if __name__ == "__main__":
# 請分別設定你的影片檔案與存放 MP3 檔的資料夾
video_file = "Documents/Dallas_imovie.mp4" # 例如:./videos/input.mp4
mp3_folder = "Documents/2025-02-27_12-17-38" # 例如:./scripts/,內含 segment_1.mp3, segment_2.mp3, 等
# 1. 透過 Whisper 轉錄取得電影逐字稿
movie_transcript = get_movie_transcript(video_file)
# 2. 從指定資料夾中讀取所有 MP3 檔並轉錄,合併成講稿
script_text = get_script_text_from_folder(mp3_folder)
print("\n=== 取得的電影逐字稿 ===")
print(movie_transcript)
print("\n=== 取得的講稿 ===")
print(script_text)
# 3. 拆分文本:將電影逐字稿與講稿拆分成段落(或句子組)
movie_segments = split_text(movie_transcript)
script_segments = split_text(script_text)
print("\n=== 電影逐字稿拆分結果 ===")
for i, seg in enumerate(movie_segments, start=1):
print(f"段落 {i}: {seg}")
print("\n=== 講稿拆分結果 ===")
for i, seg in enumerate(script_segments, start=1):
print(f"講稿段落 {i}: {seg}")
# 4. 使用 OpenAI API 批次取得嵌入
print("\n取得電影逐字稿嵌入...")
movie_embeddings = get_embeddings_batch(movie_segments)
print("取得講稿嵌入...")
script_embeddings = get_embeddings_batch(script_segments)
# 5. 進行語意匹配
mapping = match_script_to_movie(script_segments, movie_segments, script_embeddings, movie_embeddings)
print("\n=== 講稿與電影逐字稿對應結果 ===")
for item in mapping:
print(f"講稿段落:{item['script']}")
print(f"最佳匹配電影段落:{item['movie']} (索引: {item['movie_index']})")
print(f"相似度分數:{item['score']:.3f}")
print("-----------")
