package llm import ( "context" "fmt" "log" "strings" "time" "github.com/sashabaranov/go-openai" ) // OpenAIAdapter implements Adapter using OpenAI's chat completions API type OpenAIAdapter struct { client *openai.Client config Config } // NewOpenAIAdapter creates a new OpenAI LLM adapter func NewOpenAIAdapter(cfg Config) *OpenAIAdapter { if cfg.BaseURL != "" { clientConfig := openai.DefaultConfig(cfg.APIKey) clientConfig.BaseURL = strings.TrimRight(cfg.BaseURL, "/") + "/v1" return &OpenAIAdapter{client: openai.NewClientWithConfig(clientConfig), config: cfg} } return &OpenAIAdapter{ client: openai.NewClient(cfg.APIKey), config: cfg, } } func (a *OpenAIAdapter) Process(ctx context.Context, text string) (string, error) { if text == "" { return "", nil } opts := PostProcessingOptions{ RemoveStutters: a.config.RemoveStutters, AddPunctuation: a.config.AddPunctuation, FixGrammar: a.config.FixGrammar, RemoveFillerWords: a.config.RemoveFillerWords, } systemPrompt := BuildSystemPrompt(opts, a.config.Keywords) userPrompt := BuildUserPrompt(text, a.config.CustomPrompt) model := a.config.Model if model == "" { model = "gpt-4o-mini" } req := openai.ChatCompletionRequest{ Model: model, Messages: []openai.ChatCompletionMessage{ {Role: openai.ChatMessageRoleSystem, Content: systemPrompt}, {Role: openai.ChatMessageRoleUser, Content: userPrompt}, }, Temperature: 0.3, // Low temperature for consistent cleanup } start := time.Now() resp, err := a.client.CreateChatCompletion(ctx, req) duration := time.Since(start) if err != nil { log.Printf("openai-llm-adapter: API call failed after %v: %v", duration, err) return "", fmt.Errorf("openai chat completion: %w", err) } if len(resp.Choices) == 0 { return "", fmt.Errorf("openai chat completion: no response choices") } result := resp.Choices[0].Message.Content log.Printf("openai-llm-adapter: processed in %v: %q -> %q", duration, text, result) return result, nil }