Merge branch 'master' into feat/agent-flow

This commit is contained in:
Grail Finder
2026-03-13 09:26:11 +03:00
7 changed files with 56 additions and 12 deletions

View File

@@ -134,8 +134,9 @@ setup-whisper: build-whisper download-whisper-model
build-whisper: ## Build whisper.cpp from source in batteries directory build-whisper: ## Build whisper.cpp from source in batteries directory
@echo "Building whisper.cpp from source in batteries directory..." @echo "Building whisper.cpp from source in batteries directory..."
@if [ ! -d "batteries/whisper.cpp" ]; then \ @if [ ! -f "batteries/whisper.cpp/CMakeLists.txt" ]; then \
echo "Cloning whisper.cpp repository to batteries directory..."; \ echo "Cloning whisper.cpp repository to batteries directory..."; \
rm -rf batteries/whisper.cpp; \
git clone https://github.com/ggml-org/whisper.cpp.git batteries/whisper.cpp; \ git clone https://github.com/ggml-org/whisper.cpp.git batteries/whisper.cpp; \
fi fi
cd batteries/whisper.cpp && cmake -B build -DGGML_CUDA=ON -DWHISPER_SDL2=ON; cmake --build build --config Release -j 8 cd batteries/whisper.cpp && cmake -B build -DGGML_CUDA=ON -DWHISPER_SDL2=ON; cmake --build build --config Release -j 8
@@ -144,7 +145,7 @@ build-whisper: ## Build whisper.cpp from source in batteries directory
download-whisper-model: ## Download Whisper model for STT in batteries directory download-whisper-model: ## Download Whisper model for STT in batteries directory
@echo "Downloading Whisper model for STT..." @echo "Downloading Whisper model for STT..."
@if [ ! -d "batteries/whisper.cpp/models" ]; then \ @if [ ! -d "batteries/whisper.cpp/models" ]; then \
mkdir -p "batteries/whisper.cpp/models" \ mkdir -p "batteries/whisper.cpp/models"; \
fi fi
curl -o batteries/whisper.cpp/models/ggml-large-v3-turbo-q5_0.bin -L "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo-q5_0.bin?download=true" curl -o batteries/whisper.cpp/models/ggml-large-v3-turbo-q5_0.bin -L "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo-q5_0.bin?download=true"
@echo "Whisper model downloaded successfully!" @echo "Whisper model downloaded successfully!"

View File

@@ -10,6 +10,10 @@ made with use of [tview](https://github.com/rivo/tview)
- function calls (function calls are implemented natively, to avoid calling outside sources); - function calls (function calls are implemented natively, to avoid calling outside sources);
- [character specific context (unique feature)](docs/char-specific-context.md) - [character specific context (unique feature)](docs/char-specific-context.md)
#### showcase on youtube
[![gf-lt video showcase](assets/yt_thumb.jpg)](https://youtu.be/WCS4Xc902F8 "gf-lt showcase")
#### how it looks #### how it looks
![how it looks](assets/ex01.png) ![how it looks](assets/ex01.png)
@@ -34,7 +38,8 @@ make noextra-run
``` ```
#### keybinds #### keybinds
while running you can press f12 for list of keys; - use `insert` button to paste text from the clipboard to the text area, instead of shift+insert (might freeze the program);
- press f12 for list of keys;
![keybinds](assets/helppage.png) ![keybinds](assets/helppage.png)
#### setting up config #### setting up config

BIN
assets/yt_thumb.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -42,7 +42,7 @@ STT_ENABLED = false
STT_TYPE = "WHISPER_SERVER" # WHISPER_SERVER or WHISPER_BINARY STT_TYPE = "WHISPER_SERVER" # WHISPER_SERVER or WHISPER_BINARY
STT_URL = "http://localhost:8081/inference" STT_URL = "http://localhost:8081/inference"
WhisperBinaryPath = "./batteries/whisper.cpp/build/bin/whisper-cli" # Path to whisper binary (for WHISPER_BINARY mode) WhisperBinaryPath = "./batteries/whisper.cpp/build/bin/whisper-cli" # Path to whisper binary (for WHISPER_BINARY mode)
WhisperModelPath = "./batteries/whisper.cpp/ggml-large-v3-turbo-q5_0.bin" # Path to whisper model file (for WHISPER_BINARY mode) WhisperModelPath = "./batteries/whisper.cpp/models/ggml-large-v3-turbo-q5_0.bin" # Path to whisper model file (for WHISPER_BINARY mode)
STT_LANG = "en" # Language for speech recognition (for WHISPER_BINARY mode) STT_LANG = "en" # Language for speech recognition (for WHISPER_BINARY mode)
STT_SR = 16000 # Sample rate for audio recording STT_SR = 16000 # Sample rate for audio recording
# #

View File

@@ -115,9 +115,6 @@ func makePropsTable(props map[string]float32) *tview.Table {
row++ row++
} }
// Add checkboxes // Add checkboxes
addCheckboxRow("Inject role", injectRole, func(checked bool) {
injectRole = checked
})
addCheckboxRow("TTS Enabled", cfg.TTS_ENABLED, func(checked bool) { addCheckboxRow("TTS Enabled", cfg.TTS_ENABLED, func(checked bool) {
cfg.TTS_ENABLED = checked cfg.TTS_ENABLED = checked
}) })

View File

@@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@@ -161,10 +162,31 @@ func loadOldChatOrGetNew() []models.RoleMsg {
} }
func copyToClipboard(text string) error { func copyToClipboard(text string) error {
cmd := exec.Command("xclip", "-selection", "clipboard") var cmd *exec.Cmd
cmd.Stdin = nil if _, err := exec.LookPath("xclip"); err == nil {
cmd = exec.Command("xclip", "-selection", "clipboard")
} else if _, err := exec.LookPath("wl-copy"); err == nil {
cmd = exec.Command("wl-copy")
} else {
return errors.New("no clipboard tool found (install xclip or wl-clipboard)")
}
cmd.Stdin = strings.NewReader(text)
cmd.Stdout = nil cmd.Stdout = nil
cmd.Stderr = nil cmd.Stderr = nil
cmd.Stdin = strings.NewReader(text)
return cmd.Run() return cmd.Run()
} }
func readFromClipboard() (string, error) {
var cmd *exec.Cmd
if _, err := exec.LookPath("xclip"); err == nil {
cmd = exec.Command("xclip", "-selection", "clipboard", "-out")
} else if _, err := exec.LookPath("wl-paste"); err == nil {
cmd = exec.Command("wl-paste")
} else {
return "", errors.New("no clipboard tool found (install xclip or wl-clipboard)")
}
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
return out.String(), err
}

