You've already forked grok
absolute cinema
This commit is contained in:
212
main.go
212
main.go
@@ -0,0 +1,212 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/openai/openai-go/v3"
|
||||
"github.com/openai/openai-go/v3/option"
|
||||
"github.com/openai/openai-go/v3/responses"
|
||||
)
|
||||
|
||||
type OpenAIPrompter struct {
|
||||
cli openai.Client
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
func (p *OpenAIPrompter) Prompt(ctx context.Context, question string) (*HighlyTrustedResponse, error) {
|
||||
resp, err := p.cli.Responses.New(ctx, responses.ResponseNewParams{
|
||||
Input: responses.ResponseNewParamsInputUnion{
|
||||
OfString: openai.String(question),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &HighlyTrustedResponse{
|
||||
Text: resp.OutputText(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewOpenAIProoooompter(cfg *Config) *OpenAIPrompter {
|
||||
return &OpenAIPrompter{
|
||||
cli: openai.NewClient(
|
||||
option.WithBaseURL(cfg.OpenAIBaseURL),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
type HighlyTrustedResponse struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
type Proompter interface {
|
||||
Prompt(ctx context.Context, question string) (*HighlyTrustedResponse, error)
|
||||
}
|
||||
|
||||
type App struct {
|
||||
log *slog.Logger
|
||||
bot *tgbotapi.BotAPI
|
||||
proompter Proompter
|
||||
sema chan struct{}
|
||||
config *Config
|
||||
}
|
||||
|
||||
func (a *App) handleMessage(ctx context.Context, msg *tgbotapi.Message) error {
|
||||
if msg.Chat != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
chatID := msg.Chat.ID
|
||||
if chatID != a.config.ChatID || !strings.HasPrefix(msg.Text, "@grok") {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case a.sema <- struct{}{}:
|
||||
default:
|
||||
a.log.Info("concurrency limit hit", "msg", msg)
|
||||
return nil
|
||||
}
|
||||
defer func() { <-a.sema }()
|
||||
|
||||
a.log.Info("message passed all guards", "text", msg.Text)
|
||||
|
||||
response, err := a.proompter.Prompt(ctx, msg.Text)
|
||||
if err != nil {
|
||||
return fmt.Errorf("prompting: %w", err)
|
||||
}
|
||||
|
||||
_, err = a.bot.Send(tgbotapi.NewMessage(chatID, response.Text))
|
||||
if err != nil {
|
||||
return fmt.Errorf("responding: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) HandleUpdates(ctx context.Context) error {
|
||||
upds := a.bot.GetUpdatesChan(tgbotapi.UpdateConfig{})
|
||||
for {
|
||||
select {
|
||||
case upd, ok := <-upds:
|
||||
if !ok {
|
||||
return errors.New("channel closed")
|
||||
}
|
||||
|
||||
if upd.Message != nil {
|
||||
go func() {
|
||||
if err := a.handleMessage(ctx, upd.Message); err != nil {
|
||||
a.log.Error("handling message", "msg", upd.Message, "err", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func NewApp(cfg *Config, prompter Proompter) (*App, error) {
|
||||
var app App
|
||||
var err error
|
||||
|
||||
app.proompter = prompter
|
||||
|
||||
app.log = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}))
|
||||
|
||||
app.bot, err = tgbotapi.NewBotAPI(cfg.BotToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.MaxConcurrentRequests == 0 {
|
||||
return nil, errors.New("concurrency limit not set")
|
||||
}
|
||||
app.sema = make(chan struct{}, cfg.MaxConcurrentRequests)
|
||||
|
||||
app.config = cfg
|
||||
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
OpenAIBaseURL string
|
||||
BotToken string
|
||||
MaxConcurrentRequests uint
|
||||
ChatID int64
|
||||
}
|
||||
|
||||
func LoadConfig(cfg *Config) error {
|
||||
if err := godotenv.Load(".env"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.OpenAIBaseURL = os.Getenv("OPENAI_BASE_URL")
|
||||
if cfg.OpenAIBaseURL == "" {
|
||||
return errors.New("openai base url not set")
|
||||
}
|
||||
|
||||
cfg.BotToken = os.Getenv("BOT_TOKEN")
|
||||
mcg, err := strconv.ParseUint(
|
||||
os.Getenv("MAX_CONCURRENT_REQUESTS"),
|
||||
10, 64,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.MaxConcurrentRequests = uint(mcg)
|
||||
chatID, err := strconv.ParseInt(os.Getenv("CHAT_ID"), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if chatID == 0 {
|
||||
return errors.New("non-zero chat id is unsafe")
|
||||
}
|
||||
|
||||
cfg.ChatID = chatID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
log := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}))
|
||||
log.Info("Starting GROK")
|
||||
|
||||
var cfg Config
|
||||
if err := LoadConfig(&cfg); err != nil {
|
||||
log.Error("loading config", "err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
prompter := NewOpenAIProoooompter(&cfg)
|
||||
|
||||
app, err := NewApp(&cfg, prompter)
|
||||
if err != nil {
|
||||
log.Error("initializing app", "err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := app.HandleUpdates(ctx); err != nil {
|
||||
log.Error("handleUpdates exited", "err", err)
|
||||
}
|
||||
cancel()
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user