-
-
Notifications
You must be signed in to change notification settings - Fork 361
Handle streaming errors and return to user proc, with result_type
#275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
result_type
injected intoresult_type
of data or error
4e4a294
to
f4d33e0
Compare
result_type
of data or errorresult_type
Would love to see this merged, I got stuck because I was missing errors for a bit. @alexrudall or others? |
f4d33e0
to
6bb4ba0
Compare
For @gregschwartz, or anyone else who wants to use this branch before merge, you can temporarily point your Gemfile to: gem "ruby-openai", github: "harlantwood/ruby-openai", branch: "streaming-error-handling" |
results.each do |result_type, result_json| | ||
result = JSON.parse(result_json) | ||
result.merge!("result_type" => result_type) | ||
user_proc.call(result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to see result
as an object rather than an extended parsed JSON hash. The object could extend some of Hash's []
/dig
methods for backwards compatibility. Reason being, it would be nice to eventually add header info, or add other metadata that would be helpful when processing the chunks externally to this gem without polluting the response's contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, but probably for another PR — trying to keep this one as tightly scoped as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this implementation will catch all errors. I've been playing around with the solution and the regex doesn't work. Here is a sample using a hand-rolled HTTParty request with a bad API key:
irb(main):259:1* def handle_open_ai_response
irb(main):260:2* proc do |response|
irb(main):261:2* puts "IN PROC"
irb(main):262:2* puts response
irb(main):263:2* puts "PARSED RESPONSE"
irb(main):264:2* puts response.scan(/^\s*(data|error): *(\{.+\})/i)
irb(main):265:2* puts "END PARSED RESPONSE"
irb(main):266:1* end
irb(main):267:0> end
:handle_open_ai_response
irb(main):268:0> HTTParty.post("https://api.openai.com/v1/chat/completions", headers:, body:, stream_body: true, &handle_open_ai_response)
IN PROC
{
"error": {
"message": "You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY), or as the password field (with blank username) if you're accessing the API from your browser and are prompted for a username and password. You can obtain an API key from https://platform.openai.com/account/api-keys.",
"type": "invalid_request_error",
"param": null,
"code": null
}
}
PARSED RESPONSE
END PARSED RESPONSE
Notice that the Regexp does not match the error with any information.
@alexrudall any thoughts on this one? Happy to make changes if you have requests. |
6bb4ba0
to
2a8ffdd
Compare
2a8ffdd
to
e909cfb
Compare
… hash (backward compatible)
e909cfb
to
875aa34
Compare
@harlantwood thank you for this PR! |
I'm working on properly fixing these issues with #338 (and I'll follow up with a breaking change to raise actual exceptions) |
@alexrudall any thoughts on this one vs #338 ? Happy to update this one and fix tests, but if you plan to merge #338 I won’t bother. |
Big thanks for this @harlantwood -- going with #344 as simpler (and outsources some of the work to Shopify via event_stream_parser!) - but thanks a lot for taking the time to contribute this, it all helps find a solution. |
Sure thing! I think #344 is a great solution, if you’re willing to go with a breaking change. Thanks for creating a great lib — we’ve been using it in production (streaming via hotwire) and it’s been super solid. |
Currently when streaming, errors are ignored and never returned to the user's code. This includes non-starter errors (eg wrong API key) as well as errors encountered in the course of usage (eg context length exceeded). These are discussed in #256 and #270 .
This PR (the one you are reading) offers an alternative solution:
Specs have been updated, but in short:
data: { "some": "json" }
chunks are returned asdata
result_typeerror: { "some": "json" }
chunks are returned aserror
result_type{"error": {"some": "json"} }
chunks are returned aserror
result_type{"some": "json"}
chunks are returned asunknown
result_typeNote that this is carefully crafted to ensure backward compatibility with existing code! For example, this sample code will work unchanged:
.... it will just ignore the
result_type
field and look for chunks matching the expected shape.Feedback or change requests welcome.
Thanks BTW for an awesome gem, we're super happy with it!
All Submissions: