Closed 496672097 closed 11 months ago
I just confirmed that the proxy you pass is called from GenerateContent:
func TestProxy(t *testing.T) {
ctx := context.Background()
client, err := genai.NewClient(ctx,
option.WithAPIKey("your-API-key"), option.WithHTTPClient(&http.Client{Transport: panicRT{}}))
if err != nil {
t.Fatal(err)
}
defer client.Close()
model := client.GenerativeModel("gemini-pro")
if _, err := model.GenerateContent(ctx, genai.Text("What is the average size of a swallow?")); err != nil {
t.Fatal(err)
}
}
type panicRT struct{}
func (panicRT) RoundTrip(r *http.Request) (*http.Response, error) { panic("P") }
I get the panic when I run this code.
Maybe it isn't for a different method? Can you provide more of your code?
bad myself. let me found the worng whith some times
i used the example. but it not work (i can get response by POSTMAN https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=)
func test(c *http.Client) {
ctx := context.Background()
// Access your API key as an environment variable (see "Set up your API key" above)
client, err := genai.NewClient(ctx, option.WithAPIKey("AIzaSyBtFMwViEE"), option.WithHTTPClient(c))
if err != nil {
log.Fatal(err)
}
defer client.Close()
// For text-and-image input (multimodal), use the gemini-pro-vision model
model := client.GenerativeModel("gemini-pro")
prompt := genai.Text("Tell me a story about a lumberjack and his giant ox")
iter := model.GenerateContentStream(ctx, prompt)
for {
resp, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Candidates[0].Content)
}
}
the C is :
// SetAiClientSteam 设置ai 代理
func (g *GoogleAi) SetProxy() *http.Client {
proxyURL, err := url.Parse(g.Proxy)
if err != nil {
fmt.Println("出现错误:" + err.Error())
return nil
}
var transport *http.Transport
if g.Proxy != "" {
transport = &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
} else {
transport = &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
}
client := &http.Client{Transport: transport}
return client
}
the consle tell me "2023/12/16 18:54:46 googleapi: Error 403:"
I don't think it's a proxy issue, you can look at the body field of httperr in the err returned
看了源码,WithAPIKey 其实就是自己实现了一套WithHTTPClient,所以这两个一起用,会冲突,导致请求时没有带apikey,解决方法就是自己封装一个。
package tools
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
)
// 整合了APIKey和代理的 Transport
type APIKeyProxyTransport struct {
// APIKey is the API Key to set on requests.
APIKey string
// Transport is the underlying HTTP transport.
// If nil, http.DefaultTransport is used.
Transport http.RoundTripper
// ProxyURL is the URL of the proxy server. If empty, no proxy is used.
ProxyURL string
}
func (t *APIKeyProxyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
rt := t.Transport
if rt == nil {
rt = http.DefaultTransport
}
// 如果提供了 ProxyURL,则对 Transport 设置代理
if t.ProxyURL != "" {
proxyURL, err := url.Parse(t.ProxyURL)
if err != nil {
return nil, err
}
if transport, ok := rt.(*http.Transport); ok {
// 只有当 rt 为 *http.Transport 类型时,才设置代理
transport.Proxy = http.ProxyURL(proxyURL)
transport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
} else {
// 如果 rt 不是 *http.Transport 类型,则创建一个新的带代理的 http.Transport
rt = &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
}
}
// 克隆请求以避免修改原始请求
newReq := *req
args := newReq.URL.Query()
args.Set("key", t.APIKey)
newReq.URL.RawQuery = args.Encode()
// 执行 HTTP 请求,并处理可能的错误
resp, err := rt.RoundTrip(&newReq)
if err != nil {
// 返回网络请求中的错误
return nil, fmt.Errorf("error during round trip: %v", err)
}
return resp, nil
}
使用时
c := &http.Client{Transport: &tools.APIKeyProxyTransport{
APIKey: GetGeminiAPIKey(),
Transport: nil,
ProxyURL: ProxyUrl,
}}
ctx := context.Background()
client, err := genai.NewClient(ctx,option.WithHTTPClient(c))
Confirmed: using WithHTTPClient causes WithAPIKey to not take effect.
And @ghj1976 's solution helps.
谢谢老大哥, 可以解决了。
看了源码,WithAPIKey 其实就是自己实现了一套WithHTTPClient,所以这两个一起用,会冲突,导致请求时没有带apikey,解决方法就是自己封装一个。
package tools import ( "crypto/tls" "fmt" "net/http" "net/url" ) // 整合了APIKey和代理的 Transport type APIKeyProxyTransport struct { // APIKey is the API Key to set on requests. APIKey string // Transport is the underlying HTTP transport. // If nil, http.DefaultTransport is used. Transport http.RoundTripper // ProxyURL is the URL of the proxy server. If empty, no proxy is used. ProxyURL string } func (t *APIKeyProxyTransport) RoundTrip(req *http.Request) (*http.Response, error) { rt := t.Transport if rt == nil { rt = http.DefaultTransport } // 如果提供了 ProxyURL,则对 Transport 设置代理 if t.ProxyURL != "" { proxyURL, err := url.Parse(t.ProxyURL) if err != nil { return nil, err } if transport, ok := rt.(*http.Transport); ok { // 只有当 rt 为 *http.Transport 类型时,才设置代理 transport.Proxy = http.ProxyURL(proxyURL) transport.TLSClientConfig = &tls.Config{ InsecureSkipVerify: true, } } else { // 如果 rt 不是 *http.Transport 类型,则创建一个新的带代理的 http.Transport rt = &http.Transport{ Proxy: http.ProxyURL(proxyURL), TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, } } } // 克隆请求以避免修改原始请求 newReq := *req args := newReq.URL.Query() args.Set("key", t.APIKey) newReq.URL.RawQuery = args.Encode() // 执行 HTTP 请求,并处理可能的错误 resp, err := rt.RoundTrip(&newReq) if err != nil { // 返回网络请求中的错误 return nil, fmt.Errorf("error during round trip: %v", err) } return resp, nil }
使用时
c := &http.Client{Transport: &tools.APIKeyProxyTransport{ APIKey: GetGeminiAPIKey(), Transport: nil, ProxyURL: ProxyUrl, }} ctx := context.Background() client, err := genai.NewClient(ctx,option.WithHTTPClient(c))
It doesn't work because https://github.com/google/generative-ai-go/pull/152
I want to set a proxy client. but it didn't work. i need U help like: client, _ = genai.NewClient(g.ctx, option.WithAPIKey("AIzaSyBwDX0zNmutFMwViEE"), option.WithHTTPClient(httpclientByProxy))
"httpclientByProxy" is a *httpclient