将OpenAi API与Ruby一起使用! ?❤️
带有GPT-4O的文字,用耳语转录和翻译音频,或用dall·e ...创建图像...
雇用我建造您的轨道+AI应用程序|铁轨AI | ? Ruby AI Builders Discord | ? X | ?人类宝石| ? Midjourney宝石
将此行添加到您的应用程序的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.
)
要进行更强大的设置,您可以使用API键配置GEM,例如在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的任何全局配置集。例如在此示例中
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
Faraday::Error
(例如400,500s,SSL错误等等)什么会导致他们)。
如果您想启用此功能,则可以在配置客户端时将log_errors
设置为true
:
client = OpenAI :: Client . new ( log_errors : true )
您可以将Faraday中间件传递给客户端,例如。用Ruby的Logger启用详细记录:
client = OpenAI :: Client . new do | f |
f . response :logger , Logger . new ( $stdout ) , bodies : true
end
要使用Azure OpenAI Service API,您可以像这样配置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。它提供与OpenAI API的聊天兼容性。
您可以在这里下载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聊天与OpenAI API广泛兼容,存在一些较小的差异。然后从这里获取访问令牌:
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解析促使文本进入令牌,这是单词或单词的一部分。 (这些令牌与您的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
参数,以接收生成的完成块的流。每次收到一个或多个块时,每个块都会被调用一次,将其作为哈希解析。如果Openai返回错误, ruby-openai
将引起法拉第错误。
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}}
您可以使用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"
您可以将Response_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."
使用其他GPT-3型号击中OpenAI API进行完成:
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"]
您可以使用嵌入式端点获取代表输入的数字向量。然后,您可以比较这些向量的不同输入,以有效检查输入的相似之处。
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
(嵌入式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文件后,您可以通过提供文件ID,端点和完成窗口来创建新批次:
response = client . batches . create (
parameters : {
input_file_id : "file-abc123" ,
endpoint : "/v1/chat/completions" ,
completion_window : "24h"
}
)
batch_id = response [ "id" ]
您可以使用其ID检索有关特定批次的信息:
batch = client . batches . retrieve ( id : batch_id )
取消正在进行的批次:
client . batches . cancel ( id : batch_id )
您还可以列出所有批次:
client . batches . list
一旦存在批处理[“已完成_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
文件中,并获取其ID:
response = client . files . upload ( parameters : { file : "path/to/sarcasm.jsonl" , purpose : "fine-tune" } )
file_id = JSON . parse ( response . body ) [ "id" ]
然后,您可以使用此文件ID来创建微调作业:
response = client . finetunes . create (
parameters : {
training_file : file_id ,
model : "gpt-4o"
} )
fine_tune_id = response [ "id" ]
这将为您提供微调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 )
向量存储对象使文件搜索工具能够搜索您的文件。
您可以创建一个新的向量商店:
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 )
向量存储文件表示矢量存储中的文件。
您可以通过将文件附加到向量存储来创建新的矢量存储文件。
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
)
您可以获取当前在vector商店下可用的矢量存储文件的list
:
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
)
注意:这将从矢量存储中删除文件,但不会删除文件本身。要删除文件,请使用删除文件端点。
矢量存储文件批次表示操作,将多个文件添加到矢量存储中。
您可以通过将多个文件附加到矢量存储中来创建新的矢量存储文件批次。
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
)
您可以在当前在Vector Store下可用的批处理中获取所有矢量存储文件的list
:
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
您可以使用助手的ID修改现有助手(请参阅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 )
如上所述创建助手后,您需要准备一条Messages
Thread
供助手进行工作(请参阅《助手的简介》)。例如,作为初始设置,您可以执行:
# 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可以共享其内部RAG管道中使用的块来创建FileSearch结果。
可以在此处找到一个示例规格,以便您知道这是可能的。
这是如何在文件搜索中使用块。在此示例中,我正在使用此文件:
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生成图像!
512x512
dall·e 2,任何生成的图像的大小都必须是256x256
或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
或1792x1024
1024x1792
。另外,图像的质量可以指定为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
耳语是对文本模型的语音,可用于基于音频文件生成文本:
Translations 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代码提供,例如。对于尼泊尔人来说,英语或“ ne”的“ en”。您可以在此处查找代码。
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
,以允许您进行实验。
要将此GEM安装到本地计算机上,请运行bundle exec rake install
。
要运行所有测试,请执行Command bundle exec rake
,这也将运行Linter(RuboCop)。该存储库使用VCR来记录API请求。
警告
如果您在ENV
中有OPENAI_ACCESS_TOKEN
,则运行规格将使用它来针对实际的API运行规格,这将很慢,并且花费您的钱 - 2美分或更多!如果您只想根据存储的VCR响应来运行规格,则会以unset
或类似的方式将其从环境中删除。
首先在没有VCR的情况下运行规格,因此它们实际上击中了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标签.gem
文件rubygems.org。
欢迎在https://github.com/alexrudall/ruby-openai的GitHub上的错误报告和拉动请求。该项目旨在是一个安全,热情的协作空间,预计贡献者将遵守行为准则。
根据MIT许可证的条款,该宝石可作为开源。
在Ruby OpenAI项目的代码库,问题跟踪器,聊天室和邮件列表中进行互动的每个人都将遵循《行为守则》。