Skip to content

Commit b793265

Browse files
authored
Error Handling (#4)
**Added** - Response type interface created, all responses now have an Error field. - Missing fields in Model and OpenAIFile added. - Error check in DispatchRequest methods. **Changed** - Model struct is now OpenAIModel class. **Fixed** - Typo in FineTune and Choice fields.
1 parent 21fe19f commit b793265

File tree

6 files changed

+113
-30
lines changed

6 files changed

+113
-30
lines changed

Runtime/DataTypes.cs

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public struct Choice
77
{
88
public string Text { get; set; }
99
public int? Index { get; set; }
10-
public int? Logpropbs { get; set; }
10+
public int? Logprobs { get; set; }
1111
public string FinishReason { get; set; }
1212
}
1313

@@ -18,7 +18,7 @@ public struct Usage
1818
public string TotalTokens { get; set; }
1919
}
2020

21-
public struct OpenAIFile
21+
public class OpenAIFile
2222
{
2323
public string Id { get; set; }
2424
public string Object { get; set; }
@@ -27,23 +27,46 @@ public struct OpenAIFile
2727
public string Filename { get; set; }
2828
public string Purpose { get; set; }
2929
public object StatusDetails { get; set; }
30+
public string Status { get; set; }
31+
}
32+
33+
public class OpenAIFileResponse : OpenAIFile, IResponse
34+
{
35+
public ApiError Error { get; set; }
36+
}
37+
38+
public class ApiError
39+
{
40+
public string Message;
41+
public string Type;
42+
public object Param;
43+
public object Code;
3044
}
3145
#endregion
3246

3347
#region Models API Data Types
34-
public struct ListModelsResponse
48+
public struct ListModelsResponse: IResponse
3549
{
50+
public ApiError Error { get; set; }
3651
public string Object { get; set; }
37-
public Model[] Data { get; set; }
52+
public OpenAIModel[] Data { get; set; }
3853
}
3954

40-
public struct Model
55+
public class OpenAIModel
4156
{
4257
public string Id { get; set; }
4358
public string Object { get; set; }
4459
public string OwnedBy { get; set; }
60+
public long Created { get; set; }
61+
public string Root { get; set; }
62+
public string Parent { get; set; }
4563
public Dictionary<string, object>[] Permission { get; set; }
4664
}
65+
66+
public class OpenAIModelResponse : OpenAIModel, IResponse
67+
{
68+
public ApiError Error { get; set; }
69+
}
4770
#endregion
4871

4972
#region Completions API Data Types
@@ -67,8 +90,9 @@ public sealed class CreateCompletionRequest
6790
public string User { get; set; }
6891
}
6992

70-
public struct CreateCompletionResponse
93+
public struct CreateCompletionResponse: IResponse
7194
{
95+
public ApiError Error { get; set; }
7296
public string Id { get; set; }
7397
public string Object { get; set; }
7498
public long Created { get; set; }
@@ -89,8 +113,9 @@ public sealed class CreateEditRequest
89113
public int? N { get; set; } = 1;
90114
}
91115

92-
public struct CreateEditResponse
116+
public struct CreateEditResponse: IResponse
93117
{
118+
public ApiError Error { get; set; }
94119
public string Object { get; set; }
95120
public long Created { get; set; }
96121
public Choice[] Choices { get; set; }
@@ -124,8 +149,9 @@ public sealed class CreateImageVariationRequest: CreateImageRequestBase
124149
public string Image { get; set; }
125150
}
126151

127-
public struct CreateImageResponse
152+
public struct CreateImageResponse: IResponse
128153
{
154+
public ApiError Error { get; set; }
129155
public long Created { get; set; }
130156
public ImageData[] Data { get; set; }
131157
}
@@ -145,8 +171,9 @@ public struct CreateEmbeddingsRequest
145171
public string User { get; set; }
146172
}
147173

148-
public struct CreateEmbeddingsResponse
174+
public struct CreateEmbeddingsResponse: IResponse
149175
{
176+
public ApiError Error { get; set; }
150177
public string Object { get; set; }
151178
public EmbeddingData[] Data;
152179
public string Model { get; set; }
@@ -162,14 +189,16 @@ public struct EmbeddingData
162189
#endregion
163190

164191
#region Files API Data Types
165-
public struct ListFilesResponse
192+
public struct ListFilesResponse: IResponse
166193
{
194+
public ApiError Error { get; set; }
167195
public string Object { get; set; }
168196
public OpenAIFile[] Data { get; set; }
169197
}
170198

171-
public struct DeleteResponse
199+
public struct DeleteResponse: IResponse
172200
{
201+
public ApiError Error { get; set; }
173202
public string Id { get; set; }
174203
public string Object { get; set; }
175204
public bool Deleted { get; set; }
@@ -199,27 +228,29 @@ public class CreateFineTuneRequest
199228
public string Suffix { get; set; }
200229
}
201230

202-
public struct ListFineTunesResponse
231+
public struct ListFineTunesResponse: IResponse
203232
{
233+
public ApiError Error { get; set; }
204234
public string Object { get; set; }
205235
public FineTune[] Data { get; set; }
206236
}
207237

208-
public struct ListFineTuneEventsResponse
238+
public struct ListFineTuneEventsResponse: IResponse
209239
{
240+
public ApiError Error { get; set; }
210241
public string Object { get; set; }
211242
public FineTuneEvent[] Data { get; set; }
212243
}
213244

214-
public struct FineTune
245+
public class FineTune
215246
{
216247
public string Id { get; set; }
217248
public string Object { get; set; }
218249
public long CreatedAt { get; set; }
219250
public long UpdatedAt { get; set; }
220251
public string Model { get; set; }
221252
public string FineTunedModel { get; set; }
222-
public string OrganizationID { get; set; }
253+
public string OrganizationId { get; set; }
223254
public string Status { get; set; }
224255
public Dictionary<string, object> Hyperparams { get; set; }
225256
public OpenAIFile[] TrainingFiles { get; set; }
@@ -228,6 +259,11 @@ public struct FineTune
228259
public FineTuneEvent[] Events { get; set; }
229260
}
230261

262+
public class FineTuneResponse : FineTune, IResponse
263+
{
264+
public ApiError Error { get; set; }
265+
}
266+
231267
public struct FineTuneEvent
232268
{
233269
public string Object { get; set; }
@@ -244,8 +280,9 @@ public class CreateModerationRequest
244280
public string Model { get; set; } = ModerationModel.Latest;
245281
}
246282

247-
public struct CreateModerationResponse
283+
public struct CreateModerationResponse: IResponse
248284
{
285+
public ApiError Error { get; set; }
249286
public string Id { get; set; }
250287
public string Model { get; set; }
251288
public ModerationResult[] Results { get; set; }

Runtime/Interfaces.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Interfaces/IResponse.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace OpenAI
2+
{
3+
public interface IResponse
4+
{
5+
public ApiError Error { get; set; }
6+
}
7+
}

Runtime/Interfaces/IResponse.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/OpenAIApi.cs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Text;
23
using Newtonsoft.Json;
34
using System.Net.Http;
@@ -26,7 +27,8 @@ public class OpenAIApi
2627
ContractResolver = new DefaultContractResolver()
2728
{
2829
NamingStrategy = new CustomNamingStrategy()
29-
}
30+
},
31+
MissingMemberHandling = MissingMemberHandling.Error
3032
};
3133

