package glm import ( "context" "fmt" "tm/pkg/logger" ) // SDK provides a high-level interface for the GLM service type SDK struct { service GLMService client *Client config *Config } // New creates a new GLM SDK with the provided configuration and logger func New(config *Config, logger logger.Logger) (*SDK, error) { cfg := DefaultConfig() if config.BaseURL != "" { cfg.BaseURL = config.BaseURL } if config.APIKey != "" { cfg.APIKey = config.APIKey } if config.Timeout != 0 { cfg.Timeout = config.Timeout } if config.RetryAttempts != 0 { cfg.RetryAttempts = config.RetryAttempts } if config.RetryDelay != 0 { cfg.RetryDelay = config.RetryDelay } if config.EnableLogging { cfg.EnableLogging = config.EnableLogging } if config.UserAgent != "" { cfg.UserAgent = config.UserAgent } if config.DefaultModel != "" { cfg.DefaultModel = config.DefaultModel } if config.DefaultMaxTokens != 0 { cfg.DefaultMaxTokens = config.DefaultMaxTokens } if config.DefaultTopP != 0 { cfg.DefaultTopP = config.DefaultTopP } if config.DefaultTemperature != 0 { cfg.DefaultTemperature = config.DefaultTemperature } if config.DefaultFrequencyPenalty != 0 { cfg.DefaultFrequencyPenalty = config.DefaultFrequencyPenalty } if config.DefaultPresencePenalty != 0 { cfg.DefaultPresencePenalty = config.DefaultPresencePenalty } if config.EnableStreaming { cfg.EnableStreaming = config.EnableStreaming } if config.EnableThinking { cfg.EnableThinking = config.EnableThinking } if config.TranslationOptions.Model != "" { cfg.TranslationOptions.Model = config.TranslationOptions.Model } if config.TranslationOptions.MaxTokens != 0 { cfg.TranslationOptions.MaxTokens = config.TranslationOptions.MaxTokens } if config.TranslationOptions.Temperature != 0 { cfg.TranslationOptions.Temperature = config.TranslationOptions.Temperature } if config.TranslationOptions.FrequencyPenalty != 0 { cfg.TranslationOptions.FrequencyPenalty = config.TranslationOptions.FrequencyPenalty } if config.TranslationOptions.PresencePenalty != 0 { cfg.TranslationOptions.PresencePenalty = config.TranslationOptions.PresencePenalty } if config.TranslationOptions.TopP != 0 { cfg.TranslationOptions.TopP = config.TranslationOptions.TopP } if config.TranslationOptions.EnableThinking { cfg.TranslationOptions.EnableThinking = config.TranslationOptions.EnableThinking } client, err := NewClient(cfg, logger) if err != nil { return nil, err } service := NewService(client) return &SDK{ service: service, client: client, config: cfg, }, nil } // ChatCompletion performs a chat completion request func (s *SDK) ChatCompletion(ctx context.Context, req *ChatCompletionRequest) (*ChatCompletionResponse, error) { return s.service.ChatCompletion(ctx, req) } // StreamChatCompletion performs a streaming chat completion request func (s *SDK) StreamChatCompletion(ctx context.Context, req *ChatCompletionRequest, onChunk func(*StreamChatCompletionResponse) error) error { return s.service.StreamChatCompletion(ctx, req, onChunk) } // ListModels lists available models func (s *SDK) ListModels(ctx context.Context) (*ModelsResponse, error) { return s.service.ListModels(ctx) } // Health checks if the GLM service is available func (s *SDK) Health(ctx context.Context) error { return s.service.Health(ctx) } // QuickChat is a convenience method for simple chat interactions func (s *SDK) QuickChat(ctx context.Context, userMessage string) (string, error) { req := &ChatCompletionRequest{ Model: s.config.DefaultModel, Messages: []Message{ { Role: MessageRoleUser, Content: userMessage, }, }, MaxTokens: s.config.DefaultMaxTokens, TopP: s.config.DefaultTopP, Temperature: s.config.DefaultTemperature, FrequencyPenalty: s.config.DefaultFrequencyPenalty, PresencePenalty: s.config.DefaultPresencePenalty, } if s.config.EnableThinking { req.Thinking = &Thinking{Type: "true"} } resp, err := s.ChatCompletion(ctx, req) if err != nil { return "", err } if len(resp.Choices) == 0 { return "", ErrInvalidResponse("no choices returned") } return resp.Choices[0].Message.Content, nil } // QuickChatWithSystem is a convenience method for chat with system prompt func (s *SDK) QuickChatWithSystem(ctx context.Context, systemPrompt, userMessage string) (string, error) { req := &ChatCompletionRequest{ Model: s.config.DefaultModel, Messages: []Message{ { Role: MessageRoleSystem, Content: systemPrompt, }, { Role: MessageRoleUser, Content: userMessage, }, }, MaxTokens: s.config.DefaultMaxTokens, TopP: s.config.DefaultTopP, Temperature: s.config.DefaultTemperature, FrequencyPenalty: s.config.DefaultFrequencyPenalty, PresencePenalty: s.config.DefaultPresencePenalty, } if s.config.EnableThinking { req.Thinking = &Thinking{Type: "true"} } resp, err := s.ChatCompletion(ctx, req) if err != nil { return "", err } if len(resp.Choices) == 0 { return "", ErrInvalidResponse("no choices returned") } return resp.Choices[0].Message.Content, nil } // TranslateOptions represents options for translation type TranslateOptions struct { Model string `json:"model,omitempty"` MaxTokens int `json:"max_tokens,omitempty"` Temperature float64 `json:"temperature,omitempty"` FrequencyPenalty float64 `json:"frequency_penalty,omitempty"` PresencePenalty float64 `json:"presence_penalty,omitempty"` TopP float64 `json:"top_p,omitempty"` EnableThinking *bool `json:"enable_thinking,omitempty"` } // Translate is a convenience method for translation tasks using dynamic configuration parameters optimized for translation func (s *SDK) Translate(ctx context.Context, text, fromLang, toLang string) (string, error) { systemPrompt := "You are a high-precision translator specializing in professional tender documents. Always respond with only the translated text — no explanations, notes, or markdown formatting." userMessage := fmt.Sprintf("Translate the following text from %s to %s accurately and professionally:\n\"%s\"", fromLang, toLang, text) // Build request with custom options or defaults req := &ChatCompletionRequest{ Model: s.config.TranslationOptions.Model, Messages: []Message{ { Role: MessageRoleSystem, Content: systemPrompt, }, { Role: MessageRoleUser, Content: userMessage, }, }, MaxTokens: s.config.TranslationOptions.MaxTokens, TopP: s.config.TranslationOptions.TopP, Temperature: s.config.TranslationOptions.Temperature, FrequencyPenalty: s.config.TranslationOptions.FrequencyPenalty, PresencePenalty: s.config.TranslationOptions.PresencePenalty, } resp, err := s.ChatCompletion(ctx, req) if err != nil { return "", err } if len(resp.Choices) == 0 { return "", ErrInvalidResponse("no choices returned") } return resp.Choices[0].Message.Content, nil } // StreamQuickChat is a convenience method for streaming chat interactions func (s *SDK) StreamQuickChat(ctx context.Context, userMessage string, onChunk func(string) error) error { req := &ChatCompletionRequest{ Model: s.config.DefaultModel, Messages: []Message{ { Role: MessageRoleUser, Content: userMessage, }, }, MaxTokens: s.config.DefaultMaxTokens, TopP: s.config.DefaultTopP, Temperature: s.config.DefaultTemperature, FrequencyPenalty: s.config.DefaultFrequencyPenalty, PresencePenalty: s.config.DefaultPresencePenalty, Stream: true, } if s.config.EnableThinking { req.Thinking = &Thinking{Type: "true"} } return s.StreamChatCompletion(ctx, req, func(chunk *StreamChatCompletionResponse) error { if len(chunk.Choices) > 0 && chunk.Choices[0].Delta.Content != "" { return onChunk(chunk.Choices[0].Delta.Content) } return nil }) } // GetService returns the underlying service for advanced usage func (s *SDK) GetService() GLMService { return s.service } // GetConfig returns the current configuration func (s *SDK) GetConfig() *Config { return s.config }