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
14 changes: 7 additions & 7 deletions catalog/clients/python/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions catalog/internal/catalog/hf_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,8 @@ func (p *hfModelProvider) getModelsFromHF(ctx context.Context) ([]ModelProviderR
currentTime := time.Now().UnixMilli()
lastSyncedStr := strconv.FormatInt(currentTime, 10)

var failedModels []string

for _, modelName := range expandedModels {
// Skip if excluded - check before fetching to avoid unnecessary API calls
if !p.filter.Allows(modelName) {
Expand All @@ -436,6 +438,7 @@ func (p *hfModelProvider) getModelsFromHF(ctx context.Context) ([]ModelProviderR
modelInfo, err := p.fetchModelInfo(ctx, modelName)
if err != nil {
glog.Errorf("Failed to fetch model info for %s: %v", modelName, err)
failedModels = append(failedModels, modelName)
continue
}

Expand Down Expand Up @@ -467,6 +470,10 @@ func (p *hfModelProvider) getModelsFromHF(ctx context.Context) ([]ModelProviderR
records = append(records, record)
}

if len(failedModels) > 0 {
return records, fmt.Errorf("Failed to fetch some models, ensure models exist and are accessible with given credentials. Failed models: %v", failedModels)
}

return records, nil
}

Expand Down
132 changes: 132 additions & 0 deletions clients/ui/bff/internal/api/catalog_source_preview_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,137 @@ var _ = Describe("CreateCatalogSourcePreviewHandler", func() {
Expect(actual.Data.Items).To(Equal(expected.Data.Items))

})

It("should filter by filterStatus=included", func() {
By("creating a source preview with filterStatus=included")
requestIdentity := kubernetes.RequestIdentity{
UserID: "user@example.com",
}

requestBody := struct {
Data models.CatalogSourcePreviewRequest `json:"data"`
}{
Data: models.CatalogSourcePreviewRequest{
Type: "yaml",
IncludedModels: []string{},
ExcludedModels: []string{},
Properties: map[string]interface{}{
"yaml": "models:\n - name: test-model",
},
},
}
bodyBytes, _ := json.Marshal(requestBody)

actual, rs, err := setupApiTest[CatalogSourcePreviewEnvelope](http.MethodPost, "/api/v1/settings/model_catalog/source_preview?namespace=kubeflow&filterStatus=included", bytes.NewReader(bodyBytes), kubernetesMockedStaticClientFactory, requestIdentity, "kubeflow")
Expect(err).NotTo(HaveOccurred())

By("should return only included models")
Expect(rs.StatusCode).To(Equal(http.StatusOK))
for _, item := range actual.Data.Items {
Expect(item.Included).To(BeTrue(), "All items should have Included=true when filterStatus=included")
}
})

It("should filter by filterStatus=excluded", func() {
By("creating a source preview with filterStatus=excluded")
requestIdentity := kubernetes.RequestIdentity{
UserID: "user@example.com",
}

requestBody := struct {
Data models.CatalogSourcePreviewRequest `json:"data"`
}{
Data: models.CatalogSourcePreviewRequest{
Type: "yaml",
IncludedModels: []string{},
ExcludedModels: []string{},
Properties: map[string]interface{}{
"yaml": "models:\n - name: test-model",
},
},
}
bodyBytes, _ := json.Marshal(requestBody)

actual, rs, err := setupApiTest[CatalogSourcePreviewEnvelope](http.MethodPost, "/api/v1/settings/model_catalog/source_preview?namespace=kubeflow&filterStatus=excluded", bytes.NewReader(bodyBytes), kubernetesMockedStaticClientFactory, requestIdentity, "kubeflow")
Expect(err).NotTo(HaveOccurred())

By("should return only excluded models")
Expect(rs.StatusCode).To(Equal(http.StatusOK))
for _, item := range actual.Data.Items {
Expect(item.Included).To(BeFalse(), "All items should have Included=false when filterStatus=excluded")
}
})

It("should paginate with pageSize and nextPageToken", func() {
By("creating a source preview with pageSize=5")
requestIdentity := kubernetes.RequestIdentity{
UserID: "user@example.com",
}

requestBody := struct {
Data models.CatalogSourcePreviewRequest `json:"data"`
}{
Data: models.CatalogSourcePreviewRequest{
Type: "yaml",
IncludedModels: []string{},
ExcludedModels: []string{},
Properties: map[string]interface{}{
"yaml": "models:\n - name: test-model",
},
},
}
bodyBytes, _ := json.Marshal(requestBody)

actual, rs, err := setupApiTest[CatalogSourcePreviewEnvelope](http.MethodPost, "/api/v1/settings/model_catalog/source_preview?namespace=kubeflow&pageSize=5", bytes.NewReader(bodyBytes), kubernetesMockedStaticClientFactory, requestIdentity, "kubeflow")
Expect(err).NotTo(HaveOccurred())

By("should return at most 5 items with a nextPageToken")
Expect(rs.StatusCode).To(Equal(http.StatusOK))
Expect(len(actual.Data.Items)).To(BeNumerically("<=", 5))
// If there are more items available, nextPageToken should be set
if actual.Data.Size > 5 {
Expect(actual.Data.NextPageToken).NotTo(BeEmpty(), "NextPageToken should be set when more items exist")
}
})

It("should return next page when using nextPageToken", func() {
By("creating a source preview with pageSize=5 to get first page")
requestIdentity := kubernetes.RequestIdentity{
UserID: "user@example.com",
}

requestBody := struct {
Data models.CatalogSourcePreviewRequest `json:"data"`
}{
Data: models.CatalogSourcePreviewRequest{
Type: "yaml",
IncludedModels: []string{},
ExcludedModels: []string{},
Properties: map[string]interface{}{
"yaml": "models:\n - name: test-model",
},
},
}
bodyBytes, _ := json.Marshal(requestBody)

firstPage, rs, err := setupApiTest[CatalogSourcePreviewEnvelope](http.MethodPost, "/api/v1/settings/model_catalog/source_preview?namespace=kubeflow&pageSize=5", bytes.NewReader(bodyBytes), kubernetesMockedStaticClientFactory, requestIdentity, "kubeflow")
Expect(err).NotTo(HaveOccurred())
Expect(rs.StatusCode).To(Equal(http.StatusOK))

// If there's a next page token, fetch the next page
if firstPage.Data.NextPageToken != "" {
By("fetching next page using nextPageToken")
bodyBytes2, _ := json.Marshal(requestBody)
secondPage, rs2, err2 := setupApiTest[CatalogSourcePreviewEnvelope](http.MethodPost, "/api/v1/settings/model_catalog/source_preview?namespace=kubeflow&pageSize=5&nextPageToken="+firstPage.Data.NextPageToken, bytes.NewReader(bodyBytes2), kubernetesMockedStaticClientFactory, requestIdentity, "kubeflow")
Expect(err2).NotTo(HaveOccurred())
Expect(rs2.StatusCode).To(Equal(http.StatusOK))

By("should return different items on second page")
// Verify that the items are different (not overlapping)
if len(firstPage.Data.Items) > 0 && len(secondPage.Data.Items) > 0 {
Expect(firstPage.Data.Items[0].Name).NotTo(Equal(secondPage.Data.Items[0].Name), "First item on second page should be different from first page")
}
}
})
})
})
16 changes: 14 additions & 2 deletions clients/ui/bff/internal/mocks/model_catalog_client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func (m *ModelCatalogClientMock) GetAllCatalogSources(client httpclient.HTTPClie
func (m *ModelCatalogClientMock) GetCatalogSourceModelArtifacts(client httpclient.HTTPClientInterface, sourceId string, modelName string, pageValues url.Values) (*models.CatalogModelArtifactList, error) {
var allMockModelArtifacts models.CatalogModelArtifactList

if sourceId == "sample-source" && modelName == "repo1%2Fgranite-8b-code-instruct" {
if sourceId == "sample-source" && (modelName == "repo1%2Fgranite-8b-code-instruct" || modelName == "repo1%2Fgranite-8b-code-instruct-quantized.w4a16") {
performanceArtifacts := GetCatalogPerformanceMetricsArtifactListMock(4)
accuracyArtifacts := GetCatalogAccuracyMetricsArtifactListMock()
modelArtifacts := GetCatalogModelArtifactListMock()
Expand Down Expand Up @@ -215,7 +215,19 @@ func (m *ModelCatalogClientMock) GetCatalogFilterOptions(client httpclient.HTTPC
}

func (m *ModelCatalogClientMock) CreateCatalogSourcePreview(client httpclient.HTTPClientInterface, sourcePreviewPayload models.CatalogSourcePreviewRequest, pageValues url.Values) (*models.CatalogSourcePreviewResult, error) {
catalogSourcePreview := CreateCatalogSourcePreviewMock()
filterStatus := pageValues.Get("filterStatus")
if filterStatus == "" {
filterStatus = "all"
}

pageSize := 20
if ps := pageValues.Get("pageSize"); ps != "" {
_, _ = fmt.Sscanf(ps, "%d", &pageSize)
}

nextPageToken := pageValues.Get("nextPageToken")

catalogSourcePreview := CreateCatalogSourcePreviewMockWithFilter(filterStatus, pageSize, nextPageToken)

return &catalogSourcePreview, nil
}
Loading
Loading