Unreal OpenAI API 1.0.0
OpenAIProvider.h
1// OpenAI, Copyright LifeEXE. All Rights Reserved.
2
3/*
4 ___ ___ ________ _______
5|\ \ |\ \|\ _____\\ ___ \
6\ \ \ \ \ \ \ \__/\ \ __/|
7 \ \ \ \ \ \ \ __\\ \ \_|/__
8 \ \ \____\ \ \ \ \_| \ \ \_|\ \
9 \ \_______\ \__\ \__\ \ \_______\
10 \|_______|\|__|\|__| \|_______|
11
12
13
14 _______ ___ ___ _______
15|\ ___ \ |\ \ / /|\ ___ \
16\ \ __/| \ \ \/ / | \ __/|
17 \ \ \_|/__ \ \ / / \ \ \_|/__
18 \ \ \_|\ \ / \/ \ \ \_|\ \
19 \ \_______\/ /\ \ \ \_______\
20 \|_______/__/ /\ __\ \|_______|
21 |__|/ \|__|
22*/
23
24#pragma once
25
26#include "CoreMinimal.h"
27#include "HTTP.h"
28#include "Delegates.h"
29#include "Types/AllTypesHeader.h"
30#include "FuncLib/OpenAIFuncLib.h"
31#include "FuncLib/JsonFuncLib.h"
32#include "Provider/JsonParsers/ChatParser.h"
33#include "JsonObjectConverter.h"
34#include "OpenAIProvider.generated.h"
35
36class FJsonObject;
37
38namespace OpenAI
39{
40class IAPI;
41}
42
43UCLASS()
44class OPENAI_API UOpenAIProvider : public UObject
45{
46 GENERATED_BODY()
47
48public:
50
51 void SetAPI(const TSharedPtr<OpenAI::IAPI>& API);
52
53public:
58 void ListModels(const FOpenAIAuth& Auth);
59
64 void RetrieveModel(const FString& ModelName, const FOpenAIAuth& Auth);
65
70 void DeleteFineTunedModel(const FString& ModelID, const FOpenAIAuth& Auth);
71
76 void CreateCompletion(const FCompletion& Completion, const FOpenAIAuth& Auth);
77
82 void CreateChatCompletion(const FChatCompletion& Completion, const FOpenAIAuth& Auth);
83
88 void CreateImage(const FOpenAIImage& Image, const FOpenAIAuth& Auth);
89
94 void CreateImageEdit(const FOpenAIImageEdit& ImageEdit, const FOpenAIAuth& Auth);
95
100 void CreateImageVariation(const FOpenAIImageVariation& ImageVariation, const FOpenAIAuth& Auth);
101
106 void CreateEmbeddings(const FEmbeddings& Embeddings, const FOpenAIAuth& Auth);
107
112 void CreateSpeech(const FSpeech& Speech, const FOpenAIAuth& Auth);
113
118 void CreateAudioTranscription(const FAudioTranscription& AudioTranscription, const FOpenAIAuth& Auth);
119
124 void CreateAudioTranslation(const FAudioTranslation& AudioTranslation, const FOpenAIAuth& Auth);
125
130 void ListFiles(const FOpenAIAuth& Auth);
131
138 void UploadFile(const FUploadFile& UploadFile, const FOpenAIAuth& Auth);
139
144 void DeleteFile(const FString& FileID, const FOpenAIAuth& Auth);
145
150 void RetrieveFile(const FString& FileID, const FOpenAIAuth& Auth);
151
156 void RetrieveFileContent(const FString& FileID, const FOpenAIAuth& Auth);
157
162 void CreateModerations(const FModerations& Moderations, const FOpenAIAuth& Auth);
163
169 void CreateFineTuningJob(const FFineTuningJob& FineTuningJob, const FOpenAIAuth& Auth);
170
175 void ListFineTuningJobs(const FOpenAIAuth& Auth, const FFineTuningQueryParameters& FineTuningQueryParameters = {});
176
181 void ListFineTuningEvents(
182 const FString& FineTuningJobID, const FOpenAIAuth& Auth, const FFineTuningQueryParameters& FineTuningQueryParameters = {});
183
188 void ListFineTuningCheckpoints(
189 const FString& FineTuningJobID, const FOpenAIAuth& Auth, const FFineTuningQueryParameters& FineTuningQueryParameters = {});
190
195 void RetrieveFineTuningJob(const FString& FineTuningJobID, const FOpenAIAuth& Auth);
196
201 void CancelFineTuningJob(const FString& FineTuneID, const FOpenAIAuth& Auth);
202
208 void CreateBatch(const FCreateBatch& CreateBatch, const FOpenAIAuth& Auth);
209
214 void RetrieveBatch(const FString& BatchId, const FOpenAIAuth& Auth);
215
223 void CancelBatch(const FString& BatchId, const FOpenAIAuth& Auth);
224
229 void ListBatch(const FListBatch& ListBatch, const FOpenAIAuth& Auth);
230
236 void CreateUpload(const FCreateUpload& CreateUpload, const FOpenAIAuth& Auth);
237
243 void AddUploadPart(const FString& UploadId, const FAddUploadPart& AddUploadPart, const FOpenAIAuth& Auth);
244
251 void CompleteUpload(const FString& UploadId, const FCompleteUpload& CompleteUpload, const FOpenAIAuth& Auth);
252
257 void CancelUpload(const FString& UploadId, const FOpenAIAuth& Auth);
258
263 void CreateAssistant(const FCreateAssistant& CreateAssistant, const FOpenAIAuth& Auth);
264
269 void ListAssistants(const FListAssistants& ListAssistants, const FOpenAIAuth& Auth);
270
275 void RetrieveAssistant(const FString& AssistantId, const FOpenAIAuth& Auth);
276
281 void ModifyAssistant(const FString& AssistantId, const FModifyAssistant& ModifyAssistant, const FOpenAIAuth& Auth);
282
287 void DeleteAssistant(const FString& AssistantId, const FOpenAIAuth& Auth);
288
292 void SetLogEnabled(bool LogEnabled) { bLogEnabled = LogEnabled; }
293
294#define DEFINE_EVENT_GETTER(Name) \
295public: \
296 FOn##Name& On##Name() { return Name; } \
297 \
298private: \
299 FOn##Name Name;
300
301public:
302 FOnRequestError& OnRequestError() { return RequestError; };
303 DEFINE_EVENT_GETTER(ListModelsCompleted)
304 DEFINE_EVENT_GETTER(RetrieveModelCompleted)
305 DEFINE_EVENT_GETTER(CreateCompletionCompleted)
306 DEFINE_EVENT_GETTER(CreateCompletionStreamCompleted)
307 DEFINE_EVENT_GETTER(CreateCompletionStreamProgresses)
308 DEFINE_EVENT_GETTER(CreateChatCompletionCompleted)
309 DEFINE_EVENT_GETTER(CreateChatCompletionStreamCompleted)
310 DEFINE_EVENT_GETTER(CreateChatCompletionStreamProgresses)
311 DEFINE_EVENT_GETTER(CreateImageCompleted)
312 DEFINE_EVENT_GETTER(CreateImageEditCompleted)
313 DEFINE_EVENT_GETTER(CreateImageVariationCompleted)
314 DEFINE_EVENT_GETTER(CreateEmbeddingsCompleted)
315 DEFINE_EVENT_GETTER(CreateSpeechCompleted)
316 DEFINE_EVENT_GETTER(CreateAudioTranscriptionCompleted)
317 DEFINE_EVENT_GETTER(CreateAudioTranscriptionVerboseCompleted)
318 DEFINE_EVENT_GETTER(CreateAudioTranslationCompleted)
319 DEFINE_EVENT_GETTER(ListFilesCompleted)
320 DEFINE_EVENT_GETTER(UploadFileCompleted)
321 DEFINE_EVENT_GETTER(DeleteFileCompleted)
322 DEFINE_EVENT_GETTER(RetrieveFileCompleted)
323 DEFINE_EVENT_GETTER(RetrieveFileContentCompleted)
324 DEFINE_EVENT_GETTER(CreateFineTuningJobCompleted)
325 DEFINE_EVENT_GETTER(ListFineTuningJobsCompleted)
326 DEFINE_EVENT_GETTER(ListFineTuningEventsCompleted)
327 DEFINE_EVENT_GETTER(ListFineTuningCheckpointsCompleted)
328 DEFINE_EVENT_GETTER(DeleteFineTunedModelCompleted)
329 DEFINE_EVENT_GETTER(CreateModerationsCompleted)
330 DEFINE_EVENT_GETTER(RetrieveFineTuningJobCompleted)
331 DEFINE_EVENT_GETTER(CancelFineTuningJobCompleted)
332 DEFINE_EVENT_GETTER(ListBatchCompleted)
333 DEFINE_EVENT_GETTER(CreateBatchCompleted)
334 DEFINE_EVENT_GETTER(RetrieveBatchCompleted)
335 DEFINE_EVENT_GETTER(CancelBatchCompleted)
336 DEFINE_EVENT_GETTER(CreateUploadCompleted)
337 DEFINE_EVENT_GETTER(AddUploadPartCompleted)
338 DEFINE_EVENT_GETTER(CompleteUploadCompleted)
339 DEFINE_EVENT_GETTER(CancelUploadCompleted)
340 DEFINE_EVENT_GETTER(CreateAssistantCompleted)
341 DEFINE_EVENT_GETTER(ListAssistantsCompleted)
342 DEFINE_EVENT_GETTER(RetrieveAssistantCompleted)
343 DEFINE_EVENT_GETTER(ModifyAssistantCompleted)
344 DEFINE_EVENT_GETTER(DeleteAssistantCompleted)
345
346private:
347 TSharedPtr<OpenAI::IAPI> API;
348 bool bLogEnabled{true};
349 FOnRequestError RequestError;
350
351#define DECLARE_HTTP_CALLBACK(Callback) virtual void Callback(FHttpRequestPtr Request, FHttpResponsePtr Response, bool WasSuccessful);
352#define DECLARE_HTTP_CALLBACK_PROGRESS(Callback) virtual void Callback(FHttpRequestPtr Request, uint64 BytesSent, uint64 BytesReceived);
353
354 DECLARE_HTTP_CALLBACK(OnListModelsCompleted)
355 DECLARE_HTTP_CALLBACK(OnRetrieveModelCompleted)
356 DECLARE_HTTP_CALLBACK(OnCreateCompletionCompleted)
357 DECLARE_HTTP_CALLBACK(OnCreateCompletionStreamCompleted)
358 DECLARE_HTTP_CALLBACK_PROGRESS(OnCreateCompletionStreamProgress)
359 DECLARE_HTTP_CALLBACK(OnCreateChatCompletionCompleted)
360 DECLARE_HTTP_CALLBACK(OnCreateChatCompletionStreamCompleted)
361 DECLARE_HTTP_CALLBACK_PROGRESS(OnCreateChatCompletionStreamProgress)
362 DECLARE_HTTP_CALLBACK(OnCreateImageCompleted)
363 DECLARE_HTTP_CALLBACK(OnCreateImageEditCompleted)
364 DECLARE_HTTP_CALLBACK(OnCreateImageVariationCompleted)
365 DECLARE_HTTP_CALLBACK(OnCreateEmbeddingsCompleted)
366 DECLARE_HTTP_CALLBACK(OnCreateSpeechCompleted)
367 DECLARE_HTTP_CALLBACK(OnCreateAudioTranscriptionCompleted)
368 DECLARE_HTTP_CALLBACK(OnCreateAudioTranslationCompleted)
369 DECLARE_HTTP_CALLBACK(OnListFilesCompleted)
370 DECLARE_HTTP_CALLBACK(OnUploadFileCompleted)
371 DECLARE_HTTP_CALLBACK(OnDeleteFileCompleted)
372 DECLARE_HTTP_CALLBACK(OnRetrieveFileCompleted)
373 DECLARE_HTTP_CALLBACK(OnRetrieveFileContentCompleted)
374 DECLARE_HTTP_CALLBACK(OnDeleteFineTunedModelCompleted)
375 DECLARE_HTTP_CALLBACK(OnCreateModerationsCompleted)
376 DECLARE_HTTP_CALLBACK(OnCreateFineTuningJobCompleted)
377 DECLARE_HTTP_CALLBACK(OnListFineTuningJobsCompleted)
378 DECLARE_HTTP_CALLBACK(OnListFineTuningEventsCompleted)
379 DECLARE_HTTP_CALLBACK(OnListFineTuningCheckpointsCompleted)
380 DECLARE_HTTP_CALLBACK(OnRetrieveFineTuningJobCompleted)
381 DECLARE_HTTP_CALLBACK(OnCancelFineTuningJobCompleted)
382 DECLARE_HTTP_CALLBACK(OnCreateBatchCompleted)
383 DECLARE_HTTP_CALLBACK(OnRetrieveBatchCompleted)
384 DECLARE_HTTP_CALLBACK(OnCancelBatchCompleted)
385 DECLARE_HTTP_CALLBACK(OnListBatchCompleted)
386 DECLARE_HTTP_CALLBACK(OnCreateUploadCompleted)
387 DECLARE_HTTP_CALLBACK(OnAddUploadPartCompleted)
388 DECLARE_HTTP_CALLBACK(OnCompleteUploadCompleted)
389 DECLARE_HTTP_CALLBACK(OnCancelUploadCompleted)
390 DECLARE_HTTP_CALLBACK(OnCreateAssistantCompleted)
391 DECLARE_HTTP_CALLBACK(OnListAssistantsCompleted)
392 DECLARE_HTTP_CALLBACK(OnRetrieveAssistantCompleted)
393 DECLARE_HTTP_CALLBACK(OnModifyAssistantCompleted)
394 DECLARE_HTTP_CALLBACK(OnDeleteAssistantCompleted)
395
396 void ProcessRequest(FHttpRequestRef HttpRequest);
397
398 bool Success(FHttpResponsePtr Response, bool WasSuccessful);
399 void Log(const FString& Info) const;
400 void LogResponse(FHttpResponsePtr Response) const;
401 void LogError(const FString& ErrorText) const;
402
403 template <typename OutStructType>
404 FString SerializeRequest(const OutStructType& OutStruct) const
405 {
406 TSharedPtr<FJsonObject> Json = FJsonObjectConverter::UStructToJsonObject(OutStruct);
407 UJsonFuncLib::RemoveEmptyArrays(Json);
408 FString RequestBodyStr;
409 UJsonFuncLib::JsonToString(Json, RequestBodyStr);
410 return RequestBodyStr;
411 }
412
413 FHttpRequestRef MakeRequestHeaders(const FOpenAIAuth& Auth) const;
414 FOpenAIResponseMetadata GetResponseHeaders(FHttpResponsePtr Response) const;
415
416 template <typename OutStructType>
417 FHttpRequestRef MakeRequest(const OutStructType& OutStruct, const FString& URL, const FString& Method, const FOpenAIAuth& Auth) const
418 {
419 auto HttpRequest = MakeRequestHeaders(Auth);
420 HttpRequest->SetURL(URL);
421 HttpRequest->SetVerb(Method);
422
423 const FString Content = SerializeRequest(OutStruct);
424 Log(FString("Content: ").Append(Content));
425
426 const FString PostprocessedContent = UJsonFuncLib::RemoveOptionalValuesThatNotSet(Content);
427 Log(FString("Postprocessed content was set as: ").Append(PostprocessedContent));
428
429 HttpRequest->SetContentAsString(PostprocessedContent);
430 return HttpRequest;
431 }
432 // specializations
433 FHttpRequestRef MakeRequest(const FString& URL, const FString& Method, const FOpenAIAuth& Auth) const;
434 FHttpRequestRef MakeRequest(
435 const FChatCompletion& ChatCompletion, const FString& URL, const FString& Method, const FOpenAIAuth& Auth) const;
436
437 template <typename ParsedResponseType, typename DelegateType>
438 void HandleResponse(FHttpResponsePtr Response, bool WasSuccessful, DelegateType& Delegate)
439 {
440 if (!Success(Response, WasSuccessful)) return;
441
442 const FString Content = Response.IsValid() ? Response->GetContentAsString() : FString{};
443 const FString ResponseURL = Response.IsValid() ? Response->GetURL() : FString{};
444
445 ParsedResponseType ParsedResponse;
446 if (UJsonFuncLib::ParseJSONToStruct(Content, &ParsedResponse))
447 {
448 Delegate.Broadcast(ParsedResponse, GetResponseHeaders(Response));
449 }
450 else
451 {
452 LogError("JSON deserialization error");
453 RequestError.Broadcast(ResponseURL, Content);
454 }
455 }
456
457 virtual TSharedRef<IHttpRequest, ESPMode::ThreadSafe> CreateRequest() const { return FHttpModule::Get().CreateRequest(); }
458
459private:
460 void SetOptional(TSharedPtr<FJsonObject> RequestBody, const TOptional<FString>& Param, const FString& ParamName);
461 void SetOptional(TSharedPtr<FJsonObject> RequestBody, const TOptional<bool>& Param, const FString& ParamName);
462 void SetOptional(TSharedPtr<FJsonObject> RequestBody, const TOptional<TArray<float>>& Param, const FString& ParamName);
463
464 template <typename NumberType>
465 void SetOptional(TSharedPtr<FJsonObject> RequestBody, const TOptional<NumberType>& Param, const FString& ParamName)
466 {
467 if (!Param.IsSet()) return;
468 RequestBody->SetNumberField(ParamName, Param.GetValue());
469 }
470
471private:
472 TTuple<FString, FString> GetErrorData(FHttpRequestPtr Request, FHttpResponsePtr Response) const;
473
474 template <typename ResponseType>
475 bool ParseStreamRequest(FHttpResponsePtr Response, TArray<ResponseType>& Responses)
476 {
477 if (!Response.IsValid()) return false;
478
479 TArray<FString> StringArray;
480 Response->GetContentAsString().ParseIntoArrayLines(StringArray);
481
482 for (auto& String : StringArray)
483 {
484 bool LastString{false};
485 if (OpenAI::ChatParser::CleanChunkResponseString(String, LastString))
486 {
487 if (LastString)
488 {
489 break;
490 }
491 ResponseType ParsedResponse;
492 if (!UJsonFuncLib::ParseJSONToStruct(String, &ParsedResponse)) continue;
493
494 Responses.Add(ParsedResponse);
495 }
496 }
497 return true;
498 }
499
500 template <typename ResponseType, typename DelegateType>
501 void OnStreamProgress(FHttpRequestPtr Request, uint64 BytesSent, uint64 BytesReceived, DelegateType& Delegate)
502 {
503 const auto& Response = Request->GetResponse();
504 TArray<ResponseType> ParsedResponses;
505
506 if (ParseStreamRequest(Response, ParsedResponses))
507 {
508 LogResponse(Response);
509 Delegate.Broadcast(ParsedResponses, GetResponseHeaders(Response));
510 }
511 else if (Response.IsValid())
512 {
513 LogError(Response->GetContentAsString());
514 // RequestError.Broadcast(Response->GetURL(), Response->GetContentAsString());
515 }
516 else if (BytesReceived == 0)
517 {
518 // UE_5.3: on some reason OnRequestProgress() sends first time with Request = nullptr
519 // BytesReceived = 0 in this case, empty initial call ?
520 // Remove error message from log because nothing bad happened
521 }
522 else
523 {
524 LogError(FString::Format(TEXT("JSON deserialization error BytesSent:{0} BytesReceived:{1}"), {BytesSent, BytesReceived}));
525 }
526 }
527
528 template <typename ResponseType, typename DelegateType>
529 void OnStreamCompleted(FHttpRequestPtr Request, FHttpResponsePtr Response, bool WasSuccessful, DelegateType& Delegate)
530 {
531 if (!WasSuccessful)
532 {
533 const auto& [URL, Content] = GetErrorData(Request, Response);
534 LogError(Content);
535 RequestError.Broadcast(URL, Content);
536 return;
537 }
538
539 TArray<ResponseType> ParsedResponses;
540 if (ParseStreamRequest(Response, ParsedResponses))
541 {
542 LogResponse(Response);
543 Delegate.Broadcast(ParsedResponses, GetResponseHeaders(Response));
544 }
545 else
546 {
547 const FString Content = Response.IsValid() ? Response->GetContentAsString() : FString{};
548 const FString ResponseURL = Response.IsValid() ? Response->GetURL() : FString{};
549
550 LogError("JSON deserialization error");
551 LogError(Content);
552 RequestError.Broadcast(ResponseURL, Content);
553 }
554 }
555};
Definition: OpenAI.Build.cs:6
Definition: OpenAIProvider.h:45
void SetLogEnabled(bool LogEnabled)
Definition: OpenAIProvider.h:292
Definition: UploadTypes.h:58
Definition: AudioTypes.h:103
Definition: AudioTypes.h:127
Definition: ChatCommonTypes.h:159
Definition: UploadTypes.h:70
Definition: CompletionTypes.h:16
Definition: AssistantTypes.h:42
Definition: BatchTypes.h:29
Definition: UploadTypes.h:24
Definition: EmbeddingTypes.h:22
Definition: FineTuneTypes.h:103
Definition: FineTuneTypes.h:168
Definition: AssistantTypes.h:123
Definition: BatchTypes.h:68
Definition: ModerationTypes.h:21
Definition: AssistantTypes.h:179
Definition: CommonTypes.h:11
Definition: ImageTypes.h:124
Definition: ImageTypes.h:61
Definition: ImageTypes.h:183
Definition: CommonTypes.h:49
Definition: AudioTypes.h:133
Definition: FileTypes.h:28