¡Usa la API de OpenAI con Ruby! ? ❤️
Transmitir texto con GPT-4O, transcribir y traducir audio con Whisper, o crear imágenes con Dall · E ...
Contratame para construir tus rieles+aplicación Ai | Rails ai | ? Ruby AI Builders Discord | ? X | ? Gema antrópica | ? Joya de mediana
Agregue esta línea al archivo gem de su aplicación:
gem "ruby-openai"Y luego ejecutar:
$ bundle installO instalar con:
$ gem install ruby-openaiy requerir con:
require "openai" Para una prueba rápida, puede pasar su token directamente a un nuevo 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 una configuración más robusta, puede configurar la gema con sus claves API, por ejemplo, en un archivo inicializador openai.rb . Nunca codifique los secretos en su base de código; en su lugar, use algo como Dotenv para pasar las claves de manera segura a sus entornos.
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.
endEntonces puede crear un cliente como este:
client = OpenAI :: Client . newTodavía puede anular los valores predeterminados de configuración al hacer nuevos clientes; Cualquier opción que no se incluya volverá a cualquier conjunto de configuración global con OpenAI.Configure. Por ejemplo, en este ejemplo, la organización_id, request_timeout, etc. se retirará a cualquier conjunto a nivel mundial usando OpenAI.Configure, con solo el access_token anulado:
client = OpenAI :: Client . new ( access_token : "access_token_goes_here" ) request_timeout al inicializar el 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
}
)o al configurar la gema:
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 Puede pasar dinámicamente encabezados por objeto cliente, que se fusionará con cualquier encabezado establecido a nivel mundial con OpenAI.Configure:
client = OpenAI :: Client . new ( access_token : "access_token_goes_here" )
client . add_headers ( "X-Proxy-TTL" => "43200" ) Por defecto, ruby-openai no registra ningún Faraday::Error S encontrado mientras ejecuta una solicitud de red para evitar fugas de datos (por ejemplo, 400, 500, errores SSL y más, consulte aquí para obtener una lista completa de subclases de Faraday::Error y lo que puede causarlos).
Si desea habilitar esta funcionalidad, puede configurar log_errors en true al configurar el cliente:
client = OpenAI :: Client . new ( log_errors : true ) Puede pasar el middleware Faraday al cliente en un bloque, por ejemplo. Para habilitar el registro verboso con el registrador de Ruby:
client = OpenAI :: Client . new do | f |
f . response :logger , Logger . new ( $stdout ) , bodies : true
end Para usar la API del servicio Azure OpenAI, puede configurar la gema como esta:
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 Donde AZURE_OPENAI_URI es, por ejemplo, https://custom-domain.openai.azure.com/openai/deployments/gpt-35-turbo
Ollama le permite ejecutar LLM de código abierto, como Llama 3, localmente. Ofrece compatibilidad con chat con la API de OpenAI.
Puedes descargar ollama aquí. En MacOS puede instalar y ejecutar Ollama así:
brew install ollama
ollama serve
ollama pull llama3:latest # In new terminal tab.Cree un cliente usando su servidor Ollama y el modelo extraído, y transmita una conversación de forma gratuita:
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 Chat es ampliamente compatible con la API Operai, con algunas diferencias menores. Obtenga un token de acceso desde aquí, luego:
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 analiza el texto en tokens, que son palabras o porciones de palabras. (Estos tokens no están relacionados con su API Access_Token.) Contar tokens puede ayudarlo a estimar sus costos. También puede ayudarlo a garantizar que su tamaño de texto de inmediato esté dentro de los límites máximo de la ventana de contexto de su modelo, y elegir un parámetro de finalización max_tokens apropiado para que su respuesta también se ajuste.
Para estimar el conteo de token de su texto:
OpenAI . rough_token_count ( "Your text" )Si necesita un recuento más preciso, pruebe tiktoken_ruby.
Hay diferentes modelos que se pueden usar para generar texto. Para una lista completa y para recuperar información sobre un solo modelo:
client . models . list
client . models . retrieve ( id : "gpt-4o" )GPT es un modelo que se puede usar para generar texto en un estilo de conversación. Puede usarlo para generar una respuesta a una secuencia de mensajes:
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?" Guía rápida para transmitir chat con rieles 7 y hotwire
Puede transmitir desde la API en tiempo real, que puede ser mucho más rápido y utilizar para crear una experiencia de usuario más atractiva. Pase un Proc (o cualquier objeto con un método #call ) al parámetro stream para recibir el flujo de fragmentos de finalización a medida que se generan. Cada vez que se reciben uno o más fragmentos, el Proc se llamará una vez con cada fragmento, analizado como un hash. Si OpenAI devuelve un error, ruby-openai planteará un error 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 obtener información de uso, puede proporcionar el parámetro stream_options y OpenAI proporcionará un fragmento final con el uso. Aquí hay un ejemplo:
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}} Puede usar el modelo de visión GPT-4 para generar una descripción de una imagen:
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" Puede establecer la respuesta_format para solicitar respuestas en 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
# }¡Puedes transmitirlo también!
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"
# }
# }
# } Puede describir y transmitir funciones y el modelo optará de manera inteligente para generar un objeto JSON que contenga argumentos para llamarlos, por ejemplo, para usar su método get_current_weather para obtener el clima en una ubicación determinada. Tenga en cuenta que Tool_Choice es opcional, pero si lo excluye, el modelo elegirá si usar la función o no (ver aquí).
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."Llegue a la API de OpenAI para su finalización utilizando otros 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"]Puede usar el punto final de incrustaciones para obtener un vector de números que representa una entrada. Luego puede comparar estos vectores para diferentes entradas para verificar de manera eficiente cuán similares son las entradas.
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 El punto final de lotes le permite crear y administrar grandes lotes de solicitudes de API para ejecutar de manera asincrónica. Actualmente, los puntos finales compatibles para lotes son /v1/chat/completions (API de finalización de chat) y /v1/embeddings (API de incrustaciones).
Para usar el punto final de lotes, primero debe cargar un archivo JSONL que contenga las solicitudes de lotes utilizando el punto final de archivos. El archivo debe cargarse con el propósito establecido en batch . Cada línea en el archivo JSONL representa una sola solicitud y debe tener el siguiente 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? " }
]
}
}Una vez que haya cargado el archivo JSONL, puede crear un nuevo lote proporcionando la ID de archivo, el punto final y la ventana de finalización:
response = client . batches . create (
parameters : {
input_file_id : "file-abc123" ,
endpoint : "/v1/chat/completions" ,
completion_window : "24h"
}
)
batch_id = response [ "id" ]Puede recuperar información sobre un lote específico utilizando su ID:
batch = client . batches . retrieve ( id : batch_id )Para cancelar un lote que está en progreso:
client . batches . cancel ( id : batch_id )También puede enumerar todos los lotes:
client . batches . listUna vez que está presente el lote ["completado_at"], puede obtener los archivos de salida o error:
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 )Estos archivos están en formato JSONL, con cada línea que representa la salida o error para una sola solicitud. Las líneas pueden estar en cualquier orden:
{
"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. "
}
}
]
}
}Si una solicitud falla con un error no HTTP, el objeto de error contendrá más información sobre la causa de la falla.
Coloque sus datos en un archivo .jsonl como este:
{ "prompt" : " Overjoyed with my new phone! -> " , "completion" : " positive " }
{ "prompt" : " @lakers disappoint for a third straight night -> " , "completion" : " negative " } y pase la ruta (o un objeto Stringio) a client.files.upload para cargarla para OpenAi, e interactúe con ella:
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" ) Puede enviar una ruta de archivo:
client . files . upload ( parameters : { file : "path/to/file.pdf" , purpose : "assistants" } )o un objeto de archivo
my_file = File . open ( "path/to/file.pdf" , "rb" )
client . files . upload ( parameters : { file : my_file , purpose : "assistants" } )Consulte los tipos de archivos compatibles en la documentación de la API.
Cargue sus datos de ajuste fino en un archivo .jsonl como se indica anteriormente y obtenga su ID:
response = client . files . upload ( parameters : { file : "path/to/sarcasm.jsonl" , purpose : "fine-tune" } )
file_id = JSON . parse ( response . body ) [ "id" ]Luego puede usar esta ID de archivo para crear un trabajo de ajuste fino:
response = client . finetunes . create (
parameters : {
training_file : file_id ,
model : "gpt-4o"
} )
fine_tune_id = response [ "id" ]Eso te dará la identificación de ajuste fino. Si cometió un error, puede cancelar el modelo de ajuste fino antes de procesarse:
client . finetunes . cancel ( id : fine_tune_id )Es posible que deba esperar un poco de tiempo para que se complete el procesamiento. Una vez procesado, puede usar la lista o recuperar para obtener el nombre del modelo ajustado:
client . finetunes . list
response = client . finetunes . retrieve ( id : fine_tune_id )
fine_tuned_model = response [ "fine_tuned_model" ]Este nombre de modelo ajustado se puede usar en las finalizaciones de chat:
response = client . chat (
parameters : {
model : fine_tuned_model ,
messages : [ { role : "user" , content : "I love Mondays!" } ]
}
)
response . dig ( "choices" , 0 , "message" , "content" )También puede capturar los eventos para un trabajo:
client . finetunes . list_events ( id : fine_tune_id )Los objetos de la tienda vectorial le dan a la herramienta de búsqueda de archivos la capacidad de buscar en sus archivos.
Puede crear una nueva tienda vectorial:
response = client . vector_stores . create (
parameters : {
name : "my vector store" ,
file_ids : [ "file-abc123" , "file-def456" ]
}
)
vector_store_id = response [ "id" ] Dado un vector_store_id puede retrieve los valores de campo actuales:
client . vector_stores . retrieve ( id : vector_store_id ) Puede obtener una list de todas las tiendas Vector actualmente disponibles bajo la organización:
client . vector_stores . list Puede modificar una tienda vectorial existente, excepto el file_ids :
response = client . vector_stores . modify (
id : vector_store_id ,
parameters : {
name : "Modified Test Vector Store" ,
}
)Puede eliminar las tiendas Vector:
client . vector_stores . delete ( id : vector_store_id )Los archivos de la tienda vectorial representan archivos dentro de una tienda vectorial.
Puede crear un nuevo archivo de tienda vectorial adjuntando un archivo a una tienda vectorial.
response = client . vector_store_files . create (
vector_store_id : "vector-store-abc123" ,
parameters : {
file_id : "file-abc123"
}
)
vector_store_file_id = response [ "id" ] Dado un vector_store_file_id puede retrieve los valores de campo actuales:
client . vector_store_files . retrieve (
vector_store_id : "vector-store-abc123" ,
id : vector_store_file_id
) Puede obtener una list de todos los archivos Vector Store actualmente disponibles en Vector Store:
client . vector_store_files . list ( vector_store_id : "vector-store-abc123" )Puede eliminar un archivo de tienda vectorial:
client . vector_store_files . delete (
vector_store_id : "vector-store-abc123" ,
id : vector_store_file_id
)Nota: Esto eliminará el archivo de la tienda Vector, pero el archivo en sí no se eliminará. Para eliminar el archivo, use el punto final de eliminación del archivo.
Los lotes de archivos de la tienda vectorial representan operaciones para agregar múltiples archivos a una tienda vectorial.
Puede crear un nuevo lote de archivos de almacenamiento vectorial adjuntando múltiples archivos a una tienda vectorial.
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 un file_batch_id puede retrieve los valores de campo actuales:
client . vector_store_file_batches . retrieve (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
) Puede obtener una list de todos los archivos de la tienda Vector en un lote disponible actualmente en la tienda Vector:
client . vector_store_file_batches . list (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
)Puede cancelar un lote de archivo vectorial (esto intenta cancelar el procesamiento de archivos en este lote lo antes posible):
client . vector_store_file_batches . cancel (
vector_store_id : "vector-store-abc123" ,
id : file_batch_id
)Los asistentes son actores con estado que pueden tener muchas conversaciones y usar herramientas para realizar tareas (ver Descripción general del asistente).
Para crear un nuevo asistente:
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 un assistant_id , puede retrieve los valores de campo actuales:
client . assistants . retrieve ( id : assistant_id ) Puede obtener una list de todos los asistentes disponibles actualmente bajo la organización:
client . assistants . listPuede modificar un asistente existente utilizando la identificación del asistente (ver documentación de la API):
response = client . assistants . modify (
id : assistant_id ,
parameters : {
name : "Modified Test Assistant for OpenAI-Ruby" ,
metadata : { my_internal_version_id : '1.0.1' }
}
)Puede eliminar los asistentes:
client . assistants . delete ( id : assistant_id ) Una vez que haya creado un asistente como se describió anteriormente, debe preparar un Thread de Messages para que el asistente trabaje (ver Introducción en asistentes). Por ejemplo, como configuración inicial, puede hacer:
# 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 limpiar después de que ya no se necesita un hilo:
# 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 un hilo para ser evaluado con el modelo de un asistente, cree una Run de la siguiente manera:
# 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' ]Puede transmitir los fragmentos de mensaje a medida que avanzan:
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 obtener el estado de una ejecución:
response = client . runs . retrieve ( id : run_id , thread_id : thread_id )
status = response [ 'status' ] La respuesta status puede incluir las siguientes cadenas queued , in_progress , requires_action , cancelling , cancelled , failed , completed o expired que puede manejar de la siguiente manera:
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 Si la respuesta status indica que la run se completed , el thread asociado tendrá uno o más messages nuevos adjuntos:
# 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
endTambién puede actualizar los metadatos en los mensajes, incluidos los mensajes que provienen del asistente.
metadata = {
user_id : "abc123"
}
message = client . messages . modify (
id : message_id ,
thread_id : thread_id ,
parameters : { metadata : metadata } ,
)En cualquier momento puede enumerar todas las ejecuciones que se han realizado en un hilo en particular o que se están ejecutando actualmente:
client . runs . list ( thread_id : thread_id , parameters : { order : "asc" , limit : 3 } ) También puede crear un hilo y ejecutar en una llamada como esta:
response = client . runs . create_thread_and_run ( parameters : { assistant_id : assistant_id } )
run_id = response [ 'id' ]
thread_id = response [ 'thread_id' ] Puede incluir imágenes en un hilo y el LLM describirá y leerá ellas. En este ejemplo, estoy usando este archivo:
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." En caso de que esté permitiendo que el asistente acceda a las herramientas function (se definen de la misma manera que las funciones durante la finalización del chat), puede obtener un código de estado de requires_action cuando el asistente quiere que evalúe una o más herramientas de función:
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 }
)
endTenga en cuenta que tiene 10 minutos para enviar la salida de su herramienta antes de que expire la ejecución.
Respira hondo. Es posible que necesite una bebida para este.
Es posible que OpenAI comparta los fragmentos que usó en su tubería RAG interna para crear sus resultados de investigación de archivos.
Aquí se puede encontrar una especificación de ejemplo que hace esto, solo para saber que es posible.
Aquí le mostramos cómo obtener los fragmentos en una búsqueda de archivos. En este ejemplo, estoy usando este archivo:
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 )¡Genere imágenes usando Dall · E 2 o Dall · E 3!
Para Dall · E 2, el tamaño de cualquier imagen generada debe ser una de 256x256 , 512x512 o 1024x1024 , si no se especifica, la imagen será de forma predeterminada a 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, el tamaño de cualquier imagen generada debe ser una de 1024x1024 , 1024x1792 o 1792x1024 . Además, la calidad de la imagen se puede especificar a standard o 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..."Complete la parte transparente de una imagen, o cargue una máscara con secciones transparentes para indicar las partes de una imagen que se pueden cambiar de acuerdo con su aviso ...
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..."Crear n variaciones de una imagen.
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..."Pase una cadena para verificar si viola la política de contenido de OpenAI:
response = client . moderations ( parameters : { input : "I'm worried about that." } )
puts response . dig ( "results" , 0 , "category_scores" , "hate" )
# => 5.505014632944949e-05Whisper es un modelo de voz a texto que se puede usar para generar texto basado en archivos de audio:
La API de traducciones toma como entrada el archivo de audio en cualquiera de los idiomas compatibles y transcribe el audio al inglés.
response = client . audio . translate (
parameters : {
model : "whisper-1" ,
file : File . open ( "path_to_file" , "rb" ) ,
}
)
puts response [ "text" ]
# => "Translation of the text" La API de Transcriptions toma como entrada el archivo de audio que desea transcribir y devuelve el texto en el formato de archivo de salida deseado.
Puede pasar el idioma del archivo de audio para mejorar la calidad de la transcripción. Los idiomas compatibles se enumeran aquí. Debe proporcionar el idioma como un código ISO-639-1, por ejemplo. "En" para inglés o "NE" para nepalí. Puedes buscar los códigos aquí.
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" La API del discurso toma como entrada el texto y una voz y devuelve el contenido de un archivo de audio que puede escuchar.
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!"Los errores HTTP se pueden atrapar así:
begin
OpenAI :: Client . new . models . retrieve ( id : "gpt-4o" )
rescue Faraday :: Error => e
raise "Got a Faraday error: #{ e } "
end Después de revisar el repositorio, ejecute bin/setup para instalar dependencias. Puede ejecutar bin/console para un mensaje interactivo que le permitirá experimentar.
Para instalar esta gema en su máquina local, ejecute bundle exec rake install .
Para ejecutar todas las pruebas, ejecute el bundle exec rake comando, que también ejecutará el enlace (Rubocop). Este repositorio utiliza VCR para registrar solicitudes de API.
Advertencia
Si tiene un OPENAI_ACCESS_TOKEN en su ENV , ejecutar las especificaciones usará esto para ejecutar las especificaciones contra la API real, lo que será lento y le costará dinero: ¡2 centavos o más! Eliminarlo de su entorno con unset o similar si solo desea ejecutar las especificaciones con las respuestas de videograbado almacenadas.
Primero ejecute las especificaciones sin VCR para que realmente llegaran a la API. Esto costará 2 centavos o más. Establezca OpenAI_ACcess_Token en su entorno o pase así:
OPENAI_ACCESS_TOKEN=123abc bundle exec rspec
Luego, actualice el número de versión en version.rb , actualice CHANGELOG.md , ejecute bundle install para actualizar gemfile.lock y luego ejecute bundle exec rake release , que creará una etiqueta GIT para la versión, Push Git Commits y etiquetas, y presione El archivo .gem a rubygems.org.
Los informes de errores y las solicitudes de extracción son bienvenidas en GitHub en https://github.com/alexrudall/ruby-openai. Este proyecto pretende ser un espacio seguro y acogedor para la colaboración, y se espera que los contribuyentes se adhieran al Código de Conducta.
La gema está disponible como código abierto bajo los términos de la licencia MIT.
Se espera que todos los que interactúen en las bases de código, los rastreadores de problemas, las salas de chat y las listas de correo del proyecto Ruby Openai sigan el código de conducta.