3234
/// <summary>
@@ -37,7 +39,7 @@ public class OpenAIApi
3739
/// <param name="payload">An optional byte array of json payload to include in the request.</param>
3840
/// <typeparam name="T">Response type of the request.</typeparam>
3941
/// <returns>A Task containing the response from the request as the specified type.</returns>
40-
private async Task<T> DispatchRequest<T>(string path, HttpMethod method, byte[] payload = null)
42+
private async Task<T> DispatchRequest<T>(string path, HttpMethod method, byte[] payload = null) where T: IResponse
4143
{
4244
var client = new HttpClient();
4345
client.SetHeaders(configuration, ContentType.ApplicationJson);
@@ -51,7 +53,16 @@ private async Task<T> DispatchRequest<T>(string path, HttpMethod method, byte[]
5153

5254
var response = await client.SendAsync(request);
5355
var content = await response.Content.ReadAsStringAsync();
54-
return JsonConvert.DeserializeObject<T>(content, jsonSerializerSettings);
56+
57+
var data = JsonConvert.DeserializeObject<T>(content, jsonSerializerSettings);
58+
59+
if (data?.Error != null)
60+
{
61+
ApiError error = data.Error;
62+
throw new Exception($"Error Message: {error.Message}\nError Type: {error.Type}\n");
63+
}
64+
65+
return data;
5566
}
5667

5768
/// <summary>
@@ -61,14 +72,23 @@ private async Task<T> DispatchRequest<T>(string path, HttpMethod method, byte[]
6172
/// <param name="form">A multi-part data form to upload with the request.</param>
6273
/// <typeparam name="T">Response type of the request.</typeparam>
6374
/// <returns>A Task containing the response from the request as the specified type.</returns>
64-
private async Task<T> DispatchRequest<T>(string path, MultipartFormDataContent form)
75+
private async Task<T> DispatchRequest<T>(string path, MultipartFormDataContent form) where T: IResponse
6576
{
6677
var client = new HttpClient();
6778
client.SetHeaders(configuration, ContentType.MultipartFormData);
6879

6980
var response = await client.PostAsync(path, form);
7081
var content = await response.Content.ReadAsStringAsync();
71-
return JsonConvert.DeserializeObject<T>(content, jsonSerializerSettings);
82+
83+
var data = JsonConvert.DeserializeObject<T>(content, jsonSerializerSettings);
84+
85+
if (data != null && data.Error != null)
86+
{
87+
ApiError error = data.Error;
88+
throw new Exception($"Error Message: {error.Message}\nError Type: {error.Type}\n");
89+
}
90+
91+
return data;
7292
}
7393

7494
/// <summary>
@@ -97,10 +117,10 @@ public async Task<ListModelsResponse> ListModels()
97117
/// </summary>
98118
/// <param name="id">The ID of the model to use for this request</param>
99119
/// <returns>See <see cref="Model"/></returns>
100-
public async Task<Model> RetrieveModel(string id)
120+
public async Task<OpenAIModel> RetrieveModel(string id)
101121
{
102122
var path = $"{BASE_PATH}/models/{id}";
103-
return await DispatchRequest<Model>(path, HttpMethod.Get);
123+
return await DispatchRequest<OpenAIModelResponse>(path, HttpMethod.Get);
104124
}
105125

106126
/// <summary>
@@ -216,7 +236,7 @@ public async Task<OpenAIFile> CreateFile(CreateFileRequest request)
216236
form.AddJsonl(request.File, "file");
217237
form.AddValue(request.Purpose, "purpose");
218238

219-
return await DispatchRequest<OpenAIFile>(path, form);
239+
return await DispatchRequest<OpenAIFileResponse>(path, form);
220240
}
221241

222242
/// <summary>
@@ -238,7 +258,7 @@ public async Task<DeleteResponse> DeleteFile(string id)
238258
public async Task<OpenAIFile> RetrieveFile(string id)
239259
{
240260
var path = $"{BASE_PATH}/files/{id}";
241-
return await DispatchRequest<OpenAIFile>(path, HttpMethod.Get);
261+
return await DispatchRequest<OpenAIFileResponse>(path, HttpMethod.Get);
242262
}
243263

244264
/// <summary>
@@ -249,7 +269,7 @@ public async Task<OpenAIFile> RetrieveFile(string id)
249269
public async Task<OpenAIFile> DownloadFile(string id)
250270
{
251271
var path = $"{BASE_PATH}/files/{id}/content";
252-
return await DispatchRequest<OpenAIFile>(path, HttpMethod.Get);
272+
return await DispatchRequest<OpenAIFileResponse>(path, HttpMethod.Get);
253273
}
254274

255275
/// <summary>
@@ -262,7 +282,7 @@ public async Task<FineTune> CreateFineTune(CreateFineTuneRequest request)
262282
{
263283
var path = $"{BASE_PATH}/fine-tunes";
264284
var payload = CreatePayload(request);
265-
return await DispatchRequest<FineTune>(path, HttpMethod.Post, payload);
285+
return await DispatchRequest<FineTuneResponse>(path, HttpMethod.Post, payload);
266286
}
267287

268288
/// <summary>
@@ -283,7 +303,7 @@ public async Task<ListFineTunesResponse> ListFineTunes()
283303
public async Task<FineTune> RetrieveFineTune(string id)
284304
{
285305
var path = $"{BASE_PATH}/fine-tunes/{id}";
286-
return await DispatchRequest<FineTune>(path, HttpMethod.Get);
306+
return await DispatchRequest<FineTuneResponse>(path, HttpMethod.Get);
287307
}
288308

289309
/// <summary>
@@ -294,7 +314,7 @@ public async Task<FineTune> RetrieveFineTune(string id)
294314
public async Task<FineTune> CancelFineTune(string id)
295315
{
296316
var path = $"{BASE_PATH}/fine-tunes/{id}/cancel";
297-
return await DispatchRequest<FineTune>(path, HttpMethod.Post);
317+
return await DispatchRequest<FineTuneResponse>(path, HttpMethod.Post);
298318
}
299319

300320
/// <summary>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.srcnalt.openai-unity",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"displayName": "OpenAI Unity",
55
"description": "An unofficial OpenAI Unity Package that aims to help you use OpenAI API directly in Unity Game engine.",
66
"unity": "2020.3",

0 commit comments

Comments
 (0)