This repository has no description
3.6 kB
90 lines
1{ self, ... }:
2{
3 perSystem =
4 { lib, pkgs, ... }:
5 let
6 # The Android wrapper's package name (android/AndroidManifest.xml).
7 androidPackage = "us.lassul.assist";
8 # Written by `clan vars generate coaxmetal` (machines/coaxmetal/hermes-voice.nix);
9 # until then there is no assetlinks.json and Chrome opens the app as a
10 # Custom Tab.
11 fingerprint = self + "/vars/per-machine/coaxmetal/hermes-voice-android-signing/fingerprint/value";
12 assetlinks = pkgs.writeText "assetlinks.json" (
13 builtins.toJSON [
14 {
15 relation = [ "delegate_permission/common.handle_all_urls" ];
16 target = {
17 namespace = "android_app";
18 package_name = androidPackage;
19 sha256_cert_fingerprints = [ (lib.removeSuffix "\n" (builtins.readFile fingerprint)) ];
20 };
21 }
22 ]
23 );
24 icon = pkgs.runCommand "hermes-voice-icon" { nativeBuildInputs = [ pkgs.imagemagick ]; } ''
25 mkdir $out
26 for size in 192 512; do
27 magick -size 512x512 xc:'#111' -fill '#4fb477' -draw 'circle 256,256 256,128' \
28 -resize ''${size}x$size -strip -define png:exclude-chunks=date,time \
29 $out/icon-$size.png
30 done
31 '';
32 static = pkgs.runCommand "hermes-voice-static" { } ''
33 cp -r ${./static} $out
34 chmod u+w $out
35 cp ${icon}/*.png $out/
36 ${lib.optionalString (builtins.pathExists fingerprint) ''
37 mkdir $out/.well-known
38 cp ${assetlinks} $out/.well-known/assetlinks.json
39 ''}
40 '';
41 # The SDK is unfree; it only builds the APK and is not part of any system.
42 inherit
43 (import pkgs.path {
44 inherit (pkgs.stdenv.hostPlatform) system;
45 config.allowUnfree = true;
46 config.android_sdk.accept_license = true;
47 })
48 androidenv
49 ;
50 android = pkgs.callPackage ./android { inherit icon androidenv; };
51 in
52 {
53 # Full-duplex voice conversations with Hermes: gpt-live-1 in the
54 # browser, delegating real work to the Hermes API server.
55 packages.hermes-voice =
56 (pkgs.writeShellApplication {
57 name = "hermes-voice";
58 # A later --config on the command line overrides the packaged one.
59 text = ''
60 export HERMES_VOICE_STATIC=${static}
61 exec ${pkgs.python3}/bin/python3 ${./hermes_voice.py} --config ${./config.json} "$@"
62 '';
63 }).overrideAttrs
64 { passthru.usage = builtins.readFile ./usage.kdl; };
65
66 # The voice page as Android app and digital assistant (Trusted Web
67 # Activity), unsigned.
68 packages.hermes-voice-android = android;
69 checks.hermes-voice-android = android;
70
71 # Aligns and signs the APK with the keystore from
72 # `clan vars get coaxmetal hermes-voice-android-signing/keystore`.
73 packages.hermes-voice-android-sign = pkgs.writeShellApplication {
74 name = "hermes-voice-android-sign";
75 runtimeInputs = [ pkgs.jdk17_headless ];
76 text = ''
77 PATH=${android.buildTools}:$PATH
78 if [ $# -lt 3 ]; then
79 echo "usage: hermes-voice-android-sign KEYSTORE PASSWORD_FILE OUT_APK [UNSIGNED_APK]" >&2
80 exit 1
81 fi
82 aligned=$(mktemp)
83 trap 'rm -f "$aligned"' EXIT
84 zipalign -f -p 4 "''${4:-${android}/hermes-voice-android-unsigned.apk}" "$aligned"
85 apksigner sign --ks "$1" --ks-pass "file:$2" --v4-signing-enabled false --out "$3" "$aligned"
86 apksigner verify --print-certs "$3"
87 '';
88 };
89 };
90}