openai: align models list with tags (#16556)
This commit is contained in:
+7
-2
@@ -408,11 +408,16 @@ func ToCompleteChunk(id string, r api.GenerateResponse) CompletionChunk {
|
||||
func ToListCompletion(r api.ListResponse) ListCompletion {
|
||||
var data []Model
|
||||
for _, m := range r.Models {
|
||||
id := m.Model
|
||||
if id == "" {
|
||||
id = m.Name
|
||||
}
|
||||
|
||||
data = append(data, Model{
|
||||
Id: m.Name,
|
||||
Id: id,
|
||||
Object: "model",
|
||||
Created: m.ModifiedAt.Unix(),
|
||||
OwnedBy: model.ParseName(m.Name).Namespace,
|
||||
OwnedBy: model.ParseName(id).Namespace,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -356,6 +356,48 @@ func TestFromCompleteRequest_WithLogprobs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestToListCompletionUsesModelIdentity(t *testing.T) {
|
||||
modified := time.Unix(1234567890, 0).UTC()
|
||||
|
||||
result := ToListCompletion(api.ListResponse{
|
||||
Models: []api.ListModelResponse{
|
||||
{
|
||||
Name: "legacy-name:latest",
|
||||
Model: "namespace/exposed-model:latest",
|
||||
ModifiedAt: modified,
|
||||
},
|
||||
{
|
||||
Name: "fallback-name:latest",
|
||||
ModifiedAt: modified.Add(time.Second),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if result.Object != "list" {
|
||||
t.Fatalf("object = %q, want list", result.Object)
|
||||
}
|
||||
if len(result.Data) != 2 {
|
||||
t.Fatalf("models = %d, want 2", len(result.Data))
|
||||
}
|
||||
|
||||
if result.Data[0].Id != "namespace/exposed-model:latest" {
|
||||
t.Fatalf("id = %q, want model field", result.Data[0].Id)
|
||||
}
|
||||
if result.Data[0].OwnedBy != "namespace" {
|
||||
t.Fatalf("owned_by = %q, want namespace", result.Data[0].OwnedBy)
|
||||
}
|
||||
if result.Data[0].Created != modified.Unix() {
|
||||
t.Fatalf("created = %d, want %d", result.Data[0].Created, modified.Unix())
|
||||
}
|
||||
|
||||
if result.Data[1].Id != "fallback-name:latest" {
|
||||
t.Fatalf("fallback id = %q, want name field", result.Data[1].Id)
|
||||
}
|
||||
if result.Data[1].OwnedBy != "library" {
|
||||
t.Fatalf("fallback owned_by = %q, want library", result.Data[1].OwnedBy)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToChatCompletion_WithLogprobs(t *testing.T) {
|
||||
createdAt := time.Unix(1234567890, 0)
|
||||
resp := api.ChatResponse{
|
||||
|
||||
@@ -3,13 +3,20 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/ollama/ollama/api"
|
||||
"github.com/ollama/ollama/manifest"
|
||||
"github.com/ollama/ollama/openai"
|
||||
"github.com/ollama/ollama/types/model"
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
@@ -76,3 +83,104 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIListMatchesTagsModels(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
setTestHome(t, t.TempDir())
|
||||
|
||||
cache := newModelListCache()
|
||||
s := Server{modelCaches: &modelCaches{modelList: cache}}
|
||||
cache.Start(context.Background())
|
||||
if err := cache.Wait(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
createModel := func(name string) {
|
||||
t.Helper()
|
||||
|
||||
_, digest := createBinFile(t, nil, nil)
|
||||
w := createRequest(t, s.CreateHandler, api.CreateRequest{
|
||||
Model: name,
|
||||
Files: map[string]string{"model.gguf": digest},
|
||||
Stream: &stream,
|
||||
})
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("create %s status = %d, want 200: %s", name, w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
createModel("older-model")
|
||||
createModel("newer-model")
|
||||
|
||||
setManifestTime := func(name string, modified time.Time) {
|
||||
t.Helper()
|
||||
|
||||
parsed := model.ParseName(name)
|
||||
path, err := manifest.PathForName(parsed)
|
||||
if err != nil {
|
||||
t.Fatalf("manifest path for %s: %v", name, err)
|
||||
}
|
||||
if err := os.Chtimes(path, modified, modified); err != nil {
|
||||
t.Fatalf("set manifest time for %s: %v", name, err)
|
||||
}
|
||||
if err := cache.RefreshModel(parsed); err != nil {
|
||||
t.Fatalf("refresh %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
older := time.Unix(1000, 0).UTC()
|
||||
newer := time.Unix(2000, 0).UTC()
|
||||
setManifestTime("older-model:latest", older)
|
||||
setManifestTime("newer-model:latest", newer)
|
||||
|
||||
router, err := s.GenerateRoutes(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
doGet := func(path string, dest any) {
|
||||
t.Helper()
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, path, nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
body, err := io.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("read %s response: %v", path, err)
|
||||
}
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("GET %s status = %d, want 200: %s", path, w.Code, string(body))
|
||||
}
|
||||
if err := json.Unmarshal(body, dest); err != nil {
|
||||
t.Fatalf("decode %s response: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
var tags api.ListResponse
|
||||
doGet("/api/tags", &tags)
|
||||
|
||||
var models openai.ListCompletion
|
||||
doGet("/v1/models", &models)
|
||||
|
||||
if len(tags.Models) != 2 {
|
||||
t.Fatalf("/api/tags models = %d, want 2: %+v", len(tags.Models), tags.Models)
|
||||
}
|
||||
if len(models.Data) != len(tags.Models) {
|
||||
t.Fatalf("/v1/models data = %d, want %d", len(models.Data), len(tags.Models))
|
||||
}
|
||||
|
||||
for i, tagModel := range tags.Models {
|
||||
v1Model := models.Data[i]
|
||||
if v1Model.Id != tagModel.Model {
|
||||
t.Fatalf("model %d id = %q, want /api/tags model %q", i, v1Model.Id, tagModel.Model)
|
||||
}
|
||||
if v1Model.Created != tagModel.ModifiedAt.Unix() {
|
||||
t.Fatalf("model %d created = %d, want modified_at %d", i, v1Model.Created, tagModel.ModifiedAt.Unix())
|
||||
}
|
||||
}
|
||||
|
||||
if got, want := models.Data[0].Id, "newer-model:latest"; got != want {
|
||||
t.Fatalf("first /v1/models id = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user