Refactor: building binary with no extra
This commit is contained in:
8
Makefile
8
Makefile
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: setconfig run lint setup-whisper build-whisper download-whisper-model docker-up docker-down docker-logs
|
.PHONY: setconfig run lint setup-whisper build-whisper download-whisper-model docker-up docker-down docker-logs noextra-run noextra-server
|
||||||
|
|
||||||
run: setconfig
|
run: setconfig
|
||||||
go build -o gf-lt && ./gf-lt
|
go build -o gf-lt && ./gf-lt
|
||||||
@@ -6,6 +6,12 @@ run: setconfig
|
|||||||
server: setconfig
|
server: setconfig
|
||||||
go build -o gf-lt && ./gf-lt -port 3333
|
go build -o gf-lt && ./gf-lt -port 3333
|
||||||
|
|
||||||
|
noextra-run: setconfig
|
||||||
|
go build -tags '!extra' -o gf-lt && ./gf-lt
|
||||||
|
|
||||||
|
noextra-server: setconfig
|
||||||
|
go build -tags '!extra' -o gf-lt && ./gf-lt -port 3333
|
||||||
|
|
||||||
setconfig:
|
setconfig:
|
||||||
find config.toml &>/dev/null || cp config.example.toml config.toml
|
find config.toml &>/dev/null || cp config.example.toml config.toml
|
||||||
|
|
||||||
|
|||||||
62
bot.go
62
bot.go
@@ -7,7 +7,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gf-lt/config"
|
"gf-lt/config"
|
||||||
"gf-lt/extra"
|
|
||||||
"gf-lt/models"
|
"gf-lt/models"
|
||||||
"gf-lt/rag"
|
"gf-lt/rag"
|
||||||
"gf-lt/storage"
|
"gf-lt/storage"
|
||||||
@@ -29,12 +28,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
httpClient = &http.Client{}
|
httpClient = &http.Client{}
|
||||||
cluedoState *extra.CluedoRoundInfo // Current game state
|
cfg *config.Config
|
||||||
playerOrder []string // Turn order tracking
|
logger *slog.Logger
|
||||||
cfg *config.Config
|
logLevel = new(slog.LevelVar)
|
||||||
logger *slog.Logger
|
|
||||||
logLevel = new(slog.LevelVar)
|
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
activeChatName string
|
activeChatName string
|
||||||
@@ -51,8 +48,8 @@ var (
|
|||||||
chunkParser ChunkParser
|
chunkParser ChunkParser
|
||||||
lastToolCall *models.FuncCall
|
lastToolCall *models.FuncCall
|
||||||
//nolint:unused // TTS_ENABLED conditionally uses this
|
//nolint:unused // TTS_ENABLED conditionally uses this
|
||||||
orator extra.Orator
|
orator Orator
|
||||||
asr extra.STT
|
asr STT
|
||||||
localModelsMu sync.RWMutex
|
localModelsMu sync.RWMutex
|
||||||
defaultLCPProps = map[string]float32{
|
defaultLCPProps = map[string]float32{
|
||||||
"temperature": 0.8,
|
"temperature": 0.8,
|
||||||
@@ -600,32 +597,6 @@ func roleToIcon(role string) string {
|
|||||||
return "<" + role + ">: "
|
return "<" + role + ">: "
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: it should not be here; move to extra
|
|
||||||
func checkGame(role string, tv *tview.TextView) {
|
|
||||||
// Handle Cluedo game flow
|
|
||||||
// should go before form msg, since formmsg takes chatBody and makes ioreader out of it
|
|
||||||
// role is almost always user, unless it's regen or resume
|
|
||||||
// cannot get in this block, since cluedoState is nil;
|
|
||||||
if cfg.EnableCluedo {
|
|
||||||
// Initialize Cluedo game if needed
|
|
||||||
if cluedoState == nil {
|
|
||||||
playerOrder = []string{cfg.UserRole, cfg.AssistantRole, cfg.CluedoRole2}
|
|
||||||
cluedoState = extra.CluedoPrepCards(playerOrder)
|
|
||||||
}
|
|
||||||
// notifyUser("got in cluedo", "yay")
|
|
||||||
currentPlayer := playerOrder[0]
|
|
||||||
playerOrder = append(playerOrder[1:], currentPlayer) // Rotate turns
|
|
||||||
if role == cfg.UserRole {
|
|
||||||
fmt.Fprintf(tv, "Your (%s) cards: %s\n", currentPlayer, cluedoState.GetPlayerCards(currentPlayer))
|
|
||||||
} else {
|
|
||||||
chatBody.Messages = append(chatBody.Messages, models.RoleMsg{
|
|
||||||
Role: cfg.ToolRole,
|
|
||||||
Content: cluedoState.GetPlayerCards(currentPlayer),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func chatRound(userMsg, role string, tv *tview.TextView, regen, resume bool) {
|
func chatRound(userMsg, role string, tv *tview.TextView, regen, resume bool) {
|
||||||
botRespMode = true
|
botRespMode = true
|
||||||
botPersona := cfg.AssistantRole
|
botPersona := cfg.AssistantRole
|
||||||
@@ -643,9 +614,6 @@ func chatRound(userMsg, role string, tv *tview.TextView, regen, resume bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !resume {
|
|
||||||
checkGame(role, tv)
|
|
||||||
}
|
|
||||||
choseChunkParser()
|
choseChunkParser()
|
||||||
reader, err := chunkParser.FormMsg(userMsg, role, resume)
|
reader, err := chunkParser.FormMsg(userMsg, role, resume)
|
||||||
if reader == nil || err != nil {
|
if reader == nil || err != nil {
|
||||||
@@ -679,7 +647,7 @@ out:
|
|||||||
}
|
}
|
||||||
// Send chunk to audio stream handler
|
// Send chunk to audio stream handler
|
||||||
if cfg.TTS_ENABLED {
|
if cfg.TTS_ENABLED {
|
||||||
extra.TTSTextChan <- chunk
|
TTSTextChan <- chunk
|
||||||
}
|
}
|
||||||
case toolChunk := <-openAIToolChan:
|
case toolChunk := <-openAIToolChan:
|
||||||
fmt.Fprint(tv, toolChunk)
|
fmt.Fprint(tv, toolChunk)
|
||||||
@@ -698,7 +666,7 @@ out:
|
|||||||
}
|
}
|
||||||
// Send chunk to audio stream handler
|
// Send chunk to audio stream handler
|
||||||
if cfg.TTS_ENABLED {
|
if cfg.TTS_ENABLED {
|
||||||
extra.TTSTextChan <- chunk
|
TTSTextChan <- chunk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break out
|
break out
|
||||||
@@ -982,11 +950,6 @@ func addNewChat(chatName string) {
|
|||||||
func applyCharCard(cc *models.CharCard) {
|
func applyCharCard(cc *models.CharCard) {
|
||||||
cfg.AssistantRole = cc.Role
|
cfg.AssistantRole = cc.Role
|
||||||
// FIXME: remove
|
// FIXME: remove
|
||||||
// Initialize Cluedo if enabled and matching role
|
|
||||||
if cfg.EnableCluedo && cc.Role == "CluedoPlayer" {
|
|
||||||
playerOrder = []string{cfg.UserRole, cfg.AssistantRole, cfg.CluedoRole2}
|
|
||||||
cluedoState = extra.CluedoPrepCards(playerOrder)
|
|
||||||
}
|
|
||||||
history, err := loadAgentsLastChat(cfg.AssistantRole)
|
history, err := loadAgentsLastChat(cfg.AssistantRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// too much action for err != nil; loadAgentsLastChat needs to be split up
|
// too much action for err != nil; loadAgentsLastChat needs to be split up
|
||||||
@@ -1123,18 +1086,13 @@ func init() {
|
|||||||
Stream: true,
|
Stream: true,
|
||||||
Messages: lastChat,
|
Messages: lastChat,
|
||||||
}
|
}
|
||||||
// Initialize Cluedo if enabled and matching role
|
|
||||||
if cfg.EnableCluedo && cfg.AssistantRole == "CluedoPlayer" {
|
|
||||||
playerOrder = []string{cfg.UserRole, cfg.AssistantRole, cfg.CluedoRole2}
|
|
||||||
cluedoState = extra.CluedoPrepCards(playerOrder)
|
|
||||||
}
|
|
||||||
choseChunkParser()
|
choseChunkParser()
|
||||||
httpClient = createClient(time.Second * 90)
|
httpClient = createClient(time.Second * 90)
|
||||||
if cfg.TTS_ENABLED {
|
if cfg.TTS_ENABLED {
|
||||||
orator = extra.NewOrator(logger, cfg)
|
orator = NewOrator(logger, cfg)
|
||||||
}
|
}
|
||||||
if cfg.STT_ENABLED {
|
if cfg.STT_ENABLED {
|
||||||
asr = extra.NewSTT(logger, cfg)
|
asr = NewSTT(logger, cfg)
|
||||||
}
|
}
|
||||||
// Initialize scrollToEndEnabled based on config
|
// Initialize scrollToEndEnabled based on config
|
||||||
scrollToEndEnabled = cfg.AutoScrollEnabled
|
scrollToEndEnabled = cfg.AutoScrollEnabled
|
||||||
|
|||||||
28
extra.go
Normal file
28
extra.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//go:build extra
|
||||||
|
// +build extra
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gf-lt/config"
|
||||||
|
"gf-lt/extra"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interfaces and implementations when extra modules are included
|
||||||
|
|
||||||
|
type Orator = extra.Orator
|
||||||
|
type STT = extra.STT
|
||||||
|
|
||||||
|
func NewOrator(logger *slog.Logger, cfg *config.Config) Orator {
|
||||||
|
return extra.NewOrator(logger, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSTT(logger *slog.Logger, cfg *config.Config) STT {
|
||||||
|
return extra.NewSTT(logger, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TTS channels from extra package
|
||||||
|
var TTSTextChan = extra.TTSTextChan
|
||||||
|
var TTSFlushChan = extra.TTSFlushChan
|
||||||
|
var TTSDoneChan = extra.TTSDoneChan
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package extra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
rooms = []string{"HALL", "LOUNGE", "DINING ROOM", "KITCHEN", "BALLROOM", "CONSERVATORY", "BILLIARD ROOM", "LIBRARY", "STUDY"}
|
|
||||||
weapons = []string{"CANDLESTICK", "DAGGER", "LEAD PIPE", "REVOLVER", "ROPE", "SPANNER"}
|
|
||||||
people = []string{"Miss Scarlett", "Colonel Mustard", "Mrs. White", "Reverend Green", "Mrs. Peacock", "Professor Plum"}
|
|
||||||
)
|
|
||||||
|
|
||||||
type MurderTrifecta struct {
|
|
||||||
Murderer string
|
|
||||||
Weapon string
|
|
||||||
Room string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CluedoRoundInfo struct {
|
|
||||||
Answer MurderTrifecta
|
|
||||||
PlayersCards map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CluedoRoundInfo) GetPlayerCards(player string) string {
|
|
||||||
// maybe format it a little
|
|
||||||
return "cards of " + player + "are " + strings.Join(c.PlayersCards[player], ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
func CluedoPrepCards(playerOrder []string) *CluedoRoundInfo {
|
|
||||||
res := &CluedoRoundInfo{}
|
|
||||||
// Select murder components
|
|
||||||
trifecta := MurderTrifecta{
|
|
||||||
Murderer: people[rand.Intn(len(people))],
|
|
||||||
Weapon: weapons[rand.Intn(len(weapons))],
|
|
||||||
Room: rooms[rand.Intn(len(rooms))],
|
|
||||||
}
|
|
||||||
// Collect non-murder cards
|
|
||||||
var notInvolved []string
|
|
||||||
for _, room := range rooms {
|
|
||||||
if room != trifecta.Room {
|
|
||||||
notInvolved = append(notInvolved, room)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, weapon := range weapons {
|
|
||||||
if weapon != trifecta.Weapon {
|
|
||||||
notInvolved = append(notInvolved, weapon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, person := range people {
|
|
||||||
if person != trifecta.Murderer {
|
|
||||||
notInvolved = append(notInvolved, person)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Shuffle and distribute cards
|
|
||||||
rand.Shuffle(len(notInvolved), func(i, j int) {
|
|
||||||
notInvolved[i], notInvolved[j] = notInvolved[j], notInvolved[i]
|
|
||||||
})
|
|
||||||
players := map[string][]string{}
|
|
||||||
cardsPerPlayer := len(notInvolved) / len(playerOrder)
|
|
||||||
// playerOrder := []string{"{{user}}", "{{char}}", "{{char2}}"}
|
|
||||||
for i, player := range playerOrder {
|
|
||||||
start := i * cardsPerPlayer
|
|
||||||
end := (i + 1) * cardsPerPlayer
|
|
||||||
if end > len(notInvolved) {
|
|
||||||
end = len(notInvolved)
|
|
||||||
}
|
|
||||||
players[player] = notInvolved[start:end]
|
|
||||||
}
|
|
||||||
res.Answer = trifecta
|
|
||||||
res.PlayersCards = players
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package extra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPrepCards(t *testing.T) {
|
|
||||||
// Run the function to get the murder combination and player cards
|
|
||||||
roundInfo := CluedoPrepCards([]string{"{{user}}", "{{char}}", "{{char2}}"})
|
|
||||||
// Create a map to track all distributed cards
|
|
||||||
distributedCards := make(map[string]bool)
|
|
||||||
// Check that the murder combination cards are not distributed to players
|
|
||||||
murderCards := []string{roundInfo.Answer.Murderer, roundInfo.Answer.Weapon, roundInfo.Answer.Room}
|
|
||||||
for _, card := range murderCards {
|
|
||||||
if distributedCards[card] {
|
|
||||||
t.Errorf("Murder card %s was distributed to a player", card)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check each player's cards
|
|
||||||
for player, cards := range roundInfo.PlayersCards {
|
|
||||||
for _, card := range cards {
|
|
||||||
// Ensure the card is not part of the murder combination
|
|
||||||
for _, murderCard := range murderCards {
|
|
||||||
if card == murderCard {
|
|
||||||
t.Errorf("Player %s has a murder card: %s", player, card)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ensure the card is unique and not already distributed
|
|
||||||
if distributedCards[card] {
|
|
||||||
t.Errorf("Card %s is duplicated in player %s's hand", card, player)
|
|
||||||
}
|
|
||||||
distributedCards[card] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Verify that all non-murder cards are distributed
|
|
||||||
allCards := append(append([]string{}, rooms...), weapons...)
|
|
||||||
allCards = append(allCards, people...)
|
|
||||||
for _, card := range allCards {
|
|
||||||
isMurderCard := false
|
|
||||||
for _, murderCard := range murderCards {
|
|
||||||
if card == murderCard {
|
|
||||||
isMurderCard = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !isMurderCard && !distributedCards[card] {
|
|
||||||
t.Errorf("Card %s was not distributed to any player", card)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build extra
|
||||||
|
// +build extra
|
||||||
|
|
||||||
package extra
|
package extra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build extra
|
||||||
|
// +build extra
|
||||||
|
|
||||||
package extra
|
package extra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package extra
|
|
||||||
|
|
||||||
import "math/rand"
|
|
||||||
|
|
||||||
var (
|
|
||||||
chars = []string{"Shrek", "Garfield", "Jack the Ripper"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetRandomChar() string {
|
|
||||||
return chars[rand.Intn(len(chars))]
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
package extra
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package extra
|
|
||||||
|
|
||||||
import "github.com/GrailFinder/searchagent/searcher"
|
|
||||||
|
|
||||||
var WebSearcher searcher.WebSurfer
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
sa, err := searcher.NewWebSurfer(searcher.SearcherTypeScraper, "")
|
|
||||||
if err != nil {
|
|
||||||
panic("failed to init seachagent; error: " + err.Error())
|
|
||||||
}
|
|
||||||
WebSearcher = sa
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build extra
|
||||||
|
// +build extra
|
||||||
|
|
||||||
package extra
|
package extra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
73
noextra.go
Normal file
73
noextra.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
//go:build !extra
|
||||||
|
// +build !extra
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gf-lt/config"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interfaces and implementations when extra modules are not included
|
||||||
|
|
||||||
|
type Orator interface {
|
||||||
|
Speak(text string) error
|
||||||
|
Stop()
|
||||||
|
GetLogger() *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type STT interface {
|
||||||
|
StartRecording() error
|
||||||
|
StopRecording() (string, error)
|
||||||
|
IsRecording() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultOrator is a no-op implementation when TTS is not available
|
||||||
|
type DefaultOrator struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOrator(logger *slog.Logger, cfg *config.Config) Orator {
|
||||||
|
return &DefaultOrator{logger: logger}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultOrator) Speak(text string) error {
|
||||||
|
d.logger.Debug("TTS not available - extra modules disabled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultOrator) Stop() {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultOrator) GetLogger() *slog.Logger {
|
||||||
|
return d.logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultSTT is a no-op implementation when STT is not available
|
||||||
|
type DefaultSTT struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSTT(logger *slog.Logger, cfg *config.Config) STT {
|
||||||
|
return &DefaultSTT{logger: logger}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultSTT) StartRecording() error {
|
||||||
|
d.logger.Debug("STT not available - extra modules disabled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultSTT) StopRecording() (string, error) {
|
||||||
|
d.logger.Debug("STT not available - extra modules disabled")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultSTT) IsRecording() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// TTS channels - no-op when extra is not available
|
||||||
|
var TTSTextChan = make(chan string, 10000)
|
||||||
|
var TTSFlushChan = make(chan bool, 1)
|
||||||
|
var TTSDoneChan = make(chan bool, 1)
|
||||||
24
tools.go
24
tools.go
@@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gf-lt/agent"
|
"gf-lt/agent"
|
||||||
"gf-lt/extra"
|
|
||||||
"gf-lt/models"
|
"gf-lt/models"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@@ -15,6 +14,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/GrailFinder/searchagent/searcher"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -141,13 +142,6 @@ After that you are free to respond to the user.
|
|||||||
Role: "",
|
Role: "",
|
||||||
FilePath: "",
|
FilePath: "",
|
||||||
}
|
}
|
||||||
// toolCard = &models.CharCard{
|
|
||||||
// SysPrompt: toolSysMsg,
|
|
||||||
// FirstMsg: defaultFirstMsg,
|
|
||||||
// Role: "",
|
|
||||||
// FilePath: "",
|
|
||||||
// }
|
|
||||||
// sysMap = map[string]string{"basic_sys": basicSysMsg, "tool_sys": toolSysMsg}
|
|
||||||
sysMap = map[string]*models.CharCard{"basic_sys": basicCard}
|
sysMap = map[string]*models.CharCard{"basic_sys": basicCard}
|
||||||
sysLabels = []string{"basic_sys"}
|
sysLabels = []string{"basic_sys"}
|
||||||
|
|
||||||
@@ -156,6 +150,16 @@ After that you are free to respond to the user.
|
|||||||
webAgentsOnce sync.Once
|
webAgentsOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var WebSearcher searcher.WebSurfer
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
sa, err := searcher.NewWebSurfer(searcher.SearcherTypeScraper, "")
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to init seachagent; error: " + err.Error())
|
||||||
|
}
|
||||||
|
WebSearcher = sa
|
||||||
|
}
|
||||||
|
|
||||||
// getWebAgentClient returns a singleton AgentClient for web agents.
|
// getWebAgentClient returns a singleton AgentClient for web agents.
|
||||||
func getWebAgentClient() *agent.AgentClient {
|
func getWebAgentClient() *agent.AgentClient {
|
||||||
webAgentClientOnce.Do(func() {
|
webAgentClientOnce.Do(func() {
|
||||||
@@ -208,7 +212,7 @@ func websearch(args map[string]string) []byte {
|
|||||||
"limit_arg", limitS, "error", err)
|
"limit_arg", limitS, "error", err)
|
||||||
limit = 3
|
limit = 3
|
||||||
}
|
}
|
||||||
resp, err := extra.WebSearcher.Search(context.Background(), query, limit)
|
resp, err := WebSearcher.Search(context.Background(), query, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := "search tool failed; error: " + err.Error()
|
msg := "search tool failed; error: " + err.Error()
|
||||||
logger.Error(msg)
|
logger.Error(msg)
|
||||||
@@ -232,7 +236,7 @@ func readURL(args map[string]string) []byte {
|
|||||||
logger.Error(msg)
|
logger.Error(msg)
|
||||||
return []byte(msg)
|
return []byte(msg)
|
||||||
}
|
}
|
||||||
resp, err := extra.WebSearcher.RetrieveFromLink(context.Background(), link)
|
resp, err := WebSearcher.RetrieveFromLink(context.Background(), link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := "search tool failed; error: " + err.Error()
|
msg := "search tool failed; error: " + err.Error()
|
||||||
logger.Error(msg)
|
logger.Error(msg)
|
||||||
|
|||||||
3
tui.go
3
tui.go
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gf-lt/extra"
|
|
||||||
"gf-lt/models"
|
"gf-lt/models"
|
||||||
"image"
|
"image"
|
||||||
_ "image/jpeg"
|
_ "image/jpeg"
|
||||||
@@ -1147,7 +1146,7 @@ func init() {
|
|||||||
// textArea.SetText("pressed ctrl+A", true)
|
// textArea.SetText("pressed ctrl+A", true)
|
||||||
if cfg.TTS_ENABLED {
|
if cfg.TTS_ENABLED {
|
||||||
// audioStream.TextChan <- chunk
|
// audioStream.TextChan <- chunk
|
||||||
extra.TTSDoneChan <- true
|
TTSDoneChan <- true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if event.Key() == tcell.KeyCtrlW {
|
if event.Key() == tcell.KeyCtrlW {
|
||||||
|
|||||||
Reference in New Issue
Block a user