codecat打印LLM输出

Table of Contents

codecat是我以前写的一个小工具,现在放在github上,本身是用来给打印代码时候发出一些音效逗朋友玩的玩具,最近发现还有个好玩的用法。

原理

它的原理就是在编译出的二进制中,嵌入一段sfx.wav的音效文件。然后通过https://github.com/gopxl/beep 这个库,用io的方式发出声音。

import (
    "github.com/gopxl/beep"
    "github.com/gopxl/beep/speaker"
    "github.com/gopxl/beep/wav"
)
//go:embed sfx.wav
var sfx []byte

type SoundPlayer struct {
    reader   io.ReadCloser
    streamer beep.StreamSeekCloser
    buffer   *beep.Buffer
}

func NewSoundPlayer(r io.ReadCloser) (*SoundPlayer, error) {
    streamer, format, err := wav.Decode(r)
    if err != nil {
        log.Fatal(err)
    }
    speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))

    buffer := beep.NewBuffer(format)
    buffer.Append(streamer)

    return &SoundPlayer{
        reader:   r,
        streamer: streamer,
        buffer:   buffer,
    }, nil
}

func (sp *SoundPlayer) Play() {
    s := sp.buffer.Streamer(0, sp.buffer.Len())
    speaker.Play(s)
}

func (sp *SoundPlayer) Close() {
    sp.streamer.Close()
    sp.reader.Close()
}

把上面这个实现的对象嵌入到Printer中,然后在打印的时候控制interval间隔输出声音,就实现打印的音效效果了。

type Printer struct {
    reader      io.RuneReader
    Interval    int
    Color       string
    SoundPlayer interface {
        Play()
    }
}

func NewPrinter(reader io.RuneReader) *Printer {
    return &Printer{
        reader: reader,
    }
}

func (p *Printer) Print() error {
    color := Palette[p.Color]

    for {
        rn, _, err := p.reader.ReadRune()
        if err != nil {
            break
        }

        fmt.Printf(color, string(rn))
        if rn != ' ' && rn != '\t' && rn != '\n' && rn != '\r' {
            p.SoundPlayer.Play()
        }
        time.Sleep(time.Duration(p.Interval) * time.Millisecond)
    }

    return nil
}

现在,我回想起来这个程序,发现当时实现的时候,本身是可以从管道获取数据然后发声的。也就是说我可以让任意有stdout输出的程序,都可以打印的发出音效。

if !isPipe(os.Stdin) {
    r = bufio.NewReader(os.Stdin)
} else {
    if codeFile == "" {
        reader := bytes.NewReader(self)
        selfReadCloser = io.NopCloser(reader)
        r = bufio.NewReader(selfReadCloser)
    } else {
        file := codeFile
        f, err := os.Open(file)
        if err != nil {
            log.Fatal("Error opening file:", err)
            return
        }
        defer f.Close()
        r = bufio.NewReader(f)
    }
}

当我把和ollama的输出结合起来后,就可以帮我把任意llm的打印,变成有音效的打印了。

ollama run gemma2:2b  "给我一些python demo" | codecat --interval 2

这玩意倒是对我有点实际价值,我喜欢在副屏上用llm,但是有时候我眼睛注意力在主屏上。所以我就在副屏运行的时候,发出这种打印音效,当声音停止的时候,就起到了提醒我工作完成的效果了。

效果