A program for automatically generating subtitles for videos/audio using Whisper/TranslatePy/FFmpeg, and it can translate and add subtitles simultaneously.
from setuptools import setup, find_packages

requirements = [
    "openai-whisper",
    "parameterized",
    "srt",
    "ffmpeg-python",
    "translatepy"
]

setup(
    name="subtitle",
    version="1.0",
    description="Generate subtitles for video",
    install_requires=requirements,
    packages=find_packages(),
    entry_points={
        "console_scripts": [
            "subtitle = subtitle.main:main",
        ]
    },
)

setup.py
viking-man/subtitles_translator
import logging
import os.path
import time
from .whisper_model import WhisperModel
from whisper.utils import get_writer
from whisper.audio import load_audio
from translatepy import Translate
from .ffmpeg_utils import add_subtitles
from pathlib import Path


class Action:
    def __init__(self, args):
        self.args = args
        self.sampling_rate = 16000
        self.lang = self.args.lang
        self.target_lang = self.args.target_lang
        self.whisper_model = None
        self.vad_model = None
        self.detect_speech = None

        tic = time.time()
        self.whisper_model = WhisperModel(self.sampling_rate)
        self.whisper_model.load(self.args.whisper_model, self.args.device)

        logging.info(f"Done Init model in {time.time() - tic:.1f} sec")

    def transcribe(self):
        for input in self.args.inputs:
            logging.info(f'Translate {input}')
            start_time = time.time()
            path = Path(input)
            # 默认是当前路径

            audio = load_audio(input, self.sampling_rate)
            transcribe_result = self.whisper_model.transcribe(audio, self.args.lang)
            logging.info(f'Transcribe result for {input} is {transcribe_result}')

            # 输出目录
            output_dir = self.make_output_dir(self.args.output_dir, str(path.absolute().parent))
            # 生成字幕文件
            srt_file = self.writeSrtFile(output_dir, path, transcribe_result)

            srt_full_path = os.path.join(output_dir, srt_file)
            assert os.path.exists(srt_full_path), f"SRT file not generated?"
            logging.info(f"Save srt file [{input}] to [{srt_file}],time->[{time.time() - start_time:.1f}]")

            # self._save_md(filename + ".md", output, input)
            # logging.info(f'Saved texts to {filename + ".md"} to mark sentences')

    # 使用whisper自带的writer生成字幕文件
    def writeSrtFile(self, output_dir, path, transcribe_result):

        for segment in transcribe_result["segments"]:
            # 不想用到whsiper的新功能，高亮和字符限制的，只能用到英文上
            if "words" in segment:
                del segment["words"]
            # whisper字幕有点超前,延迟0.5s
            segment["start"] = segment["start"] + 0.5
            segment["end"] = segment["end"] + 0.5

        srt_writer = get_writer("srt", output_dir)
        srt_file = path.stem + ".srt"
        logging.info(f"output_dir->{output_dir},srt->{srt_file}")
        srt_writer(transcribe_result, srt_file, {"max_line_width": 47, "max_line_count": 1, "highlight_words": False})
        return srt_file

    def translate(self):
        for input in self.args.inputs:
            logging.info(f'Translate {input} from {self.lang} to {self.target_lang}')
            assert os.path.exists(input), f"File {input} does not exist"
            start_time = time.time()
            path = Path(input)
            #
            audio = load_audio(input, self.sampling_rate)
            translate_result = self.whisper_model.translate(audio, self.args.lang)
            logging.info(f'Translate result for {input} is {translate_result}')

            # 国内无法使用google翻译，默认使用英语
            self.translateToTargetLang(translate_result)
            logging.info(f'Translated result->{translate_result}')

            # 默认是输入文件的当前目录
            output_dir = self.make_output_dir(self.args.output_dir, str(path.absolute().parent))
            # 生成字幕文件
            srt_file = self.writeSrtFile(output_dir, path, translate_result)

            srt_full_path = os.path.join(output_dir, srt_file)
            assert os.path.exists(srt_full_path), f"SRT file not generated?"
            logging.info(f"Translate srt file [{input}] to [{srt_file}],time->[{time.time() - start_time:.1f}]")

        logging.info(f'Translate for {self.args.inputs} end')

    def translateToTargetLang(self, translate_result):
        if not self.args.China and self.args.target_lang is not "en":
            logging.info(f"Translate to {self.args.target_lang} start.")
            translator = Translate()
            # translate
            for i in range(len(translate_result["segments"])):
                segment_text = translate_result["segments"][i]["text"]
                try:
                    text_ = segment_text.replace("<u>", "").replace("</u>", "")
                    translate_text = translator.translate(text_, self.target_lang).result
                except Exception as e:
                    # 处理其他所有类型的异常
                    logging.info(f"An exception occurred when translate->{segment_text},error->{str(e)}")
                    translate_text = segment_text
                translate_result["segments"][i]["text"] = translate_text

    def add_subtitles(self):

        # 没有指定字幕文件，先自动生成
        target_subtitles = self.args.target_subtitles
        if target_subtitles is None:
            logging.info(f'Did not specify target subtitles,transcribe subtitles for {self.args.inputs}')
            self.transcribe()

        self.addSubtitles()

    def addSubtitles(self):
        for i in range(len(self.args.inputs)):

            input = self.args.inputs[i]
            logging.info(f"Add subtitles for [{input}] starting")
            start_time = time.time()
            path = Path(input)
            input_name = path.stem
            suffix = path.suffix

            output_dir = self.make_output_dir(self.args.output_dir, str(path.absolute().parent))
            # 如果没有指定字幕文件，获取自动生成的字幕文件
            if self.args.target_subtitles is None:
                # 默认是当前路径
                target_subtitle = os.path.join(output_dir, input_name + ".srt")
            else:
                target_subtitle = str(Path(self.args.target_subtitles[i]).absolute())

            # 文件输出路径
            outputs = self.args.outputs
            if outputs is not None:
                output = str(Path(outputs[i]).absolute())
            else:
                output = os.path.join(output_dir, input_name + "_subtitle" + suffix)

            # 使用ffmpeg添加字幕
            logging.info(f'input_file->{input},subtitle_file->{target_subtitle},output_file->{output}')
            add_subtitles(input, target_subtitle, output)

            logging.info(f'Add subtitles for {input} end,output->{output},time->[{time.time() - start_time:.1f}]')

    def union(self):
        start_time = time.time()
        # translate
        self.translate()
        # add subtitles to video
        self.addSubtitles()

        logging.info(f'Union operations end,time->[{time.time() - start_time:.1f}]')

    # 生成视频对应的语言字幕，不做翻译
    def unionForTranscribe(self):
        # translate to english
        self.transcribe()
        # add subtitle to video
        self.addSubtitles()

        logging.info(f'Union operations for Transcribe end')

    def make_output_dir(self, output_dir, input_dir):
        if output_dir is None:
            output_dir = input_dir
        folder = os.path.abspath(output_dir)
        if not os.path.exists(folder):
            os.makedirs(folder)
        # os.chdir(folder)
        # assert os.getcwd() == folder
        return folder

