diff --git a/pkgs/by-name/vo/voicevox-core/package.nix b/pkgs/by-name/vo/voicevox-core/package.nix new file mode 100644 index 0000000000000..0283b9cbfb4cb --- /dev/null +++ b/pkgs/by-name/vo/voicevox-core/package.nix @@ -0,0 +1,74 @@ +{ + lib, + stdenv, + fetchzip, + autoPatchelfHook, +}: + +let + platformInfoTable = { + "x86_64-linux" = { + id = "linux-x64"; + hash = "sha256-/PD5e0bWgnIsIrvyOypoJw30VkgbOFWV1NJpPS2G0WM="; + }; + "aarch64-linux" = { + id = "linux-arm64"; + hash = "sha256-zfiorXZyIISZPXPwmcdYeHceDmQXkUhsvTkNZScg648="; + }; + "x86_64-darwin" = { + id = "osx-x64"; + hash = "sha256-cdNdV1fVPkz6B7vtKZiPsLQGqnIiDtYa9KTcwSkjdJg="; + }; + "aarch64-darwin" = { + id = "osx-arm64"; + hash = "sha256-Z1dq2t/HBQulbPF23ZCihOrcZHMpTXEQ6yXKORZaFPk="; + }; + }; + + platformInfo = + platformInfoTable.${stdenv.hostPlatform.system} + or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); +in +stdenv.mkDerivation (finalAttrs: { + pname = "voicevox-core"; + version = "0.15.4"; + + # Note: Only the prebuilt binaries are able to decrypt the encrypted voice models + src = fetchzip { + url = "https://github.com/VOICEVOX/voicevox_core/releases/download/${finalAttrs.version}/voicevox_core-${platformInfo.id}-cpu-${finalAttrs.version}.zip"; + inherit (platformInfo) hash; + }; + + nativeBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [ autoPatchelfHook ]; + + buildInputs = [ stdenv.cc.cc.lib ]; + + installPhase = '' + runHook preInstall + + install -Dm755 libonnxruntime.* libvoicevox_core.* -t $out/lib + install -Dm644 model/* -t $out/lib/model + install -Dm644 *.h -t $out/include + install -Dm644 README.txt -t $out/share/doc/voicevox-core + + runHook postInstall + ''; + + meta = { + changelog = "https://github.com/VOICEVOX/voicevox_core/releases/tag/${finalAttrs.version}"; + description = "Core library for the VOICEVOX speech synthesis software"; + homepage = "https://github.com/VOICEVOX/voicevox_core"; + license = with lib.licenses; [ + mit + ({ + name = "VOICEVOX Core Library Terms of Use"; + url = "https://github.com/VOICEVOX/voicevox_resource/blob/main/core/README.md"; + free = false; + redistributable = true; + }) + ]; + maintainers = with lib.maintainers; [ tomasajt ]; + platforms = lib.attrNames platformInfoTable; + sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ]; + }; +}) diff --git a/pkgs/by-name/vo/voicevox-engine/make-installable.patch b/pkgs/by-name/vo/voicevox-engine/make-installable.patch new file mode 100644 index 0000000000000..6cc3b04ad05b3 --- /dev/null +++ b/pkgs/by-name/vo/voicevox-engine/make-installable.patch @@ -0,0 +1,21 @@ +diff --git a/pyproject.toml b/pyproject.toml +index fa23446..6a7705c 100644 +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -40,7 +40,15 @@ use_parentheses = true + datas = "datas" # PyInstaller's argument + + [tool.poetry] +-package-mode = false ++name = "voicevox-engine" ++version = "@version@" ++authors = [] ++description = "" ++packages = [ { include = "voicevox_engine" } ] ++include = [ "resources/**/*", "run.py", "engine_manifest.json", "presets.yaml"] ++ ++[tool.poetry.scripts] ++voicevox-engine = "run:main" + + [tool.poetry.dependencies] + python = "~3.11" diff --git a/pkgs/by-name/vo/voicevox-engine/mecab-remove-deprecated.patch b/pkgs/by-name/vo/voicevox-engine/mecab-remove-deprecated.patch new file mode 100644 index 0000000000000..b9ac0e1c10795 --- /dev/null +++ b/pkgs/by-name/vo/voicevox-engine/mecab-remove-deprecated.patch @@ -0,0 +1,92 @@ +diff --git a/lib/open_jtalk/src/mecab/src/char_property.h b/lib/open_jtalk/src/mecab/src/char_property.h +index 35f4b05..9c904ba 100644 +--- a/lib/open_jtalk/src/mecab/src/char_property.h ++++ b/lib/open_jtalk/src/mecab/src/char_property.h +@@ -37,7 +37,7 @@ class CharProperty { + inline const char *seekToOtherType(const char *begin, const char *end, + CharInfo c, CharInfo *fail, + size_t *mblen, size_t *clen) const { +- register const char *p = begin; ++ const char *p = begin; + *clen = 0; + while (p != end && c.isKindOf(*fail = getCharInfo(p, end, mblen))) { + p += *mblen; +diff --git a/lib/open_jtalk/src/mecab/src/darts.h b/lib/open_jtalk/src/mecab/src/darts.h +index 91b2eae..d6736cf 100644 +--- a/lib/open_jtalk/src/mecab/src/darts.h ++++ b/lib/open_jtalk/src/mecab/src/darts.h +@@ -404,10 +404,10 @@ class DoubleArrayImpl { + T result; + set_result(result, -1, 0); + +- register array_type_ b = array_[node_pos].base; +- register array_u_type_ p; ++ array_type_ b = array_[node_pos].base; ++ array_u_type_ p; + +- for (register size_t i = 0; i < len; ++i) { ++ for (size_t i = 0; i < len; ++i) { + p = b +(node_u_type_)(key[i]) + 1; + if (static_cast(b) == array_[p].check) + b = array_[p].base; +@@ -431,12 +431,12 @@ class DoubleArrayImpl { + size_t node_pos = 0) const { + if (!len) len = length_func_()(key); + +- register array_type_ b = array_[node_pos].base; +- register size_t num = 0; +- register array_type_ n; +- register array_u_type_ p; ++ array_type_ b = array_[node_pos].base; ++ size_t num = 0; ++ array_type_ n; ++ array_u_type_ p; + +- for (register size_t i = 0; i < len; ++i) { ++ for (size_t i = 0; i < len; ++i) { + p = b; // + 0; + n = array_[p].base; + if ((array_u_type_) b == array_[p].check && n < 0) { +@@ -469,8 +469,8 @@ class DoubleArrayImpl { + size_t len = 0) const { + if (!len) len = length_func_()(key); + +- register array_type_ b = array_[node_pos].base; +- register array_u_type_ p; ++ array_type_ b = array_[node_pos].base; ++ array_u_type_ p; + + for (; key_pos < len; ++key_pos) { + p = b +(node_u_type_)(key[key_pos]) + 1; +diff --git a/lib/open_jtalk/src/mecab/src/dictionary.cpp b/lib/open_jtalk/src/mecab/src/dictionary.cpp +index 5717d4d..3ab6e1f 100644 +--- a/lib/open_jtalk/src/mecab/src/dictionary.cpp ++++ b/lib/open_jtalk/src/mecab/src/dictionary.cpp +@@ -66,7 +66,7 @@ int progress_bar_darts(size_t current, size_t total) { + } + + template +-struct pair_1st_cmp: public std::binary_function { ++struct pair_1st_cmp { + bool operator()(const std::pair &x1, + const std::pair &x2) { + return x1.first < x2.first; +diff --git a/lib/open_jtalk/src/mecab/src/viterbi.cpp b/lib/open_jtalk/src/mecab/src/viterbi.cpp +index 6277fe9..5ccefb7 100644 +--- a/lib/open_jtalk/src/mecab/src/viterbi.cpp ++++ b/lib/open_jtalk/src/mecab/src/viterbi.cpp +@@ -318,11 +318,11 @@ template bool connect(size_t pos, Node *rnode, + const Connector *connector, + Allocator *allocator) { + for (;rnode; rnode = rnode->bnext) { +- register long best_cost = 2147483647; ++ long best_cost = 2147483647; + Node* best_node = 0; + for (Node *lnode = end_node_list[pos]; lnode; lnode = lnode->enext) { +- register int lcost = connector->cost(lnode, rnode); // local cost +- register long cost = lnode->cost + lcost; ++ int lcost = connector->cost(lnode, rnode); // local cost ++ long cost = lnode->cost + lcost; + + if (cost < best_cost) { + best_node = lnode; diff --git a/pkgs/by-name/vo/voicevox-engine/package.nix b/pkgs/by-name/vo/voicevox-engine/package.nix new file mode 100644 index 0000000000000..bc9a67617e9fb --- /dev/null +++ b/pkgs/by-name/vo/voicevox-engine/package.nix @@ -0,0 +1,126 @@ +{ + lib, + fetchFromGitHub, + python3Packages, + replaceVars, + voicevox-core, +}: + +python3Packages.buildPythonApplication rec { + pname = "voicevox-engine"; + version = "0.20.0"; + pyproject = true; + + src = fetchFromGitHub { + owner = "VOICEVOX"; + repo = "voicevox_engine"; + rev = "refs/tags/${version}"; + hash = "sha256-Gib5R7oleg+XXyu2V65EqrflQ1oiAR7a09a0MFhSITc="; + }; + + patches = [ + # the upstream package only uses poetry for dependency management, not for package definition + # this patch makes the package installable via poetry-core + (replaceVars ./make-installable.patch { + inherit version; + }) + ]; + + build-system = with python3Packages; [ + poetry-core + ]; + + dependencies = + [ + passthru.pyopenjtalk + ] + ++ (with python3Packages; [ + numpy + fastapi + jinja2 + python-multipart + uvicorn + soundfile + pyyaml + pyworld + semver + platformdirs + soxr + pydantic + starlette + ]); + + pythonRemoveDeps = [ + # upstream wants fastapi-slim, but we provide fastapi instead + "fastapi-slim" + ]; + + pythonRelaxDeps = true; + + preConfigure = '' + # copy demo metadata to temporary directory + mv resources/character_info test_character_info + + # populate the `character_info` directory with the actual model metadata instead of the demo metadata + cp -r --no-preserve=all ${passthru.resources}/character_info resources/character_info + + # the `character_info` directory copied from `resources` doesn't exactly have the expected format, + # so we transform them to be acceptable by `voicevox-engine` + pushd resources/character_info + for dir in *; do + # remove unused large files + rm $dir/*/*.png_large + + # rename directory from "$name_$uuid" to "$uuid" + mv $dir ''${dir#*"_"} + done + popd + ''; + + makeWrapperArgs = [ + ''--add-flags "--voicelib_dir=${voicevox-core}/lib"'' + ]; + + preCheck = '' + # some tests assume $HOME actually exists + export HOME=$(mktemp -d) + + # since the actual metadata files have been installed to `$out` by this point, + # we can move the demo metadata back to its place for the tests to succeed + rm -r resources/character_info + mv test_character_info resources/character_info + ''; + + disabledTests = [ + # this test checks the behaviour of openapi + # one of the functions returns a slightly different output due to openapi version differences + "test_OpenAPIの形が変わっていないことを確認" + ]; + + nativeCheckInputs = with python3Packages; [ + pytestCheckHook + syrupy + httpx + ]; + + passthru = { + resources = fetchFromGitHub { + owner = "VOICEVOX"; + repo = "voicevox_resource"; + rev = "refs/tags/${version}"; + hash = "sha256-m888DF9qgGbK30RSwNnAoT9D0tRJk6cD5QY72FRkatM="; + }; + + pyopenjtalk = python3Packages.callPackage ./pyopenjtalk.nix { }; + }; + + meta = { + changelog = "https://github.com/VOICEVOX/voicevox_engine/releases/tag/${version}"; + description = "Engine for the VOICEVOX speech synthesis software"; + homepage = "https://github.com/VOICEVOX/voicevox_engine"; + license = lib.licenses.lgpl3Only; + mainProgram = "voicevox-engine"; + maintainers = with lib.maintainers; [ tomasajt ]; + platforms = lib.platforms.linux ++ lib.platforms.darwin; + }; +} diff --git a/pkgs/by-name/vo/voicevox-engine/pyopenjtalk.nix b/pkgs/by-name/vo/voicevox-engine/pyopenjtalk.nix new file mode 100644 index 0000000000000..01ef7ec6ee840 --- /dev/null +++ b/pkgs/by-name/vo/voicevox-engine/pyopenjtalk.nix @@ -0,0 +1,75 @@ +{ + lib, + python, + buildPythonPackage, + fetchFromGitHub, + fetchzip, + setuptools, + cython_0, + cmake, + numpy, + oldest-supported-numpy, + six, + tqdm, +}: + +let + dic-dirname = "open_jtalk_dic_utf_8-1.11"; + dic-src = fetchzip { + url = "https://github.com/r9y9/open_jtalk/releases/download/v1.11.1/${dic-dirname}.tar.gz"; + hash = "sha256-+6cHKujNEzmJbpN9Uan6kZKsPdwxRRzT3ZazDnCNi3s="; + }; +in +buildPythonPackage { + pname = "pyopenjtalk"; + version = "0-unstable-2023-09-08"; + pyproject = true; + + src = fetchFromGitHub { + owner = "VOICEVOX"; + repo = "pyopenjtalk"; + rev = "b35fc89fe42948a28e33aed886ea145a51113f88"; + hash = "sha256-DbZkCMdirI6wSRUQSJrkojyjGmViqGeQPO0kSKiw2gE="; + fetchSubmodules = true; + }; + + patches = [ + # this patch fixes the darwin build + # open_jtalk uses mecab, which uses the register keyword and std::binary_function, which are not allowed in c++17 + # this patch removes them + ./mecab-remove-deprecated.patch + ]; + + postPatch = '' + substituteInPlace pyproject.toml \ + --replace-fail 'setuptools ["7za.exe", "7zzs", "7zz"].includes(fileName), +- ); +- +-if (!sevenZipFile) { +- throw new Error( +- "7z binary file not found. Run `node ./build/download7z.js` first.", +- ); +-} +- + /** @type {import("electron-builder").Configuration} */ + const builderOptions = { + beforeBuild: async () => { +@@ -88,14 +75,6 @@ const builderOptions = { + from: "build/README.txt", + to: extraFilePrefix + "README.txt", + }, +- { +- from: VOICEVOX_ENGINE_DIR, +- to: path.join(extraFilePrefix, "vv-engine"), +- }, +- { +- from: path.resolve(__dirname, "build", "vendored", "7z", sevenZipFile), +- to: extraFilePrefix + sevenZipFile, +- }, + ], + // electron-builder installer + productName: "VOICEVOX", +diff --git a/src/backend/electron/manager/vvppManager.ts b/src/backend/electron/manager/vvppManager.ts +index 6aa17b6..b8b52b7 100644 +--- a/src/backend/electron/manager/vvppManager.ts ++++ b/src/backend/electron/manager/vvppManager.ts +@@ -196,16 +196,8 @@ export class VvppManager { + + const args = ["x", "-o" + outputDir, archiveFile, "-t" + format]; + +- let sevenZipPath = import.meta.env.VITE_7Z_BIN_NAME; +- if (!sevenZipPath) { +- throw new Error("7z path is not defined"); +- } +- if (import.meta.env.PROD) { +- sevenZipPath = path.join( +- path.dirname(app.getPath("exe")), +- sevenZipPath, +- ); +- } ++ const sevenZipPath = `@sevenzip_path@`; ++ + log.log( + "Spawning 7z:", + sevenZipPath, diff --git a/pkgs/by-name/vo/voicevox/package.nix b/pkgs/by-name/vo/voicevox/package.nix new file mode 100644 index 0000000000000..e4935091c87bd --- /dev/null +++ b/pkgs/by-name/vo/voicevox/package.nix @@ -0,0 +1,116 @@ +{ + lib, + stdenv, + buildNpmPackage, + fetchFromGitHub, + replaceVars, + makeDesktopItem, + copyDesktopItems, + makeWrapper, + electron, + _7zz, + voicevox-engine, +}: + +buildNpmPackage rec { + pname = "voicevox"; + version = "0.20.0"; + + src = fetchFromGitHub { + owner = "VOICEVOX"; + repo = "voicevox"; + rev = "refs/tags/${version}"; + hash = "sha256-05WTecNc1xxe7SGDPZbLtRELNghFkMTqI4pkX4PsVWI="; + }; + + patches = [ + (replaceVars ./hardcode-paths.patch { + sevenzip_path = lib.getExe _7zz; + voicevox_engine_path = lib.getExe voicevox-engine; + }) + ]; + + postPatch = '' + substituteInPlace package.json \ + --replace-fail "999.999.999" "${version}" \ + --replace-fail "postinstall" "_postinstall" + ''; + + npmDepsHash = "sha256-g3avCj3S96qYPAyGXn4yvrZ4gteJld+g4eV4aRtv/3g="; + + nativeBuildInputs = + [ + makeWrapper + ] + ++ lib.optionals stdenv.hostPlatform.isLinux [ + copyDesktopItems + ]; + + env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1"; + + # disable code signing on Darwin + env.CSC_IDENTITY_AUTO_DISCOVERY = "false"; + + buildPhase = '' + runHook preBuild + + # build command taken from the definition of the `electron:build` npm script + VITE_TARGET=electron npm exec vite build + + cp -r ${electron.dist} electron-dist + chmod -R u+w electron-dist + + npm exec electron-builder -- \ + --dir \ + --config electron-builder.config.js \ + -c.electronDist=electron-dist \ + -c.electronVersion=${electron.version} + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + ${lib.optionalString stdenv.hostPlatform.isLinux '' + install -Dm644 public/icon.png $out/share/icons/hicolor/256x256/apps/voicevox.png + + mkdir -p $out/share/voicevox + cp -r dist_electron/*-unpacked/{locales,resources{,.pak}} $out/share/voicevox + + makeWrapper ${lib.getExe electron} $out/bin/voicevox \ + --add-flags $out/share/voicevox/resources/app.asar \ + --add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations}}" \ + --inherit-argv0 + ''} + + ${lib.optionalString stdenv.hostPlatform.isDarwin '' + mkdir -p $out/Applications + cp -r dist_electron/mac*/VOICEVOX.app $out/Applications + makeWrapper $out/Applications/VOICEVOX.app/Contents/MacOS/VOICEVOX $out/bin/voicevox + ''} + + runHook postInstall + ''; + + desktopItems = [ + (makeDesktopItem { + name = "voicevox"; + exec = "voicevox"; + icon = "voicevox"; + desktopName = "VOICEVOX"; + categories = [ "AudioVideo" ]; + mimeTypes = [ "application/x-voicevox" ]; + }) + ]; + + meta = { + changelog = "https://github.com/VOICEVOX/voicevox/releases/tag/${version}"; + description = "Editor for the VOICEVOX speech synthesis software"; + homepage = "https://github.com/VOICEVOX/voicevox"; + license = lib.licenses.lgpl3Only; + mainProgram = "voicevox"; + maintainers = with lib.maintainers; [ tomasajt ]; + platforms = electron.meta.platforms; + }; +}