首页
/ 从 YouTube 字幕到语义搜索索引:Generative AI For Beginners 第 08 课的 Azure OpenAI 转录数据预处理管线

从 YouTube 字幕到语义搜索索引:Generative AI For Beginners 第 08 课的 Azure OpenAI 转录数据预处理管线

2026-09-04 20:26:47作者:谭伦延

本文围绕 translations/ar/08-building-search-applications/scripts/README.md(转录数据预处理指南,原文为英文仓库 08-building-search-applications/scripts/README.md 的阿拉伯语译文)展开,完整覆盖用 Azure CLI 创建 Azure OpenAI 服务资源、配置环境变量、安装 Python 依赖并运行数据预处理脚本的全过程,并结合 scripts 目录下的六个 Python 脚本与编排脚本(Bash / PowerShell / Batch),深入讲解"下载 YouTube 字幕 → 提取说话人 → 按 3 分钟分桶 → 摘要 → 向量化"这条数据管线的实现细节。读完本文,你能够独立复现该管线,并理解语义搜索索引 embedding_index_3m.json 是如何一步步被构建出来的。

1. 管线总览:这套脚本解决什么问题

本指南所属的预处理脚本(transcription data prep scripts)用于下载 YouTube 视频的字幕文本,并将其加工成可供"Semantic Search with OpenAI Embeddings and Functions"示例使用的语义搜索索引。它是第 08 课"Building Search Applications"的教学配套工程:该课的场景是为一所教育创业公司构建搜索应用——学生输入一个问题(如"What are Jupyter Notebooks?"),应用从微软 AI Show YouTube 频道的字幕中检索出相关视频,并返回带时间戳的链接,定位到答案所在的视频位置(见 08-building-search-applications/README.md)。

指南明确声明了脚本的已测试平台:Windows 11、macOS Ventura 与 Ubuntu 22.04(及更高版本)的最新发行版。

从编排脚本 prepare_transcripts_ai_show.sh 头部注释可以看到,整条管线由六个阶段组成:

  1. 从 YouTube 下载字幕(transcripts);
  2. 用 OpenAI Functions 为字幕补充说话人信息;
  3. 将字幕按固定分钟数(3 分钟)分桶
  4. 用 OpenAI Chat 生成每段的摘要
  5. 为每段生成 OpenAI Embeddings 向量
  6. 生成**精简版(lite)**索引——移除 text 属性以减小体积。

管线的最终产物是两个 JSON 文件:完整版 embedding_index_full_3m.json(保留摘要、文本等全部字段)和供搜索应用使用的精简版 embedding_index_3m.json。仓库中已经附带生成好的索引 embedding_index_3m.json,学习者无需重跑管线即可完成第 08 课的搜索应用练习;本指南的价值在于让你能够复现、修改或将其应用到自己的语料上。

2. 创建 Azure OpenAI 服务资源

指南要求先将 Azure CLI 更新到最新版本,以保证与 OpenAI 相关命令的兼容性。以下命令默认在 East US 区域、名为 semantic-video-search 的资源组中执行;资源组名称可以更改,但更换资源区域时,需要自行核对该区域可用的 OpenAI 模型清单(不同区域的模型可用性不同)。

2.1 创建资源组

az group create --name semantic-video-search --location eastus

2.2 创建 Azure OpenAI 服务账户

az cognitiveservices account create --name semantic-video-openai --resource-group semantic-video-search \
    --location eastus --kind OpenAI --sku s0

要点:--kind OpenAI 声明这是 OpenAI 服务,--sku s0 表示 Standard 档位(S0)。

2.3 获取 endpoint 与 API key

后续脚本需要服务 endpoint 与密钥,用 jq 从 JSON 输出中直接抽取:

az cognitiveservices account show --name semantic-video-openai \
   --resource-group  semantic-video-search | jq -r .properties.endpoint
az cognitiveservices account keys list --name semantic-video-openai \
   --resource-group semantic-video-search | jq -r .key1

2.4 部署模型

管线需要部署两个部署(deployment):

部署名称 模型 版本要求 用途
text-embedding-ada-002 text-embedding-ada-002 2 或更高 生成 1536 维文本向量
gpt-4o-mini gpt-4o-mini 最新 说话人实体抽取 + 段落摘要(Chat/Functions)
az cognitiveservices account deployment create \
    --name semantic-video-openai \
    --resource-group  semantic-video-search \
    --deployment-name text-embedding-ada-002 \
    --model-name text-embedding-ada-002 \
    --model-version "2"  \
    --model-format OpenAI \
    --scale-settings-scale-type "Standard"
az cognitiveservices account deployment create \
    --name semantic-video-openai \
    --resource-group  semantic-video-search \
    --deployment-name gpt-4o-mini \
    --model-name gpt-4o-mini \
    --model-format OpenAI \
    --sku-capacity 100 \
    --sku-name "Standard"