subtitle/action.py
viking-man/subtitles_translator
import logging
import ffmpeg
import os
import re
import sys
from pathlib import Path


def escape_windows_path(path):
    # 将单个反斜杠替换为双反斜杠
    sub = re.sub(r'\\', r'\\\\', path)
    sub = "\'" + sub + "\'"
    split = sub.split(":")
    if len(split) == 2:
        return split[0] + "\\" + ":" + split[1]

    return sub


def is_windows():
    return sys.platform.startswith('win')

def add_subtitles(video_file, subtitle_file, output_file):
    # 使用 ffmpeg.input() 来指定输入文件和字幕文件
    input_video = ffmpeg.input(Path(video_file))
    input_subtitle = ffmpeg.input(Path(subtitle_file))

    # 区分系统
    if is_windows():
        subtitle_file = escape_windows_path(subtitle_file)
    logging.info(f'subtitle_file after transfer->{subtitle_file}')

    # 使用 filter() 添加字幕
    output = ffmpeg.output(
        input_video,  # 输入视频文件
        input_subtitle,  # 输入字幕文件
        output_file,
        # vcodec='copy',  # 视频编解码器，此处保持原样
        acodec='copy',  # 音频编解码器，此处保持原样
        scodec='mov_text',  # 字幕编解码器
        f='mp4',  # 输出文件格式
        vf=f'subtitles={subtitle_file}',  # 添加字幕滤镜
        strict='experimental',  # 使用实验性字幕编解码器
    )

    # 运行 ffmpeg 命令以创建输出文件
    ffmpeg.run(output)

    logging.info(f'字幕已添加到 {output_file}')

subtitle/ffmpeg_utils.py
viking-man/subtitles_translator
import argparse
import logging
from .type import WhisperModelEnum
from .action import Action


