Chore: simplify

This commit is contained in:
Grail Finder
2025-11-24 15:20:36 +03:00
parent b5ade05489
commit 9686915545

123
llm.go
View File

@@ -3,10 +3,8 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"gf-lt/models" "gf-lt/models"
"io" "io"
"os"
"strings" "strings"
) )
@@ -78,12 +76,6 @@ type OpenRouterChat struct {
Model string Model string
} }
func min(a, b int) int {
if a < b {
return a
}
return b
}
func (lcp LlamaCPPeer) GetToken() string { func (lcp LlamaCPPeer) GetToken() string {
return "" return ""
@@ -211,9 +203,9 @@ func (op OpenAIer) FormMsg(msg, role string, resume bool) (io.Reader, error) {
newMsg = models.NewRoleMsg(role, msg) newMsg = models.NewRoleMsg(role, msg)
} else { } else {
newMsg.AddImagePart(imageURL) newMsg.AddImagePart(imageURL)
}
// Only clear the global image attachment after successfully processing it in this API call // Only clear the global image attachment after successfully processing it in this API call
imageAttachmentPath = "" // Clear the attachment after use imageAttachmentPath = "" // Clear the attachment after use
}
} else { } else {
// Create a simple text message // Create a simple text message
newMsg = models.NewRoleMsg(role, msg) newMsg = models.NewRoleMsg(role, msg)
@@ -505,20 +497,7 @@ func (or OpenRouterChat) FormMsg(msg, role string, resume bool) (io.Reader, erro
if msg != "" { // otherwise let the bot continue if msg != "" { // otherwise let the bot continue
var newMsg models.RoleMsg var newMsg models.RoleMsg
// Check if we have an image to add to this message // Check if we have an image to add to this message
logger.Debug("checking for image attachment", "imageAttachmentPath", localImageAttachmentPath, "msg", msg, "role", role)
if localImageAttachmentPath != "" { if localImageAttachmentPath != "" {
logger.Info("processing image attachment for OpenRouter", "path", localImageAttachmentPath, "msg", msg)
// Check if file exists before attempting to create image URL
if _, err := os.Stat(localImageAttachmentPath); os.IsNotExist(err) {
logger.Error("image file does not exist", "path", localImageAttachmentPath)
// Fallback to simple text message
newMsg = models.NewRoleMsg(role, msg)
} else if err != nil {
logger.Error("error checking image file", "path", localImageAttachmentPath, "error", err)
// Fallback to simple text message
newMsg = models.NewRoleMsg(role, msg)
} else {
logger.Debug("image file exists, proceeding to create URL", "path", localImageAttachmentPath)
// Create a multimodal message with both text and image // Create a multimodal message with both text and image
newMsg = models.NewMultimodalMsg(role, []interface{}{}) newMsg = models.NewMultimodalMsg(role, []interface{}{})
// Add the text content // Add the text content
@@ -530,12 +509,10 @@ func (or OpenRouterChat) FormMsg(msg, role string, resume bool) (io.Reader, erro
// If image processing fails, fall back to simple text message // If image processing fails, fall back to simple text message
newMsg = models.NewRoleMsg(role, msg) newMsg = models.NewRoleMsg(role, msg)
} else { } else {
logger.Info("image URL created successfully for OpenRouter", "imageURL", imageURL[:min(len(imageURL), 50)]+"...")
newMsg.AddImagePart(imageURL) newMsg.AddImagePart(imageURL)
}
// Only clear the global image attachment after successfully processing it in this API call // Only clear the global image attachment after successfully processing it in this API call
imageAttachmentPath = "" // Clear the attachment after use imageAttachmentPath = "" // Clear the attachment after use
}
}
} else { } else {
// Create a simple text message // Create a simple text message
newMsg = models.NewRoleMsg(role, msg) newMsg = models.NewRoleMsg(role, msg)
@@ -561,72 +538,13 @@ func (or OpenRouterChat) FormMsg(msg, role string, resume bool) (io.Reader, erro
} }
for i, msg := range chatBody.Messages { for i, msg := range chatBody.Messages {
logger.Debug("checking roles", "#", i, "role", msg.Role)
// Check if this message has content parts (multimodal) by attempting to marshal and checking structure
msgBytes, err := json.Marshal(msg)
if err != nil {
logger.Error("failed to serialize message for inspection", "error", err)
// Fallback to direct assignment
bodyCopy.Messages[i] = msg bodyCopy.Messages[i] = msg
} else { // Standardize role if it's a user role
// Try to deserialize to check if it has content parts if bodyCopy.Messages[i].Role == cfg.UserRole {
var tempMsg map[string]interface{}
if err := json.Unmarshal(msgBytes, &tempMsg); err != nil {
logger.Error("failed to inspect message structure", "error", err)
bodyCopy.Messages[i] = msg
} else {
// Check if content is an array (indicating content parts) or string (simple content)
if content, ok := tempMsg["content"]; ok {
if _, isArray := content.([]interface{}); isArray {
logger.Info("multimodal message detected", "#", i, "role", msg.Role)
// Deserialize to RoleMsg to access ContentParts
var detailedMsg models.RoleMsg
if err := json.Unmarshal(msgBytes, &detailedMsg); err == nil {
if len(detailedMsg.ContentParts) > 0 {
for j, part := range detailedMsg.ContentParts {
if textPart, ok := part.(models.TextContentPart); ok {
logger.Debug("text content part", "msg#", i, "part#", j, "text", textPart.Text)
} else if imgPart, ok := part.(models.ImageContentPart); ok {
logger.Info("image content part", "msg#", i, "part#", j, "url", imgPart.ImageURL.URL[:min(len(imgPart.ImageURL.URL), 50)]+"...")
} else {
logger.Debug("other content part", "msg#", i, "part#", j, "type", fmt.Sprintf("%T", part))
}
}
}
}
}
}
}
}
// Create a proper copy of the message that preserves all internal state
// First, serialize and deserialize to ensure content parts are preserved
copyMsgBytes, err := json.Marshal(msg)
if err != nil {
logger.Error("failed to serialize message", "error", err)
// Fallback to direct assignment
bodyCopy.Messages[i] = msg
} else {
// Deserialize back to preserve all internal state
var copiedMsg models.RoleMsg
err := json.Unmarshal(copyMsgBytes, &copiedMsg)
if err != nil {
logger.Error("failed to deserialize message", "error", err)
// Fallback to direct assignment
bodyCopy.Messages[i] = msg
} else {
bodyCopy.Messages[i] = copiedMsg
}
}
// Standardize role if it's a user role or first message
if bodyCopy.Messages[i].Role == cfg.UserRole || i == 1 {
bodyCopy.Messages[i].Role = "user" bodyCopy.Messages[i].Role = "user"
logger.Debug("replaced role in body", "#", i)
} }
} }
// Log the final request body before sending to OpenRouter
orBody := models.NewOpenRouterChatReq(*bodyCopy, defaultLCPProps) orBody := models.NewOpenRouterChatReq(*bodyCopy, defaultLCPProps)
data, err := json.Marshal(orBody) data, err := json.Marshal(orBody)
if err != nil { if err != nil {
@@ -634,38 +552,5 @@ func (or OpenRouterChat) FormMsg(msg, role string, resume bool) (io.Reader, erro
return nil, err return nil, err
} }
logger.Info("OpenRouter request prepared", "messages_count", len(orBody.Messages))
for i, msg := range orBody.Messages {
// Check if this final message has content parts (multimodal)
msgBytes, err := json.Marshal(msg)
if err == nil {
var tempMsg map[string]interface{}
if err := json.Unmarshal(msgBytes, &tempMsg); err == nil {
if content, ok := tempMsg["content"]; ok {
if _, isArray := content.([]interface{}); isArray {
logger.Debug("final message", "#", i, "role", msg.Role, "hasContentParts", true)
// Deserialize to access content parts
var detailedMsg models.RoleMsg
if err := json.Unmarshal(msgBytes, &detailedMsg); err == nil {
if len(detailedMsg.ContentParts) > 0 {
for j, part := range detailedMsg.ContentParts {
if textPart, ok := part.(models.TextContentPart); ok {
logger.Debug("final text part", "msg#", i, "part#", j, "text", textPart.Text)
} else if imgPart, ok := part.(models.ImageContentPart); ok {
logger.Info("final image part sent to OpenRouter", "msg#", i, "part#", j, "url", imgPart.ImageURL.URL[:min(len(imgPart.ImageURL.URL), 50)]+"...")
} else {
logger.Debug("final other part", "msg#", i, "part#", j, "type", fmt.Sprintf("%T", part))
}
}
}
}
} else {
logger.Debug("final message", "#", i, "role", msg.Role, "hasContentParts", false)
}
}
}
}
}
return bytes.NewReader(data), nil return bytes.NewReader(data), nil
} }