需要注意的一个版本差异:阿拉伯语译文里给出的第二个部署是 gpt-35-turbo(版本 0613),而当前仓库源码已切换到 gpt-4o-mini——transcript_enrich_speaker.pyAZURE_OPENAI_MODEL_DEPLOYMENT_NAME 的默认值就是 "gpt-4o-mini"。因此部署模型时请以源码默认值 gpt-4o-mini 为准,部署名与默认值保持一致即可免配环境变量。

3. 软件要求与环境变量

软件要求:Python 3.9 或更高版本(脚本中使用了 f-string、from __future__ 之外的现代语法与 | 类型联合等特性,建议直接使用 3.10+)。

脚本运行依赖以下 4 个环境变量。从源码看,各脚本在启动时通过 dotenv.load_dotenv() 加载环境(兼容 .env 文件),再直接读取这些变量:

变量名 含义 在源码中的使用位置
AZURE_OPENAI_API_KEY Azure OpenAI 服务的 API key 所有调用 OpenAI 的脚本
AZURE_OPENAI_ENDPOINT 服务 endpoint 同上
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME Chat/Functions 模型的部署名,缺省 gpt-4o-mini transcript_enrich_speaker.py
GOOGLE_DEVELOPER_API_KEY Google 开发者 API key,用于 YouTube Data API 遍历播放列表 transcript_download.py

另外还有一个可选变量:transcript_enrich_embeddings.py 读取 AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT,缺省值为 text-embedding-ada-002,与部署名一致时无需设置。

3.1 在 Windows 上配置

指南建议将其添加到 user 级环境变量,路径为:Windows 开始 > 编辑系统环境变量 > 环境变量 > 用户 [USER] 的 用户变量 > 新建

AZURE_OPENAI_API_KEY  <your Azure OpenAI Service API key>
AZURE_OPENAI_ENDPOINT <your Azure OpenAI Service endpoint>
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME <your Azure OpenAI Service model deployment name>
GOOGLE_DEVELOPER_API_KEY = <your Google developer API key>

3.2 在 Linux 与 macOS 上配置

建议把如下 export 追加到 ~/.bashrc~/.zshrc

export AZURE_OPENAI_API_KEY=<your Azure OpenAI Service API key>
export AZURE_OPENAI_ENDPOINT=<your Azure OpenAI Service endpoint>
export AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=<your Azure OpenAI Service model deployment name>
export GOOGLE_DEVELOPER_API_KEY=<your Google developer API key>

4. 安装 Python 依赖

指南中"克隆示例仓库 → 进入 data_prep 目录 → 建虚拟环境 → 安装依赖"的步骤,对应到当前仓库时更简单:六个 Python 脚本与编排脚本均已包含在 08-building-search-applications/scripts/ 目录中,直接在本地运行即可。在 scripts 目录下执行:

创建并激活虚拟环境:

# Windows
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
# macOS / Linux
python3 -m venv .venv
source .venv/bin/activate
pip3 install -r requirements.txt

仓库中实际的依赖清单 requirements.txt 及其在管线中的角色如下:

