Skip to content

Commit b9b540b

Browse files
authored
feat: add llm api proxy parameters (#782)
## What type of PR is this? /kind feature ## What this PR does / why we need it: add llm api proxy parameters ## Which issue(s) this PR fixes: Fixes #736
1 parent c1a6f6e commit b9b540b

File tree

6 files changed

+108
-20
lines changed

6 files changed

+108
-20
lines changed

cmd/karpor/app/options/ai.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ type AIOptions struct {
2626
AIModel string
2727
AITemperature float32
2828
AITopP float32
29+
// proxy options
30+
AIProxyEnabled bool
31+
AIHTTPProxy string
32+
AIHTTPSProxy string
33+
AINoProxy string
2934
}
3035

3136
const (
@@ -51,6 +56,10 @@ func (o *AIOptions) ApplyTo(config *registry.ExtraConfig) error {
5156
config.AIModel = o.AIModel
5257
config.AITemperature = o.AITemperature
5358
config.AITopP = o.AITopP
59+
config.AIProxyEnabled = o.AIProxyEnabled
60+
config.AIHTTPProxy = o.AIHTTPProxy
61+
config.AIHTTPSProxy = o.AIHTTPSProxy
62+
config.AINoProxy = o.AINoProxy
5463
return nil
5564
}
5665

@@ -66,4 +75,8 @@ func (o *AIOptions) AddFlags(fs *pflag.FlagSet) {
6675
fs.StringVar(&o.AIModel, "ai-model", defaultModel, "The ai model")
6776
fs.Float32Var(&o.AITemperature, "ai-temperature", defaultTemperature, "The ai temperature")
6877
fs.Float32Var(&o.AITopP, "ai-top-p", defaultTopP, "The ai top-p")
78+
fs.BoolVar(&o.AIProxyEnabled, "ai-proxy-enabled", false, "The ai proxy enable")
79+
fs.StringVar(&o.AIHTTPProxy, "ai-http-proxy", "", "The ai http proxy")
80+
fs.StringVar(&o.AIHTTPSProxy, "ai-https-proxy", "", "The ai https proxy")
81+
fs.StringVar(&o.AINoProxy, "ai-no-proxy", "", "The ai no-proxy")
6982
}

pkg/infra/ai/azureopenai.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ func (c *AzureAIClient) Configure(cfg AIConfig) error {
3434

3535
defaultConfig := openai.DefaultAzureConfig(cfg.AuthToken, cfg.BaseURL)
3636

37+
if cfg.ProxyEnabled {
38+
defaultConfig.HTTPClient.Transport = GetProxyHTTPClient(cfg)
39+
}
40+
3741
client := openai.NewClientWithConfig(defaultConfig)
3842
if client == nil {
3943
return errors.New("error creating Azure OpenAI client")

pkg/infra/ai/huggingface.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package ai
1616

1717
import (
1818
"context"
19+
"net/http"
1920

2021
"github.com/hupe1980/go-huggingface"
2122
)
@@ -27,9 +28,16 @@ type HuggingfaceClient struct {
2728
}
2829

2930
func (c *HuggingfaceClient) Configure(cfg AIConfig) error {
30-
client := huggingface.NewInferenceClient(cfg.AuthToken)
31+
if cfg.ProxyEnabled {
32+
c.client = huggingface.NewInferenceClient(cfg.AuthToken, func(o *huggingface.InferenceClientOptions) {
33+
o.HTTPClient = &http.Client{
34+
Transport: GetProxyHTTPClient(cfg),
35+
}
36+
})
37+
} else {
38+
c.client = huggingface.NewInferenceClient(cfg.AuthToken)
39+
}
3140

32-
c.client = client
3341
c.model = cfg.Model
3442
c.temperature = cfg.Temperature
3543
return nil

pkg/infra/ai/openai.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ func (c *OpenAIClient) Configure(cfg AIConfig) error {
3434
defaultConfig.BaseURL = cfg.BaseURL
3535
}
3636

37+
if cfg.ProxyEnabled {
38+
defaultConfig.HTTPClient.Transport = GetProxyHTTPClient(cfg)
39+
}
40+
3741
client := openai.NewClientWithConfig(defaultConfig)
3842
if client == nil {
3943
return errors.New("error creating OpenAI client")

pkg/infra/ai/types.go

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ package ai
1616

1717
import (
1818
"context"
19+
"net/http"
20+
"net/url"
21+
"strings"
1922

2023
"github.com/KusionStack/karpor/pkg/kubernetes/registry"
24+
"k8s.io/klog/v2"
2125
)
2226

2327
const (
@@ -52,22 +56,30 @@ type AIProvider interface {
5256

5357
// AIConfig represents the configuration settings for an AI client.
5458
type AIConfig struct {
55-
Name string
56-
AuthToken string
57-
BaseURL string
58-
Model string
59-
Temperature float32
60-
TopP float32
59+
Name string
60+
AuthToken string
61+
BaseURL string
62+
Model string
63+
Temperature float32
64+
TopP float32
65+
ProxyEnabled bool
66+
HTTPProxy string
67+
HTTPSProxy string
68+
NoProxy string
6169
}
6270

6371
func ConvertToAIConfig(c registry.ExtraConfig) AIConfig {
6472
return AIConfig{
65-
Name: c.AIBackend,
66-
AuthToken: c.AIAuthToken,
67-
BaseURL: c.AIBaseURL,
68-
Model: c.AIModel,
69-
Temperature: c.AITemperature,
70-
TopP: c.AITopP,
73+
Name: c.AIBackend,
74+
AuthToken: c.AIAuthToken,
75+
BaseURL: c.AIBaseURL,
76+
Model: c.AIModel,
77+
Temperature: c.AITemperature,
78+
TopP: c.AITopP,
79+
ProxyEnabled: c.AIProxyEnabled,
80+
HTTPProxy: c.AIHTTPProxy,
81+
HTTPSProxy: c.AIHTTPSProxy,
82+
NoProxy: c.AINoProxy,
7183
}
7284
}
7385

@@ -79,3 +91,46 @@ func NewClient(name string) AIProvider {
7991
// default client
8092
return &OpenAIClient{}
8193
}
94+
95+
// GetProxyHTTPClient returns a new http.Transport with proxy configuration
96+
func GetProxyHTTPClient(cfg AIConfig) *http.Transport {
97+
noProxyList := strings.Split(cfg.NoProxy, ",")
98+
99+
return &http.Transport{
100+
Proxy: func(req *http.Request) (*url.URL, error) {
101+
host := req.URL.Host
102+
// Check if host matches NoProxy list
103+
for _, np := range noProxyList {
104+
if np = strings.TrimSpace(np); np != "" {
105+
// exact match
106+
if host == np {
107+
klog.Infof("Skip proxy for %s: exact match in no_proxy list", host)
108+
return nil, nil
109+
}
110+
// Domain suffix match with dot to prevent false positives
111+
// e.g. pattern "le.com", it would incorrectly match host "example.com".
112+
if !strings.HasPrefix(np, ".") {
113+
np = "." + np
114+
}
115+
if strings.HasSuffix(host, np) {
116+
klog.Infof("Skip proxy for %s: suffix match with %s in no_proxy list", host, np)
117+
return nil, nil
118+
}
119+
}
120+
}
121+
122+
var proxyURL string
123+
if req.URL.Scheme == "https" && cfg.HTTPSProxy != "" {
124+
proxyURL = cfg.HTTPSProxy
125+
} else if req.URL.Scheme == "http" && cfg.HTTPProxy != "" {
126+
proxyURL = cfg.HTTPProxy
127+
}
128+
129+
if proxyURL != "" {
130+
klog.Infof("Using proxy %s for %s", proxyURL, req.URL)
131+
return url.Parse(proxyURL)
132+
}
133+
return nil, nil
134+
},
135+
}
136+
}

pkg/kubernetes/registry/types.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,14 @@ type ExtraConfig struct {
4848
ExtendExpiration bool
4949

5050
// AI configs
51-
AIBackend string
52-
AIAuthToken string
53-
AIBaseURL string
54-
AIModel string
55-
AITemperature float32
56-
AITopP float32
51+
AIBackend string
52+
AIAuthToken string
53+
AIBaseURL string
54+
AIModel string
55+
AITemperature float32
56+
AITopP float32
57+
AIProxyEnabled bool
58+
AIHTTPProxy string
59+
AIHTTPSProxy string
60+
AINoProxy string
5761
}

0 commit comments

Comments
 (0)