From e597617266e5c891e025b380a8ed9c8e0d6106f2 Mon Sep 17 00:00:00 2001 From: "Christoph K." Date: Thu, 12 Mar 2026 19:49:50 +0100 Subject: [PATCH] no brain command --- .gitignore | 1 + cmd/discord/main.go | 63 +++++++++++++++++++++++++++++++------------ internal/brain/ask.go | 34 +++++++++++++++++++++++ 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index ae6c55c..e3b2f11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ bin/ config.yml ask +discord diff --git a/cmd/discord/main.go b/cmd/discord/main.go index bd6a1fb..7a84387 100644 --- a/cmd/discord/main.go +++ b/cmd/discord/main.go @@ -23,7 +23,19 @@ var ( commands = []*discordgo.ApplicationCommand{ { Name: "ask", - Description: "Stelle eine Frage an deinen AI Brain", + Description: "Stelle eine Frage an deinen AI Brain (mit Wissensdatenbank)", + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionString, + Name: "frage", + Description: "Die Frage, die du stellen möchtest", + Required: true, + }, + }, + }, + { + Name: "asknobrain", + Description: "Stelle eine Frage direkt ans LLM (ohne Wissensdatenbank)", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionString, @@ -95,17 +107,16 @@ func onReady(s *discordgo.Session, r *discordgo.Ready) { func registerCommands() { guildID := config.Cfg.Discord.GuildID - for _, cmd := range commands { - _, err := dg.ApplicationCommandCreate(dg.State.User.ID, guildID, cmd) - if err != nil { - log.Printf("⚠️ Slash-Command /%s konnte nicht registriert werden: %v", cmd.Name, err) - } else { - scope := "global" - if guildID != "" { - scope = "guild " + guildID - } - fmt.Printf("📝 Slash-Command /%s registriert (%s)\n", cmd.Name, scope) - } + registered, err := dg.ApplicationCommandBulkOverwrite(dg.State.User.ID, guildID, commands) + if err != nil { + log.Fatalf("❌ Slash-Commands konnten nicht registriert werden: %v", err) + } + scope := "global" + if guildID != "" { + scope = "guild " + guildID + } + for _, cmd := range registered { + fmt.Printf("📝 Slash-Command /%s registriert (%s)\n", cmd.Name, scope) } } @@ -116,7 +127,9 @@ func onInteraction(s *discordgo.Session, i *discordgo.InteractionCreate) { switch i.ApplicationCommandData().Name { case "ask": - handleAsk(s, i, i.ApplicationCommandData().Options[0].StringValue()) + handleAsk(s, i, i.ApplicationCommandData().Options[0].StringValue(), true) + case "asknobrain": + handleAsk(s, i, i.ApplicationCommandData().Options[0].StringValue(), false) case "ingest": handleIngest(s, i) case "remember": @@ -157,13 +170,22 @@ func onMessage(s *discordgo.Session, m *discordgo.MessageCreate) { s.ChannelMessageSendReply(m.ChannelID, reply, m.Reference()) } -func handleAsk(s *discordgo.Session, i *discordgo.InteractionCreate, question string) { - // Sofort mit "Denke nach..." antworten (Discord-Timeout: 3s) +func handleAsk(s *discordgo.Session, i *discordgo.InteractionCreate, question string, useBrain bool) { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseDeferredChannelMessageWithSource, }) - reply := queryAndFormat(question) + var reply string + if useBrain { + reply = queryAndFormat(question) + } else { + answer, err := brain.ChatDirect(question) + if err != nil { + reply = fmt.Sprintf("❌ Fehler: %v", err) + } else { + reply = fmt.Sprintf("💬 **Antwort:** _%s_\n\n%s", question, answer) + } + } s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ Content: &reply, @@ -190,7 +212,14 @@ func handleRemember(s *discordgo.Session, i *discordgo.InteractionCreate) { }) text := i.ApplicationCommandData().Options[0].StringValue() - author := i.Member.User.Username + var author string + if i.Member != nil { + author = i.Member.User.Username + } else if i.User != nil { + author = i.User.Username + } else { + author = "unknown" + } source := fmt.Sprintf("discord/#%s", i.ChannelID) err := brain.IngestChatMessage(text, author, source) diff --git a/internal/brain/ask.go b/internal/brain/ask.go index b033ee2..2c1dabd 100755 --- a/internal/brain/ask.go +++ b/internal/brain/ask.go @@ -169,4 +169,38 @@ func buildContext(chunks []KnowledgeChunk) string { return b.String() } +// ChatDirect stellt eine Frage direkt an das LLM ohne Datenbankkontext. +func ChatDirect(question string) (string, error) { + ctx := context.Background() + chatClient := config.NewChatClient() + + systemPrompt := `Du bist ein hilfreicher persönlicher Assistent. Antworte auf Deutsch, präzise und direkt.` + + stream, err := chatClient.CreateChatCompletionStream(ctx, openai.ChatCompletionRequest{ + Model: config.Cfg.Chat.Model, + Messages: []openai.ChatCompletionMessage{ + {Role: openai.ChatMessageRoleSystem, Content: systemPrompt}, + {Role: openai.ChatMessageRoleUser, Content: question}, + }, + Temperature: 0.7, + MaxTokens: 500, + }) + if err != nil { + return "", fmt.Errorf("LLM Fehler: %w", err) + } + defer stream.Close() + + var answer strings.Builder + for { + response, err := stream.Recv() + if err != nil { + break + } + if len(response.Choices) > 0 { + answer.WriteString(response.Choices[0].Delta.Content) + } + } + return answer.String(), nil +} + func floatPtr(f float32) *float32 { return &f }