23
tui.go
View File

@@ -68,8 +68,8 @@ var (
[yellow]F4[white]: edit msg [yellow]F4[white]: edit msg
[yellow]F5[white]: toggle fullscreen for input/chat window [yellow]F5[white]: toggle fullscreen for input/chat window
[yellow]F6[white]: interrupt bot resp [yellow]F6[white]: interrupt bot resp
[yellow]F7[white]: copy last msg to clipboard (linux xclip) [yellow]F7[white]: copy last msg to clipboard (linux xclip or wl-copy)
[yellow]F8[white]: copy n msg to clipboard (linux xclip) [yellow]F8[white]: copy n msg to clipboard (linux xclip or wl-copy)
[yellow]F9[white]: table to copy from; with all code blocks [yellow]F9[white]: table to copy from; with all code blocks
[yellow]F10[white]: switch if LLM will respond on this message (for user to write multiple messages in a row) [yellow]F10[white]: switch if LLM will respond on this message (for user to write multiple messages in a row)
[yellow]F11[white]: import json chat file [yellow]F11[white]: import json chat file
@@ -104,6 +104,7 @@ var (
[yellow]Alt+t[white]: toggle thinking blocks visibility (collapse/expand <think> blocks) [yellow]Alt+t[white]: toggle thinking blocks visibility (collapse/expand <think> blocks)
[yellow]Ctrl+t[white]: toggle tool call/response visibility (collapse/expand tool calls and non-shell tool responses) [yellow]Ctrl+t[white]: toggle tool call/response visibility (collapse/expand tool calls and non-shell tool responses)
[yellow]Alt+i[white]: show colorscheme selection popup [yellow]Alt+i[white]: show colorscheme selection popup
[yellow]Insert[white]: paste from clipboard to the text area (use it instead shift+insert)
=== scrolling chat window (some keys similar to vim) === === scrolling chat window (some keys similar to vim) ===
[yellow]arrows up/down and j/k[white]: scroll up and down [yellow]arrows up/down and j/k[white]: scroll up and down
@@ -318,6 +319,24 @@ func initTUI() {
textArea = tview.NewTextArea(). textArea = tview.NewTextArea().
SetPlaceholder("input is multiline; press <Enter> to start the next line;\npress <Esc> to send the message.") SetPlaceholder("input is multiline; press <Enter> to start the next line;\npress <Esc> to send the message.")
textArea.SetBorder(true).SetTitle("input") textArea.SetBorder(true).SetTitle("input")
textArea.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyInsert {
text, err := readFromClipboard()
if err != nil {
logger.Error("failed to read clipboard", "error", err)
return event
}
maxPaste := 100000
if len(text) > maxPaste {
text = text[:maxPaste]
showToast("paste truncated", "pasted text exceeded 100KB limit")
}
current := textArea.GetText()
textArea.SetText(current+text, true)
return nil
}
return event
})
textView = tview.NewTextView(). textView = tview.NewTextView().
SetDynamicColors(true). SetDynamicColors(true).
SetRegions(true). SetRegions(true).