Skip to content

Commit ac284bc

Browse files
committed
feat(nl-search): add natural language search models support
- add `NlSearchModels` class with CRUD operations for model management - add `NlSearchModel` class for individual model operations - integrate `nl_search_models` into main `Client` class - add comprehensive integration tests for all model operations - support create, retrieve, update, and delete operations for nl search models
1 parent 73390bc commit ac284bc

5 files changed

Lines changed: 174 additions & 1 deletion

File tree

lib/typesense.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ module Typesense
3535
require_relative 'typesense/stemming'
3636
require_relative 'typesense/stemming_dictionaries'
3737
require_relative 'typesense/stemming_dictionary'
38+
require_relative 'typesense/nl_search_models'
39+
require_relative 'typesense/nl_search_model'

lib/typesense/client.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module Typesense
44
class Client
55
attr_reader :configuration, :collections, :aliases, :keys, :debug, :health, :metrics, :stats, :operations,
6-
:multi_search, :analytics, :presets, :stemming
6+
:multi_search, :analytics, :presets, :stemming, :nl_search_models
77

88
def initialize(options = {})
99
@configuration = Configuration.new(options)
@@ -20,6 +20,7 @@ def initialize(options = {})
2020
@analytics = Analytics.new(@api_call)
2121
@stemming = Stemming.new(@api_call)
2222
@presets = Presets.new(@api_call)
23+
@nl_search_models = NlSearchModels.new(@api_call)
2324
end
2425
end
2526
end

lib/typesense/nl_search_model.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# frozen_string_literal: true
2+
3+
module Typesense
4+
class NlSearchModel
5+
def initialize(model_id, api_call)
6+
@model_id = model_id
7+
@api_call = api_call
8+
end
9+
10+
def retrieve
11+
@api_call.get(endpoint_path)
12+
end
13+
14+
def update(update_schema)
15+
@api_call.put(endpoint_path, update_schema)
16+
end
17+
18+
def delete
19+
@api_call.delete(endpoint_path)
20+
end
21+
22+
private
23+
24+
def endpoint_path
25+
"#{NlSearchModels::RESOURCE_PATH}/#{URI.encode_www_form_component(@model_id)}"
26+
end
27+
end
28+
end

lib/typesense/nl_search_models.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# frozen_string_literal: true
2+
3+
module Typesense
4+
class NlSearchModels
5+
RESOURCE_PATH = '/nl_search_models'
6+
7+
def initialize(api_call)
8+
@api_call = api_call
9+
@nl_search_models = {}
10+
end
11+
12+
def create(schema)
13+
@api_call.post(RESOURCE_PATH, schema)
14+
end
15+
16+
def retrieve
17+
@api_call.get(RESOURCE_PATH)
18+
end
19+
20+
def [](model_id)
21+
@nl_search_models[model_id] ||= NlSearchModel.new(model_id, @api_call)
22+
end
23+
end
24+
end
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../spec_helper'
4+
5+
describe 'NlSearchModels', :integration do
6+
# These tests require external API access and should not run on CI by default
7+
next unless ENV['OPENAI_API_KEY']
8+
9+
let(:client) do
10+
Typesense::Client.new(
11+
nodes: [{ host: 'localhost', port: '8108', protocol: 'http' }],
12+
api_key: 'xyz',
13+
connection_timeout_seconds: 10
14+
)
15+
end
16+
17+
18+
def create_model_schema(id_suffix = nil)
19+
model_id = id_suffix ? "test_openai_model_#{id_suffix}" : "test_openai_model_#{Time.now.to_i}_#{rand(1000)}"
20+
{
21+
'id' => model_id,
22+
'model_name' => 'openai/gpt-4.1',
23+
'api_key' => ENV['OPENAI_API_KEY'],
24+
'max_bytes' => 16000,
25+
'temperature' => 0.0
26+
}
27+
end
28+
29+
def cleanup_model(model_id)
30+
client.nl_search_models[model_id].delete
31+
rescue Typesense::Error::ObjectNotFound
32+
# Model doesn't exist, that's fine
33+
end
34+
35+
before do
36+
WebMock.disable!
37+
end
38+
39+
after do
40+
WebMock.enable!
41+
end
42+
43+
it 'can create a nl search model' do
44+
model_schema = create_model_schema('create_test')
45+
46+
begin
47+
response = client.nl_search_models.create(model_schema)
48+
expect(response['id']).to eq(model_schema['id'])
49+
expect(response['model_name']).to eq('openai/gpt-4.1')
50+
expect(response['max_bytes']).to eq(16000)
51+
expect(response['temperature']).to eq(0.0)
52+
ensure
53+
cleanup_model(model_schema['id'])
54+
end
55+
end
56+
57+
it 'can retrieve a specific nl search model' do
58+
model_schema = create_model_schema('retrieve_test')
59+
60+
begin
61+
client.nl_search_models.create(model_schema)
62+
response = client.nl_search_models[model_schema['id']].retrieve
63+
expect(response['id']).to eq(model_schema['id'])
64+
expect(response['model_name']).to eq('openai/gpt-4.1')
65+
ensure
66+
cleanup_model(model_schema['id'])
67+
end
68+
end
69+
70+
it 'can retrieve all nl search models' do
71+
model_schema = create_model_schema('list_test')
72+
73+
begin
74+
client.nl_search_models.create(model_schema)
75+
76+
response = client.nl_search_models.retrieve
77+
expect(response).to be_an(Array)
78+
expect(response.length).to be >= 1
79+
80+
model_ids = response.map { |model| model['id'] }
81+
expect(model_ids).to include(model_schema['id'])
82+
ensure
83+
cleanup_model(model_schema['id'])
84+
end
85+
end
86+
87+
it 'can update a nl search model' do
88+
model_schema = create_model_schema('update_test')
89+
90+
begin
91+
client.nl_search_models.create(model_schema)
92+
93+
update_schema = {
94+
'temperature' => 0.5,
95+
'system_prompt' => 'Updated system prompt for electronics search'
96+
}
97+
98+
response = client.nl_search_models[model_schema['id']].update(update_schema)
99+
expect(response['temperature']).to eq(0.5)
100+
expect(response['system_prompt']).to eq('Updated system prompt for electronics search')
101+
ensure
102+
cleanup_model(model_schema['id'])
103+
end
104+
end
105+
106+
it 'can delete a nl search model' do
107+
model_schema = create_model_schema('delete_test')
108+
109+
client.nl_search_models.create(model_schema)
110+
111+
response = client.nl_search_models[model_schema['id']].delete
112+
expect(response['id']).to eq(model_schema['id'])
113+
114+
expect {
115+
client.nl_search_models[model_schema['id']].retrieve
116+
}.to raise_error(Typesense::Error::ObjectNotFound)
117+
end
118+
end

0 commit comments

Comments
 (0)