Используйте API OpenAI с Ruby! ? ❤
Поток текст с GPT-4O, транскрибируйте и переведйте звук с шепотом или создайте изображения с помощью Dall · e ...
Наймите меня, чтобы построить свои рельсы+приложение AI | Rails ai | ? Ruby AI Builders Discord | ? X | ? Антропический драгоценный камень | ? Midjourney Gem
Добавьте эту строку в Gemfile вашего приложения:
gem "ruby-openai"
А затем выполнить:
$ bundle install
Или установить с:
$ gem install ruby-openai
и требовать с:
require "openai"
Для быстрого теста вы можете передать свой токен непосредственно новому клиенту:
client = OpenAI :: Client . new (
access_token : "access_token_goes_here" ,
log_errors : true # Highly recommended in development, so you can see what errors OpenAI is returning. Not recommended in production because it could leak private data to your logs.
)
Для более надежной настройки вы можете настроить GEM с вашим клавиш API, например, в файле инициализатора openai.rb
. Никогда не секреты хардкодов в свою кодовую базу - вместо этого используйте что -то вроде Dotenv, чтобы безопасно передать ключи в ваши среды.
OpenAI . configure do | config |
config . access_token = ENV . fetch ( "OPENAI_ACCESS_TOKEN" )
config . organization_id = ENV . fetch ( "OPENAI_ORGANIZATION_ID" ) # Optional
config . log_errors = true # Highly recommended in development, so you can see what errors OpenAI is returning. Not recommended in production because it could leak private data to your logs.
end
Тогда вы можете создать клиента, как это:
client = OpenAI :: Client . new
Вы все еще можете переопределить по умолчанию конфигурации при создании новых клиентов; Любые варианты не включены в любой глобальный набор конфигураций с OpenAI.Configure. Например, в этом примере Organization_ID, request_timeout и т. д.
client = OpenAI :: Client . new ( access_token : "access_token_goes_here" )
request_timeout
при инициализации клиента. client = OpenAI :: Client . new (
access_token : "access_token_goes_here" ,
uri_base : "https://oai.hconeai.com/" ,
request_timeout : 240 ,
extra_headers : {
"X-Proxy-TTL" => "43200" , # For https://github.com/6/openai-caching-proxy-worker#specifying-a-cache-ttl
"X-Proxy-Refresh" : "true" , # For https://github.com/6/openai-caching-proxy-worker#refreshing-the-cache
"Helicone-Auth" : "Bearer HELICONE_API_KEY" , # For https://docs.helicone.ai/getting-started/integration-method/openai-proxy
"helicone-stream-force-format" => "true" , # Use this with Helicone otherwise streaming drops chunks # https://github.com/alexrudall/ruby-openai/issues/251
}
)
или при настройке драгоценного камня:
OpenAI . configure do | config |
config . access_token = ENV . fetch ( "OPENAI_ACCESS_TOKEN" )
config . log_errors = true # Optional
config . organization_id = ENV . fetch ( "OPENAI_ORGANIZATION_ID" ) # Optional
config . uri_base = "https://oai.hconeai.com/" # Optional
config . request_timeout = 240 # Optional
config . extra_headers = {
"X-Proxy-TTL" => "43200" , # For https://github.com/6/openai-caching-proxy-worker#specifying-a-cache-ttl
"X-Proxy-Refresh" : "true" , # For https://github.com/6/openai-caching-proxy-worker#refreshing-the-cache
"Helicone-Auth" : "Bearer HELICONE_API_KEY" # For https://docs.helicone.ai/getting-started/integration-method/openai-proxy
} # Optional
end
Вы можете динамически передавать заголовки на объект клиента, который будет объединен с любыми заголовками, установленными во всем мире с OpenAI.Configure:
client = OpenAI :: Client . new ( access_token : "access_token_goes_here" )
client . add_headers ( "X-Proxy-TTL" => "43200" )
По умолчанию, ruby-openai
не регистрирует никакой встречи Faraday::Error
S, выполняя сетевой запрос, чтобы избежать протекания данных (например, 400, 500, SSL -ошибки и многое другое - см. Здесь для полного списка подклассов Faraday::Error
что может их вызвать).
Если вы хотите включить эту функциональность, вы можете установить log_errors
в true
при настройке клиента:
client = OpenAI :: Client . new ( log_errors : true )
Вы можете передать промежуточное программное обеспечение Faraday клиенту в блоке, например. Чтобы включить многословную регистрацию с помощью регистрации Ruby:
client = OpenAI :: Client . new do | f |
f . response :logger , Logger . new ( $stdout ) , bodies : true
end
Чтобы использовать ARESE API Service API Azure, вы можете настроить GEM таким образом:
OpenAI . configure do | config |
config . access_token = ENV . fetch ( "AZURE_OPENAI_API_KEY" )
config . uri_base = ENV . fetch ( "AZURE_OPENAI_URI" )
config . api_type = :azure
config . api_version = "2023-03-15-preview"
end
где AZURE_OPENAI_URI
, например, https://custom-domain.openai.azure.com/openai/deployments/gpt-35-turbo
Ollama позволяет вам запускать LLM с открытым исходным кодом, такие как Llama 3, локально. Он предлагает совместимость чата с API OpenAI.
Вы можете скачать Ollama здесь. На MacOS вы можете установить и запустить Ollama, как это:
brew install ollama
ollama serve
ollama pull llama3:latest # In new terminal tab.
Создайте клиента, используя ваш сервер Ollama и вытянутую модель, и бесплатно транслируйте разговор:
client = OpenAI :: Client . new (
uri_base : "http://localhost:11434"
)
client . chat (
parameters : {
model : "llama3" , # Required.
messages : [ { role : "user" , content : "Hello!" } ] , # Required.
temperature : 0.7 ,
stream : proc do | chunk , _bytesize |
print chunk . dig ( "choices" , 0 , "delta" , "content" )
end
}
)
# => Hi! It's nice to meet you. Is there something I can help you with, or would you like to chat?
Чат Groq API в целом совместим с API OpenAI, с несколькими незначительными различиями. Получите токен доступа отсюда, тогда:
client = OpenAI :: Client . new (
access_token : "groq_access_token_goes_here" ,
uri_base : "https://api.groq.com/openai"
)
client . chat (
parameters : {
model : "llama3-8b-8192" , # Required.
messages : [ { role : "user" , content : "Hello!" } ] , # Required.
temperature : 0.7 ,
stream : proc do | chunk , _bytesize |
print chunk . dig ( "choices" , 0 , "delta" , "content" )
end
}
)
Openai Sackses подсказывает текст в токены, которые являются словами или частями слов. (Эти токены не связаны с вашим API Access_token.) Подсчет токенов может помочь вам оценить ваши затраты. Это также может помочь вам убедиться, что ваш размер текста находится в пределах максимальных пределов окна контекста вашей модели и выбрать соответствующий параметр завершения max_tokens
, чтобы ваш ответ также соответствовал.
Чтобы оценить токен-центр вашего текста:
OpenAI . rough_token_count ( "Your text" )
Если вам нужен более точный счет, попробуйте tiktoken_ruby.
Существуют разные модели, которые можно использовать для генерации текста. Для полного списка и для получения информации о одной модели:
client . models . list
client . models . retrieve ( id : "gpt-4o" )
GPT - это модель, которую можно использовать для создания текста в разговорном стиле. Вы можете использовать его для создания ответа на последовательность сообщений:
response = client . chat (
parameters : {
model : "gpt-4o" , # Required.
messages : [ { role : "user" , content : "Hello!" } ] , # Required.
temperature : 0.7 ,
}
)
puts response . dig ( "choices" , 0 , "message" , "content" )
# => "Hello! How may I assist you today?"
Быстрый гид по потоковому чату с Rails 7 и Hotwire
Вы можете транслировать из API в режиме реального времени, что может быть намного быстрее и использовать для создания более привлекательного пользовательского опыта. Передайте PROC (или любой объект с помощью метода #call
) в параметр stream
, чтобы получить поток кусков завершения по мере их сгенерирования. Каждый раз, когда получается один или несколько кусков, PROC будет вызывается один раз с каждым кусочком, проанализированным как хэш. Если OpenAI вернет ошибку, ruby-openai
вынесет ошибку Faraday.
client . chat (
parameters : {
model : "gpt-4o" , # Required.
messages : [ { role : "user" , content : "Describe a character called Anna!" } ] , # Required.
temperature : 0.7 ,
stream : proc do | chunk , _bytesize |
print chunk . dig ( "choices" , 0 , "delta" , "content" )
end
}
)
# => "Anna is a young woman in her mid-twenties, with wavy chestnut hair that falls to her shoulders..."
ПРИМЕЧАНИЕ. Чтобы получить информацию о использовании, вы можете предоставить параметр stream_options
, а OpenAI предоставит окончательный кусок с использованием. Вот пример:
stream_proc = proc { | chunk , _bytesize | puts "--------------" ; puts chunk . inspect ; }
client . chat (
parameters : {
model : "gpt-4o" ,
stream : stream_proc ,
stream_options : { include_usage : true } ,
messages : [ { role : "user" , content : "Hello!" } ] ,
}
)
# => --------------
# => {"id"=>"chatcmpl-7bbq05PiZqlHxjV1j7OHnKKDURKaf", "object"=>"chat.completion.chunk", "created"=>1718750612, "model"=>"gpt-4o-2024-05-13", "system_fingerprint"=>"fp_9cb5d38cf7", "choices"=>[{"index"=>0, "delta"=>{"role"=>"assistant", "content"=>""}, "logprobs"=>nil, "finish_reason"=>nil}], "usage"=>nil}
# => --------------
# => {"id"=>"chatcmpl-7bbq05PiZqlHxjV1j7OHnKKDURKaf", "object"=>"chat.completion.chunk", "created"=>1718750612, "model"=>"gpt-4o-2024-05-13", "system_fingerprint"=>"fp_9cb5d38cf7", "choices"=>[{"index"=>0, "delta"=>{"content"=>"Hello"}, "logprobs"=>nil, "finish_reason"=>nil}], "usage"=>nil}
# => --------------
# => ... more content chunks
# => --------------
# => {"id"=>"chatcmpl-7bbq05PiZqlHxjV1j7OHnKKDURKaf", "object"=>"chat.completion.chunk", "created"=>1718750612, "model"=>"gpt-4o-2024-05-13", "system_fingerprint"=>"fp_9cb5d38cf7", "choices"=>[{"index"=>0, "delta"=>{}, "logprobs"=>nil, "finish_reason"=>"stop"}], "usage"=>nil}
# => --------------
# => {"id"=>"chatcmpl-7bbq05PiZqlHxjV1j7OHnKKDURKaf", "object"=>"chat.completion.chunk", "created"=>1718750612, "model"=>"gpt-4o-2024-05-13", "system_fingerprint"=>"fp_9cb5d38cf7", "choices"=>[], "usage"=>{"prompt_tokens"=>9, "completion_tokens"=>9, "total_tokens"=>18}}
Вы можете использовать модель Vision GPT-4 для создания описания изображения:
messages = [
{ "type" : "text" , "text" : "What’s in this image?" } ,
{ "type" : "image_url" ,
"image_url" : {
"url" : "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg" ,
} ,
}
]
response = client . chat (
parameters : {
model : "gpt-4-vision-preview" , # Required.
messages : [ { role : "user" , content : messages } ] , # Required.
}
)
puts response . dig ( "choices" , 0 , "message" , "content" )
# => "The image depicts a serene natural landscape featuring a long wooden boardwalk extending straight ahead"
Вы можете установить recsion_format, чтобы попросить ответы в JSON:
response = client . chat (
parameters : {
model : "gpt-4o" ,
response_format : { type : "json_object" } ,
messages : [ { role : "user" , content : "Hello! Give me some JSON please." } ] ,
temperature : 0.7 ,
} )
puts response . dig ( "choices" , 0 , "message" , "content" )
# =>
# {
# "name": "John",
# "age": 30,
# "city": "New York",
# "hobbies": ["reading", "traveling", "hiking"],
# "isStudent": false
# }
Вы также можете транслировать его!
response = client . chat (
parameters : {
model : "gpt-4o" ,
messages : [ { role : "user" , content : "Can I have some JSON please?" } ] ,
response_format : { type : "json_object" } ,
stream : proc do | chunk , _bytesize |
print chunk . dig ( "choices" , 0 , "delta" , "content" )
end
}
)
# =>
# {
# "message": "Sure, please let me know what specific JSON data you are looking for.",
# "JSON_data": {
# "example_1": {
# "key_1": "value_1",
# "key_2": "value_2",
# "key_3": "value_3"
# },
# "example_2": {
# "key_4": "value_4",
# "key_5": "value_5",
# "key_6": "value_6"
# }
# }
# }
Вы можете описать и передавать функции, и модель разумно выберет для вывода объекта JSON, содержащего аргументы, чтобы позвонить им - например, для использования вашего метода get_current_weather
, чтобы получить погоду в данном месте. Обратите внимание, что Tool_choice является необязательным, но если вы исключите ее, модель выберет, использовать ли функцию или нет (см. Здесь).
def get_current_weather ( location : , unit : "fahrenheit" )
# Here you could use a weather api to fetch the weather.
"The weather in #{ location } is nice ? #{ unit } "
end
messages = [
{
"role" : "user" ,
"content" : "What is the weather like in San Francisco?" ,
} ,
]
response =
client . chat (
parameters : {
model : "gpt-4o" ,
messages : messages , # Defined above because we'll use it again
tools : [
{
type : "function" ,
function : {
name : "get_current_weather" ,
description : "Get the current weather in a given location" ,
parameters : { # Format: https://json-schema.org/understanding-json-schema
type : :object ,
properties : {
location : {
type : :string ,
description : "The city and state, e.g. San Francisco, CA" ,
} ,
unit : {
type : "string" ,
enum : %w[ celsius fahrenheit ] ,
} ,
} ,
required : [ "location" ] ,
} ,
} ,
}
] ,
# Optional, defaults to "auto"
# Can also put "none" or specific functions, see docs
tool_choice : "required"
} ,
)
message = response . dig ( "choices" , 0 , "message" )
if message [ "role" ] == "assistant" && message [ "tool_calls" ]
message [ "tool_calls" ] . each do | tool_call |
tool_call_id = tool_call . dig ( "id" )
function_name = tool_call . dig ( "function" , "name" )
function_args = JSON . parse (
tool_call . dig ( "function" , "arguments" ) ,
{ symbolize_names : true } ,
)
function_response =
case function_name
when "get_current_weather"
get_current_weather ( ** function_args ) # => "The weather is nice ?"
else
# decide how to handle
end
# For a subsequent message with the role "tool", OpenAI requires the preceding message to have a tool_calls argument.
messages << message
messages << {
tool_call_id : tool_call_id ,
role : "tool" ,
name : function_name ,
content : function_response
} # Extend the conversation with the results of the functions
end
second_response = client . chat (
parameters : {
model : "gpt-4o" ,
messages : messages
}
)
puts second_response . dig ( "choices" , 0 , "message" , "content" )
# At this point, the model has decided to call functions, you've called the functions
# and provided the response back, and the model has considered this and responded.
end
# => "It looks like the weather is nice and sunny in San Francisco! If you're planning to go out, it should be a pleasant day."
Нажмите API OpenAI для завершения, используя другие модели GPT-3:
response = client . completions (
parameters : {
model : "gpt-4o" ,
prompt : "Once upon a time" ,
max_tokens : 5
}
)
puts response [ "choices" ] . map { | c | c [ "text" ] }
# => [", there lived a great"]
Вы можете использовать конечную точку Enterdings, чтобы получить вектор чисел, представляющих вход. Затем вы можете сравнить эти векторы для различных входов, чтобы эффективно проверить, насколько похожи входы.
response = client . embeddings (
parameters : {
model : "text-embedding-ada-002" ,
input : "The food was delicious and the waiter..."
}
)
puts response . dig ( "data" , 0 , "embedding" )
# => Vector representation of your embedding
Конечная точка пакетов позволяет создавать и управлять большими партиями запросов API, чтобы работать асинхронно. В настоящее время поддерживаемыми конечными точками для партий являются /v1/chat/completions
(API завершения чата) и /v1/embeddings
(Enterdings API).
Чтобы использовать конечную точку партий, вам необходимо сначала загрузить файл JSONL, содержащий пакетные запросы с использованием конечной точки файлов. Файл должен быть загружен с целью, установленной на batch
. Каждая строка в файле JSONL представляет собой один запрос и должен иметь следующий формат:
{
"custom_id" : " request-1 " ,
"method" : " POST " ,
"url" : " /v1/chat/completions " ,
"body" : {
"model" : " gpt-4o " ,
"messages" : [
{ "role" : " system " , "content" : " You are a helpful assistant. " },
{ "role" : " user " , "content" : " What is 2+2? " }
]
}
}
После того, как вы загрузили файл JSONL, вы можете создать новую партию, предоставив идентификатор файла, конечную точку и окно завершения:
response = client . batches . create (
parameters : {
input_file_id : "file-abc123" ,
endpoint : "/v1/chat/completions" ,
completion_window : "24h"
}
)
batch_id = response [ "id" ]
Вы можете получить информацию о конкретной партии, используя его идентификатор:
batch = client . batches . retrieve ( id : batch_id )
Чтобы отменить партию, которая находится в процессе:
client . batches . cancel ( id : batch_id )
Вы также можете перечислить все партии:
client . batches . list
Как только пакет ["reflect_at"] присутствует, вы можете получить файлы вывода или ошибок:
batch = client . batches . retrieve ( id : batch_id )
output_file_id = batch [ "output_file_id" ]
output_response = client . files . content ( id : output_file_id )
error_file_id = batch [ "error_file_id" ]
error_response = client . files . content ( id : error_file_id )
Эти файлы находятся в формате JSONL, причем каждая строка представляет выход или ошибку для одного запроса. Линии могут быть в любом порядке:
{
"id" : " response-1 " ,
"custom_id" : " request-1 " ,
"response" : {
"id" : " chatcmpl-abc123 " ,
"object" : " chat.completion " ,
"created" : 1677858242 ,
"model" : " gpt-4o " ,
"choices" : [
{
"index" : 0 ,
"message" : {
"role" : " assistant " ,
"content" : " 2+2 equals 4. "
}
}
]
}
}
Если запрос не работает с ошибкой без HTTP, объект ошибки будет содержать больше информации о причине сбоя.
Поместите ваши данные в файл .jsonl
таким образом:
{ "prompt" : " Overjoyed with my new phone! -> " , "completion" : " positive " }
{ "prompt" : " @lakers disappoint for a third straight night -> " , "completion" : " negative " }
и передайте путь (или объект stringio) к client.files.upload
, чтобы загрузить его в Openai, а затем взаимодействовать с ним:
client . files . upload ( parameters : { file : "path/to/sentiment.jsonl" , purpose : "fine-tune" } )
client . files . list
client . files . retrieve ( id : "file-123" )
client . files . content ( id : "file-123" )
client . files . delete ( id : "file-123" )
Вы можете отправить путь к файлу:
client . files . upload ( parameters : { file : "path/to/file.pdf" , purpose : "assistants" } )
или объект файла
my_file = File . open ( "path/to/file.pdf" , "rb" )
client . files . upload ( parameters : { file : my_file , purpose : "assistants" } )
См. Поддерживаемые типы файлов на документации API.
Загрузите свои данные с тонкой настройкой в файл .jsonl
, как указано выше, и получите его идентификатор:
response = client . files . upload ( parameters : { file : "path/to/sarcasm.jsonl" , purpose : "fine-tune" } )
file_id = JSON . parse ( response . body ) [ "id" ]
Затем вы можете использовать этот идентификатор файла, чтобы создать задание с тонкой настройкой:
response = client . finetunes . create (
parameters : {
training_file : file_id ,
model : "gpt-4o"
} )
fine_tune_id = response [ "id" ]
Это даст вам тонкую настройку идентификатора. Если вы допустили ошибку, вы можете отменить модель с тонкой настройкой, прежде чем она будет обработана:
client . finetunes . cancel ( id : fine_tune_id )
Вам может потребоваться короткое время для завершения обработки. После обработки вы можете использовать список или получить, чтобы получить имя тонкой модели:
client . finetunes . list
response = client . finetunes . retrieve ( id : fine_tune_id )
fine_tuned_model = response [ "fine_tuned_model" ]
Это имени модели с тонкой настройкой можно использовать при завершении чата:
response = client . chat (
parameters : {
model : fine_tuned_model ,
messages : [ { role : "user" , content : "I love Mondays!" } ]
}
)
response . dig ( "choices" , 0 , "message" , "content" )
Вы также можете захватить события для работы:
client . finetunes . list_events ( id : fine_tune_id )
Объекты Vector Store Дайте инструменту поиска файла возможность поиска ваших файлов.
Вы можете создать новый векторный магазин:
response = client . vector_stores . create (
parameters : {
name : "my vector store" ,
file_ids : [ "file-abc123" , "file-def456" ]
}
)
vector_store_id = response [ "id" ]
Учитывая vector_store_id
, вы можете retrieve
текущие значения поля:
client . vector_stores . retrieve ( id : vector_store_id )
Вы можете получить list
всех векторных магазинов, доступных в настоящее время в организации:
client . vector_stores . list
Вы можете изменить существующий векторный хранилище, за исключением file_ids
:
response = client . vector_stores . modify (
id : vector_store_id ,
parameters : {
name : "Modified Test Vector Store" ,
}
)
Вы можете удалить векторные магазины:
client . vector_stores . delete ( id : vector_store_id )
Файлы Vector Store представляют файлы в векторном хранилище.
Вы можете создать новый файл Vector Store, подключив файл в векторный магазин.
response = client . vector_store_files . create (
vector_store_id : "vector-store-abc123" ,
parameters : {
file_id : "file-abc123"
}
)
vector_store_file_id = response [ "id" ]
Учитывая vector_store_file_id
, вы можете retrieve
текущие значения поля:
client . vector_store_files . retrieve (
vector_store_id : "vector-store-abc123" ,
id : vector_store_file_id
)
Вы можете получить list
всех файлов Vector Store, доступных в настоящее время в Vector Store:
client . vector_store_files . list ( vector_store_id : "vector-store-abc123" )
Вы можете удалить файл векторного хранилища:
client . vector_store_files . delete (
vector_store_id : "vector-store-abc123" ,
id : vector_store_file_id
)
Примечание. Это удалит файл из векторного хранилища, но сам файл не будет удален. Чтобы удалить файл, используйте конечную точку Delete File.
Пакеты файлов Vector Store представляют операции для добавления нескольких файлов в векторный хранилище.
Вы можете создать новую партию файла Vector Store, подключив несколько файлов в векторный хранилище.
response = client . vector_store_file_batches . create (
vector_store_id : "vector-store-abc123" ,
parameters : {
file_ids : [ "file-abc123" , "file-def456" ]
}
)
file_batch_id = response [ "id" ]
Учитывая file_batch_id
, вы можете retrieve
текущие значения поля:
client . vector_store_file_batches . retrieve (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
)
Вы можете получить list
всех файлов Vector Store в партии, доступной в настоящее время в Vector Store:
client . vector_store_file_batches . list (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
)
Вы можете отменить партию файла векторного хранилища (это пытается отменить обработку файлов в этой партии как можно скорее):
client . vector_store_file_batches . cancel (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
)
Помощники являются государственными актерами, которые могут иметь много разговоров и использовать инструменты для выполнения задач (см. Обзор помощника).
Чтобы создать нового помощника:
response = client . assistants . create (
parameters : {
model : "gpt-4o" ,
name : "OpenAI-Ruby test assistant" ,
description : nil ,
instructions : "You are a Ruby dev bot. When asked a question, write and run Ruby code to answer the question" ,
tools : [
{ type : "code_interpreter" } ,
{ type : "file_search" }
] ,
tool_resources : {
code_interpreter : {
file_ids : [ ] # See Files section above for how to upload files
} ,
file_search : {
vector_store_ids : [ ] # See Vector Stores section above for how to add vector stores
}
} ,
"metadata" : { my_internal_version_id : "1.0.0" }
}
)
assistant_id = response [ "id" ]
Учитывая assistant_id
, вы можете retrieve
текущие значения поля:
client . assistants . retrieve ( id : assistant_id )
Вы можете получить list
всех помощников, доступных в настоящее время в рамках организации:
client . assistants . list
Вы можете изменить существующего помощника, используя идентификатор помощника (см. Документацию API):
response = client . assistants . modify (
id : assistant_id ,
parameters : {
name : "Modified Test Assistant for OpenAI-Ruby" ,
metadata : { my_internal_version_id : '1.0.1' }
}
)
Вы можете удалить помощников:
client . assistants . delete ( id : assistant_id )
После того, как вы создали помощника, как описано выше, вам необходимо подготовить Thread
Messages
для помощника для работы (см. Введение в Assistants). Например, в качестве начальной настройки вы могли бы сделать:
# Create thread
response = client . threads . create # Note: Once you create a thread, there is no way to list it
# or recover it currently (as of 2023-12-10). So hold onto the `id`
thread_id = response [ "id" ]
# Add initial message from user (see https://platform.openai.com/docs/api-reference/messages/createMessage)
message_id = client . messages . create (
thread_id : thread_id ,
parameters : {
role : "user" , # Required for manually created messages
content : "Can you help me write an API library to interact with the OpenAI API please?"
}
) [ "id" ]
# Retrieve individual message
message = client . messages . retrieve ( thread_id : thread_id , id : message_id )
# Review all messages on the thread
messages = client . messages . list ( thread_id : thread_id )
Очистить после того, как нить больше не нужна:
# To delete the thread (and all associated messages):
client . threads . delete ( id : thread_id )
client . messages . retrieve ( thread_id : thread_id , id : message_id ) # -> Fails after thread is deleted
Чтобы отправить поток для оценки с моделью помощника, создайте Run
следующим образом:
# Create run (will use instruction/model/tools from Assistant's definition)
response = client . runs . create (
thread_id : thread_id ,
parameters : {
assistant_id : assistant_id ,
max_prompt_tokens : 256 ,
max_completion_tokens : 16
}
)
run_id = response [ 'id' ]
Вы можете транслировать куски сообщения, когда они проходят через:
client . runs . create (
thread_id : thread_id ,
parameters : {
assistant_id : assistant_id ,
max_prompt_tokens : 256 ,
max_completion_tokens : 16 ,
stream : proc do | chunk , _bytesize |
if chunk [ "object" ] == "thread.message.delta"
print chunk . dig ( "delta" , "content" , 0 , "text" , "value" )
end
end
}
)
Чтобы получить статус пробега:
response = client . runs . retrieve ( id : run_id , thread_id : thread_id )
status = response [ 'status' ]
Ответ status
может включать в себя следующие строки queued
, in_progress
, requires_action
, cancelling
, cancelled
, failed
, completed
или expired
, что вы можете обрабатывать следующим образом:
while true do
response = client . runs . retrieve ( id : run_id , thread_id : thread_id )
status = response [ 'status' ]
case status
when 'queued' , 'in_progress' , 'cancelling'
puts 'Sleeping'
sleep 1 # Wait one second and poll again
when 'completed'
break # Exit loop and report result to user
when 'requires_action'
# Handle tool calls (see below)
when 'cancelled' , 'failed' , 'expired'
puts response [ 'last_error' ] . inspect
break # or `exit`
else
puts "Unknown status response: #{ status } "
end
end
Если ответ status
указывает на то, что run
completed
, связанный thread
будет иметь одно или несколько новых messages
:
# Either retrieve all messages in bulk again, or...
messages = client . messages . list ( thread_id : thread_id , parameters : { order : 'asc' } )
# Alternatively retrieve the `run steps` for the run which link to the messages:
run_steps = client . run_steps . list ( thread_id : thread_id , run_id : run_id , parameters : { order : 'asc' } )
new_message_ids = run_steps [ 'data' ] . filter_map do | step |
if step [ 'type' ] == 'message_creation'
step . dig ( 'step_details' , "message_creation" , "message_id" )
end # Ignore tool calls, because they don't create new messages.
end
# Retrieve the individual messages
new_messages = new_message_ids . map do | msg_id |
client . messages . retrieve ( id : msg_id , thread_id : thread_id )
end
# Find the actual response text in the content array of the messages
new_messages . each do | msg |
msg [ 'content' ] . each do | content_item |
case content_item [ 'type' ]
when 'text'
puts content_item . dig ( 'text' , 'value' )
# Also handle annotations
when 'image_file'
# Use File endpoint to retrieve file contents via id
id = content_item . dig ( 'image_file' , 'file_id' )
end
end
end
Вы также можете обновить метаданные на сообщениях, включая сообщения, которые поступают от помощника.
metadata = {
user_id : "abc123"
}
message = client . messages . modify (
id : message_id ,
thread_id : thread_id ,
parameters : { metadata : metadata } ,
)
В любое время вы можете перечислить все прогоны, которые были выполнены в конкретном потоке или в настоящее время работают:
client . runs . list ( thread_id : thread_id , parameters : { order : "asc" , limit : 3 } )
Вы также можете создать ветку и запустить в одном вызове, как это:
response = client . runs . create_thread_and_run ( parameters : { assistant_id : assistant_id } )
run_id = response [ 'id' ]
thread_id = response [ 'thread_id' ]
Вы можете включить изображения в ветку, и они будут описаны и прочитаны LLM. В этом примере я использую этот файл:
require "openai"
# Make a client
client = OpenAI :: Client . new (
access_token : "access_token_goes_here" ,
log_errors : true # Don't log errors in production.
)
# Upload image as a file
file_id = client . files . upload (
parameters : {
file : "path/to/example.png" ,
purpose : "assistants" ,
}
) [ "id" ]
# Create assistant (You could also use an existing one here)
assistant_id = client . assistants . create (
parameters : {
model : "gpt-4o" ,
name : "Image reader" ,
instructions : "You are an image describer. You describe the contents of images." ,
}
) [ "id" ]
# Create thread
thread_id = client . threads . create [ "id" ]
# Add image in message
client . messages . create (
thread_id : thread_id ,
parameters : {
role : "user" , # Required for manually created messages
content : [
{
"type" : "text" ,
"text" : "What's in this image?"
} ,
{
"type" : "image_file" ,
"image_file" : { "file_id" : file_id }
}
]
}
)
# Run thread
run_id = client . runs . create (
thread_id : thread_id ,
parameters : { assistant_id : assistant_id }
) [ "id" ]
# Wait until run in complete
status = nil
until status == "completed" do
sleep ( 0.1 )
status = client . runs . retrieve ( id : run_id , thread_id : thread_id ) [ 'status' ]
end
# Get the response
messages = client . messages . list ( thread_id : thread_id , parameters : { order : 'asc' } )
messages . dig ( "data" , - 1 , "content" , 0 , "text" , "value" )
=> "The image contains a placeholder graphic with a tilted, stylized representation of a postage stamp in the top part, which includes an abstract landscape with hills and a sun. Below the stamp, in the middle of the image, there is italicized text in a light golden color that reads, " This is just an example. " The background is a light pastel shade, and a yellow border frames the entire image."
Если вы позволяете помощнику получить доступ к инструментам function
(они определяются так же, как и функции во время завершения чата), вы можете получить код состояния requires_action
когда помощник хочет, чтобы вы оценили один или несколько инструментов функции:
def get_current_weather ( location : , unit : "celsius" )
# Your function code goes here
if location =~ /San Francisco/i
return unit == "celsius" ? "The weather is nice ? at 27°C" : "The weather is nice ? at 80°F"
else
return unit == "celsius" ? "The weather is icy ? at -5°C" : "The weather is icy ? at 23°F"
end
end
if status == 'requires_action'
tools_to_call = response . dig ( 'required_action' , 'submit_tool_outputs' , 'tool_calls' )
my_tool_outputs = tools_to_call . map { | tool |
# Call the functions based on the tool's name
function_name = tool . dig ( 'function' , 'name' )
arguments = JSON . parse (
tool . dig ( "function" , "arguments" ) ,
{ symbolize_names : true } ,
)
tool_output = case function_name
when "get_current_weather"
get_current_weather ( ** arguments )
end
{
tool_call_id : tool [ 'id' ] ,
output : tool_output ,
}
}
client . runs . submit_tool_outputs (
thread_id : thread_id ,
run_id : run_id ,
parameters : { tool_outputs : my_tool_outputs }
)
end
Обратите внимание, что у вас есть 10 минут, чтобы отправить вывод инструмента до истечения срока действия.
Сделайте глубокий вдох. Вам может понадобиться выпить для этого.
OpenAI может поделиться тем, какие куски он использовал во внутреннем тряпком трубопроводе, чтобы создать свои результаты файла.
Пример спецификации можно найти здесь, которая делает это, просто чтобы вы знали, что это возможно.
Вот как использовать куски в поиске файлов. В этом примере я использую этот файл:
require "openai"
# Make a client
client = OpenAI :: Client . new (
access_token : "access_token_goes_here" ,
log_errors : true # Don't log errors in production.
)
# Upload your file(s)
file_id = client . files . upload (
parameters : {
file : "path/to/somatosensory.pdf" ,
purpose : "assistants"
}
) [ "id" ]
# Create a vector store to store the vectorised file(s)
vector_store_id = client . vector_stores . create ( parameters : { } ) [ "id" ]
# Vectorise the file(s)
vector_store_file_id = client . vector_store_files . create (
vector_store_id : vector_store_id ,
parameters : { file_id : file_id }
) [ "id" ]
# Check that the file is vectorised (wait for status to be "completed")
client . vector_store_files . retrieve ( vector_store_id : vector_store_id , id : vector_store_file_id ) [ "status" ]
# Create an assistant, referencing the vector store
assistant_id = client . assistants . create (
parameters : {
model : "gpt-4o" ,
name : "Answer finder" ,
instructions : "You are a file search tool. Find the answer in the given files, please." ,
tools : [
{ type : "file_search" }
] ,
tool_resources : {
file_search : {
vector_store_ids : [ vector_store_id ]
}
}
}
) [ "id" ]
# Create a thread with your question
thread_id = client . threads . create ( parameters : {
messages : [
{ role : "user" ,
content : "Find the description of a nociceptor." }
]
} ) [ "id" ]
# Run the thread to generate the response. Include the "GIVE ME THE CHUNKS" incantation.
run_id = client . runs . create (
thread_id : thread_id ,
parameters : {
assistant_id : assistant_id
} ,
query_parameters : { include : [ "step_details.tool_calls[*].file_search.results[*].content" ] } # incantation
) [ "id" ]
# Get the steps that happened in the run
steps = client . run_steps . list (
thread_id : thread_id ,
run_id : run_id ,
parameters : { order : "asc" }
)
# Retrieve all the steps. Include the "GIVE ME THE CHUNKS" incantation again.
steps = steps [ "data" ] . map do | step |
client . run_steps . retrieve (
thread_id : thread_id ,
run_id : run_id ,
id : step [ "id" ] ,
parameters : { include : [ "step_details.tool_calls[*].file_search.results[*].content" ] } # incantation
)
end
# Now we've got the chunk info, buried deep. Loop through the steps and find chunks if included:
chunks = steps . flat_map do | step |
included_results = step . dig ( "step_details" , "tool_calls" , 0 , "file_search" , "results" )
next if included_results . nil? || included_results . empty?
included_results . flat_map do | result |
result [ "content" ] . map do | content |
content [ "text" ]
end
end
end . compact
# The first chunk will be the closest match to the prompt. Finally, if you want to view the completed message(s):
client . messages . list ( thread_id : thread_id )
Создайте изображения, используя Dall · E 2 или Dall · E 3!
Для Dall · e 2 размер любых сгенерированных изображений должен быть одним из 256x256
, 512x512
или 1024x1024
- если не указано, изображение будет по умолчанию до 1024x1024
.
response = client . images . generate (
parameters : {
prompt : "A baby sea otter cooking pasta wearing a hat of some sort" ,
size : "256x256" ,
}
)
puts response . dig ( "data" , 0 , "url" )
# => "https://oaidalleapiprodscus.blob.core.windows.net/private/org-Rf437IxKhh..."
Для Dall · E 3 размер любых сгенерированных изображений должен быть одним из 1024x1024
, 1024x1792
или 1792x1024
. Кроме того, качество изображения может быть указано как standard
, так и hd
.
response = client . images . generate (
parameters : {
prompt : "A springer spaniel cooking pasta wearing a hat of some sort" ,
model : "dall-e-3" ,
size : "1024x1792" ,
quality : "standard" ,
}
)
puts response . dig ( "data" , 0 , "url" )
# => "https://oaidalleapiprodscus.blob.core.windows.net/private/org-Rf437IxKhh..."
Заполните прозрачную часть изображения или загрузите маску с прозрачными разделами, чтобы указать части изображения, которые можно изменить в соответствии с вашей подсказкой ...
response = client . images . edit (
parameters : {
prompt : "A solid red Ruby on a blue background" ,
image : "image.png" ,
mask : "mask.png" ,
}
)
puts response . dig ( "data" , 0 , "url" )
# => "https://oaidalleapiprodscus.blob.core.windows.net/private/org-Rf437IxKhh..."
Создать n вариаций изображения.
response = client . images . variations ( parameters : { image : "image.png" , n : 2 } )
puts response . dig ( "data" , 0 , "url" )
# => "https://oaidalleapiprodscus.blob.core.windows.net/private/org-Rf437IxKhh..."
Передайте строку, чтобы проверить, нарушает ли она политика контента Openai:
response = client . moderations ( parameters : { input : "I'm worried about that." } )
puts response . dig ( "results" , 0 , "category_scores" , "hate" )
# => 5.505014632944949e-05
Whisper - это модель речи к текстовым
API переводов принимает в качестве ввода аудиофайл на любом из поддерживаемых языков и транскрибирует звук на английский.
response = client . audio . translate (
parameters : {
model : "whisper-1" ,
file : File . open ( "path_to_file" , "rb" ) ,
}
)
puts response [ "text" ]
# => "Translation of the text"
API транскрипции принимает ввод аудиофайл, который вы хотите транскрибировать, и возвращает текст в нужном формате выходного файла.
Вы можете передать язык аудиофайла, чтобы улучшить качество транскрипции. Поддерживаемые языки перечислены здесь. Вы должны предоставить язык в качестве кода ISO-639-1, например. "en" для английского или "ne" для непальских. Вы можете посмотреть коды здесь.
response = client . audio . transcribe (
parameters : {
model : "whisper-1" ,
file : File . open ( "path_to_file" , "rb" ) ,
language : "en" , # Optional
}
)
puts response [ "text" ]
# => "Transcription of the text"
API речи принимает ввод текста и голоса и возвращает контент аудиофайла, который вы можете прослушать.
response = client . audio . speech (
parameters : {
model : "tts-1" ,
input : "This is a speech test!" ,
voice : "alloy" ,
response_format : "mp3" , # Optional
speed : 1.0 , # Optional
}
)
File . binwrite ( 'demo.mp3' , response )
# => mp3 file that plays: "This is a speech test!"
Ошибки HTTP можно поймать так:
begin
OpenAI :: Client . new . models . retrieve ( id : "gpt-4o" )
rescue Faraday :: Error => e
raise "Got a Faraday error: #{ e } "
end
После проверки репо, запустите bin/setup
для установки зависимостей. Вы можете запустить bin/console
для интерактивной подсказки, которая позволит вам экспериментировать.
Чтобы установить этот драгоценный камень на локальную машину, запустите bundle exec rake install
.
Чтобы запустить все тесты, выполните bundle exec rake
, который также запустит Linter (Rubocop). Этот репозиторий использует VCR для запросов API log.
Предупреждение
Если у вас есть OPENAI_ACCESS_TOKEN
в вашей ENV
, запуск спецификаций будет использовать это для запуска спецификаций против фактического API, который будет медленным и будет стоить вам денег - 2 цента или более! Удалите его из своей среды с помощью unset
или аналогичного, если вы просто хотите запустить спецификации против хранимых ответов в видеомагнитофонах.
Сначала запустите спецификации без видеомагнитофоны, чтобы они фактически попали в API. Это будет стоить 2 цента или более. Установите OpenAI_ACCESS_TOKEN в вашей среде или передайте его так:
OPENAI_ACCESS_TOKEN=123abc bundle exec rspec
Затем обновите номер версии в version.rb
, обновление CHANGELOG.md
, запустите bundle install
для обновления gemfile.lock, а затем запустите bundle exec rake release
, который создаст тег GIT для версии, нажимайте GIT Commits и Tags и нажмите Файл .gem
на rubygems.org.
Отчеты об ошибках и запросы на тягу приветствуются на GitHub по адресу https://github.com/alexrudall/ruby-openai. Этот проект предназначен для безопасного, гостеприимного места для сотрудничества, и ожидается, что участники будут придерживаться кодекса поведения.
Драгоценный камень доступен в качестве открытого исходного кода в соответствии с условиями лицензии MIT.
Ожидается, что все, кто взаимодействует в кодовых базах проекта Ruby Openai, трекеров выпуска, чат и списках рассылки.