def getParser():
    parser = argparse.ArgumentParser(
        description="Generate subtitles of video by whisper transcribe",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument("inputs", type=str, nargs="+", help="Inputs filenames/folders")
    parser.add_argument(
        "-t",
        "--transcribe",
        help="Transcribe videos/audio into subtitles",
        action=argparse.BooleanOptionalAction,
    )
    parser.add_argument(
        "-tl",
        "--translate",
        help="1.Transcribe videos/audio to subtitles. 2.Translate generated subtitles to target language",
        action=argparse.BooleanOptionalAction,
    )
    parser.add_argument(
        "-a",
        "--add",
        help="Add generated subtitles into video",
        action=argparse.BooleanOptionalAction,
    )
    parser.add_argument(
        "-u",
        "--union",
        help="Union operations,including transcribe->translate->add subtitles to video",
        action=argparse.BooleanOptionalAction,
    )
    parser.add_argument(
        "-ut",
        "--union-transcribe",
        help="Union operations,including transcribe->add subtitles to video,not including translate",
        action=argparse.BooleanOptionalAction,
    )
    parser.add_argument(
        "--outputs",
        type=str,
        nargs="+",
        help="Outputs filenames/folders"
    )
    parser.add_argument(
        "--target-subtitles",
        nargs="+",
        default=None,
        help="The file name of target subtitles,if it's not specified,generate subtiltles for input",
    )
    parser.add_argument(
        "--China",
        default=None,
        help="Google translate is disable,cannot translate subtitles",
        action=argparse.BooleanOptionalAction,
    )
    parser.add_argument(
        "--output-dir",
        default=None,
        help="The directory of output,default is current path",
    )
    parser.add_argument(
        "--lang",
        type=str,
        default=None,
        choices=[
            "zh",
            "en",
            "Afrikaans",
            "Arabic",
            "Armenian",
            "Azerbaijani",
            "Belarusian",
            "Bosnian",
            "Bulgarian",
            "Catalan",
            "Croatian",
            "Czech",
            "Danish",
            "Dutch",
            "Estonian",
            "Finnish",
            "French",
            "Galician",
            "German",
            "Greek",
            "Hebrew",
            "Hindi",
            "Hungarian",
            "Icelandic",
            "Indonesian",
            "Italian",
            "Japanese",
            "Kannada",
            "Kazakh",
            "Korean",
            "Latvian",
            "Lithuanian",
            "Macedonian",
            "Malay",
            "Marathi",
            "Maori",
            "Nepali",
            "Norwegian",
            "Persian",
            "Polish",
            "Portuguese",
            "Romanian",
            "Russian",
            "Serbian",
            "Slovak",
            "Slovenian",
            "Spanish",
            "Swahili",
            "Swedish",
            "Tagalog",
            "Tamil",
            "Thai",
            "Turkish",
            "Ukrainian",
            "Urdu",
            "Vietnamese",
            "Welsh",
        ],
        help="The input language of transcription/translation",
    )
    parser.add_argument(
        "--target-lang",
        type=str,
        default="zh",
        choices=[
            "zh",
            "en",
            "Afrikaans",
            "Arabic",
            "Armenian",
            "Azerbaijani",
            "Belarusian",
            "Bosnian",
            "Bulgarian",
            "Catalan",
            "Croatian",
            "Czech",
            "Danish",
            "Dutch",
            "Estonian",
            "Finnish",
            "French",
            "Galician",
            "German",
            "Greek",
            "Hebrew",
            "Hindi",
            "Hungarian",
            "Icelandic",
            "Indonesian",
            "Italian",
            "Japanese",
            "Kannada",
            "Kazakh",
            "Korean",
            "Latvian",
            "Lithuanian",
            "Macedonian",
            "Malay",
            "Marathi",
            "Maori",
            "Nepali",
            "Norwegian",
            "Persian",
            "Polish",
            "Portuguese",
            "Romanian",
            "Russian",
            "Serbian",
            "Slovak",
            "Slovenian",
            "Spanish",
            "Swahili",
            "Swedish",
            "Tagalog",
            "Tamil",
            "Thai",
            "Turkish",
            "Ukrainian",
            "Urdu",
            "Vietnamese",
            "Welsh",
        ],
        help="The output language of translation",
    )
    parser.add_argument(
        "--whisper-model",
        type=str,
        default=WhisperModelEnum.SMALL.value,
        choices=WhisperModelEnum.get_values(),
        help="The whisper model used to transcribe.",
    )
    parser.add_argument(
        "--bitrate",
        type=str,
        default="10m",
        help="The bitrate to export the cutted video, such as 10m, 1m, or 500k",
    )
    # whisper 不支持mps
    parser.add_argument(
        "--device",
        type=str,
        default=None,
        choices=["cpu", "cuda"],
        help="Force to CPU/GPU for transcribing. In default automatically use GPU if available."
    )

    return parser


def main():
    # 命令行参数
    parser = getParser()
    logging.basicConfig(
        format="[parrot:%(filename)s:L%(lineno)d] %(levelname)-6s %(message)s"
    )
    logging.getLogger().setLevel(logging.INFO)
    args = parser.parse_args()
    print(args)
    if args.transcribe:
        logging.info("Transcribe start")

        Action(args).transcribe()
    elif args.translate:
        logging.info(f"Translate starting,input file->{args.inputs}")
        Action(args).translate()

    elif args.add:
        logging.info(f"Add subtitle->[{args.target_subtitles}] for [{args.inputs}] start")
        Action(args).add_subtitles()

    elif args.union:
        logging.info(f"Union operations for [{args.inputs}] start")
        Action(args).union()
    elif args.union_transcribe:
        logging.info(f"Union operations not including translate for [{args.inputs}] start")
        Action(args).unionForTranscribe()


#
if __name__ == "__main__":
    main()

subtitle/main.py
viking-man/subtitles_translator
from enum import Enum
from typing import TypedDict, Literal

SPEECH_ARRAY_INDEX = TypedDict("SPEECH_ARRAY_INDEX", {"start": float, "end": float})

LANG = Literal[
    "zh",
    "en",
    "Afrikaans",
    "Arabic",
    "Armenian",
    "Azerbaijani",
    "Belarusian",
    "Bosnian",
    "Bulgarian",
    "Catalan",
    "Croatian",
    "Czech",
    "Danish",
    "Dutch",
    "Estonian",
    "Finnish",
    "French",
    "Galician",
    "German",
    "Greek",
    "Hebrew",
    "Hindi",
    "Hungarian",
    "Icelandic",
    "Indonesian",
    "Italian",
    "Japanese",
    "Kannada",
    "Kazakh",
    "Korean",
    "Latvian",
    "Lithuanian",
    "Macedonian",
    "Malay",
    "Marathi",
    "Maori",
    "Nepali",
    "Norwegian",
    "Persian",
    "Polish",
    "Portuguese",
    "Romanian",
    "Russian",
    "Serbian",
    "Slovak",
    "Slovenian",
    "Spanish",
    "Swahili",
    "Swedish",
    "Tagalog",
    "Tamil",
    "Thai",
    "Turkish",
    "Ukrainian",
    "Urdu",
    "Vietnamese",
    "Welsh",
]



class WhisperModelEnum(Enum):
    TINY = "tiny"
    BASE = "base"
    SMALL = "small"
    MEDIUM = "medium"
    LARGE = "large"
    LARGE_V2 = "large-v2"

    @staticmethod
    def get_values():
        return [i.value for i in WhisperModelEnum]


subtitle/type.py
viking-man/subtitles_translator
import logging
import os
import numpy as np
import ffmpeg


def check_exists(output, force):
    if os.path.exists(output):
        if force:
            logging.info(f"{output} exists. Will overwrite it")
        else:
            logging.info(
                f"{output} exists, skipping... Use the --force flag to overwrite"
            )
            return True
    return False


def load_audio(file: str, sr: int = 16000) -> np.ndarray:
    try:
        out, _ = (
            ffmpeg.input(file, threads=0)
            .output("-", format="s16le", acodec="pcm_s16le", ac=1, ar=sr)
            .run(cmd=["ffmpeg", "-nostdin"], capture_stdout=True, capture_stderr=True)
        )
    except ffmpeg.Error as e:
        raise RuntimeError(f"Failed to load audio: {e.stderr.decode()}") from e

    return np.frombuffer(out, np.int16).flatten().astype(np.float32) / 32768.0

subtitle/utils.py
viking-man/subtitles_translator
from typing import Literal, Union, List, Any, TypedDict
import time
import logging


class WhisperModel:
    def __init__(self, sample_rate=16000):
        self.sample_rate = sample_rate
        self.device = None

    def load(self, model_name: Literal["tiny", "base", "small", "medium", "large", "large-v2"] = "small",
             device: Union[Literal["cpu", "cuda"], None] = None):
        self.device = device
        import whisper
        # 默认model保存在.cache文件夹下
        self.whisper_model = whisper.load_model(model_name, device)

    def transcribe(self, audio, lang):
        tic = time.time()

        res = self.whisper_model.transcribe(
            audio,
            task="transcribe",
            language=lang,
            verbose=True,
            word_timestamps=True
        )

        logging.info(f"Done transcription in {time.time() - tic:.1f} sec")
        return res

    def translate(self, audio, lang):
        tic = time.time()

        res = self.whisper_model.transcribe(
            audio,
            task="translate",
            language=lang,
            verbose=True,
            word_timestamps=True
        )

        logging.info(f"Done translate in {time.time() - tic:.1f} sec")
        return res

subtitle/whisper_model.py
viking-man/subtitles_translator
import re

import pytest
from translatepy import Translator
from translatepy.translators.google import GoogleTranslate
from pathlib import Path
import torch
import os
from subtitle.main import main
from subtitle import ffmpeg_utils


def test_tranlator():
    translator = Translator()
    result = translator.translate("이번에 마리또하잖아요", "Chinese")
    print(type(result))
    assert str == type(result.result)
    print(result.result)

    google_translate = GoogleTranslate()
    result_google = google_translate.translate("이번에 마리또하잖아요", "Chinese")
    print(result_google)


def test_path():
    path = Path("assets/tzuyu_20.mp4")
    assert path.stem == "tzuyu_20"
    assert path.suffix == ".mp4"
    print("resolve:" + str(path.resolve()))
    print("absolute:" + str(path.absolute().parent))
    # assert path.resolve().name == "xxx/xxxx/test"
    print(path)
    print(path.name)

    folder = os.path.abspath("xxx/")
    print("os-absolute->" + folder)

    folder = os.path.abspath("xxx/test.mp3")
    print(folder)
    print(os.getcwd())
    assert os.path.exists(os.path.abspath("."))
    print(os.path.abspath("."))

    path_absolute = Path("/Users/viking/video/trump_speech.mp4")
    assert path_absolute.stem == "trump_speech"
    print(path_absolute)

    path3 = os.path.abspath("/Users/viking/video/trump_speech.mp4")
    print(path3)
    print(os.path.dirname("/Users/viking/video/trump_speech.mp4"))


def test_loop():
    array = [1, 2, 3, 4, 5, 6]
    for i in range(len(array)):
        array[i] = array[i] + 1
    for e in array:
        print(e)


def test_not():
    assert not None == True
    assert not False == True


def escape_windows_path(path):
    # 将单个反斜杠替换为双反斜杠
    sub = re.sub(r'\\', r'\\\\', path)
    sub = sub.replace("\"", "\'")
    split = sub.split(":")
    if len(split) == 2:
        return split[0] + "\\" + ":" + split[1]

    return sub


def test_escape():
    path = "D:\\tools\\python\\test.srt"
    print(path)
    print(ffmpeg_utils.escape_windows_path(path))

test/FunctionTest.py
viking-man/subtitles_translator
import logging
import os
import unittest

from parameterized import parameterized, param
from subtitle.action import Action
from config import TEST_MEDIA_FILE, TEST_ASSETS_PATH, TestArgs
from pathlib import Path


class testTranslate(unittest.TestCase):

    # @classmethod
    def removeFileAfterTest(cls):
        for file in os.listdir(TEST_ASSETS_PATH):
            if file.endswith("srt") or "_subtitle" in os.path.basename(file):
                logging.info(f"remove srt file->{file}")
                os.remove(os.path.join(TEST_ASSETS_PATH, file))

    def test_default_transcribe(self):
        logging.info("检查默认参数生成字幕")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        # abspath = Path(full_path).absolute()
        # args.inputs = [abspath]
        args.inputs = [full_path]
        Action(args).transcribe()

        # os.chdir("../")
        srt_ = full_path.split(".")[0] + ".srt"
        logging.info(srt_)
        assert os.path.exists(srt_)

        self.removeFileAfterTest()

    def test_translate(self):
        logging.info("检查自动翻译成字幕")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        args.inputs = [full_path]
        Action(args).translate()

        srt_ = full_path.split(".")[0] + ".srt"
        logging.info(srt_)
        assert os.path.exists(srt_)

        self.removeFileAfterTest()

    def test_translate_with_lang(self):
        logging.info("检查自动翻译成目标语言字幕")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        args.inputs = [full_path]
        args.target_lang = "en"
        Action(args).translate()

        srt_ = full_path.split(".")[0] + ".srt"
        logging.info(srt_)
        assert os.path.exists(srt_)

        self.removeFileAfterTest()

    def test_union(self):
        logging.info("检查联合操作")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        args.inputs = [full_path]
        Action(args).union()

        srt_ = full_path.split(".")[0] + ".srt"
        assert os.path.exists(srt_)
        subtitle_video = full_path.split(".")[0] + "_subtitle.mp4"
        assert os.path.exists(subtitle_video)

        self.removeFileAfterTest()

    def test_union_for_china(self):
        logging.info("检查中国联合操作")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        args.inputs = [full_path]
        args.China = True
        Action(args).union()

        srt_ = full_path.split(".")[0] + ".srt"
        assert os.path.exists(srt_)
        subtitle_video = full_path.split(".")[0] + "_subtitle.mp4"
        assert os.path.exists(subtitle_video)

        self.removeFileAfterTest()

    def test_union_use_mediun_model(self):
        logging.info("检查使用中等模型")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        args.inputs = [full_path]
        args.whisper_model = "medium"
        Action(args).union()

        srt_ = full_path.split(".")[0] + ".srt"
        assert os.path.exists(srt_)
        subtitle_video = full_path.split(".")[0] + "_subtitle.mp4"
        assert os.path.exists(subtitle_video)

        self.removeFileAfterTest()

    def test_add_subtitle(self):
        logging.info("检查添加字幕")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        args.inputs = [full_path]
        args.target_subtitles = ["srt/tzuyu_20.srt"]
        Action(args).add_subtitles()

        subtitle_video = full_path.split(".")[0] + "_subtitle.mp4"
        assert os.path.exists(subtitle_video)

        self.removeFileAfterTest()

    def test_union_transcribe(self):
        logging.info("检查不包含翻译的联合操作")
        args = TestArgs()
        full_path = TEST_ASSETS_PATH + TEST_MEDIA_FILE
        args.inputs = [full_path]
        Action(args).unionForTranscribe()

        srt_ = full_path.split(".")[0] + ".srt"
        assert os.path.exists(srt_)
        subtitle_video = full_path.split(".")[0] + "_subtitle.mp4"
        assert os.path.exists(subtitle_video)

        self.removeFileAfterTest()

test/TranslateTest.py
viking-man/subtitles_translator
import logging
import os

# 定义一个日志收集器
logger = logging.getLogger()
# 设置收集器的级别，不设定的话，默认收集warning及以上级别的日志
logger.setLevel("DEBUG")
# 设置日志格式
fmt = logging.Formatter("%(filename)s-%(lineno)d-%(asctime)s-%(levelname)s-%(message)s")
# 设置日志处理器-输出到文件,并且设置编码格式
if not os.path.exists("./log"):
    os.makedirs("./log")
file_handler = logging.FileHandler("./log/log.txt", encoding="utf-8")
# 设置日志处理器级别
file_handler.setLevel("DEBUG")
# 处理器按指定格式输出日志
file_handler.setFormatter(fmt)
# 输出到控制台
ch = logging.StreamHandler()
# 设置日志处理器级别
ch.setLevel("DEBUG")
# 处理器按指定格式输出日志
ch.setFormatter(fmt)
# 收集器和处理器对接，指定输出渠道
# 日志输出到文件
logger.addHandler(file_handler)
# 日志输出到控制台
logger.addHandler(ch)

TEST_ASSETS_PATH = "assets/"
TEST_MEDIA_FILE = "tzuyu_20.mp4"


class TestArgs:
    def __init__(
            self,
            encoding="utf-8",
            sampling_rate=16000,
            bitrate="10m",
            lang="Korean",
            whisper_model="small",
            device=None,
            target_lang="zh",
            vad_model=None,
            output_dir=None,
            outputs=None,
            target_subtitles=None,
            China=None
    ):
        self.inputs = []
        self.bitrate = bitrate
        self.encoding = encoding
        self.sampling_rate = sampling_rate
        self.lang = lang
        self.whisper_model = whisper_model
        self.device = device
        self.target_lang = target_lang
        self.vad_model = vad_model
        self.output_dir = output_dir
        self.outputs = outputs
        self.target_subtitles = target_subtitles
        self.China = China

test/config.py
viking-man/subtitles_translator