~geb/numen

feat: local ./bin install using make v1 PROPOSED

WillForan: 1
 feat: local ./bin install using make

 5 files changed, 114 insertions(+), 15 deletions(-)
Glad there's anything useful in it! I'm happy to see requests
ruthlessly rejected [0].

Two is one too many install methods.
I hadn't seen libexec conventions before and didn't understand how the
pieces fit together.
In retrospect, I should have started exploring with PKGBUILD instead of Makefile

And "packaging" into ./bin with your suggested NUMEN_LIBEXEC tweaks
is an elegant solution to the try-before-you-by local install I was going for.


The mic note should have been a separate patch. Sorry.
`--audiolog ` was super useful. I used it to find that the alsa
default was just static for me.
I thought I had to dig into `record` to see if there were settings
that my card didn't like.
In the end, I just needed to specify the mic ... which was well
documented save for an example.
My first working arecord test was with -D hw:0,0 but I couldn't pass
that on as --mic=hw:0,0


Thanks for sharing numen!
I spent a good amount of time yesterday speaking ridiculous
incantations to a vim buffer.
It feels like magic. (except that the computer cannot understand
however I'm saying 'eve'. I switched to 'egg')

[0]: https://www.jeffgeerling.com/blog/2016/why-i-close-prs-oss-project-maintainer-notes
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~geb/numen/patches/44627/mbox | git am -3
Learn more about email & git

[PATCH] feat: local ./bin install using make Export this patch

refactor install-numen.sh: dependancy check moved to ./depcheck.sh
and reused by Makefile

additional changes to install-numen.sh:
 - annotated input argument default values
 - notes on where files go
---
 .gitignore       |  1 +
 Makefile         | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
 README.md        | 17 ++++++++++++++
 depcheck.sh      | 24 +++++++++++++++++++
 install-numen.sh | 26 +++++++++------------
 5 files changed, 114 insertions(+), 15 deletions(-)
 create mode 100644 Makefile
 create mode 100755 depcheck.sh

diff --git a/.gitignore b/.gitignore
index 84bbfa1..296cb0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/tmp/
/speech
/model/
rewrite-libexec.sed
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b69c313
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,61 @@
.PHONY: local-install dirs run check-depends

# final output directory used to sed replace hardcoded /usr/libexec/numen
PWD := $(abspath $(shell pwd))

# groups of files into bin bin/etc,bin/phrases, bin/etc/{phrases,handlers}
handlers      := $(addprefix bin/etc/,$(wildcard handlers/*))
phrases       := $(addprefix bin/,$(wildcard phrases/*.phrases))
phrasescripts := $(subst phrasescripts/,bin/etc/phrases/,$(wildcard phrasescripts/*))
etc           := $(addprefix bin/etc/,speech awk instructor record scribe) 
bin           := $(addprefix bin/,numen numenc)

# how to run after installing
run: check-depends local-install
	# might need to update: --mic=sysdefault:CARD=PCH 
	cd bin && ./numen --verbose phrases/*.phrases

check-depends:
	./depcheck.sh

# all the files we need to exist
local-install: $(bin) $(etc) $(handlers) $(phrasescripts) $(phrases) bin/numen.1 bin/model

# install eg. vosk-api-bin
# also see ./install-vosk.sh
# 'wrapper' will check this location by default. don't need to symlink it
bin/model: /usr/local/share/vosk-models/small-en-us/
	ln -s $< $@

dirs:
	@mkdir -p bin/etc/handlers/
	@mkdir -p bin/etc/phrases/
	@mkdir -p bin/phrases/

rewrite-libexec.sed: | dirs
	echo 's:/usr/libexec/numen:$(PWD)/bin/etc:g' > $@

bin/etc/%: % | rewrite-libexec.sed
	sed -f rewrite-libexec.sed $< > $@
	chmod +x $@

bin/numen.1: doc/numen.1.scd | dirs
	scdoc < $< > $@

bin/speech: speech.go | dirs
	go build $< -o $@

bin/etc/handlers/%: handlers/% | rewrite-libexec.sed
	sed -f rewrite-libexec.sed $< > $@
	chmod +x $@

bin/phrases/%.phrases: phrases/%.phrases | rewrite-libexec.sed
	sed -f rewrite-libexec.sed $< > $@

bin/etc/phrases/%: phrasescripts/% | rewrite-libexec.sed
	sed -f rewrite-libexec.sed $< > $@
	chmod +x $@

bin/%: % | rewrite-libexec.sed
	sed -f rewrite-libexec.sed $< > $@
	chmod +x $@
diff --git a/README.md b/README.md
index 138bbd6..10bc14e 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,12 @@ Finally, `numen` itself can be installed with:

    sudo ./install-numen.sh

### Without root
Use `make run` to try without modifying system files.

Instead, make will create `./bin` and organize files within after checking for dependencies.
See [`Makefile`](Makefile). 

## Permission

`dotool` requires permission to `/dev/uinput` to create the virtual input
@@ -39,6 +45,17 @@ If need be, you can run:

and re-login and trigger the udev rule or just reboot.

## Mic Check

Confirm the `arecord` captures audio

```
mic=default # as set by `bin/etc/record` without `numen --mic=...`
arecord -q -D "$mic" -f S16_LE -c 1 -r 16000 -d 5 test.wav # recs for 5 secs
aplay test.wav
```
(on an integrated Intel HDA: `mic=sysdefault:CARD=PCH`)

## Getting Started

Once you've got a microphone, you can run it with:
diff --git a/depcheck.sh b/depcheck.sh
new file mode 100755
index 0000000..518c516
--- /dev/null
+++ b/depcheck.sh
@@ -0,0 +1,24 @@
#!/bin/sh
# 20230218WF - adapted from install-numen.sh. reused in Makefile
RET=0
have() { command -v "$1" > /dev/null;}
nohave_msg() { ! have "$1" && echo "$2" && RET=$((RET+1)); }
nohave_msg arecord 'Need the "alsa-utils" package to record audio'
nohave_msg dotool  'Need "dotool" to simulate keypresses'
nohave_msg gcc     'Need "gcc"' # Why?
nohave_msg go      'Need "go" (aka "golang") to build speech.go'
nohave_msg scdoc   'Need "scdoc" to compile documentation'

if have dotool && ! dotool --version >/dev/null 2>&1; then
	echo 'You need a newer version of dotool (version 1.1 or later),'
	echo 'use your package manager or run: sudo ./install-dotool.sh'
	RET=$((RET+1))
fi

! [ -r /lib/libvosk.so ] &&
   echo 'Need /lib/libvosk.so for speach to text. see ./install-vosk.sh' && RET=$((RET+1))

! [ -d /usr/local/share/vosk-models/ ] &&
   echo 'Need model for vosk. see ./install-model.sh' && RET=$((RET+1))

exit $RET
diff --git a/install-numen.sh b/install-numen.sh
index 399d685..a8d65ae 100755
--- a/install-numen.sh
+++ b/install-numen.sh
@@ -1,26 +1,22 @@
#!/bin/sh
# ./install-numen.sh [DESTDIR] [BINDIR]
# ./install-numen.sh [DESTDIR=""] [BINDIR=/usr/local/bin/]
# installs
#  - numen,numenc  to $DESTDIR/$BINDIR
#  - etc           to $DESTDIR/usr/libexec/numen
#    where etc is handlers/ phrasescripts/ record awk ...etc
#    you do not want these on PATH
#    e.g. includes a awk wrapper called 'awk'
#
# If the environment variable PACKAGING is set, compiling speech.go is left
# to you to do beforehand. It is meant for build systems packaging numen.
# Example: PACKAGING=true ./install-numen.sh "$DESTDIR" /usr/bin
#
# NB: /usr/libexec/numen/ is hard coded in e.g. numen, scribe, phrase, ...
#     see Makefile's rewrite-libexec.sed if this is a problem
version="$(git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 0.6)"

if ! [ "$PACKAGING" ]; then
	ok=1
	! command -v arecord > /dev/null && echo 'you need the alsa-utils package' && unset ok
	! command -v dotool > /dev/null && echo 'you need dotool' && unset ok
	! command -v gcc > /dev/null && echo 'you need gcc' && unset ok
	! command -v go > /dev/null && echo 'you need go (sometimes packaged as golang)' && unset ok
	! command -v scdoc > /dev/null && echo 'you need scdoc' && unset ok
	[ "$ok" ] || exit

	if ! dotool --version >/dev/null 2>&1; then
		echo 'You need a newer version of dotool (version 1.1 or later),'
		echo 'use your package manager or run: sudo ./install-dotool.sh'
		exit 1
	fi

	./depcheck.sh || exit
	go build speech.go || exit
fi

-- 
2.39.0
Thanks Will, it's cool to get a patch! I don't think I'll merge it directly
but you've raised some good ideas like the ./bin install and mic checking help.

Honestly I don't think there should be two ways to install numen and I
don't see the benefit of a makefile here.  Perhaps wrapper could export an
environment variable of the libexec dir that everything should use and then
you could install numen locally like:

    mkdir bin || exit
    ./install-numen.sh bin || exit
    sed -i 's:^export NUMEN_LIBEXEC=:export NUMEN_LIBEXEC=bin:' || exit
    ln -sf /usr/local/share/vosk-models bin/usr/local/share || exit

I recently added --audiolog for checking the mic but I should add something
to the readme.
I decided to do a big rewrite so now numen's just one binary instead of the
weird libexec dream. Now you should be able to just do:

    go run . phrases/*.phrases

for your try-before-you-buying.

--mic=hw:0,0 should work now too :)