-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' into feature/dashboard-page
- Loading branch information
Showing
24 changed files
with
225 additions
and
336 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace ChatRPG.API; | ||
|
||
public class HttpClientFactory : IHttpClientFactory | ||
{ | ||
private HttpMessageHandlerFactory _httpMessageHandlerFactory; | ||
|
||
public HttpClientFactory(HttpMessageHandlerFactory httpMessageHandlerFactory) | ||
{ | ||
_httpMessageHandlerFactory = httpMessageHandlerFactory; | ||
} | ||
|
||
public HttpClient CreateClient(string name) | ||
{ | ||
return new HttpClient(_httpMessageHandlerFactory.CreateHandler()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1,48 @@ | ||
using Microsoft.IdentityModel.Tokens; | ||
using RestSharp; | ||
using RestSharp.Authenticators; | ||
using OpenAI_API; | ||
using OpenAI_API.Chat; | ||
|
||
namespace ChatRPG.API; | ||
|
||
public class OpenAiLlmClient : IOpenAiLlmClient, IDisposable | ||
public class OpenAiLlmClient : IOpenAiLlmClient | ||
{ | ||
private const string OpenAiBaseUrl = "https://api.openai.com/v1/"; | ||
private const string Model = "gpt-3.5-turbo"; | ||
private const double Temperature = 0.7; | ||
private const double PromptToken1KCost = 0.0015; | ||
private const double CompletionToken1KCost = 0.002; | ||
|
||
private readonly ILogger<OpenAiLlmClient> _logger; | ||
private readonly RestClient _client; | ||
private readonly OpenAIAPI _openAiApi; | ||
|
||
public OpenAiLlmClient(ILogger<OpenAiLlmClient> logger, IConfiguration configuration, | ||
HttpMessageHandler httpMessageHandler) | ||
public OpenAiLlmClient(IConfiguration configuration, IHttpClientFactory httpClientFactory) | ||
{ | ||
_logger = logger; | ||
|
||
var options = new RestClientOptions(OpenAiBaseUrl) | ||
{ | ||
Authenticator = new JwtAuthenticator(configuration.GetSection("ApiKeys").GetValue<string>("OpenAI") ?? string.Empty), | ||
FailOnDeserializationError = false, | ||
ConfigureMessageHandler = _ => httpMessageHandler | ||
}; | ||
_client = new RestClient(options); | ||
_openAiApi = new OpenAIAPI(configuration.GetSection("ApiKeys")?.GetValue<string>("OpenAI")); | ||
_openAiApi.Chat.DefaultChatRequestArgs.Model = Model; | ||
_openAiApi.Chat.DefaultChatRequestArgs.Temperature = Temperature; | ||
_openAiApi.HttpClientFactory = httpClientFactory; | ||
} | ||
|
||
public async Task<ChatCompletionObject> GetChatCompletion(List<OpenAiGptInputMessage> inputs) | ||
public async Task<string> GetChatCompletion(params OpenAiGptMessage[] inputs) | ||
{ | ||
if (inputs.IsNullOrEmpty()) throw new ArgumentNullException(nameof(inputs)); | ||
|
||
var openAiGptInput = new OpenAiGptInput(Model, inputs, Temperature); | ||
Conversation chat = CreateConversation(inputs); | ||
|
||
var request = new RestRequest("chat/completions", Method.Post); | ||
request.AddJsonBody(openAiGptInput, ContentType.Json); | ||
|
||
_logger.LogInformation(""" | ||
Request URL: {Url} | ||
Method: {Method} | ||
Parameters: {Parameters} | ||
Messages: {Messages} | ||
""", | ||
OpenAiBaseUrl + request.Resource, | ||
request.Method, | ||
string.Join(", ", request.Parameters.Select(p => $"{p.Name}={p.Value}")), | ||
string.Join(", ", inputs.Select(input => input.Content)) | ||
); | ||
return await chat.GetResponseFromChatbotAsync(); | ||
} | ||
|
||
var response = await _client.ExecuteAsync<ChatCompletionObject>(request); | ||
public IAsyncEnumerable<string> GetStreamedChatCompletion(params OpenAiGptMessage[] inputs) | ||
{ | ||
Conversation chat = CreateConversation(inputs); | ||
|
||
if (response.ErrorException != null) | ||
{ | ||
_logger.LogError("Error retrieving data from API: {ErrorExceptionMessage}", response.ErrorException.Message); | ||
} | ||
return chat.StreamResponseEnumerableFromChatbotAsync(); | ||
} | ||
|
||
var data = response!.Data; | ||
private Conversation CreateConversation(params OpenAiGptMessage[] messages) | ||
{ | ||
if (messages.IsNullOrEmpty()) throw new ArgumentNullException(nameof(messages)); | ||
|
||
if (data is null) | ||
Conversation chat = _openAiApi.Chat.CreateConversation(); | ||
foreach (OpenAiGptMessage openAiGptInputMessage in messages) | ||
{ | ||
throw new EmptyResponseException(response, "The API response has no data."); | ||
chat.AppendMessage(ChatMessageRole.FromString(openAiGptInputMessage.Role), openAiGptInputMessage.Content); | ||
} | ||
|
||
var promptTokens = data.Usage.PromptTokens; | ||
var completionTokens = data.Usage.CompletionTokens; | ||
|
||
var promptCost = (promptTokens / 1000.0) * PromptToken1KCost; | ||
var completionCost = (completionTokens / 1000.0) * CompletionToken1KCost; | ||
var estimatedCost = promptCost + completionCost; | ||
|
||
_logger.LogInformation(""" | ||
Prompt tokens: {PTokens} | ||
Completion tokens: {CTokens} | ||
Estimated cost: {EstCost} | ||
""", | ||
promptTokens, | ||
completionTokens, | ||
"$" + estimatedCost | ||
); | ||
|
||
return data; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_client.Dispose(); | ||
GC.SuppressFinalize(this); | ||
} | ||
} | ||
|
||
public class EmptyResponseException : Exception | ||
{ | ||
public RestResponse Response; | ||
public EmptyResponseException(RestResponse response, string message) : base(message) | ||
{ | ||
Response = response; | ||
return chat; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.