From d818e7947aa20be4e5f73f558d5400cbd1b68886 Mon Sep 17 00:00:00 2001 From: wangbo Date: Fri, 17 Jul 2026 22:39:11 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=20Gemini=20=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=8E=A5=E5=8F=A3=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/internal/httpapi/gemini_compat.go | 2 +- .../internal/httpapi/gemini_compat_test.go | 49 +++++++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/apps/api/internal/httpapi/gemini_compat.go b/apps/api/internal/httpapi/gemini_compat.go index 16366fc..3e3b93e 100644 --- a/apps/api/internal/httpapi/gemini_compat.go +++ b/apps/api/internal/httpapi/gemini_compat.go @@ -40,9 +40,9 @@ type geminiUploadSession struct { } var geminiGenerateContentRoutePrefixes = []string{ + "/api/v1/models/", "/v1beta/models/", "/v1/models/", - "/models/", } func (s *Server) registerGeminiGenerateContentRoutes(mux *http.ServeMux) { diff --git a/apps/api/internal/httpapi/gemini_compat_test.go b/apps/api/internal/httpapi/gemini_compat_test.go index d7e5c79..fcf20ec 100644 --- a/apps/api/internal/httpapi/gemini_compat_test.go +++ b/apps/api/internal/httpapi/gemini_compat_test.go @@ -1,6 +1,14 @@ package httpapi -import "testing" +import ( + "io" + "log/slog" + "net/http" + "net/http/httptest" + "testing" + + "github.com/easyai/easyai-ai-gateway/apps/api/internal/auth" +) func TestGeminiGenerateContentModelFromPath(t *testing.T) { tests := []struct { @@ -25,9 +33,9 @@ func TestGeminiGenerateContentModelFromPath(t *testing.T) { wantOK: true, }, { - name: "bare model path", - prefix: "/models/", - requestPath: "/models/gemini-image:generateContent", + name: "gateway api v1 model", + prefix: "/api/v1/models/", + requestPath: "/api/v1/models/gemini-image:generateContent", wantModel: "gemini-image", wantOK: true, }, @@ -61,6 +69,39 @@ func TestGeminiGenerateContentModelFromPath(t *testing.T) { } } +func TestRegisterGeminiGenerateContentRoutes(t *testing.T) { + server := &Server{ + auth: auth.New("test-secret", "", ""), + logger: slog.New(slog.NewTextHandler(io.Discard, nil)), + } + mux := http.NewServeMux() + mux.HandleFunc("GET /api/v1/models", func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }) + server.registerGeminiGenerateContentRoutes(mux) + + tests := []struct { + method string + path string + status int + }{ + {method: http.MethodGet, path: "/api/v1/models", status: http.StatusNoContent}, + {method: http.MethodPost, path: "/api/v1/models/gemini-image:generateContent", status: http.StatusUnauthorized}, + {method: http.MethodPost, path: "/v1/models/gemini-image:generateContent", status: http.StatusUnauthorized}, + {method: http.MethodPost, path: "/v1beta/models/gemini-image:generateContent", status: http.StatusUnauthorized}, + {method: http.MethodPost, path: "/models/gemini-image:generateContent", status: http.StatusNotFound}, + } + for _, tt := range tests { + t.Run(tt.method+" "+tt.path, func(t *testing.T) { + response := httptest.NewRecorder() + mux.ServeHTTP(response, httptest.NewRequest(tt.method, tt.path, nil)) + if response.Code != tt.status { + t.Fatalf("status = %d, want %d; body=%s", response.Code, tt.status, response.Body.String()) + } + }) + } +} + func TestGeminiImageTaskBodyMapsTextOnlyToImageGenerate(t *testing.T) { mapping, err := geminiImageTaskBody("gemini-image", map[string]any{ "contents": []any{