Use a API Openai com Ruby! ? ❤️
Texto de transmissão com GPT-4O, transcreva e traduz áudio com sussurro ou crie imagens com dall · e ...
Contrate -me para construir seus Rails+AI Ap App | Trilhos ai | ? Ruby AI Builders Discord | ? X | ? Gem Antrópica | ? Midjourney Gem
Adicione esta linha ao GemFile do seu aplicativo:
gem "ruby-openai"E depois execute:
$ bundle installOu instalar com:
$ gem install ruby-openaie exigir com:
require "openai" Para um teste rápido, você pode passar seu token diretamente para um novo cliente:
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.
) Para uma configuração mais robusta, você pode configurar a gema com suas teclas de API, por exemplo, em um arquivo inicializador openai.rb . Nunca segredos de código hardcodes na sua base de código - em vez disso, use algo como o dotenv para passar as chaves em segurança em seus ambientes.
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.
endEntão você pode criar um cliente como este:
client = OpenAI :: Client . newVocê ainda pode substituir os padrões de configuração ao criar novos clientes; Quaisquer opções não incluídas voltarão a qualquer conjunto de configurações globais com o OpenAI.Configure. Por exemplo, neste exemplo, o Organization_ID, Request_Timeout, etc. Fallback de qualquer conjunto globalmente usando o OpenAI.Configure, com apenas o substituto Access_Token:
client = OpenAI :: Client . new ( access_token : "access_token_goes_here" ) request_timeout ao inicializar o cliente. 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
}
)ou ao configurar a jóia:
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 Você pode passar dinamicamente cabeçalhos por objeto cliente, que será mesclado com qualquer cabeçalho definido globalmente com o OpenAi.configure:
client = OpenAI :: Client . new ( access_token : "access_token_goes_here" )
client . add_headers ( "X-Proxy-TTL" => "43200" ) Por padrão, ruby-openai não registra nenhum erro de Faraday::Error Faraday::Error o que pode causá -los).
Se você deseja ativar essa funcionalidade, pode definir log_errors como true ao configurar o cliente:
client = OpenAI :: Client . new ( log_errors : true ) Você pode passar o Middleware Faraday para o cliente em um bloco, por exemplo. Para ativar o logbose de registro com o madeireiro de Ruby:
client = OpenAI :: Client . new do | f |
f . response :logger , Logger . new ( $stdout ) , bodies : true
end Para usar a API de serviço do Azure Openai, você pode configurar a jóia assim:
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 Onde AZURE_OPENAI_URI é por exemplo, https://custom-domain.openai.azure.com/openai/deployments/gpt-35-turbo
Ollama permite que você execute LLMs de código aberto, como LLAMA 3, localmente. Oferece compatibilidade com a API do OpenAI.
Você pode baixar o Ollama aqui. No macOS, você pode instalar e executar o ollama assim:
brew install ollama
ollama serve
ollama pull llama3:latest # In new terminal tab.Crie um cliente usando o seu servidor ollama e o modelo puxado e transmita uma conversa gratuitamente:
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? O chat da API Groq é amplamente compatível com a API OpenAI, com algumas pequenas diferenças. Obtenha um token de acesso a partir daqui, então:
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
}
) Open Pareses Promot um texto em tokens, que são palavras ou partes das palavras. (Esses tokens não estão relacionados ao seu API Access_Token.) A contagem de tokens pode ajudá -lo a estimar seus custos. Também pode ajudá-lo a garantir que o tamanho do seu texto rápido esteja dentro dos limites máximos da janela de contexto do seu modelo e escolha um parâmetro de conclusão max_tokens apropriado para que sua resposta também se encaixe.
Para estimar a contagem de token do seu texto:
OpenAI . rough_token_count ( "Your text" )Se você precisar de uma contagem mais precisa, tente Tiktoken_ruby.
Existem diferentes modelos que podem ser usados para gerar texto. Para uma lista completa e para recuperar informações sobre um único modelo:
client . models . list
client . models . retrieve ( id : "gpt-4o" )O GPT é um modelo que pode ser usado para gerar texto em um estilo de conversação. Você pode usá -lo para gerar uma resposta a uma sequência de mensagens:
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?" Guia rápido para transmitir bate -papo com Rails 7 e Hotwire
Você pode transmitir a partir da API em tempo real, que pode ser muito mais rápida e usada para criar uma experiência mais envolvente do usuário. Passe um PROC (ou qualquer objeto com um método #call ) para o parâmetro stream para receber o fluxo de pedaços de conclusão à medida que são gerados. Cada vez que um ou mais pedaços é recebido, o PROC será chamado uma vez a cada pedaço, analisado como um hash. Se o OpenAI retornar um erro, ruby-openai levantará um erro de 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..." Nota: Para obter informações de uso, você pode fornecer o parâmetro stream_options e o OpenAI fornecerá um pedaço final com o uso. Aqui está um exemplo:
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}} Você pode usar o modelo de visão GPT-4 para gerar uma descrição de uma imagem:
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" Você pode definir o Response_Format para pedir respostas no 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
# }Você pode transmitir isso também!
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"
# }
# }
# } Você pode descrever e passar nas funções e o modelo escolherá de forma inteligente produzir um objeto JSON contendo argumentos para chamá -los - por exemplo, usar seu método get_current_weather para obter o clima em um determinado local. Observe que Tool_choice é opcional, mas se você o excluir, o modelo escolherá se deve usar ou não a função (veja aqui).
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."Bata na API Openai para uma conclusão usando outros modelos 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"]Você pode usar o endpoint de incorporação para obter um vetor de números representando uma entrada. Você pode comparar esses vetores para obter diferentes entradas para verificar com eficiência como as entradas são semelhantes.
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 O ponto final dos lotes permite criar e gerenciar grandes lotes de solicitações de API para executar de forma assíncrona. Atualmente, os pontos de extremidade suportados para lotes são /v1/chat/completions (API de conclusão de bate -papo) e /v1/embeddings (API de incorporação).
Para usar o ponto final dos lotes, você precisa primeiro fazer upload de um arquivo JSONL contendo as solicitações de lotes usando o terminal de arquivos. O arquivo deve ser carregado com o objetivo definido para batch . Cada linha no arquivo jsonl representa uma única solicitação e deve ter o seguinte formato:
{
"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? " }
]
}
}Depois de enviar o arquivo jsonl, você pode criar um novo lote, fornecendo o ID do arquivo, o terminal e a janela de conclusão:
response = client . batches . create (
parameters : {
input_file_id : "file-abc123" ,
endpoint : "/v1/chat/completions" ,
completion_window : "24h"
}
)
batch_id = response [ "id" ]Você pode recuperar informações sobre um lote específico usando seu ID:
batch = client . batches . retrieve ( id : batch_id )Para cancelar um lote que está em andamento:
client . batches . cancel ( id : batch_id )Você também pode listar todos os lotes:
client . batches . listDepois que o lote ["complete_at"] estiver presente, você pode buscar os arquivos de saída ou erro:
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 )Esses arquivos estão no formato JSONL, com cada linha representando a saída ou erro para uma única solicitação. As linhas podem estar em qualquer ordem:
{
"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. "
}
}
]
}
}Se uma solicitação falhar com um erro não HTTP, o objeto de erro conterá mais informações sobre a causa da falha.
Coloque seus dados em um arquivo .jsonl como este:
{ "prompt" : " Overjoyed with my new phone! -> " , "completion" : " positive " }
{ "prompt" : " @lakers disappoint for a third straight night -> " , "completion" : " negative " } e passe o caminho (ou um objeto stringio) para client.files.upload para carregá -lo para o OpenAI e, em seguida, interaja com ele:
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" ) Você pode enviar um caminho de arquivo:
client . files . upload ( parameters : { file : "path/to/file.pdf" , purpose : "assistants" } )ou um objeto de arquivo
my_file = File . open ( "path/to/file.pdf" , "rb" )
client . files . upload ( parameters : { file : my_file , purpose : "assistants" } )Consulte Tipos de arquivo suportados na documentação da API.
Carregue seus dados de ajuste fino em um arquivo .jsonl como acima e obtenha seu ID:
response = client . files . upload ( parameters : { file : "path/to/sarcasm.jsonl" , purpose : "fine-tune" } )
file_id = JSON . parse ( response . body ) [ "id" ]Você pode usar este ID do arquivo para criar um trabalho de ajuste fino:
response = client . finetunes . create (
parameters : {
training_file : file_id ,
model : "gpt-4o"
} )
fine_tune_id = response [ "id" ]Isso lhe dará o ID de ajuste fino. Se você cometeu um erro, pode cancelar o modelo de ajuste fino antes de ser processado:
client . finetunes . cancel ( id : fine_tune_id )Pode ser necessário esperar um curto período de tempo para o processamento ser concluído. Depois de processado, você pode usar a lista ou recuperar para obter o nome do modelo ajustado:
client . finetunes . list
response = client . finetunes . retrieve ( id : fine_tune_id )
fine_tuned_model = response [ "fine_tuned_model" ]Este nome do modelo ajustado pode ser usado nas conclusões do bate-papo:
response = client . chat (
parameters : {
model : fine_tuned_model ,
messages : [ { role : "user" , content : "I love Mondays!" } ]
}
)
response . dig ( "choices" , 0 , "message" , "content" )Você também pode capturar os eventos para um emprego:
client . finetunes . list_events ( id : fine_tune_id )Os objetos do Vector Store fornecem à ferramenta de pesquisa de arquivos a capacidade de pesquisar seus arquivos.
Você pode criar uma nova loja de vetores:
response = client . vector_stores . create (
parameters : {
name : "my vector store" ,
file_ids : [ "file-abc123" , "file-def456" ]
}
)
vector_store_id = response [ "id" ] Dado um vector_store_id você pode retrieve os valores atuais do campo:
client . vector_stores . retrieve ( id : vector_store_id ) Você pode obter uma list de todas as lojas de vetores atualmente disponíveis na organização:
client . vector_stores . list Você pode modificar uma loja de vetores existente, exceto os file_ids :
response = client . vector_stores . modify (
id : vector_store_id ,
parameters : {
name : "Modified Test Vector Store" ,
}
)Você pode excluir lojas vetoriais:
client . vector_stores . delete ( id : vector_store_id )Os arquivos do Vector Store representam arquivos dentro de uma loja de vetores.
Você pode criar um novo arquivo de loja de vetores anexando um arquivo a uma loja de vetores.
response = client . vector_store_files . create (
vector_store_id : "vector-store-abc123" ,
parameters : {
file_id : "file-abc123"
}
)
vector_store_file_id = response [ "id" ] Dado um vector_store_file_id você pode retrieve os valores atuais do campo:
client . vector_store_files . retrieve (
vector_store_id : "vector-store-abc123" ,
id : vector_store_file_id
) Você pode obter uma list de todos os arquivos do Vector Store atualmente disponíveis no Vector Store:
client . vector_store_files . list ( vector_store_id : "vector-store-abc123" )Você pode excluir um arquivo de loja de vetores:
client . vector_store_files . delete (
vector_store_id : "vector-store-abc123" ,
id : vector_store_file_id
)NOTA: Isso removerá o arquivo do armazenamento do vetor, mas o próprio arquivo não será excluído. Para excluir o arquivo, use o terminal de exclusão do arquivo.
O Vector Store File Luts representa operações para adicionar vários arquivos a um loja de vetores.
Você pode criar um novo lote de arquivo de loja de vetores, anexando vários arquivos a um loja de vetores.
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" ] Dado um file_batch_id você pode retrieve os valores atuais do campo:
client . vector_store_file_batches . retrieve (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
) Você pode obter uma list de todos os arquivos do Vector Store em um lote atualmente disponível no Vector Store:
client . vector_store_file_batches . list (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
)Você pode cancelar um lote de arquivos do Vector Store (isso tenta cancelar o processamento de arquivos neste lote o mais rápido possível):
client . vector_store_file_batches . cancel (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
)Os assistentes são atores com estado que podem ter muitas conversas e usar ferramentas para executar tarefas (consulte a visão geral do assistente).
Para criar um novo assistente:
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" ] Dado um assistant_id você pode retrieve os valores atuais do campo:
client . assistants . retrieve ( id : assistant_id ) Você pode obter uma list de todos os assistentes atualmente disponíveis na organização:
client . assistants . listVocê pode modificar um assistente existente usando o ID do assistente (consulte a documentação da API):
response = client . assistants . modify (
id : assistant_id ,
parameters : {
name : "Modified Test Assistant for OpenAI-Ruby" ,
metadata : { my_internal_version_id : '1.0.1' }
}
)Você pode excluir assistentes:
client . assistants . delete ( id : assistant_id ) Depois de criar um assistente conforme descrito acima, você precisa preparar um Thread de Messages para o assistente trabalhar (consulte Introdução aos assistentes). Por exemplo, como uma configuração inicial, você pode fazer:
# 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 )Para limpar depois que um tópico não é mais necessário:
# 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 Para enviar um tópico a ser avaliado com o modelo de um assistente, crie uma Run da seguinte maneira:
# 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' ]Você pode transmitir os pedaços de mensagem à medida que eles passam:
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
}
)Para obter o status de uma corrida:
response = client . runs . retrieve ( id : run_id , thread_id : thread_id )
status = response [ 'status' ] A resposta status pode incluir as seguintes cordas queued , in_progress , requires_action , cancelling , cancelled , failed , completed ou expired com o que você pode manusear da seguinte forma:
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 Se a resposta status indicar que a run for completed , o thread associado terá uma ou mais novas messages anexadas:
# 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
endVocê também pode atualizar os metadados nas mensagens, incluindo mensagens provenientes do assistente.
metadata = {
user_id : "abc123"
}
message = client . messages . modify (
id : message_id ,
thread_id : thread_id ,
parameters : { metadata : metadata } ,
)A qualquer momento, você pode listar todas as execuções que foram realizadas em um tópico específico ou estão em execução atualmente:
client . runs . list ( thread_id : thread_id , parameters : { order : "asc" , limit : 3 } ) Você também pode criar um tópico e executar em uma chamada assim:
response = client . runs . create_thread_and_run ( parameters : { assistant_id : assistant_id } )
run_id = response [ 'id' ]
thread_id = response [ 'thread_id' ] Você pode incluir imagens em um thread e elas serão descritas e lidas pelo LLM. Neste exemplo, estou usando este arquivo:
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." Caso você esteja permitindo que o assistente acesse as ferramentas function (elas são definidas da mesma maneira que as funções durante a conclusão do bate -papo), você pode obter um código de status de requires_action quando o assistente deseja que você avalie uma ou mais ferramentas de função:
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 }
)
endObserve que você tem 10 minutos para enviar a saída da sua ferramenta antes que a execução expire.
Respire fundo. Você pode precisar de uma bebida para este.
É possível para o OpenAi compartilhar quais partes usadas em seu pipeline RAG interno para criar seus resultados de pesquisa de arquivos.
Um exemplo de especificação pode ser encontrado aqui que faz isso, apenas para que você saiba que é possível.
Veja como usar os pedaços usados em uma pesquisa de arquivo. Neste exemplo, estou usando este arquivo:
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 )Gere imagens usando Dall · E 2 ou Dall · E 3!
Para Dall · E 2, o tamanho de qualquer imagens geradas deve ser uma das 256x256 , 512x512 ou 1024x1024 - se não for especificada, a imagem será padrão para 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..." Para Dall · E 3, o tamanho de qualquer imagens geradas deve ser uma das 1024x1024 , 1024x1792 ou 1792x1024 . Além disso, a qualidade da imagem pode ser especificada para standard ou 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..."Preencha a parte transparente de uma imagem ou faça o upload de uma máscara com seções transparentes para indicar as partes de uma imagem que pode ser alterada de acordo com o seu prompt ...
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..."Crie n variações de uma imagem.
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..."Passe uma string para verificar se viola a política de conteúdo da OpenAI:
response = client . moderations ( parameters : { input : "I'm worried about that." } )
puts response . dig ( "results" , 0 , "category_scores" , "hate" )
# => 5.505014632944949e-05Whisper é um modelo de fala para texto que pode ser usado para gerar texto com base em arquivos de áudio:
A API de traduções toma como entrada o arquivo de áudio em qualquer um dos idiomas suportados e transcreve o áudio para o inglês.
response = client . audio . translate (
parameters : {
model : "whisper-1" ,
file : File . open ( "path_to_file" , "rb" ) ,
}
)
puts response [ "text" ]
# => "Translation of the text" A API de transcrições toma como entrada o arquivo de áudio que você deseja transcrever e retorna o texto no formato de arquivo de saída desejado.
Você pode passar no idioma do arquivo de áudio para melhorar a qualidade da transcrição. Os idiomas suportados estão listados aqui. Você precisa fornecer o idioma como um código ISO-639-1, por exemplo. "EN" para inglês ou "NE" para o nepalês. Você pode procurar os códigos aqui.
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" A API de fala toma como entrada o texto e uma voz e retorna o conteúdo de um arquivo de áudio que você pode ouvir.
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!"Os erros de HTTP podem ser capturados assim:
begin
OpenAI :: Client . new . models . retrieve ( id : "gpt-4o" )
rescue Faraday :: Error => e
raise "Got a Faraday error: #{ e } "
end Depois de verificar o repositório, execute bin/setup para instalar dependências. Você pode executar bin/console para um prompt interativo que permitirá experimentar.
Para instalar esta gema na sua máquina local, execute bundle exec rake install .
Para executar todos os testes, execute o comando bundle exec rake , que também executará o Linter (Rubocop). Este repositório usa videocassete para registrar solicitações de API.
Aviso
Se você tiver um OPENAI_ACCESS_TOKEN em seu ENV , executar as especificações usará isso para executar as especificações em relação à API real, que será lenta e custará dinheiro - 2 centavos ou mais! Remova -o do seu ambiente com unset ou similar se você deseja executar as especificações nas respostas de videocassete armazenadas.
Primeiro, execute as especificações sem videocassete para que elas realmente atinjam a API. Isso custará 2 centavos ou mais. Defina o OpenAI_ACCESS_TOKen em seu ambiente ou passe assim:
OPENAI_ACCESS_TOKEN=123abc bundle exec rspec
Em seguida, atualize o número da versão no version.rb , atualize CHANGELOG.md , execute bundle install para atualizar o gemfile.lock e, em seguida, execute bundle exec rake release , que criará uma tag git para a versão, push git comete e tags e empurre O arquivo .gem para rubygems.org.
Relatórios de bug e solicitações de tração são bem-vindos no Github em https://github.com/alexrudall/ruby-openai. Este projeto deve ser um espaço seguro e acolhedor para a colaboração, e os colaboradores devem aderir ao Código de Conduta.
A GEM está disponível como código aberto nos termos da licença do MIT.
Todos interagindo nas bases de código do Ruby Openai Project, rastreadores, salas de bate -papo e listas de discussão devem seguir o código de conduta.