embed_test.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. //go:build integration
  2. package integration
  3. import (
  4. "context"
  5. "math"
  6. "testing"
  7. "time"
  8. "github.com/ollama/ollama/api"
  9. )
  10. func floatsEqual32(a, b float32) bool {
  11. return math.Abs(float64(a-b)) <= 1e-4
  12. }
  13. func floatsEqual64(a, b float64) bool {
  14. return math.Abs(a-b) <= 1e-4
  15. }
  16. func TestAllMiniLMEmbeddings(t *testing.T) {
  17. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
  18. defer cancel()
  19. req := api.EmbeddingRequest{
  20. Model: "all-minilm",
  21. Prompt: "why is the sky blue?",
  22. }
  23. res, err := embeddingTestHelper(ctx, t, req)
  24. if err != nil {
  25. t.Fatalf("error: %v", err)
  26. }
  27. if len(res.Embedding) != 384 {
  28. t.Fatalf("expected 384 floats, got %d", len(res.Embedding))
  29. }
  30. if !floatsEqual64(res.Embedding[0], 0.06642947345972061) {
  31. t.Fatalf("expected 0.06642947345972061, got %.16f", res.Embedding[0])
  32. }
  33. }
  34. func TestAllMiniLMEmbed(t *testing.T) {
  35. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
  36. defer cancel()
  37. req := api.EmbedRequest{
  38. Model: "all-minilm",
  39. Input: "why is the sky blue?",
  40. }
  41. res, err := embedTestHelper(ctx, t, req)
  42. if err != nil {
  43. t.Fatalf("error: %v", err)
  44. }
  45. if len(res.Embeddings) != 1 {
  46. t.Fatalf("expected 1 embedding, got %d", len(res.Embeddings))
  47. }
  48. if len(res.Embeddings[0]) != 384 {
  49. t.Fatalf("expected 384 floats, got %d", len(res.Embeddings[0]))
  50. }
  51. if !floatsEqual32(res.Embeddings[0][0], 0.010071031) {
  52. t.Fatalf("expected 0.010071031, got %.8f", res.Embeddings[0][0])
  53. }
  54. if res.PromptEvalCount != 6 {
  55. t.Fatalf("expected 6 prompt tokens, got %d", res.PromptEvalCount)
  56. }
  57. }
  58. func TestAllMiniLMBatchEmbed(t *testing.T) {
  59. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
  60. defer cancel()
  61. req := api.EmbedRequest{
  62. Model: "all-minilm",
  63. Input: []string{"why is the sky blue?", "why is the grass green?"},
  64. }
  65. res, err := embedTestHelper(ctx, t, req)
  66. if err != nil {
  67. t.Fatalf("error: %v", err)
  68. }
  69. if len(res.Embeddings) != 2 {
  70. t.Fatalf("expected 2 embeddings, got %d", len(res.Embeddings))
  71. }
  72. if len(res.Embeddings[0]) != 384 {
  73. t.Fatalf("expected 384 floats, got %d", len(res.Embeddings[0]))
  74. }
  75. if !floatsEqual32(res.Embeddings[0][0], 0.010071031) || !floatsEqual32(res.Embeddings[1][0], -0.009802706) {
  76. t.Fatalf("expected 0.010071031 and -0.009802706, got %.8f and %.8f", res.Embeddings[0][0], res.Embeddings[1][0])
  77. }
  78. if res.PromptEvalCount != 12 {
  79. t.Fatalf("expected 12 prompt tokens, got %d", res.PromptEvalCount)
  80. }
  81. }
  82. func TestAllMiniLMEmbedTruncate(t *testing.T) {
  83. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
  84. defer cancel()
  85. truncTrue, truncFalse := true, false
  86. type testReq struct {
  87. Name string
  88. Request api.EmbedRequest
  89. }
  90. reqs := []testReq{
  91. {
  92. Name: "Target Truncation",
  93. Request: api.EmbedRequest{
  94. Model: "all-minilm",
  95. Input: "why",
  96. },
  97. },
  98. {
  99. Name: "Default Truncate",
  100. Request: api.EmbedRequest{
  101. Model: "all-minilm",
  102. Input: "why is the sky blue?",
  103. Options: map[string]any{"num_ctx": 1},
  104. },
  105. },
  106. {
  107. Name: "Explicit Truncate",
  108. Request: api.EmbedRequest{
  109. Model: "all-minilm",
  110. Input: "why is the sky blue?",
  111. Truncate: &truncTrue,
  112. Options: map[string]any{"num_ctx": 1},
  113. },
  114. },
  115. }
  116. res := make(map[string]*api.EmbedResponse)
  117. for _, req := range reqs {
  118. response, err := embedTestHelper(ctx, t, req.Request)
  119. if err != nil {
  120. t.Fatalf("error: %v", err)
  121. }
  122. res[req.Name] = response
  123. }
  124. if res["Target Truncation"].Embeddings[0][0] != res["Default Truncate"].Embeddings[0][0] {
  125. t.Fatal("expected default request to truncate correctly")
  126. }
  127. if res["Default Truncate"].Embeddings[0][0] != res["Explicit Truncate"].Embeddings[0][0] {
  128. t.Fatal("expected default request and truncate true request to be the same")
  129. }
  130. // check that truncate set to false returns an error if context length is exceeded
  131. _, err := embedTestHelper(ctx, t, api.EmbedRequest{
  132. Model: "all-minilm",
  133. Input: "why is the sky blue?",
  134. Truncate: &truncFalse,
  135. Options: map[string]any{"num_ctx": 1},
  136. })
  137. if err == nil {
  138. t.Fatal("expected error, got nil")
  139. }
  140. }
  141. func embeddingTestHelper(ctx context.Context, t *testing.T, req api.EmbeddingRequest) (*api.EmbeddingResponse, error) {
  142. client, _, cleanup := InitServerConnection(ctx, t)
  143. defer cleanup()
  144. if err := PullIfMissing(ctx, client, req.Model); err != nil {
  145. t.Fatalf("failed to pull model %s: %v", req.Model, err)
  146. }
  147. response, err := client.Embeddings(ctx, &req)
  148. if err != nil {
  149. return nil, err
  150. }
  151. return response, nil
  152. }
  153. func embedTestHelper(ctx context.Context, t *testing.T, req api.EmbedRequest) (*api.EmbedResponse, error) {
  154. client, _, cleanup := InitServerConnection(ctx, t)
  155. defer cleanup()
  156. if err := PullIfMissing(ctx, client, req.Model); err != nil {
  157. t.Fatalf("failed to pull model %s: %v", req.Model, err)
  158. }
  159. response, err := client.Embed(ctx, &req)
  160. if err != nil {
  161. return nil, err
  162. }
  163. return response, nil
  164. }