Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion internal/claude/claude.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net/http"

httpClient "github.com/dfanso/commit-msg/internal/http"
"github.com/dfanso/commit-msg/pkg/types"
)

Expand Down Expand Up @@ -58,7 +59,7 @@ func GenerateCommitMessage(config *types.Config, changes string, apiKey string,
req.Header.Set("x-api-key", apiKey)
req.Header.Set("anthropic-version", "2023-06-01")

client := &http.Client{}
client := httpClient.GetClient()
resp, err := client.Do(req)
if err != nil {
return "", err
Expand Down
30 changes: 2 additions & 28 deletions internal/grok/grok.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,15 @@ package grok

import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
"sync"
"time"

httpClient "github.com/dfanso/commit-msg/internal/http"
"github.com/dfanso/commit-msg/pkg/types"
)

var (
grokClientOnce sync.Once
grokClient *http.Client
)

func getHTTPClient() *http.Client {
grokClientOnce.Do(func() {
transport := &http.Transport{
TLSHandshakeTimeout: 10 * time.Second,
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
},
}
grokClient = &http.Client{
Timeout: 30 * time.Second,
Transport: transport,
}
})
return grokClient
}

// GenerateCommitMessage calls X.AI's Grok API to create a commit message from
// the provided Git diff and generation options.
func GenerateCommitMessage(config *types.Config, changes string, apiKey string, opts *types.GenerationOptions) (string, error) {
Expand Down Expand Up @@ -71,7 +45,7 @@ func GenerateCommitMessage(config *types.Config, changes string, apiKey string,
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))

client := getHTTPClient()
client := httpClient.GetClient()
resp, err := client.Do(req)
if err != nil {
return "", err
Expand Down
7 changes: 3 additions & 4 deletions internal/groq/groq.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"io"
"net/http"
"os"
"time"

httpClient "github.com/dfanso/commit-msg/internal/http"
"github.com/dfanso/commit-msg/pkg/types"
)

Expand Down Expand Up @@ -38,8 +38,7 @@ const defaultModel = "llama-3.3-70b-versatile"

var (
// allow overrides in tests
baseURL = "https://api.groq.com/openai/v1/chat/completions"
httpClient = &http.Client{Timeout: 30 * time.Second}
baseURL = "https://api.groq.com/openai/v1/chat/completions"
)

// GenerateCommitMessage calls Groq's OpenAI-compatible chat completions API.
Expand Down Expand Up @@ -83,7 +82,7 @@ func GenerateCommitMessage(_ *types.Config, changes string, apiKey string, opts
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))

resp, err := httpClient.Do(req)
resp, err := httpClient.GetClient().Do(req)
if err != nil {
return "", fmt.Errorf("failed to call Groq API: %w", err)
}
Expand Down
51 changes: 51 additions & 0 deletions internal/http/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package http

import (
"crypto/tls"
"net/http"
"sync"
"time"
)

var (
clientOnce sync.Once
sharedClient *http.Client

ollamaClientOnce sync.Once
ollamaClient *http.Client
)

// createTransport creates a shared HTTP transport with optimized settings
func createTransport() *http.Transport {
return &http.Transport{
TLSHandshakeTimeout: 10 * time.Second,
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
},
}
}

// GetClient returns a shared HTTP client with optimized settings for cloud APIs
func GetClient() *http.Client {
clientOnce.Do(func() {
sharedClient = &http.Client{
Timeout: 30 * time.Second,
Transport: createTransport(),
}
})
return sharedClient
}

// GetOllamaClient returns an HTTP client with extended timeout for local Ollama inference
func GetOllamaClient() *http.Client {
ollamaClientOnce.Do(func() {
ollamaClient = &http.Client{
Timeout: 10 * time.Minute, // 10 minutes for local inference
Transport: createTransport(),
}
})
return ollamaClient
}
9 changes: 8 additions & 1 deletion internal/ollama/ollama.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net/http"

httpClient "github.com/dfanso/commit-msg/internal/http"
"github.com/dfanso/commit-msg/pkg/types"
)

Expand Down Expand Up @@ -46,7 +47,13 @@ func GenerateCommitMessage(_ *types.Config, changes string, url string, model st
return "", fmt.Errorf("failed to marshal request: %v", err)
}

resp, err := http.Post(url, "application/json", bytes.NewBuffer(body))
req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
return "", fmt.Errorf("failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")

resp, err := httpClient.GetOllamaClient().Do(req)
if err != nil {
return "", fmt.Errorf("failed to send request to Ollama: %v", err)
}
Expand Down
Loading