Files
Maven/cmd/mavsttd/main.go
T

132 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package main is mavsttd — maven's stt module process.
//
// Per spec: stt/tts are restart-free, key-free, fail-independent modules —
// separate processes from core, reachable over the worker boundary
// (internal/worker). Core dials mavsttd's unix socket and ships audio bytes
// for transcription; mavsttd ships text back.
//
// With -model <path>: loads a whisper.cpp ggml model (e.g. ggml-small.bin)
// for real transcription. Without -model: serves the stub transcriber
// (deterministic no-model floor) so the loop is exercisable end-to-end
// without weights.
//
// Module topology:
//
// $ mavsttd -socket /run/user/$UID/maven/stt.sock
//
// The daemon's config points at this socket:
//
// "stt": { "socket": "/run/user/1000/maven/stt.sock" }
//
// Both processes are same-user on the box ⇒ the 0600 socket floor (same
// unix user) is sufficient today; the wg / mTLS cuts in internal/auth are
// for the NETWORK radius (client↔core), not the local module radius.
package main
import (
"context"
"errors"
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
"github.com/kami/maven/internal/worker"
)
func main() {
if err := run(os.Args[1:]); err != nil {
fmt.Fprintln(os.Stderr, "mavsttd:", err)
os.Exit(1)
}
}
func run(args []string) error {
sock := flag.String("socket", defaultSocket("stt.sock"), "unix socket path")
model := flag.String("model", "", "path to whisper ggml model file")
flag.CommandLine.Parse(args)
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
defer stop()
var t worker.Transcriber
if *model != "" {
w, err := newWhisperHandler(*model)
if err != nil {
return fmt.Errorf("whisper: %w", err)
}
t = w
defer func() {
log.Printf("mavsttd: closing whisper model")
w.Close()
}()
log.Printf("mavsttd: loaded whisper model from %s", *model)
} else {
log.Printf("mavsttd: no model specified, using stub handler")
t = &stubHandler{}
}
srv := worker.NewServer(*sock, t)
if err := srv.Listen(); err != nil {
return err
}
defer srv.Close()
log.Printf("mavsttd: worker listening on %s", srv.Path())
errCh := make(chan error, 1)
go func() { errCh <- srv.Serve() }()
select {
case <-ctx.Done():
log.Printf("mavsttd: shutdown signal received")
srv.Close()
return nil
case err := <-errCh:
if err != nil && !errors.Is(err, net.ErrClosed) {
return err
}
return nil
}
}
// stubHandler — worker.Transcriber that delegates to the package Stub. Tiny
// now; the production swap replaces this whole struct with a faster-whisper
// / vosk-backed struct (the same Worker.Transcriber interface).
type stubHandler struct{}
func (h *stubHandler) Transcribe(ctx context.Context, req worker.TranscribeReq) (worker.TranscribeResp, error) {
// delegate to the same deterministic Stub the daemon could have wired
// in-process; mavsttd is the "separate process" equivalent.
_ = req
// hash for variation; same approach as stt.Stub.
if len(req.Audio.Bytes) == 0 {
return worker.TranscribeResp{Text: "maven, что у меня сегодня", Confidence: 1.0}, nil
}
// vary phrase by first byte for visibility in logs/tests.
phrases := []string{
"maven, отметь что я выпил воды",
"maven, напомни через 4 часа размяться",
"maven, restart nginx",
"maven, что у меня сегодня по календарю",
"note: staggered cooldown by time of day",
"slept 6h",
}
idx := int(req.Audio.Bytes[0]) % len(phrases)
return worker.TranscribeResp{Text: phrases[idx], Confidence: 1.0}, nil
}
// defaultSocket returns XDG_RUNTIME_DIR/maven/<name> if set, falling back
// to a homedir-relative path (mirrors config.defaultRuntimeDir).
func defaultSocket(name string) string {
if x := os.Getenv("XDG_RUNTIME_DIR"); x != "" {
return x + "/maven/" + name
}
home, err := os.UserHomeDir()
if err != nil || home == "" {
return name
}
return home + "/.local/share/maven/" + name
}