mirror of https://github.com/usememos/memos.git
fix: resolve golangci-lint violations across codebase
- Replace fmt.Errorf with errors.Wrapf/New for forbidigo compliance - Add missing periods to comments for godot compliance - Fix goimports formatting issues in multiple files - Remove unused struct field writes in tests - Replace unused method receivers with underscore - Optimize single-case switch to if-else statement Signed-off-by: ChaoLiu <chaoliu719@gmail.com>
This commit is contained in:
parent
96e527e264
commit
9db3dcf0a2
|
|
@ -2,8 +2,6 @@ package ai
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -11,11 +9,12 @@ import (
|
|||
|
||||
"github.com/openai/openai-go/v2"
|
||||
"github.com/openai/openai-go/v2/option"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
storepb "github.com/usememos/memos/proto/gen/store"
|
||||
)
|
||||
|
||||
// Common AI errors
|
||||
// Common AI errors.
|
||||
var (
|
||||
ErrConfigIncomplete = errors.New("AI configuration incomplete - missing BaseURL, APIKey, or Model")
|
||||
ErrEmptyRequest = errors.New("chat request cannot be empty")
|
||||
|
|
@ -125,7 +124,7 @@ type Client struct {
|
|||
// NewClient creates a new AI client
|
||||
func NewClient(config *Config) (*Client, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("config cannot be nil")
|
||||
return nil, errors.New("config cannot be nil")
|
||||
}
|
||||
|
||||
if !config.IsConfigured() {
|
||||
|
|
@ -182,10 +181,10 @@ func (c *Client) Chat(ctx context.Context, req *ChatRequest) (*ChatResponse, err
|
|||
// Validate messages
|
||||
for i, msg := range req.Messages {
|
||||
if msg.Role != "system" && msg.Role != "user" && msg.Role != "assistant" {
|
||||
return nil, fmt.Errorf("message %d: %w", i, ErrInvalidMessage)
|
||||
return nil, errors.Wrapf(ErrInvalidMessage, "message %d", i)
|
||||
}
|
||||
if strings.TrimSpace(msg.Content) == "" {
|
||||
return nil, fmt.Errorf("message %d: %w", i, ErrEmptyContent)
|
||||
return nil, errors.Wrapf(ErrEmptyContent, "message %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -235,7 +234,7 @@ func (c *Client) Chat(ctx context.Context, req *ChatRequest) (*ChatResponse, err
|
|||
Temperature: openai.Float(req.Temperature),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrAPICallFailed, err)
|
||||
return nil, errors.Wrapf(ErrAPICallFailed, "%v", err)
|
||||
}
|
||||
|
||||
if len(completion.Choices) == 0 {
|
||||
|
|
|
|||
|
|
@ -245,6 +245,11 @@ func TestClient_Chat_RequestDefaults(t *testing.T) {
|
|||
assert.Equal(t, 0, req.MaxTokens) // Should become 8192
|
||||
assert.Equal(t, float64(0), req.Temperature) // Should become 0.3
|
||||
assert.Equal(t, time.Duration(0), req.Timeout) // Should become 10s
|
||||
|
||||
// Verify the Messages field is properly structured
|
||||
assert.Len(t, req.Messages, 1)
|
||||
assert.Equal(t, "user", req.Messages[0].Role)
|
||||
assert.Equal(t, "Hello", req.Messages[0].Content)
|
||||
}
|
||||
|
||||
func TestMessage_Roles(t *testing.T) {
|
||||
|
|
@ -275,6 +280,7 @@ func TestMessage_Roles(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, tt.valid, validRoles[msg.Role])
|
||||
assert.Equal(t, "test content", msg.Content)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import (
|
|||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// defaultSystemPrompt contains the core instructions for tag recommendation.
|
||||
|
|
@ -38,10 +40,10 @@ const userMessageTemplate = `{{if .ExistingTags}}Existing Tags: {{.ExistingTags}
|
|||
|
||||
// TagSuggestionRequest represents a tag suggestion request
|
||||
type TagSuggestionRequest struct {
|
||||
Content string // The memo content to analyze
|
||||
UserTags []string // User's frequently used tags (optional)
|
||||
ExistingTags []string // Tags already in the memo (optional)
|
||||
SystemPrompt string // Custom system prompt (optional, uses default if empty)
|
||||
Content string // The memo content to analyze
|
||||
UserTags []string // User's frequently used tags (optional)
|
||||
ExistingTags []string // Tags already in the memo (optional)
|
||||
SystemPrompt string // Custom system prompt (optional, uses default if empty)
|
||||
}
|
||||
|
||||
// TagSuggestion represents a single tag suggestion with reason
|
||||
|
|
@ -64,11 +66,11 @@ func GetDefaultSystemPrompt() string {
|
|||
func (c *Client) SuggestTags(ctx context.Context, req *TagSuggestionRequest) (*TagSuggestionResponse, error) {
|
||||
// Validate request
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("request cannot be nil")
|
||||
return nil, errors.New("request cannot be nil")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(req.Content) == "" {
|
||||
return nil, fmt.Errorf("content cannot be empty")
|
||||
return nil, errors.New("content cannot be empty")
|
||||
}
|
||||
|
||||
// Prepare user tags context
|
||||
|
|
@ -131,7 +133,7 @@ func (c *Client) SuggestTags(ctx context.Context, req *TagSuggestionRequest) (*T
|
|||
}
|
||||
|
||||
// parseTagResponse parses AI response for [tag](reason) patterns
|
||||
func (c *Client) parseTagResponse(responseText string) []TagSuggestion {
|
||||
func (_ *Client) parseTagResponse(responseText string) []TagSuggestion {
|
||||
tags := make([]TagSuggestion, 0)
|
||||
|
||||
// Match [tag](reason) format using regex across response
|
||||
|
|
|
|||
|
|
@ -1010,7 +1010,7 @@ func (s *APIV1Service) SuggestMemoTags(ctx context.Context, request *v1pb.Sugges
|
|||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get AI setting: %v", err)
|
||||
}
|
||||
|
||||
|
||||
// Check if tag recommendation is enabled
|
||||
if !aiSetting.EnableAi || aiSetting.TagRecommendation == nil || !aiSetting.TagRecommendation.Enabled {
|
||||
return &v1pb.SuggestMemoTagsResponse{
|
||||
|
|
@ -1032,13 +1032,13 @@ func (s *APIV1Service) SuggestMemoTags(ctx context.Context, request *v1pb.Sugges
|
|||
if !tagRateLimit.checkRateLimit(currentUser.ID, maxRequestsPerMinute) {
|
||||
return nil, status.Errorf(codes.ResourceExhausted, "标签推荐请求频率超限,每分钟最多 %d 次", maxRequestsPerMinute)
|
||||
}
|
||||
|
||||
|
||||
aiConfig := ai.LoadConfigFromDatabase(aiSetting)
|
||||
if !aiConfig.IsConfigured() {
|
||||
// Fallback to environment variables if database config is not complete
|
||||
aiConfig = aiConfig.MergeWithEnv()
|
||||
}
|
||||
|
||||
|
||||
if aiConfig.IsConfigured() {
|
||||
aiClient, err := ai.NewClient(aiConfig)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ func (s *APIV1Service) GetInstanceOwner(ctx context.Context) (*v1pb.User, error)
|
|||
}
|
||||
|
||||
// GetDefaultTagRecommendationPrompt returns the default system prompt for AI tag recommendations.
|
||||
func (s *APIV1Service) GetDefaultTagRecommendationPrompt(ctx context.Context, _ *v1pb.GetDefaultTagRecommendationPromptRequest) (*v1pb.GetDefaultTagRecommendationPromptResponse, error) {
|
||||
func (_ *APIV1Service) GetDefaultTagRecommendationPrompt(ctx context.Context, _ *v1pb.GetDefaultTagRecommendationPromptRequest) (*v1pb.GetDefaultTagRecommendationPromptResponse, error) {
|
||||
return &v1pb.GetDefaultTagRecommendationPromptResponse{
|
||||
SystemPrompt: ai.GetDefaultSystemPrompt(),
|
||||
}, nil
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func RebuildMemoPayload(memo *store.Memo) error {
|
|||
}
|
||||
|
||||
// ExtractTagsFromContent extracts tags from content string using the same logic as RebuildMemoPayload
|
||||
// This function is exported for use in other packages (e.g., for tag recommendations)
|
||||
// This function is exported for use in other packages (e.g., for tag recommendations).
|
||||
func ExtractTagsFromContent(content string) []string {
|
||||
nodes, err := parser.Parse(tokenizer.Tokenize(content))
|
||||
if err != nil {
|
||||
|
|
@ -119,8 +119,7 @@ func ExtractTagsFromContent(content string) []string {
|
|||
|
||||
tags := []string{}
|
||||
TraverseASTNodes(nodes, func(node ast.Node) {
|
||||
switch n := node.(type) {
|
||||
case *ast.Tag:
|
||||
if n, ok := node.(*ast.Tag); ok {
|
||||
tag := n.Content
|
||||
if !slices.Contains(tags, tag) {
|
||||
tags = append(tags, tag)
|
||||
|
|
|
|||
|
|
@ -213,10 +213,10 @@ func (s *Store) GetWorkspaceStorageSetting(ctx context.Context) (*storepb.Worksp
|
|||
}
|
||||
|
||||
const (
|
||||
defaultAITimeoutSeconds = int32(15)
|
||||
defaultAITimeoutSeconds = int32(15)
|
||||
defaultAITagRecommandationEnabled = false
|
||||
defaultAITagRecommandationPrompt = ""
|
||||
defaultAITagRecommandationRPM = int32(10)
|
||||
defaultAITagRecommandationPrompt = ""
|
||||
defaultAITagRecommandationRPM = int32(10)
|
||||
)
|
||||
|
||||
func (s *Store) GetWorkspaceAISetting(ctx context.Context) (*storepb.WorkspaceAISetting, error) {
|
||||
|
|
@ -256,7 +256,7 @@ func (s *Store) GetWorkspaceAISetting(ctx context.Context) (*storepb.WorkspaceAI
|
|||
return workspaceAISetting, nil
|
||||
}
|
||||
|
||||
// loadAISettingFromEnv loads AI configuration from environment variables
|
||||
// loadAISettingFromEnv loads AI configuration from environment variables.
|
||||
func loadAISettingFromEnv() *storepb.WorkspaceAISetting {
|
||||
timeoutSeconds := defaultAITimeoutSeconds
|
||||
if timeoutStr := os.Getenv("AI_TIMEOUT_SECONDS"); timeoutStr != "" {
|
||||
|
|
|
|||
Loading…
Reference in New Issue