依赖(版本约束) 管线中的作用
openai>=1.54.0,<2.0.0 调用 Azure OpenAI 的 Responses/Chat/Embeddings API
google-api-python-client>=2.98.0,<3.0.0 YouTube Data API v3,分页遍历播放列表
youtube-transcript-api>=0.6.1,<1.0.0 按视频 ID 拉取字幕,支持 WebVTT 格式
tiktoken>=0.8.0,<1.0.0 分桶阶段统计 token 数,防止超出模型上下文
pandas>=2.1.0,<3.0.0scipyscikit-learn 后续搜索应用加载索引、计算余弦相似度
matplotlib>=3.7.2plotly>=5.16.1,<5.17.0 结果可视化
rich>=13.5.2 各脚本中的进度条展示(Progress
tenacity>=8.2.3 API 调用的指数退避重试

5. 运行数据预处理脚本

指南给出的入口命令是 .\transcripts_prepare.ps1(Windows)与 ./transcripts_prepare.sh(macOS/Linux)——这两个文件名来自外部示例仓库的目录约定;在当前仓库中,对应的编排脚本是同一目录下的三件套

三个脚本逻辑完全一致,直接运行即可(确保环境变量已生效,且当前目录为 scripts):

.\prepare_transcripts_ai_show.ps1
./prepare_transcripts_ai_show.sh

prepare_transcripts_ai_show.sh 为例,它的完整执行序列是:

export TRANSCRIPT_FOLDER=transcripts_the_ai_show
export TRANSCRIPT_BUCKET_MINUTES=3

mkdir -p $TRANSCRIPT_FOLDER/output

python3 transcript_download.py -f $TRANSCRIPT_FOLDER -p PLlrxD0HtieHi0mwteKBOfEeOYf0LJU4O1

python3 transcript_enrich_speaker.py -f $TRANSCRIPT_FOLDER
python3 transcript_enrich_bucket.py -f $TRANSCRIPT_FOLDER -m $TRANSCRIPT_BUCKET_MINUTES
python3 transcript_enrich_summaries.py -f $TRANSCRIPT_FOLDER
python3 transcript_enrich_embeddings.py -f $TRANSCRIPT_FOLDER
python3 transcript_enrich_lite.py -f $TRANSCRIPT_FOLDER

# 若 master_enriched.json 存在,重命名为 embedding_index_full_3m.json
if [ -f "./$TRANSCRIPT_FOLDER/output/master_enriched.json" ]; then
    mv ./$TRANSCRIPT_FOLDER/output/master_enriched.json ./$TRANSCRIPT_FOLDER/output/embedding_index_full_${TRANSCRIPT_BUCKET_MINUTES}m.json
fi

# 若 master_enriched_lite.json 存在,重命名为 embedding_index_3m.json
if [ -f "./$TRANSCRIPT_FOLDER/output/master_enriched_lite.json" ]; then
    mv ./$TRANSCRIPT_FOLDER/output/master_enriched_lite.json ./$TRANSCRIPT_FOLDER/output/embedding_index_${TRANSCRIPT_BUCKET_MINUTES}m.json
fi

可以读出几个关键约定:

  • TRANSCRIPT_FOLDER=transcripts_the_ai_show 是所有阶段的统一工作目录,output 子目录存放中间产物;
  • -p PLlrxD0HtieHi0mwteKBOfEeOYf0LJU4O1 是 AI Show 播放列表的 ID,决定下载哪些视频;
  • -m 3 让分桶阶段按 3 分钟切段,文件名后缀 _3m 由此而来(改成其他分钟数会自动体现在输出文件名中,如 embedding_index_5m.json);
  • 最后的两个 mv 把内部通用文件名 master_enriched.json / master_enriched_lite.json 重命名为带段长的最终产物名,供搜索应用引用。

6. 管线六个阶段的源码级实现

以下各节均基于 scripts 目录源码,帮助你在复现或排错时理解每个脚本到底做了什么。

6.1 字幕下载:transcript_download.py

transcript_download.py 同时依赖两个外部 API:

  • YouTube Data API v3googleapiclient.discovery.build("youtube", "v3", ...)):调用 playlistItems().list(part="snippet", playlistId=..., maxResults=50) 并按 nextPageToken 循环翻页,把播放列表里所有视频条目压入线程队列(L136-L160);
  • youtube-transcript-apiYouTubeTranscriptApi.get_transcript(video_id) 拉取单个视频字幕。

实现上有几个值得注意的工程细节:

  • 并发度 PROCESSING_THREADS = 40,用 40 个线程消费队列下载字幕;
  • 每个视频生成两个文件:<videoId>.json(元数据:titledescriptionvideoId、初始为空的 speaker)与 <videoId>.json.vtt(字幕片段数组,每项含 text/start/duration,并清理了换行符);
  • 幂等设计:若 .json.vtt 文件已存在则跳过该视频,因此脚本可以安全地中断后重跑(L92-L95)。

6.2 说话人识别:transcript_enrich_speaker.py

transcript_enrich_speaker.pyOpenAI Functions(函数调用)做实体抽取:从"标题 + 视频描述 + 前 3 分钟字幕"中提取讲者姓名。

  • 输入文本由三部分拼接:The title is: <title> <description> <前 SEGMENT_MIN_LENGTH_MINUTES=3 分钟的字幕>L195);
  • 函数定义 get_speaker_name 要求返回一个 speakers 字符串字段;请求中 temperature=0.0tool_choice 强制使用该函数,保证输出结构稳定(L115-L130);
  • 通过 OpenAI SDK 的 base_url=f"{endpoint}/openai/v1/" 直连 Azure OpenAI,即把 Azure 服务当作兼容端点使用;
  • 可靠性用 tenacity 装饰器保障:最多重试 4 次、wait_random_exponential(min=6, max=10) 指数退避,且 BadRequestError 不重试(参数错误重试无意义)(L104-L108);
  • 10 个线程并发处理队列文件,若累计错误超过 100 个则整体退出,避免带着大量脏数据继续跑后续阶段。

6.3 三分钟分桶:transcript_enrich_bucket.py

