
最近在处理一批课程录制视频时我遇到了一个很典型的麻烦几百个文件全部叫VID_20250101_100001.mp4这种名字除了日期和序号完全看不出内容是什么。想从里面找到某次需求评审会的录像只能挨个点开预览每次少则花几分钟多则半小时。手动重命名显然不现实传统按时间、按设备命名的工具又解决不了文件内容是什么这个最核心的问题。批量智能重命名的关键其实不在于“重命名”这个动作而在于“让文件名自动携带视频内容信息”。这个需求拆开来看就两条路先把视频里的语音转成文本再让大模型根据文本生成一个语义化文件名。本文要讲的正是这样一套两步法语音识别字幕 AI 改名并且会完整覆盖远程 Linux 环境下的实操过程包括环境搭建、API 配置、全套 Python 代码、运行验证和避坑清单。读完这篇文章你可以在自己的远程服务器或本地 Linux 环境中跑通一整套视频批量智能重命名工具并且搞清楚 API 配置中那些最容易出错的地方。文章不会给你一个只存在于 PPT 里的方案而是把每一步命令、每一段代码、每一个可能报错的位置都摆出来。1. 为什么要做视频批量智能重命名从真实痛点说起先还原一下场景。你手头的视频来源通常很杂手机拍摄、相机录制、会议软件录屏、直播回放、课程切片默认文件名五花八门。手机拍出来一般是VID_20250101_123456.mp4。相机的命名规则可能是_DSC0001.MOV。录屏软件通常是Recording 2025-01-01 10.30.00.mp4。从网上下载的课程甚至可能是lesson_12_final_v3.mp4。这些文件名有一个共同问题它们只描述“文件是什么时候产生的”不描述“文件里面讲了什么”。等到视频数量超过几十个检索成本会急剧上升。你依赖的不是文件名而是记忆。但人的记忆恰恰不可靠。三个月后再去找某一次线上分享的录像你大概率已经不记得它存在哪个目录下了。传统自动命名工具能做什么按拍摄时间重命名、按文件大小去重、按目录结构归档。这些方案本质上都是在整理“容器”而不是整理“内容”。真正要解决视频检索问题必须让文件名携带内容语义。比如一个视频语音识别后是“本期我们讨论混合精度训练在 8 卡环境下的显存优化策略”那么文件名如果变成显存优化_混合精度训练_20250101.mp4你三个月后一眼就知道这是什么。这就引出了智能重命名的价值判断它降低的不是“改文件名”的操作成本而是“找视频”的认知成本。操作成本是几秒钟的事认知成本却可能在每次检索时反复发生。一个能理解视频内容的命名工具把低频操作转化为一次性的自动化流程长期收益非常明显。当然要提前说明适用边界。这套方案依赖视频里有可识别的语音内容。如果视频全程静音、只有背景音乐或者画面内容才是重点那纯语音识别方案会失效。后续如果要处理这类视频需要结合 OCR 识别画面文字、或提取关键帧再做多模态理解那是另一个话题。2. 两步法整体架构语音识别 AI 改名的核心逻辑2.1 两步法究竟是哪两步第一步是语音识别也就是 ASRAutomatic Speech Recognition。把视频音轨提取出来转成文字。这一步的输出是一段对话文本可以带时间戳也可以不带。对重命名场景来说通常不需要精确到秒的时间戳只需要把识别出来的文本按顺序拼接成完整段落。第二步是 AI 改名也就是调用大模型 LLM API。把第一步得到的文本作为上下文让模型生成一个符合文件系统命名规则的文件名。这一步的本质不是“翻译”或“总结”而是“语义压缩”把几百上千字的语音内容压缩成 4 到 30 个字的文件名。为什么是两步而不是一步因为语音识别和语义理解是两个不同层次的问题。语音识别模型负责把声音变成字这是事实层面的转换大模型负责理解这段话在讲什么主题这是语义层面的提炼。如果直接在语音识别阶段让模型输出文件名会让 ASR 模型承担它不擅长的工作结果往往不稳定。拆成两步之后每一环都可以独立优化识别不准就换 ASR 模型名字不理想就调 Prompt 或换 LLM 模型。2.2 核心概念速览在继续之前先统一几个关键术语后面所有代码和配置都会用到。ASR自动语音识别把音频转成文字。本文采用的 faster-whisper 是 OpenAI Whisper 模型的高效实现在 CPU 上也能跑对远程服务器很友好。字幕文本语音识别输出的文本。可以理解为带时间轴的纯文本但重命名场景只需要纯文本内容。LLM API大模型接口。本文采用 OpenAI 兼容接口统一用base_url api_key的方式访问国内外的多种服务商都支持这种协议。Prompt 工程构造给模型的指令。本文的重点不是让模型写作文而是让它严格输出一个文件名所以 Prompt 必须明确约束格式和长度。dry-run预演模式。不真正改文件名只打印“原文件名 - 新文件名”的重命名计划。这是批量重命名工具的生命线。幂等性同一个输入多次执行结果一致不会重复改名或覆盖文件。通过目标文件存在检测和唯一后缀来实现。这些概念不复杂但它们共同决定了整个工具的正确性和安全性。很多人做一个批量重命名脚本第一版就敢直接用os.rename结果目标文件已存在时数据被覆盖或者文件名含非法字符导致失败。这些都是可以提前规避的工程问题。2.3 本地 ASR 与云端识别怎么选语音识别这一环有两种路线本地模型和云端 API。两者差异明显。对比维度本地 ASRfaster-whisper云端 ASR API成本一次部署之后免费按音频时长计费量大成本高隐私音频不出服务器音频需上传到第三方识别速度取决于 CPU/GPUCPU 可用 int8 加速取决于网络和服务端负载部署难度需要安装 Python 依赖和模型文件只需要 API Key不用部署模型离线可用完全离线可用必须联网从工程角度看本地 ASR 更适合批量处理。尤其当你处理的是几十上百个视频时云端 API 的费用会成为一个不可忽视的成本项。本地部署的 faster-whisper 在 CPU 上用small模型处理一小时音频耗时大概在几分钟到十几分钟之间完全可以接受。隐私也是另一个考量点很多会议录像包含内部信息不该上传到第三方识别。所以本文采用本地 faster-whisper 方案把成本控制在自己这边。3. 远程环境准备与 API 配置避坑3.1 远程服务器环境规划本文的场景是“远程实操”也就是你已经通过 SSH 登录到一台 Linux 服务器上没有图形界面全部操作通过命令行完成。更稳妥的判断是大多数个人服务器和云主机都是 Ubuntu 或 Debian 系系统因此下面的命令以这类系统为例。如果你的系统是 CentOS 或其它发行版包管理器命令需要相应调整。建议先规划好目录结构避免把所有文件堆在一个目录里。mkdir -p ~/video-renamer/{input,work,logs} cd ~/video-renamerinput存放待重命名的视频文件。work存放临时音频文件和中间结果可随时清理。logs存放运行日志。video_renamer.py核心脚本放在~/video-renamer根目录。然后创建 Python 虚拟环境并安装依赖。版本方面建议 Python 3.10 或更高版本具体以你服务器上可用的版本为准本文示例不绑定特定版本。cd ~/video-renamer python3 -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install faster-whisper openai python-dotenv这里有一个容易踩坑的地方faster-whisper依赖ctranslate2在部分服务器上安装会比较慢需要耐心等待。如果安装失败先检查 pip 源是否可用必要时可以换成国内镜像源但这不是本文讨论的重点。ffmpeg 是另一个必须的组件。语音识别前需要从视频中提取音频ffmpeg 负责完成这个任务。执行下面的命令检查ffmpeg -version如果提示没有安装在 Ubuntu/Debian 上执行sudo apt update sudo apt install -y ffmpegffmpeg 装好后音频提取基本不会出问题。后面代码里会用subprocess调用它所以它不仅要在当前 shell 里可用还要在脚本的 PATH 环境变量里可找到。这一点在远程环境中通常没问题但如果你通过 systemd 或 cron 运行脚本要注意 PATH 可能被精简过。3.2 API Key 配置.env 文件与环境变量AI 改名环节需要调用 LLM API。这里的关键安全原则是API Key 不要硬编码在代码里也不要提交到 Git 仓库。推荐方式是用.env文件配合python-dotenv加载。在项目根目录创建.env文件# 文件路径~/video-renamer/.env # 语音识别模型tiny / base / small / medium / large-v3 # 本地 CPU 运行推荐 small速度和效果比较均衡 VIDEO_RENAME_ASR_MODELsmall # LLM API Key请换成你自己的 VIDEO_RENAME_API_KEYsk-xxxxxxxxxxxxxxxxxxxxxxxx # OpenAI 兼容接口地址按你使用的服务商文档填写 VIDEO_RENAME_BASE_URLhttps://api.openai.com/v1 # 使用的模型名 VIDEO_RENAME_LLM_MODELgpt-4o-mini注意.env文件里的值不要加单引号或双引号python-dotenv会原样读取。如果值中包含#字符会被当作注释所以避免在 Key 中使用特殊字符更稳妥的做法是按服务商生成的原始 Key 复制粘贴不要手动增删字符。为什么不直接用环境变量因为远程环境下你每次新建 SSH 会话都要重新export一遍很麻烦。.env文件是项目级的配置方案脚本启动时自动加载团队协作时每个人用自己的.env互不干扰。3.3 API 配置避坑清单这部分是标题里重点提到的“避坑讲解”。API 配置表面简单但在远程实操中有一堆具体的坑这里逐一列出。第一环境变量名不要用太通用的名字。比如API_KEY、OPENAI_API_KEY这种名字很容易和服务器上其它项目冲突。如果你的 shell 里已经导出了一个同名变量脚本读取到的就是旧值跟你实际填写的 Key 不一致排查起来非常隐蔽。更稳妥的做法是用带项目前缀的名字比如VIDEO_RENAME_API_KEY。第二.env文件里的值不要带引号。很多人习惯了在配置项里写sk-xxxx但python-dotenv不会像 shell 那样自动去掉引号它会把引号当成 Key 的一部分。最终结果是认证失败报 401。如果你在 Windows 上用记事本编辑过.env上传到 Linux 后还要注意换行符问题可以用cat -A .env检查如果每行结尾出现^M说明有\r字符残留需要用dos2unix .env转换。第三BASE_URL的路径不要重复拼接。OpenAI 兼容接口的地址通常是https://api.openai.com/v1OpenAI SDK 会自动在请求路径上追加/chat/completions。如果你填成https://api.openai.com/v1/chat/completionsSDK 会再次拼接导致请求地址变成/v1/chat/completions/chat/completions直接 404。这里真正容易出错的地方是不同服务商的文档写法不同有的写https://api.xxx.com/v1有的已经包含了完整路径。更稳妥的判断是SDK 的base_url只应填到版本号不要包含具体接口路径。第四模型权限不一致会导致 403 或 404。有时候你的 Key 本身有效但该 Key 对应的账号没有某个模型的访问权限。比如 Key 是 A 模型的权限你却填了 B 模型名。排查时看返回信息里的model字段确认服务商侧是否对这个模型开放了访问。第五网络超时问题在远程环境里很常见。服务器到 API 服务商的网络质量决定了请求是否稳定。OpenAI SDK 允许设置timeout参数建议设置成 30 到 60 秒避免默认值过短导致误判失败。同时脚本中应加入重试逻辑对 429、500、网络错误做指数退避重试。这些在代码示例里会体现出来。第六也是容易被忽略的一点先在脚本里打印一次 Key 的前几位确认配置真正被加载了再去做后续请求。很多“明明配置了却报错”的问题最后都是因为.env文件路径不对load_dotenv()没找到文件。脚本默认从当前工作目录查找.env如果你在别的目录执行脚本就会加载失败。处理方法是给.env文件写绝对路径。4. 核心流程拆解从视频到文件名要经过哪些步骤4.1 第一步提取音频视频文件不能直接交给 ASR 模型需要先把音轨提取成固定格式的音频。这里用 ffmpeg 把任意视频格式转换成 16kHz 单声道 WAV。为什么是 16kHz因为 Whisper 系列模型在训练时对音频做了统一处理16kHz 是它的标准输入采样率。单声道-ac 1可以减少数据量对语音识别没有负面影响。这个参数组合是语音识别任务中的通用实践。ffmpeg -y -i input.mp4 -ac 1 -ar 16000 -f wav output.wav-y表示覆盖已存在的文件。在实际脚本中每个视频会生成一个独立的临时音频文件处理完可以清理也可以保留在work目录里方便排查问题。4.2 第二步语音识别生成字幕文本音频提取完成后交给 faster-whisper 转写。faster-whisper 支持多种模型尺寸从tiny到large-v3。模型越大识别越准但推理耗时越长内存占用也越高。在远程服务器上更稳妥的选择是small或base。small在 CPU 上运行速度尚可识别准确率也能接受。tiny虽然快但对中文、英文、口音的识别效果差很多。如果你的服务器有 GPU可以考虑medium或large-v3识别质量会有明显提升。调用时建议开启vad_filterTrue也就是语音活动检测。它能过滤掉静音片段和纯音乐片段让输出的文本更干净。否则视频中的长时间停顿可能导致识别出大量空片段。from faster_whisper import WhisperModel model WhisperModel(small, devicecpu, compute_typeint8) segments, info model.transcribe(output.wav, languagezh, vad_filterTrue) text .join(seg.text.strip() for seg in segments)languagezh是显式指定识别语言如果你不确定视频语言可以省略这个参数让模型自动检测。自动检测会稍微增加延迟但通用性更强。4.3 第三步文本清洗与截断语音识别输出的文本通常包含大量口语内容比如“嗯”“啊”“然后”“就是说”这类填充词。这些词对生成文件名没有帮助反而会干扰模型理解主题。所以需要做基本的清洗。清洗规则不需要太复杂去掉空白符和换行符把多段识别结果拼接成一个完整段落。去掉无意义的语气词。这一步可以用正则表达式做简单的过滤。控制文本长度。LLM 输入有 token 限制而且超长文本会显著增加费用和延迟。对重命名来说视频前几分钟通常已经能表达主题所以截断到 1000 到 1500 字符是合理的。import re def clean_transcript(transcript: str, max_chars: int 1200) - str: transcript re.sub(r\s, , transcript) transcript re.sub(r嗯|啊|呃|然后|就是说, , transcript) if len(transcript) max_chars: transcript transcript[:max_chars] return transcript4.4 第四步构造 Prompt 并调用 LLM API这是整个流程中最需要调优的环节。Prompt 写得好不好直接决定生成的文件名是否可用。我的经验是把系统 Prompt 写得非常明确你是视频文件命名助手不是聊天助手也不是摘要生成器。你只输出一个文件名不要解释不要加引号不要带扩展名。同时明确禁止文件系统非法字符。system_prompt ( 你是一个视频文件命名助手。你会收到一段语音识别出来的字幕文本 请根据这段文本为视频生成一个简洁、可读的文件名不要扩展名。 要求中文优先字数控制在 4 到 30 个字之间 不要使用斜杠、反斜杠、冒号、星号、问号、双引号、尖括号、竖线等非法字符 只输出一个文件名不要任何解释和标点符号开头。 ) user_prompt f字幕文本\n{transcript}调用时使用 OpenAI 兼容接口。temperature0.3是一个较稳定的选择太低可能输出过于机械太高容易产生格式漂移。from openai import OpenAI client OpenAI(api_keyapi_key, base_urlbase_url) resp client.chat.completions.create( modelllm_model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature0.3, max_tokens80, ) raw_name resp.choices[0].message.content.strip()注意max_tokens80就够用了文件名不需要很长。如果模型返回了带引号的内容后面需要做过滤处理。4.5 第五步生成安全文件名LLM 返回的内容不能直接当文件名使用必须经过一层安全过滤。这一步做三件事过滤非法字符、去掉首尾空格和点号、限制最大长度。def safe_filename(name: str, max_len: int 80) - str: name re.sub(r[\\/:*?|\r\n\t], _, name) name name.strip( ._) name name.strip(\) if len(name) max_len: name name[:max_len].rstrip( ._) return name为什么需要max_len因为文件系统对文件名长度有限制常见限制是 255 字节。对中文文件名来说虽然中文在 Linux 下通常按 3 字节计算但保险起见80 个字符的上限足够覆盖绝大多数场景。这个上限同时也能约束 LLM 输出避免模型生成一大段句子充当文件名。4.6 第六步批量执行与重命名安全最后一步是重命名。这里最重要的工程习惯是先计划后执行。脚本默认只打印重命名方案展示每个文件的旧名字和新名字用户确认无误后再加--apply参数真正执行。重命名时要处理目标文件已存在的情况。如果你把A.mp4改成B.mp4而目录里正好有一个B.mp4直接os.rename会覆盖已有文件这是不可接受的。所以脚本里实现了unique_path逻辑如果目标文件已存在自动追加_1、_2这样的后缀直到找到不冲突的名字。def unique_path(target: Path) - Path: if not target.exists(): return target stem, suffix target.stem, target.suffix i 1 while True: candidate target.with_name(f{stem}_{i}{suffix}) if not candidate.exists(): return candidate i 15. 完整示例与代码实现可复制的视频批量重命名工具下面给出一个完整的 Python 脚本集成了上面所有步骤。你可以把它保存为video_renamer.py放在~/video-renamer目录下运行。#!/usr/bin/env python3 # 文件路径~/video-renamer/video_renamer.py 视频批量智能重命名工具 流程 1. ffmpeg 提取音频 2. faster-whisper 语音识别生成字幕文本 3. LLM API 根据文本生成文件名 4. dry-run 预演 / --apply 执行重命名 用法 python video_renamer.py --input ./input --dry-run python video_renamer.py --input ./input --apply import argparse import os import re import subprocess import sys from pathlib import Path from dotenv import load_dotenv # 项目根目录下的 .env BASE_DIR Path(__file__).resolve().parent load_dotenv(BASE_DIR / .env) VIDEO_EXTS {.mp4, .mkv, .mov, .avi, .flv, .webm, .ts, .m4v} AUDIO_SAMPLE_RATE 16000 def load_api_config(): api_key os.getenv(VIDEO_RENAME_API_KEY, ).strip() base_url os.getenv(VIDEO_RENAME_BASE_URL, https://api.openai.com/v1).strip() llm_model os.getenv(VIDEO_RENAME_LLM_MODEL, gpt-4o-mini).strip() asr_model os.getenv(VIDEO_RENAME_ASR_MODEL, small).strip() if not api_key: print([错误] 未找到 VIDEO_RENAME_API_KEY请检查 .env 文件) sys.exit(1) return api_key, base_url, llm_model, asr_model def get_video_files(input_dir: Path): files [] for f in sorted(input_dir.iterdir()): if f.is_file() and f.suffix.lower() in VIDEO_EXTS: files.append(f) return files def extract_audio(video_path: Path, wav_path: Path): cmd [ ffmpeg, -y, -i, str(video_path), -ac, 1, -ar, str(AUDIO_SAMPLE_RATE), -f, wav, str(wav_path), ] subprocess.run(cmd, checkTrue, capture_outputTrue) def load_asr_model(asr_model_name: str): from faster_whisper import WhisperModel print(f[信息] 加载 ASR 模型{asr_model_name}) return WhisperModel(asr_model_name, devicecpu, compute_typeint8) def transcribe(model, wav_path: Path, language: str None) - str: segments, _ model.transcribe( str(wav_path), languagelanguage, vad_filterTrue, beam_size5, ) texts [] for seg in segments: texts.append(seg.text.strip()) return .join(texts) def clean_transcript(transcript: str, max_chars: int 1200) - str: transcript re.sub(r\s, , transcript) if len(transcript) max_chars: transcript transcript[:max_chars] return transcript def build_prompt(transcript: str): system_prompt ( 你是一个视频文件命名助手。你会收到一段语音识别出来的字幕文本 请根据这段文本为视频生成一个简洁、可读的文件名不要扩展名。 要求中文优先字数控制在 4 到 30 个字之间 不要使用斜杠、反斜杠、冒号、星号、问号、双引号、尖括号、竖线等非法字符 只输出一个文件名不要任何解释和标点符号开头。 ) user_prompt f字幕文本\n{transcript} return system_prompt, user_prompt def gen_filename(system_prompt: str, user_prompt: str, api_key: str, base_url: str, llm_model: str) - str: from openai import OpenAI client OpenAI(api_keyapi_key, base_urlbase_url, timeout60) resp client.chat.completions.create( modelllm_model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature0.3, max_tokens80, ) return resp.choices[0].message.content.strip() def safe_filename(name: str, max_len: int 80) - str: name re.sub(r[\\/:*?|\r\n\t], _, name) name name.strip( ._) name name.strip(\) if len(name) max_len: name name[:max_len].rstrip( ._) return name def unique_path(target: Path) - Path: if not target.exists(): return target stem, suffix target.stem, target.suffix i 1 while True: candidate target.with_name(f{stem}_{i}{suffix}) if not candidate.exists(): return candidate i 1 def main(): parser argparse.ArgumentParser(description视频批量智能重命名工具) parser.add_argument(--input, requiredTrue, help存放视频的目录) parser.add_argument(--language, defaultNone, help语音识别语言如 zh/ja/en默认自动检测) parser.add_argument(--model, defaultNone, helpASR 模型大小默认读取 .env 或 small) parser.add_argument(--llm-model, defaultNone, helpLLM 模型名默认读取 .env) parser.add_argument(--apply, actionstore_true, help真正执行重命名默认只打印计划) args parser.parse_args() api_key, base_url, llm_model_default, asr_model_default load_api_config() asr_model args.model or asr_model_default llm_model args.llm_model or llm_model_default input_dir Path(args.input) if not input_dir.is_dir(): print(f[错误] 输入目录不存在{input_dir}) sys.exit(1) videos get_video_files(input_dir) if not videos: print([提示] 目录下没有找到视频文件) return work_dir input_dir / .rename_work work_dir.mkdir(exist_okTrue) print(f[信息] 发现 {len(videos)} 个视频文件) print(f[信息] ASR 模型{asr_model}LLM 模型{llm_model}) print(f[信息] 当前模式{正式执行--apply if args.apply else 预演dry-run}) model load_asr_model(asr_model) plan [] for idx, video in enumerate(videos, start1): print(f[{idx}/{len(videos)}] 处理{video.name}) wav_path work_dir / f{video.stem}_{idx}.wav try: print( 提取音频...) extract_audio(video, wav_path) print( 语音识别...) transcript transcribe(model, wav_path, args.language) if not transcript: print(f[警告] {video.name} 未识别到有效语音跳过) continue transcript clean_transcript(transcript) system_prompt, user_prompt build_prompt(transcript) print( 调用 LLM 生成文件名...) raw_name gen_filename(system_prompt, user_prompt, api_key, base_url, llm_model) new_name safe_filename(raw_name) video.suffix.lower() target unique_path(input_dir / new_name) plan.append((video, target)) print(f 字幕前缀{transcript[:50]}...) print(f 建议文件名{new_name}) except Exception as e: print(f[错误] {video.name} 处理失败{e}) continue if not plan: print([信息] 没有可重命名的文件) return print(\n 重命名计划 ) for old, new in plan: print(f {old.name} - {new.name}) if not args.apply: print(\n[提示] 当前为预演模式未真正修改文件。确认无误后加 --apply 执行。) return print(\n开始执行重命名...) for old, new in plan: if str(old) str(new): continue try: os.rename(old, new) print(f 已重命名{old.name} - {new.name}) except OSError as e: print(f[错误] 重命名失败{old.name} - {new.name}原因{e}) if __name__ __main__: main()这段代码有几个设计点需要解释。第一load_dotenv(BASE_DIR / .env)用的是绝对路径这样无论你在哪个目录下执行脚本都能找到.env文件。这比默认的相对路径可靠得多。第二ASR 模型在循环外只加载一次。如果把模型加载放在每个视频的识别函数里每处理一个视频就要重新载入一次模型CPU 环境下会浪费大量时间。这里先把模型加载提到主流程中再传给transcribe函数。第三openaiSDK 初始化时设置了timeout60秒避免请求卡死。如果你要处理的文件很多这个超时设置能帮助你及时发现问题。第四脚本默认就是 dry-run 模式只有显式加--apply才会真正改名。这种设计是为了防止误操作。日志里会完整打印重命名计划你可以先检查计划是否符合预期再决定是否执行。第五临时音频文件会保留在.rename_work目录中。如果后续需要排查识别问题可以直接用这些音频文件做测试不用重新提取。6. 运行结果与效果验证6.1 先跑一个视频验证流程第一次使用建议只用单个视频测试。比如在~/video-renamer/input目录下放一个真实的课程或会议视频然后运行cd ~/video-renamer source .venv/bin/activate python video_renamer.py --input ./input --language zh --dry-run--language zh显式指定中文识别可以减少自动检测带来的不确定性。如果视频是英文、日文等改成对应语言代码即可。运行成功后预期控制台输出类似下面的信息[信息]