diff --git a/README.md b/README.md index 8e2f79e1..d1926247 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Ruby OpenAI + [![Gem Version](https://img.shields.io/gem/v/ruby-openai.svg)](https://rubygems.org/gems/ruby-openai) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/alexrudall/ruby-openai/blob/main/LICENSE.txt) [![CircleCI Build Status](https://circleci.com/gh/alexrudall/ruby-openai.svg?style=shield)](https://circleci.com/gh/alexrudall/ruby-openai) @@ -16,7 +17,7 @@ Stream chats with the Responses API, transcribe and translate audio with Whisper ## Contents - [Ruby OpenAI](#ruby-openai) -- [Table of Contents](#table-of-contents) + - [Contents](#contents) - [Installation](#installation) - [Bundler](#bundler) - [Gem install](#gem-install) @@ -39,6 +40,13 @@ Stream chats with the Responses API, transcribe and translate audio with Whisper - [Vision](#vision) - [JSON Mode](#json-mode) - [Responses API](#responses-api) + - [Create a Response](#create-a-response) + - [Follow-up Messages](#follow-up-messages) + - [Tool Calls](#tool-calls) + - [Streaming](#streaming) + - [Retrieve a Response](#retrieve-a-response) + - [Delete a Response](#delete-a-response) + - [List Input Items](#list-input-items) - [Functions](#functions) - [Completions](#completions) - [Embeddings](#embeddings) @@ -70,6 +78,7 @@ Stream chats with the Responses API, transcribe and translate audio with Whisper - [Usage](#usage) - [Errors](#errors-1) - [Development](#development) + - [To check for deprecations](#to-check-for-deprecations) - [Release](#release) - [Contributing](#contributing) - [License](#license) @@ -88,7 +97,7 @@ gem "ruby-openai" And then execute: ```bash -$ bundle install +bundle install ``` ### Gem install @@ -96,7 +105,7 @@ $ bundle install Or install with: ```bash -$ gem install ruby-openai +gem install ruby-openai ``` and require with: @@ -472,9 +481,11 @@ You can stream it as well! ``` ### Responses API + [OpenAI's most advanced interface for generating model responses](https://platform.openai.com/docs/api-reference/responses). Supports text and image inputs, and text outputs. Create stateful interactions with the model, using the output of previous responses as input. Extend the model's capabilities with built-in tools for file search, web search, computer use, and more. Allow the model access to external systems and data using function calling. #### Create a Response + ```ruby response = client.responses.create(parameters: { model: "gpt-4o", @@ -485,6 +496,7 @@ puts response.dig("output", 0, "content", 0, "text") ``` #### Follow-up Messages + ```ruby followup = client.responses.create(parameters: { model: "gpt-4o", @@ -496,6 +508,7 @@ puts followup.dig("output", 0, "content", 0, "text") ``` #### Tool Calls + ```ruby response = client.responses.create(parameters: { model: "gpt-4o", @@ -523,6 +536,7 @@ puts response.dig("output", 0, "name") ``` #### Streaming + ```ruby client.responses.create( parameters: { @@ -540,6 +554,7 @@ client.responses.create( ``` #### Retrieve a Response + ```ruby retrieved_response = client.responses.retrieve(response_id: response["id"]) puts retrieved_response["object"] @@ -547,6 +562,7 @@ puts retrieved_response["object"] ``` #### Delete a Response + ```ruby deletion = client.responses.delete(response_id: response["id"]) puts deletion["deleted"] @@ -554,6 +570,7 @@ puts deletion["deleted"] ``` #### List Input Items + ```ruby input_items = client.responses.input_items(response_id: response["id"]) puts input_items["object"] # => "list" @@ -910,6 +927,27 @@ response = client.vector_stores.modify( ) ``` +You can search a vector store for relevant chunks based on a query: + +```ruby +response = client.vector_stores.search( + id: vector_store_id, + parameters: { + query: "What is the return policy?", + max_num_results: 20, + ranking_options: { + # Add any ranking options here in line with the API documentation + }, + rewrite_query: true, + filters: { + type: "eq", + property: "region", + value: "us" + } + } +) +``` + You can delete vector stores: ```ruby @@ -1588,6 +1626,7 @@ File.binwrite('demo.mp3', response) ``` ### Usage + The Usage API provides information about the cost of various OpenAI services within your organization. To use Admin APIs like Usage, you need to set an OPENAI_ADMIN_TOKEN, which can be generated [here](https://platform.openai.com/settings/organization/admin-keys). diff --git a/lib/openai/vector_stores.rb b/lib/openai/vector_stores.rb index e16410ee..0b8cb775 100644 --- a/lib/openai/vector_stores.rb +++ b/lib/openai/vector_stores.rb @@ -23,5 +23,9 @@ def modify(id:, parameters: {}) def delete(id:) @client.delete(path: "/vector_stores/#{id}") end + + def search(id:, parameters: {}) + @client.json_post(path: "/vector_stores/#{id}/search", parameters: parameters) + end end end diff --git a/spec/fixtures/cassettes/vector_stores_search.yml b/spec/fixtures/cassettes/vector_stores_search.yml new file mode 100644 index 00000000..f9c6ac8b --- /dev/null +++ b/spec/fixtures/cassettes/vector_stores_search.yml @@ -0,0 +1,100 @@ +--- +http_interactions: + - request: + method: post + uri: https://api.openai.com/v1/vector_stores/vs_abc123/search + body: + encoding: UTF-8 + string: '{"query":"Test search query","max_num_results":5,"rewrite_query":false}' + headers: + Content-Type: + - application/json + Authorization: + - Bearer + Openai-Beta: + - assistants=v2 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 15 Oct 2024 10:45:12 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Openai-Version: + - "2020-10-01" + Openai-Organization: + - user-test123456 + X-Request-Id: + - req_abc123def456 + Openai-Processing-Ms: + - "152" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - __cf_bm=abcdefg123456; path=/; expires=Tue, 15-Oct-24 11:15:12 GMT; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + - _cfuvid=abcdefg123456-0.0.1.1-604800000; path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + X-Content-Type-Options: + - nosniff + Server: + - cloudflare + Cf-Ray: + - abcdefg123456-XYZ + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + { + "object": "vector_store.search_results.page", + "search_query": "Test search query", + "data": [ + { + "file_id": "file-abc123", + "filename": "test_document.pdf", + "score": 0.95, + "attributes": { + "author": "Test Author", + "date": "2024-10-15" + }, + "content": [ + { + "type": "text", + "text": "This is a test document that contains information relevant to the search query." + } + ] + }, + { + "file_id": "file-def456", + "filename": "another_document.txt", + "score": 0.85, + "attributes": { + "author": "Another Author", + "date": "2024-10-14" + }, + "content": [ + { + "type": "text", + "text": "This is another document with some relevant content for testing." + } + ] + } + ], + "has_more": false, + "next_page": null + } + recorded_at: Tue, 15 Oct 2024 10:45:12 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/cassettes/vector_stores_search_setup.yml b/spec/fixtures/cassettes/vector_stores_search_setup.yml new file mode 100644 index 00000000..eaff0925 --- /dev/null +++ b/spec/fixtures/cassettes/vector_stores_search_setup.yml @@ -0,0 +1,75 @@ +--- +http_interactions: + - request: + method: post + uri: https://api.openai.com/v1/vector_stores + body: + encoding: UTF-8 + string: "{}" + headers: + Content-Type: + - application/json + Authorization: + - Bearer + Openai-Beta: + - assistants=v2 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 15 Oct 2024 10:45:10 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Openai-Version: + - "2020-10-01" + Openai-Organization: + - user-test123456 + X-Request-Id: + - req_abc123def456 + Openai-Processing-Ms: + - "152" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - __cf_bm=abcdefg123456; path=/; expires=Tue, 15-Oct-24 11:15:10 GMT; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + - _cfuvid=abcdefg123456-0.0.1.1-604800000; path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + X-Content-Type-Options: + - nosniff + Server: + - cloudflare + Cf-Ray: + - abcdefg123456-XYZ + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + { + "id": "vs_abc123", + "object": "vector_store", + "created_at": 1725678310, + "name": null, + "file_counts": { + "total": 0, + "completed": 0, + "processing": 0, + "failed": 0 + }, + "expires_after": null + } + recorded_at: Tue, 15 Oct 2024 10:45:10 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/openai/client/vector_stores_spec.rb b/spec/openai/client/vector_stores_spec.rb index 7cf2350a..65c25dfd 100644 --- a/spec/openai/client/vector_stores_spec.rb +++ b/spec/openai/client/vector_stores_spec.rb @@ -72,5 +72,25 @@ end end end + + describe "#search" do + let(:cassette) { "vector_stores search" } + let(:response) do + OpenAI::Client.new.vector_stores.search( + id: vector_store_id, + parameters: { + query: "Test search query", + max_num_results: 5, + rewrite_query: false + } + ) + end + + it "succeeds" do + VCR.use_cassette(cassette) do + expect(response["object"]).to eq("vector_store.search_results.page") + end + end + end end end