From 19c052d2ccf397bb24e00e12db2a970b7b3353b6 Mon Sep 17 00:00:00 2001 From: Weathercold Date: Fri, 5 Dec 2025 02:14:42 -0500 Subject: [PATCH] feat(nix/stage-tamagotchi): update to electron rewrite (#646) Co-authored-by: Neko --- .github/workflows/update-nix-assets-hash.yaml | 4 +- .gitignore | 4 +- flake.lock | 6 +- flake.nix | 10 +- nix/assets-hash.txt | 2 +- nix/common.nix | 81 ++++++++ nix/package.nix | 180 ++++++------------ nix/pnpm-deps-hash.txt | 2 +- 8 files changed, 152 insertions(+), 137 deletions(-) create mode 100644 nix/common.nix diff --git a/.github/workflows/update-nix-assets-hash.yaml b/.github/workflows/update-nix-assets-hash.yaml index 47aaf0ffa..df4c074e2 100644 --- a/.github/workflows/update-nix-assets-hash.yaml +++ b/.github/workflows/update-nix-assets-hash.yaml @@ -6,8 +6,8 @@ on: branches: - main paths: - - 'apps/stage-tamagotchi/package.json' - - 'apps/stage-tamagotchi/vite.config.ts' + - 'apps/stage-web/package.json' + - 'apps/stage-web/vite.config.ts' permissions: contents: write diff --git a/.gitignore b/.gitignore index f7fa904c8..a9a6a5d2d 100644 --- a/.gitignore +++ b/.gitignore @@ -108,5 +108,5 @@ twitter-session.json # Symlinks created by nix build result* - - +# Nix develop outputs +outputs/ diff --git a/flake.lock b/flake.lock index a850282ed..a7457cc94 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1757487488, - "narHash": "sha256-zwE/e7CuPJUWKdvvTCB7iunV4E/+G0lKfv4kk/5Izdg=", + "lastModified": 1764517877, + "narHash": "sha256-pp3uT4hHijIC8JUK5MEqeAWmParJrgBVzHLNfJDZxg4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ab0f3607a6c7486ea22229b92ed2d355f1482ee0", + "rev": "2d293cbfa5a793b4c50d17c05ef9e385b90edf6c", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 5513ff9e8..8c7f75aad 100644 --- a/flake.nix +++ b/flake.nix @@ -21,11 +21,10 @@ { formatter = forAllSystems (system: (pkgsForSystem system).nixfmt-tree); - packages = forAllSystems (system: { - default = self.packages.${system}.airi; - airi = (pkgsForSystem system).callPackage ./nix/package.nix { }; - airi-debug = (pkgsForSystem system).callPackage ./nix/package.nix { debugBuild = true; }; - }); + packages = forAllSystems ( + system: + { default = self.packages.${system}.airi; } // self.overlays.airi (pkgsForSystem system) null + ); overlays = { default = self.overlays.airi; @@ -40,6 +39,7 @@ inputsFrom = [ self.packages.${system}.airi ]; packages = [ nixd + nixfmt-rfc-style nixfmt-tree pnpm ]; diff --git a/nix/assets-hash.txt b/nix/assets-hash.txt index bcc9fb77d..b4d17777e 100644 --- a/nix/assets-hash.txt +++ b/nix/assets-hash.txt @@ -1 +1 @@ -sha256-r2tJiQa/yk04bGLq8EVvUWFsY/Ntvdoh7r33ykTHbq4= \ No newline at end of file +sha256-69tCpJaxRUnyR9CrHlmWJWEWLDpYzyzska7ui9++QoY= \ No newline at end of file diff --git a/nix/common.nix b/nix/common.nix new file mode 100644 index 000000000..418cea467 --- /dev/null +++ b/nix/common.nix @@ -0,0 +1,81 @@ +{ + lib, + stdenvNoCC, + + pnpm, + + cacert, + gitMinimal, + nodejs, +}: + +stdenvNoCC.mkDerivation (final: { + pname = "airi"; + version = "0.8.0-alpha.6"; + + src = ../.; + + pnpmDeps = pnpm.fetchDeps { + inherit (final) pname version src; + fetcherVersion = 2; + hash = builtins.readFile ./pnpm-deps-hash.txt; + }; + + # Cache of assets downloaded during vite build + assets = stdenvNoCC.mkDerivation { + pname = "airi-assets"; + inherit (final) version src pnpmDeps; + + nativeBuildInputs = [ + cacert # For network request + gitMinimal # For unplugin-info + nodejs + pnpm.configHook + ]; + + buildPhase = '' + runHook preBuild + + pnpm run build:packages + pnpm -F @proj-airi/stage-web run build + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p "$out" + cp -r .cache/* "$out" + cp -r apps/stage-web/.cache/assets/* "$out" + + runHook postInstall + ''; + + outputHashMode = "recursive"; + outputHash = builtins.readFile ./assets-hash.txt; + }; + + meta = { + description = "Self-hostable AI waifu / companion / VTuber"; + longDescription = '' + AIRI is a soul container of AI waifu / virtual characters to bring them into our world, + wishing to achieve Neuro-sama's altitude. It's completely LLM and AI driven, capable of + realtime voice chat, playing Minecraft and Factorio. It can be run in browser or on desktop. + This is the desktop version. + ''; + homepage = "https://github.com/moeru-ai/airi"; + changelog = "https://github.com/moeru-ai/airi/releases/tag/v${final.version}"; + # While airi itself is licensed under MIT, it uses the nonfree Cubism SDK. Whether it's + # redistributable remains a question, so we say it's not. + license = lib.licenses.unfree; + platforms = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + mainProgram = final.pname; + maintainers = with lib.maintainers; [ weathercold ]; + }; +}) diff --git a/nix/package.nix b/nix/package.nix index 545833f33..f0253dcd7 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,152 +1,86 @@ { - lib, - stdenv, stdenvNoCC, - rustPlatform, + callPackage, - autoPatchelfHook, - cargo-tauri, - pkg-config, + copyDesktopItems, + makeDesktopItem, + makeWrapper, pnpm, - wrapGAppsHook3, - alsa-lib, - atk, - cacert, - glib, - libayatana-appindicator, + asar, + electron, nodejs, - onnxruntime, - openssl, - systemdLibs, - webkitgtk_4_1, - xorg, - - debugBuild ? false, }: -rustPlatform.buildRustPackage (final: { - pname = "airi"; - version = "0.7.2-beta.3"; - - src = ../.; - - cargoLock = { - lockFile = ../Cargo.lock; - outputHashes."rdev-0.6.0" = "sha256-mGt44/kVo5EJO1Wf6MPLq0sZgwGTzuQjeVT6HxVzpQY="; - }; - - pnpmDeps = pnpm.fetchDeps { - inherit (final) pname version src; - fetcherVersion = 1; - hash = builtins.readFile ./pnpm-deps-hash.txt; - }; - - # Cache of assets downloaded during vite build - assets = stdenvNoCC.mkDerivation { - pname = "${final.pname}-assets"; - inherit (final) version src pnpmDeps; - - nativeBuildInputs = [ - cacert # For network request - nodejs - pnpm.configHook - ]; - - buildPhase = '' - runHook preBuild - - pnpm run build:packages - pnpm -F @proj-airi/stage-tamagotchi run build - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - mkdir -p $out - cp -r apps/stage-tamagotchi/.cache/assets $out - - runHook postInstall - ''; - - outputHashMode = "recursive"; - outputHash = builtins.readFile ./assets-hash.txt; - }; - +(callPackage ./common.nix { }).overrideAttrs (final: { nativeBuildInputs = [ - cargo-tauri.hook + asar + copyDesktopItems + makeWrapper nodejs - pkg-config pnpm.configHook - ] - ++ lib.optionals stdenv.isLinux [ - wrapGAppsHook3 - autoPatchelfHook ]; - buildInputs = [ - glib # Used by glib-sys - onnxruntime # Used by ort-sys - openssl # Used by openssl-sys - ] - ++ lib.optionals stdenv.isLinux [ - alsa-lib # Used by alsa-sys - atk # Used by atk-sys - libayatana-appindicator # Used by libappindicator-sys - systemdLibs # For libudev used by libudev-sys - webkitgtk_4_1 - xorg.libXtst # Used by x11 + desktopItems = [ + (makeDesktopItem { + desktopName = "AIRI"; + comment = final.meta.description; + categories = [ + "AudioVideo" + "Amusement" + ]; + exec = final.meta.mainProgram; + icon = final.meta.mainProgram; + name = final.meta.mainProgram; + }) ]; + env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1"; + configurePhase = '' runHook preConfigure echo Setting up asset cache - mkdir apps/stage-tamagotchi/.cache - cp -r $assets/assets apps/stage-tamagotchi/.cache + ln -s "$assets" .cache + mkdir apps/stage-tamagotchi/src/renderer/.cache + ln -s "$assets" apps/stage-tamagotchi/src/renderer/.cache/assets runHook postConfigure ''; - preBuild = '' + buildPhase = '' + runHook preBuild + pnpm run build:packages + cd apps/stage-tamagotchi + pnpm run build + pnpm exec electron-builder build \ + --dir --${if stdenvNoCC.isLinux then "linux" else "darwin"} \ + -c.electronDist="${electron.dist}" \ + -c.electronVersion="${electron.version}" + + runHook postBuild ''; - buildAndTestSubdir = "apps/stage-tamagotchi"; - buildType = if debugBuild then "debug" else "release"; + installPhase = '' + runHook preInstall - postInstall = lib.optionalString stdenv.isDarwin '' - mkdir -p "$out/bin" - ln -sf "$out/Applications/AIRI.app/Contents/MacOS/airi" "$out/bin/airi" + mkdir -p "$out/opt" + cp -r dist/*-unpacked "$out/opt/AIRI" + # The icon is actually 1500x1500... install it anyway + install -Dm644 resources/icon.png "$out/share/icons/hicolor/64x64/apps/airi.png" + + # Patch the asar to include the assets + cd "$out/opt/AIRI/resources" + asar extract app.asar app + rm -r app.asar.unpacked + cp -r "$assets"/{vrm,live2d} app/out/renderer/assets + asar pack app app.asar + + makeWrapper "${electron}/bin/electron" "$out/bin/airi" \ + --add-flags "$out/opt/AIRI/resources/app.asar" \ + --add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--enable-wayland-ime=true --wayland-text-input-version=3}}" + + runHook postInstall ''; - - # Add missing runtime dependency - preFixup = lib.optionalString stdenv.isLinux '' - patchelf --add-needed libayatana-appindicator3.so.1 $out/bin/airi - ''; - - meta = { - description = "Self-hostable AI waifu / companion / VTuber"; - longDescription = '' - AIRI is a soul container of AI waifu / virtual characters to bring them into our world, - wishing to achieve Neuro-sama's altitude. It's completely LLM and AI driven, capable of - realtime voice chat, playing Minecraft and Factorio. It can be run in browser or on desktop. - This is the desktop version. - ''; - homepage = "https://github.com/moeru-ai/airi"; - changelog = "https://github.com/moeru-ai/airi/releases/tag/v${final.version}"; - # While airi itself is licensed under MIT, it uses the nonfree Cubism SDK. Whether it's - # redistributable remains a question, so we say it's not. - license = lib.licenses.unfree; - platforms = [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - mainProgram = "airi"; - maintainers = with lib.maintainers; [ weathercold ]; - }; }) diff --git a/nix/pnpm-deps-hash.txt b/nix/pnpm-deps-hash.txt index 4af14d65a..5c3ab4802 100644 --- a/nix/pnpm-deps-hash.txt +++ b/nix/pnpm-deps-hash.txt @@ -1 +1 @@ -sha256-kGQHGj21R191Uqw7rapX+xomef5fgW6CV0zIpElaP5k= \ No newline at end of file +sha256-BPlyjdmTJctjrBtJOYIDP0SaVdgVkgEKnozEM2Dlc1o= \ No newline at end of file