Pipeline working, implements FFmpegSetupManager

This commit is contained in:
Guillaume Tâche
2024-08-09 20:30:21 +02:00
parent c2efb71195
commit 155b011c2b
54 changed files with 984 additions and 314 deletions

View File

@@ -1,11 +1,11 @@
package com.github.gtache.autosubtitle.modules.setup.whisper;
import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.setup.whisper.CondaSetupConfiguration;
import dagger.Module;
import dagger.Provides;
import javax.inject.Singleton;
import java.net.http.HttpClient;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -13,54 +13,54 @@ import java.nio.file.Paths;
* Setup module for Conda
*/
@Module
public abstract class CondaSetupModule {
public final class CondaSetupModule {
private static final String CONDA = "conda";
private static final String MINICONDA3 = "miniconda3";
@Provides
@Singleton
static HttpClient providesHttpClient() {
return HttpClient.newHttpClient();
private CondaSetupModule() {
}
@Provides
static CondaSetupConfiguration providesCondaSetupConfiguration(@CondaSystemPath final Path condaSystemPath, @CondaBundledPath final Path condaBundledPath,
@CondaMinimumMajorVersion final int condaMinimumMajorVersion, @CondaMinimumMinorVersion final int condaMinimumMinorVersion,
@CondaInstallerPath final Path condaInstallerPath, @CondaRootPath final Path condaRootPath,
final OS os, final Architecture architecture) {
return new CondaSetupConfiguration(condaRootPath, condaSystemPath, condaBundledPath, condaMinimumMajorVersion, condaMinimumMinorVersion, condaInstallerPath, os, architecture);
}
@Provides
@Singleton
@CondaSystemPath
static Path providesCondaSystemPath(final OS os) {
return Paths.get(os == OS.WINDOWS ? CONDA + ".bat" : CONDA);
}
@Provides
@Singleton
@CondaBundledPath
static Path providesCondaBundledPath(@CondaRootPath final Path root, final OS os) {
return root.resolve("condabin").resolve(Paths.get(os == OS.WINDOWS ? CONDA + ".bat" : CONDA));
}
@Provides
@Singleton
@CondaMinimumMajorVersion
static int providesCondaMinimumMajorVersion() {
return 24;
}
@Provides
@Singleton
@CondaMinimumMinorVersion
static int providesCondaMinimumMinorVersion() {
return 5;
}
@Provides
@Singleton
@CondaRootPath
static Path providesCondaRootPath(@WhisperBundledRoot final Path root, final OS os) {
return root.resolve(MINICONDA3);
}
@Provides
@Singleton
@CondaInstallerPath
static Path providesCondaInstallerPath(@WhisperBundledRoot final Path root, final OS os) {
return root.resolve("cache").resolve("conda-install" + (os == OS.WINDOWS ? ".exe" : ".sh"));

View File

@@ -7,7 +7,6 @@ import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import javax.inject.Singleton;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -21,28 +20,24 @@ public abstract class WhisperSetupModule {
abstract SetupManager bindsSubtitleExtractorSetupManager(final WhisperSetupManager manager);
@Provides
@Singleton
@PythonVersion
static String providesPythonVersion() {
return "3.9.19";
}
@Provides
@Singleton
@WhisperVersion
static String providesWhisperVersion() {
return "20231117";
}
@Provides
@Singleton
@WhisperBundledRoot
static Path providesWhisperBundledRoot() {
return Paths.get("tools", "whisper");
}
@Provides
@Singleton
@WhisperVenvPath
static Path providesWhisperVenvPath(@WhisperBundledRoot final Path root) {
return root.resolve("whisper-env");

View File

@@ -11,6 +11,10 @@ import dagger.Module;
@Module
public abstract class WhisperExtractorModule {
private WhisperExtractorModule() {
}
@Binds
abstract SubtitleExtractor bindsSubtitleExtractor(final WhisperSubtitleExtractor extractor);
}

View File

@@ -14,6 +14,10 @@ import javax.inject.Singleton;
@Module
public abstract class WhisperJsonModule {
private WhisperJsonModule() {
}
@Binds
@IntoMap
@StringKey("json")

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.modules.whisper;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperSetupModule;
import com.github.gtache.autosubtitle.modules.subtitle.extractor.whisper.WhisperExtractorModule;
import com.github.gtache.autosubtitle.modules.subtitle.parser.json.whisper.WhisperJsonModule;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
@@ -10,9 +11,13 @@ import dagger.Module;
/**
* Dagger module for Whisper
*/
@Module(includes = {WhisperJsonModule.class, WhisperExtractorModule.class})
@Module(includes = {WhisperSetupModule.class, WhisperJsonModule.class, WhisperExtractorModule.class})
public abstract class WhisperModule {
private WhisperModule() {
}
@Binds
abstract ExtractionModelProvider bindsExtractionModelProvider(final WhisperExtractionModelProvider provider);
}

View File

@@ -0,0 +1,30 @@
package com.github.gtache.autosubtitle.setup.whisper;
import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.impl.OS;
import java.nio.file.Path;
import java.util.Objects;
/**
* Configuration for conda setup
*/
public record CondaSetupConfiguration(Path condaRootPath, Path condaSystemPath, Path condaBundledPath,
int condaMinimumMajorVersion, int condaMinimumMinorVersion,
Path condaInstallerPath, OS os, Architecture architecture) {
public CondaSetupConfiguration {
Objects.requireNonNull(condaRootPath);
Objects.requireNonNull(condaSystemPath);
Objects.requireNonNull(condaBundledPath);
if (condaMinimumMajorVersion <= 0) {
throw new IllegalArgumentException("Conda minimum major version must be > 0 : " + condaMinimumMajorVersion);
}
if (condaMinimumMinorVersion < 0) {
throw new IllegalArgumentException("Conda minimum minor version must be >= 0 : " + condaMinimumMinorVersion);
}
Objects.requireNonNull(condaInstallerPath);
Objects.requireNonNull(os);
Objects.requireNonNull(architecture);
}
}

View File

@@ -1,13 +1,6 @@
package com.github.gtache.autosubtitle.setup.whisper;
import com.github.gtache.autosubtitle.impl.Architecture;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.modules.setup.whisper.CondaBundledPath;
import com.github.gtache.autosubtitle.modules.setup.whisper.CondaInstallerPath;
import com.github.gtache.autosubtitle.modules.setup.whisper.CondaMinimumMajorVersion;
import com.github.gtache.autosubtitle.modules.setup.whisper.CondaMinimumMinorVersion;
import com.github.gtache.autosubtitle.modules.setup.whisper.CondaRootPath;
import com.github.gtache.autosubtitle.modules.setup.whisper.CondaSystemPath;
import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupStatus;
import com.github.gtache.autosubtitle.setup.impl.AbstractSetupManager;
@@ -17,10 +10,7 @@ import org.apache.logging.log4j.Logger;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
@@ -36,30 +26,12 @@ public class CondaSetupManager extends AbstractSetupManager {
private static final Logger logger = LogManager.getLogger(CondaSetupManager.class);
private final Path condaSystemPath;
private final Path condaBundledPath;
private final int condaMinimumMajorVersion;
private final int condaMinimumMinorVersion;
private final Path condaInstallerPath;
private final Path condaRootPath;
private final OS os;
private final Architecture architecture;
private final HttpClient httpClient;
private final CondaSetupConfiguration configuration;
@Inject
CondaSetupManager(@CondaSystemPath final Path condaSystemPath, @CondaBundledPath final Path condaBundledPath,
@CondaMinimumMajorVersion final int condaMinimumMajorVersion, @CondaMinimumMinorVersion final int condaMinimumMinorVersion,
@CondaInstallerPath final Path condaInstallerPath, @CondaRootPath final Path condaRootPath,
final OS os, final Architecture architecture, final HttpClient httpClient) {
this.condaSystemPath = requireNonNull(condaSystemPath);
this.condaBundledPath = requireNonNull(condaBundledPath);
this.condaMinimumMajorVersion = condaMinimumMajorVersion;
this.condaMinimumMinorVersion = condaMinimumMinorVersion;
this.condaInstallerPath = requireNonNull(condaInstallerPath);
this.condaRootPath = requireNonNull(condaRootPath);
this.os = requireNonNull(os);
this.architecture = requireNonNull(architecture);
this.httpClient = requireNonNull(httpClient);
CondaSetupManager(final CondaSetupConfiguration configuration, final HttpClient httpClient) {
super(httpClient);
this.configuration = requireNonNull(configuration);
}
@Override
@@ -86,14 +58,15 @@ public class CondaSetupManager extends AbstractSetupManager {
}
private void installConda() throws SetupException {
if (Files.exists(condaInstallerPath)) {
logger.info("Conda exists at {}", condaInstallerPath);
final var installerPath = configuration.condaInstallerPath();
if (Files.exists(installerPath)) {
logger.info("Conda exists at {}", installerPath);
} else {
logger.info("Conda installer not found, downloading");
downloadConda();
logger.info("Conda downloaded");
}
switch (os) {
switch (configuration.os()) {
case WINDOWS -> installWindows();
case MAC, LINUX -> installLinux();
}
@@ -101,10 +74,12 @@ public class CondaSetupManager extends AbstractSetupManager {
private void installLinux() throws SetupException {
try {
logger.info("Installing conda using {}", condaInstallerPath);
final var result = run("bash", condaInstallerPath.toString(), "-b", "-p", condaRootPath.toString());
final var installerPath = configuration.condaInstallerPath();
final var rootPath = configuration.condaRootPath();
logger.info("Installing conda using {}", installerPath);
final var result = run("bash", installerPath.toString(), "-b", "-p", rootPath.toString());
if (result.exitCode() == 0) {
logger.info("Installed conda to {}", condaRootPath);
logger.info("Installed conda to {}", rootPath);
} else {
throw new SetupException("Error installing conda: " + result);
}
@@ -115,10 +90,12 @@ public class CondaSetupManager extends AbstractSetupManager {
private void installWindows() throws SetupException {
try {
logger.info("Installing conda using {}", condaInstallerPath);
final var result = run(condaInstallerPath.toString(), "/InstallationType=JustMe", "/RegisterPython=0", "/S", "/D=" + condaRootPath.toString());
final var installerPath = configuration.condaInstallerPath();
final var rootPath = configuration.condaRootPath();
logger.info("Installing conda using {}", installerPath);
final var result = run(installerPath.toString(), "/InstallationType=JustMe", "/RegisterPython=0", "/S", "/D=" + rootPath.toString());
if (result.exitCode() == 0) {
logger.info("Installed conda to {}", condaRootPath);
logger.info("Installed conda to {}", rootPath);
} else {
throw new SetupException("Error installing conda: " + result);
}
@@ -128,15 +105,16 @@ public class CondaSetupManager extends AbstractSetupManager {
}
private void downloadConda() throws SetupException {
switch (os) {
switch (configuration.os()) {
case WINDOWS -> downloadCondaWindows();
case MAC -> downloadCondaMac();
case LINUX -> downloadCondaLinux();
}
logger.info("Downloaded conda to {}", condaInstallerPath);
logger.info("Downloaded conda to {}", configuration.condaInstallerPath());
}
private void downloadCondaLinux() throws SetupException {
final var architecture = configuration.architecture();
if (architecture.isAMD64()) {
downloadConda("https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh");
} else if (architecture.isARM64()) {
@@ -147,6 +125,7 @@ public class CondaSetupManager extends AbstractSetupManager {
}
private void downloadCondaMac() throws SetupException {
final var architecture = configuration.architecture();
if (architecture.isAMD64()) {
downloadConda("https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh");
} else if (architecture.isARM64()) {
@@ -162,25 +141,12 @@ public class CondaSetupManager extends AbstractSetupManager {
}
private void downloadConda(final String url) throws SetupException {
final var request = HttpRequest.newBuilder().uri(URI.create(url)).GET().build();
try {
final var result = httpClient.send(request, HttpResponse.BodyHandlers.ofFile(condaInstallerPath));
if (result.statusCode() == 200) {
logger.info("Conda download successful");
} else {
throw new SetupException("Error downloading conda: " + result.body());
}
} catch (final IOException e) {
throw new SetupException(e);
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new SetupException(e);
}
download(url, configuration.condaInstallerPath());
}
@Override
public void uninstall() throws SetupException {
deleteFolder(condaRootPath);
deleteFolder(configuration.condaRootPath());
}
@Override
@@ -208,7 +174,7 @@ public class CondaSetupManager extends AbstractSetupManager {
throw new SetupException("Error creating venv " + path + ": " + result.output());
}
// On Windows, we need to copy the DLLs otherwise pip may not work
if (os == OS.WINDOWS) {
if (configuration.os() == OS.WINDOWS) {
final var sourceFolder = path.resolve("Library").resolve("bin");
try (final var files = Files.find(sourceFolder, 1, (p, a) -> p.getFileName().toString().contains("libcrypto") || p.getFileName().toString().contains("libssl"))) {
final var fileList = files.toList();
@@ -225,16 +191,16 @@ public class CondaSetupManager extends AbstractSetupManager {
}
public boolean venvExists(final Path path) {
return Files.exists(path.resolve("bin").resolve(os == OS.WINDOWS ? "python.exe" : "python"));
return Files.exists(path.resolve("bin").resolve(configuration.os() == OS.WINDOWS ? "python.exe" : "python"));
}
private Path getCondaPath() throws SetupException {
return isSystemCondaInstalled() ? condaSystemPath : condaBundledPath;
return isSystemCondaInstalled() ? configuration.condaSystemPath() : configuration.condaBundledPath();
}
private boolean isSystemCondaInstalled() throws SetupException {
try {
final var result = run(condaSystemPath.toString(), "--version");
final var result = run(configuration.condaSystemPath().toString(), "--version");
if (result.exitCode() == 0) {
final var output = result.output().getFirst();
final var versionString = output.substring(output.indexOf(' ') + 1);
@@ -242,7 +208,7 @@ public class CondaSetupManager extends AbstractSetupManager {
if (version.length == 3) {
final var major = Integer.parseInt(version[0]);
final var minor = Integer.parseInt(version[1]);
return major >= condaMinimumMajorVersion && minor >= condaMinimumMinorVersion;
return major >= configuration.condaMinimumMajorVersion() && minor >= configuration.condaMinimumMinorVersion();
} else {
throw new SetupException("Unexpected python version: " + versionString);
}
@@ -255,6 +221,6 @@ public class CondaSetupManager extends AbstractSetupManager {
}
private boolean isBundledCondaInstalled() {
return Files.isRegularFile(condaBundledPath);
return Files.isRegularFile(configuration.condaBundledPath());
}
}

View File

@@ -0,0 +1,21 @@
package com.github.gtache.autosubtitle.setup.whisper;
import com.github.gtache.autosubtitle.impl.OS;
import java.nio.file.Path;
import java.util.Objects;
/**
* Configuration for whisper setup
*/
public record WhisperSetupConfiguration(Path root, Path venvPath, String pythonVersion,
String whisperVersion, OS os) {
public WhisperSetupConfiguration {
Objects.requireNonNull(root);
Objects.requireNonNull(venvPath);
Objects.requireNonNull(pythonVersion);
Objects.requireNonNull(whisperVersion);
Objects.requireNonNull(os);
}
}

View File

@@ -1,10 +1,6 @@
package com.github.gtache.autosubtitle.setup.whisper;
import com.github.gtache.autosubtitle.impl.OS;
import com.github.gtache.autosubtitle.modules.setup.whisper.PythonVersion;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperBundledRoot;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperVenvPath;
import com.github.gtache.autosubtitle.modules.setup.whisper.WhisperVersion;
import com.github.gtache.autosubtitle.setup.SetupAction;
import com.github.gtache.autosubtitle.setup.SetupException;
import com.github.gtache.autosubtitle.setup.SetupStatus;
@@ -20,28 +16,23 @@ import java.nio.file.Path;
import static java.util.Objects.requireNonNull;
//TODO add gpg/signature check
/**
* Setup manager for Whisper
*/
@Singleton
public class WhisperSetupManager extends AbstractSetupManager {
private static final Logger logger = LogManager.getLogger(WhisperSetupManager.class);
private static final String CONDA_ENV = "conda-env";
private final CondaSetupManager condaSetupManager;
private final String pythonVersion;
private final Path whisperRoot;
private final Path venvPath;
private final OS os;
private final String whisperVersion;
private final WhisperSetupConfiguration configuration;
@Inject
WhisperSetupManager(final CondaSetupManager condaSetupManager, @PythonVersion final String pythonVersion,
@WhisperBundledRoot final Path whisperRoot, @WhisperVenvPath final Path venvPath, final OS os,
@WhisperVersion final String whisperVersion) {
WhisperSetupManager(final CondaSetupManager condaSetupManager, final WhisperSetupConfiguration configuration) {
this.condaSetupManager = requireNonNull(condaSetupManager);
this.pythonVersion = requireNonNull(pythonVersion);
this.whisperRoot = requireNonNull(whisperRoot);
this.venvPath = requireNonNull(venvPath);
this.os = requireNonNull(os);
this.whisperVersion = requireNonNull(whisperVersion);
this.configuration = requireNonNull(configuration);
}
@Override
@@ -83,12 +74,12 @@ public class WhisperSetupManager extends AbstractSetupManager {
private void checkInstallVenv() throws SetupException {
sendStartEvent(SetupAction.CHECK, CONDA_ENV, 0.33);
if (condaSetupManager.venvExists(venvPath)) {
if (condaSetupManager.venvExists(configuration.venvPath())) {
sendEndEvent(SetupAction.CHECK, CONDA_ENV, 0.66);
} else {
sendEndEvent(SetupAction.CHECK, CONDA_ENV, -1);
sendStartEvent(SetupAction.INSTALL, CONDA_ENV, -1);
condaSetupManager.createVenv(venvPath, pythonVersion);
condaSetupManager.createVenv(configuration.venvPath(), configuration.pythonVersion());
sendEndEvent(SetupAction.INSTALL, CONDA_ENV, 0.66);
}
}
@@ -107,7 +98,7 @@ public class WhisperSetupManager extends AbstractSetupManager {
@Override
public void uninstall() throws SetupException {
deleteFolder(whisperRoot);
deleteFolder(configuration.root());
}
@Override
@@ -124,19 +115,21 @@ public class WhisperSetupManager extends AbstractSetupManager {
}
private Path getPythonPath() {
return venvPath.resolve(os == OS.WINDOWS ? "python.exe" : "python");
return configuration.venvPath().resolve(configuration.os() == OS.WINDOWS ? "python.exe" : "python");
}
private void installWhisper() throws SetupException {
final var path = getPythonPath();
try {
logger.info("Installing whisper");
final var result = run(path.toString(), "-m", "pip", "install", "-U", "openai-whisper==" + whisperVersion, "numpy<2");
final var result = run(path.toString(), "-m", "pip", "install", "-U", "openai-whisper==" + configuration.whisperVersion(), "numpy<2");
if (result.exitCode() == 0) {
logger.info("Whisper installed");
} else {
throw new SetupException("Error installing whisper: " + result.output());
}
//TODO cuda?
final var cudaResult = run(path.toString(), "-m", "pip", "install", "-U", "torch", "--index-url", "https://download.pytorch.org/whl/cu124");
} catch (final IOException e) {
throw new SetupException(e);
}

View File

@@ -41,7 +41,10 @@ import static java.util.Objects.requireNonNull;
public class WhisperSubtitleExtractor extends AbstractProcessRunner implements SubtitleExtractor {
private static final Logger logger = LogManager.getLogger(WhisperSubtitleExtractor.class);
private static final String AUTOSUBTITLE = "autosubtitle";
private static final Pattern LINE_PROGRESS_PATTERN = Pattern.compile("^\\[\\d{2}:\\d{2}\\.\\d{3} --> (?<minutes>\\d{2}):(?<seconds>\\d{2})\\.(?<millis>\\d{3})]");
private static final Pattern TQDM_PROGRESS_PATTERN = Pattern.compile("^(?<progress>\\d{1,3})%|.+");
private final Path venvPath;
private final SubtitleConverter converter;
private final OS os;
@@ -80,7 +83,7 @@ public class WhisperSubtitleExtractor extends AbstractProcessRunner implements S
return extract(f.path(), language, model, video.info().duration());
} else {
try {
final var path = Files.createTempFile("autosubtitle", video.info().videoFormat());
final var path = Files.createTempFile(AUTOSUBTITLE, video.info().videoFormat());
try (final var in = video.getInputStream()) {
Files.copy(in, path);
final var ret = extract(path, language, model, video.info().duration());
@@ -99,7 +102,7 @@ public class WhisperSubtitleExtractor extends AbstractProcessRunner implements S
return extract(f.path(), language, model, audio.info().duration());
} else {
try {
final var path = Files.createTempFile("autosubtitle", audio.info().audioFormat());
final var path = Files.createTempFile(AUTOSUBTITLE, audio.info().audioFormat());
try (final var in = audio.getInputStream()) {
Files.copy(in, path);
final var ret = extract(path, language, model, audio.info().duration());
@@ -114,13 +117,13 @@ public class WhisperSubtitleExtractor extends AbstractProcessRunner implements S
private SubtitleCollection extract(final Path path, final Language language, final ExtractionModel model, final long duration) throws ExtractException {
try {
final var outputDir = Files.createTempDirectory("autosubtitle");
final var outputDir = Files.createTempDirectory(AUTOSUBTITLE);
final var args = createArgs(path, language, model, outputDir);
final var processListener = startListen(args);
var line = processListener.readLine();
var oldProgress = -1.0;
var line = processListener.readLine();
while (line != null) {
logger.info("Whisper output : {}", line);
logger.info("[whisper]: {}", line);
final var newProgress = computeProgress(line, duration, oldProgress);
notifyListeners(new ExtractEventImpl(line, newProgress));
oldProgress = newProgress;
@@ -131,11 +134,7 @@ public class WhisperSubtitleExtractor extends AbstractProcessRunner implements S
final var filename = path.getFileName().toString();
final var subtitleFilename = filename.substring(0, filename.lastIndexOf('.')) + ".json";
final var subtitleFile = outputDir.resolve(subtitleFilename);
try {
return converter.parse(subtitleFile);
} catch (final ParseException e) {
throw new ExtractException(e);
}
return parseResult(subtitleFile);
} else {
throw new ExtractException("Error extracting subtitles: " + result.output());
}
@@ -144,6 +143,14 @@ public class WhisperSubtitleExtractor extends AbstractProcessRunner implements S
}
}
private SubtitleCollection parseResult(final Path subtitleFile) throws ExtractException {
try {
return converter.parse(subtitleFile);
} catch (final ParseException e) {
throw new ExtractException(e);
}
}
private static double computeProgress(final CharSequence line, final long duration, final double oldProgress) {
final var matcher = LINE_PROGRESS_PATTERN.matcher(line);
if (matcher.find()) {
@@ -152,6 +159,11 @@ public class WhisperSubtitleExtractor extends AbstractProcessRunner implements S
final var millis = Integer.parseInt(matcher.group("millis"));
return ((minutes * 60L + seconds) * 1000 + millis) / (double) duration;
} else {
final var tqdmMatcher = TQDM_PROGRESS_PATTERN.matcher(line);
if (tqdmMatcher.find()) {
final var progress = Integer.parseInt(tqdmMatcher.group("progress"));
return progress / 100.0;
}
return oldProgress;
}
}
@@ -161,6 +173,8 @@ public class WhisperSubtitleExtractor extends AbstractProcessRunner implements S
args.add(getPythonPath().toString());
args.add("-m");
args.add("whisper");
args.add("--verbose");
args.add("False");
args.add("--model");
if (model != WhisperModels.LARGE && language == Language.EN) {
args.add(model.name().toLowerCase() + ".en");

View File

@@ -53,7 +53,7 @@ public class JSONSubtitleConverter implements SubtitleConverter {
return new SubtitleImpl(s.text(), start, end, null, null);
}).sorted(Comparator.comparing(Subtitle::start).thenComparing(Subtitle::end)).toList();
final var language = Language.getLanguage(json.language());
final var subtitlesText = subtitles.stream().map(Subtitle::content).collect(Collectors.joining(" "));
final var subtitlesText = subtitles.stream().map(Subtitle::content).collect(Collectors.joining(""));
if (!Objects.equals(json.text(), subtitlesText)) {
logger.warn("Not same text: {}\n\n{}", json.text(), subtitlesText);
}