diff --git a/OpenAI.API.pas b/OpenAI.API.pas
index 623e076..dacb137 100644
--- a/OpenAI.API.pas
+++ b/OpenAI.API.pas
@@ -4,7 +4,7 @@ interface
uses
System.Classes, System.Net.HttpClient, System.Net.URLClient, System.Net.Mime,
- System.JSON, OpenAI.API.Params, System.SysUtils;
+ System.JSON, OpenAI.Errors, OpenAI.API.Params, System.SysUtils;
type
OpenAIException = class(Exception)
@@ -19,6 +19,41 @@ OpenAIException = class(Exception)
constructor Create(const Text, &Type: string; const Param: string = ''; Code: Int64 = -1); reintroduce;
end;
+ OpenAIExceptionAPI = class(Exception);
+
+ ///
+ /// An InvalidRequestError indicates that your request was malformed or
+ // missing some required parameters, such as a token or an input.
+ // This could be due to a typo, a formatting error, or a logic error in your code.
+ ///
+ OpenAIExceptionInvalidRequestError = class(OpenAIException);
+
+ ///
+ /// A `RateLimitError` indicates that you have hit your assigned rate limit.
+ /// This means that you have sent too many tokens or requests in a given period of time,
+ /// and our services have temporarily blocked you from sending more.
+ ///
+ OpenAIExceptionRateLimitError = class(OpenAIException);
+
+ ///
+ /// An `AuthenticationError` indicates that your API key or token was invalid,
+ /// expired, or revoked. This could be due to a typo, a formatting error, or a security breach.
+ ///
+ OpenAIExceptionAuthenticationError = class(OpenAIException);
+
+ ///
+ /// This error message indicates that your account is not part of an organization
+ ///
+ OpenAIExceptionPermissionError = class(OpenAIException);
+
+ ///
+ /// This error message indicates that our servers are experiencing high
+ /// traffic and are unable to process your request at the moment
+ ///
+ OpenAIExceptionTryAgain = class(OpenAIException);
+
+ OpenAIExceptionInvalidResponse = class(OpenAIException);
+
{$WARNINGS OFF}
TOpenAIAPI = class
const
@@ -31,6 +66,8 @@ TOpenAIAPI = class
procedure SetToken(const Value: string);
procedure SetBaseUrl(const Value: string);
procedure SetOrganization(const Value: string);
+ procedure ParseAndRaiseError(Error: TError; Code: Int64);
+ procedure ParseError(const Code: Int64; const ResponseText: string);
protected
function GetHeaders: TNetHeaders;
function Get(const Path: string; Response: TStringStream): Integer; overload;
@@ -70,7 +107,7 @@ TOpenAIAPIRoute = class
implementation
uses
- OpenAI.Errors, REST.Json;
+ REST.Json;
constructor TOpenAIAPI.Create;
begin
@@ -236,43 +273,22 @@ procedure TOpenAIAPI.GetFile(const Path: string; Response: TStream);
var
Headers: TNetHeaders;
Code: Integer;
- Error: TErrorResponse;
Strings: TStringStream;
begin
CheckAPI;
Headers := GetHeaders;
Code := FHTTPClient.Get(FBaseUrl + '/' + Path, Response, Headers).StatusCode;
case Code of
- 200..299: {success}
- ;
+ 200..299:
+ ; {success}
else
- Error := nil;
+ Strings := TStringStream.Create;
try
- try
- Strings := TStringStream.Create;
- try
- Response.Position := 0;
- Strings.LoadFromStream(Response);
- {$WARNINGS OFF}
- {$IFDEF ANDROID}
- Error := TJson.JsonToObject(Strings.DataString);
- {$ELSE}
- Error := TJson.JsonToObject(UTF8ToString(Strings.DataString));
- {$ENDIF}
- {$WARNINGS ON}
- finally
- Strings.Free;
- end;
- except
- Error := nil;
- end;
- if Assigned(Error) and Assigned(Error.Error) then
- raise OpenAIException.Create(Error.Error.Message, Error.Error.&Type, Error.Error.Param, Error.Error.Code)
- else
- raise OpenAIException.Create('Unknown error', '', '', Code);
+ Response.Position := 0;
+ Strings.LoadFromStream(Response);
+ ParseError(Code, Strings.DataString);
finally
- if Assigned(Error) then
- Error.Free;
+ Strings.Free;
end;
end;
end;
@@ -287,53 +303,72 @@ function TOpenAIAPI.GetHeaders: TNetHeaders;
procedure TOpenAIAPI.CheckAPI;
begin
if FToken.IsEmpty then
- raise Exception.Create('Token is empty!');
+ raise OpenAIExceptionAPI.Create('Token is empty!');
if FBaseUrl.IsEmpty then
- raise Exception.Create('Base url is empty!');
+ raise OpenAIExceptionAPI.Create('Base url is empty!');
end;
-function TOpenAIAPI.ParseResponse(const Code: Int64; const ResponseText: string): T;
+procedure TOpenAIAPI.ParseAndRaiseError(Error: TError; Code: Int64);
+begin
+ case Code of
+ 429:
+ raise OpenAIExceptionRateLimitError.Create(Error.Message, Error.&Type, Error.Param, Error.Code);
+ 400, 404, 415:
+ raise OpenAIExceptionInvalidRequestError.Create(Error.Message, Error.&Type, Error.Param, Error.Code);
+ 401:
+ raise OpenAIExceptionAuthenticationError.Create(Error.Message, Error.&Type, Error.Param, Error.Code);
+ 403:
+ raise OpenAIExceptionPermissionError.Create(Error.Message, Error.&Type, Error.Param, Error.Code);
+ 409:
+ raise OpenAIExceptionTryAgain.Create(Error.Message, Error.&Type, Error.Param, Error.Code);
+ else
+ raise OpenAIException.Create(Error.Message, Error.&Type, Error.Param, Error.Code);
+ end;
+end;
+
+procedure TOpenAIAPI.ParseError(const Code: Int64; const ResponseText: string);
var
Error: TErrorResponse;
+begin
+ Error := nil;
+ try
+ try
+ {$IFDEF ANDROID}
+ Error := TJson.JsonToObject(ResponseText);
+ {$ELSE}
+ Error := TJson.JsonToObject(UTF8ToString(RawByteString(ResponseText)));
+ {$ENDIF}
+ except
+ Error := nil;
+ end;
+ if Assigned(Error) and Assigned(Error.Error) then
+ ParseAndRaiseError(Error.Error, Code)
+ else
+ raise OpenAIException.Create('Unknown error', '', '', Code);
+ finally
+ if Assigned(Error) then
+ Error.Free;
+ end;
+end;
+
+function TOpenAIAPI.ParseResponse(const Code: Int64; const ResponseText: string): T;
begin
case Code of
200..299:
try
- {$WARNINGS OFF}
{$IFDEF ANDROID}
Result := TJson.JsonToObject(ResponseText);
{$ELSE}
- Result := TJson.JsonToObject(UTF8ToString(ResponseText));
+ Result := TJson.JsonToObject(UTF8ToString(RawByteString(ResponseText)));
{$ENDIF}
- {$WARNINGS ON}
except
Result := nil;
end;
else
- Error := nil;
- try
- try
- {$WARNINGS OFF}
- {$IFDEF ANDROID}
- Error := TJson.JsonToObject(ResponseText);
- {$ELSE}
- Error := TJson.JsonToObject(UTF8ToString(ResponseText));
- {$ENDIF}
- {$WARNINGS ON}
- except
- Error := nil;
- end;
- if Assigned(Error) and Assigned(Error.Error) then
- raise OpenAIException.Create(Error.Error.Message, Error.Error.&Type, Error.Error.Param, Error.Error.Code)
- else
- raise OpenAIException.Create('Unknown error', '', '', Code);
- finally
- if Assigned(Error) then
- Error.Free;
- end;
+ ParseError(Code, ResponseText);
end;
if not Assigned(Result) then
- raise OpenAIException.Create('Empty or invalid response', '', '', Code);
+ raise OpenAIExceptionInvalidResponse.Create('Empty or invalid response', '', '', Code);
end;
procedure TOpenAIAPI.SetBaseUrl(const Value: string);