Skip to content

Commit 2d5b822

Browse files
csg-pr-botDev Agent
authored andcommitted
aigateway: allow unauthenticated GET /v1/models (#959)
Co-authored-by: Dev Agent <dev-agent@example.com>
1 parent 7a2d395 commit 2d5b822

4 files changed

Lines changed: 137 additions & 15 deletions

File tree

aigateway/component/openai.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,19 @@ type openaiComponentImpl struct {
4747
// GetAvailableModels returns a list of running models
4848
func (m *openaiComponentImpl) GetAvailableModels(c context.Context, userName string) ([]types.Model, error) {
4949
var models []types.Model
50-
user, err := m.userStore.FindByUsername(c, userName)
51-
if err != nil {
52-
return nil, fmt.Errorf("failed to find user by username in db,error:%w", err)
50+
var userID int64
51+
var userUUID string
52+
if strings.TrimSpace(userName) != "" {
53+
user, err := m.userStore.FindByUsername(c, userName)
54+
if err != nil {
55+
return nil, fmt.Errorf("failed to find user by username in db,error:%w", err)
56+
}
57+
userID = user.ID
58+
userUUID = user.UUID
5359
}
54-
csghubModels, err := m.getCSGHubModels(c, user.ID)
60+
var csghubModels []types.Model
61+
var err error
62+
csghubModels, err = m.getCSGHubModels(c, userID)
5563
if err != nil {
5664
return nil, err
5765
}
@@ -70,15 +78,18 @@ func (m *openaiComponentImpl) GetAvailableModels(c context.Context, userName str
7078
}
7179
}(models)
7280

73-
req := &types.UserPreferenceRequest{
74-
UserUUID: user.UUID,
75-
Models: models,
76-
Scenario: types.AgenticHubApp,
77-
}
78-
models, err = m.userPreference(c, req)
79-
if err != nil {
80-
slog.Warn("failed to apply user preference", "error", err)
81-
// Continue with original models if user preference fails
81+
if strings.TrimSpace(userUUID) != "" {
82+
req := &types.UserPreferenceRequest{
83+
UserUUID: userUUID,
84+
Models: models,
85+
Scenario: types.AgenticHubApp,
86+
}
87+
var prefErr error
88+
models, prefErr = m.userPreference(c, req)
89+
if prefErr != nil {
90+
slog.Warn("failed to apply user preference", "error", prefErr)
91+
// Continue with original models if user preference fails
92+
}
8293
}
8394

8495
return models, nil

aigateway/component/openai_ce_test.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,118 @@ func TestOpenAIComponent_GetAvailableModels(t *testing.T) {
4242
assert.Nil(t, models)
4343
})
4444

45+
t.Run("anonymous user can see public CSGHub models", func(t *testing.T) {
46+
now := time.Now()
47+
deploys := []database.Deploy{
48+
{
49+
ID: 1,
50+
SvcName: "svc1",
51+
Type: commontypes.InferenceType,
52+
UserID: 1,
53+
SecureLevel: commontypes.EndpointPublic,
54+
Repository: &database.Repository{
55+
Name: "model1",
56+
Path: "model1",
57+
},
58+
User: &database.User{
59+
Username: "publicuser",
60+
UUID: "publicuser-uuid",
61+
},
62+
Endpoint: "endpoint1",
63+
Task: "text-generation",
64+
},
65+
{
66+
ID: 2,
67+
SvcName: "svc2",
68+
Type: commontypes.ServerlessType,
69+
UserID: 2,
70+
SecureLevel: commontypes.EndpointPublic,
71+
Repository: &database.Repository{
72+
HFPath: "hf-model2",
73+
},
74+
User: &database.User{
75+
Username: "serverless-owner",
76+
UUID: "serverless-owner-uuid",
77+
},
78+
Endpoint: "endpoint2",
79+
Task: "text-to-image",
80+
},
81+
}
82+
deploys[0].CreatedAt = now
83+
deploys[1].CreatedAt = now
84+
85+
mockDeployStore.EXPECT().RunningVisibleToUser(mock.Anything, int64(0)).
86+
Return(deploys, nil).Once()
87+
mockLLMConfigStore.EXPECT().Index(mock.Anything, 50, 1, mock.Anything).
88+
Return([]*database.LLMConfig{}, 0, nil)
89+
90+
expectModels := []types.Model{
91+
{
92+
BaseModel: types.BaseModel{
93+
ID: "model1:svc1",
94+
OwnedBy: "publicuser",
95+
Object: "model",
96+
Created: deploys[0].CreatedAt.Unix(),
97+
Task: "text-generation",
98+
DisplayName: "model1",
99+
Public: true,
100+
},
101+
Endpoint: "endpoint1",
102+
InternalModelInfo: types.InternalModelInfo{
103+
CSGHubModelID: deploys[0].Repository.Path,
104+
OwnerUUID: deploys[0].User.UUID,
105+
ClusterID: deploys[0].ClusterID,
106+
SvcName: deploys[0].SvcName,
107+
SvcType: deploys[0].Type,
108+
ImageID: deploys[0].ImageID,
109+
},
110+
InternalUse: true,
111+
},
112+
{
113+
BaseModel: types.BaseModel{
114+
ID: "hf-model2:svc2",
115+
OwnedBy: "OpenCSG",
116+
Object: "model",
117+
Created: deploys[1].CreatedAt.Unix(),
118+
Task: "text-to-image",
119+
Public: true,
120+
},
121+
Endpoint: "endpoint2",
122+
InternalModelInfo: types.InternalModelInfo{
123+
OwnerUUID: deploys[1].User.UUID,
124+
ClusterID: deploys[1].ClusterID,
125+
SvcName: deploys[1].SvcName,
126+
SvcType: deploys[1].Type,
127+
ImageID: deploys[1].ImageID,
128+
},
129+
InternalUse: true,
130+
},
131+
}
132+
var wg sync.WaitGroup
133+
wg.Add(1)
134+
for _, model := range expectModels {
135+
expectJson, _ := json.Marshal(model)
136+
mockCache.EXPECT().HSet(mock.Anything, modelCacheKey, model.ID, string(expectJson)).
137+
Return(nil).Once()
138+
}
139+
mockCache.EXPECT().Expire(mock.Anything, modelCacheKey, modelCacheTTL).
140+
RunAndReturn(func(ctx context.Context, s string, d time.Duration) error {
141+
wg.Done()
142+
return nil
143+
}).Once()
144+
145+
models, err := comp.GetAvailableModels(context.Background(), "")
146+
require.NoError(t, err)
147+
require.Len(t, models, 2)
148+
assert.Equal(t, "model1:svc1", models[0].ID)
149+
assert.Equal(t, "publicuser", models[0].OwnedBy)
150+
assert.True(t, models[0].Public)
151+
assert.Equal(t, "hf-model2:svc2", models[1].ID)
152+
assert.Equal(t, "OpenCSG", models[1].OwnedBy)
153+
assert.True(t, models[1].Public)
154+
wg.Wait()
155+
})
156+
45157
t.Run("successful case", func(t *testing.T) {
46158
user := &database.User{
47159
ID: 1,

aigateway/handler/openai.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ type OpenAIHandlerImpl struct {
139139
}
140140

141141
// ListModels godoc
142-
// @Security ApiKey
143142
// @Summary List available models
144143
// @Description Returns a list of available models, supports fuzzy search by model_id query parameter and filtering by public status
145144
// @Tags AIGateway

aigateway/router/aigateway.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func NewRouter(config *config.Config) (*gin.Engine, error) {
5353
if err != nil {
5454
return nil, fmt.Errorf("error creating openai handler :%w", err)
5555
}
56-
v1Group.GET("/models", middlewareCollection.Auth.NeedLogin, openAIhandler.ListModels)
56+
v1Group.GET("/models", openAIhandler.ListModels)
5757
v1Group.GET("/models/:model", middlewareCollection.Auth.NeedLogin, openAIhandler.GetModel)
5858
v1Group.POST("/chat/completions", middlewareCollection.Auth.NeedLogin, openAIhandler.Chat)
5959
v1Group.POST("/embeddings", middlewareCollection.Auth.NeedLogin, openAIhandler.Embedding)

0 commit comments

Comments
 (0)