transcript_enrich_bucket.py 把完整字幕切分为固定长度的文本段,这是决定"搜索定位粒度"的核心步骤:

  • 段长由命令行 -m 控制,脚本内部默认值 SEGMENT_LENGTH_MINUTES = 5,而编排脚本传入 -m 3,最终生效为 3 分钟;
  • 重叠机制:常量 PERCENTAGE_OVERLAP = 0.05L20)。每当开启新段时,会把下一段开头约 5% 的单词追加到上一段末尾(append_text_to_previous_segment),防止句子在边界处被截断,提升检索上下文的完整性——这对应了课程 README 中"段与段之间重叠约 20 个词"的描述,从源码看其实现是按下一段词数的百分比计算的;
  • Token 预算MAX_TOKENS = 2048,用 tiktokengpt-4o-mini 的编码实时统计 token 数(L43-L44)。除了时间到 3 分钟外,token 数接近上限也会提前切段,为下一步 60 词摘要请求预留 1024 token 空间(源码注释明示);
  • 每段文本开头会拼接 The speaker's name is <speaker>. <title>. <description>.,让说话人与视频信息进入向量语义空间;
  • 产物写入 output/master_transcriptions.jsonL229-L231)。

6.4 段落摘要:transcript_enrich_summaries.py

transcript_enrich_summaries.py 将每个 3 分钟文本段交给 OpenAI Chat 部署(AZURE_OPENAI_MODEL_DEPLOYMENT_NAME,缺省 gpt-4o-mini)压缩为约 60 词的摘要。摘要随后存入索引,作用是:搜索结果可以直接展示"这一段讲了什么",而不必把原始 3 分钟口语文本整段抛给用户,同时也让向量更聚焦于段落主旨。

6.5 向量化:transcript_enrich_embeddings.py

transcript_enrich_embeddings.py 读取 output/master_enriched.json,对每段文本调用 Azure OpenAI Embeddings API:

client = AzureOpenAI(
    api_key=API_KEY,
    azure_endpoint=RESOURCE_ENDPOINT,
    api_version="2024-10-21",
)
  • 使用 SDK 的 AzureOpenAI 客户端,固定 api_version="2024-10-21"L33-L37);
  • 嵌入部署名从 AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT 读取,缺省 text-embedding-ada-002
  • tiktokencl100k_base 编码做文本规范化与长度控制,6 个线程并发请求;
  • 每个文本段得到一个 1536 维向量,与段文本、时间戳、说话人、摘要等字段一起写入索引——这正是课程 README 中"Embedding API returns a vector of 1536 numbers"的实现来源。

6.6 精简版索引:transcript_enrich_lite.py

transcript_enrich_lite.py 基于完整版索引生成 lite 版本,移除 text 属性(保留向量、摘要、时间戳等)。搜索应用加载索引后并不直接展示原始口语文本,去掉该字段可以显著减小 JSON 体积、加快加载;完整版 embedding_index_full_3m.json 仍保留原文供调试与再处理使用。

7. 产物如何被第 08 课消费

管线跑完后得到的 embedding_index_3m.json 与仓库内预置的 embedding_index_3m.json 结构一致。第 08 课的练习与解答 Notebook(08-building-search-applications/python/aoai-assignment.ipynbaoai-solution.ipynb)直接加载该索引到 Pandas DataFrame,将用户问题同样调用 Embeddings API 向量化后,与索引中每个 3 分钟片段做余弦相似度排序,返回相似度最高的片段及其视频时间戳。

语义查询 "can you use rstudio with azure ml?" 返回带时间戳的 YouTube 视频链接

两个工程提示(来自课程 README 与源码结构):

  1. 存储选型:教学场景用 JSON 文件 + Pandas 即可;生产环境应把索引存入向量数据库(如 Azure Cognitive Search、Redis、Pinecone、Weaviate 等),由数据库承担近似最近邻检索;
  2. 为什么用余弦相似度而非欧氏距离:两个文档即使因长度不同导致欧氏距离很大,只要方向接近,余弦相似度依然很高,因此对"语义相近"的文本段更鲁棒。

8. 复现要点清单

  • 平台前提:Windows 11 / macOS Ventura / Ubuntu 22.04+,Python ≥ 3.9;
  • 先用 Azure CLI 更新版本,再按顺序执行:创建资源组 → 创建 --kind OpenAI 账户 → 取 endpoint 与 key → 部署 text-embedding-ada-002(v2+)与 gpt-4o-mini 两个部署;
  • 配置 4 个必填环境变量(可选 AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT),在 scripts 目录建虚拟环境并 pip install -r requirements.txt
  • 直接运行三平台对应的 prepare_transcripts_ai_show.* 编排脚本,按 下载 → 说话人 → 分桶(-m 3) → 摘要 → 向量化 → 精简 的顺序执行;
  • 产物位于 transcripts_the_ai_show/output/ 下:embedding_index_full_3m.json(完整)与 embedding_index_3m.json(精简,供搜索应用);各下载步骤具备幂等性,可断点重跑,OpenAI 调用侧内置了指数退避重试。
登录后查看全文
热门项目推荐
相关项目推荐