2023-06-01 20:01:27 +00:00
|
|
|
|
using System.Diagnostics;
|
2023-06-20 19:25:11 +00:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2023-06-01 20:01:27 +00:00
|
|
|
|
using Gpt4All.Bindings;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
2023-05-22 19:56:49 +00:00
|
|
|
|
|
2023-06-20 19:25:11 +00:00
|
|
|
|
[assembly: InternalsVisibleTo("Gpt4All.Tests")]
|
|
|
|
|
|
2023-05-22 19:56:49 +00:00
|
|
|
|
namespace Gpt4All;
|
|
|
|
|
|
|
|
|
|
public class Gpt4All : IGpt4AllModel
|
|
|
|
|
{
|
|
|
|
|
private readonly ILLModel _model;
|
2023-06-01 20:01:27 +00:00
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
|
|
|
|
|
|
private const string ResponseErrorMessage =
|
|
|
|
|
"The model reported an error during token generation error={ResponseError}";
|
2023-05-22 19:56:49 +00:00
|
|
|
|
|
2023-05-28 23:57:00 +00:00
|
|
|
|
/// <inheritdoc/>
|
|
|
|
|
public IPromptFormatter? PromptFormatter { get; set; }
|
|
|
|
|
|
2023-06-01 20:01:27 +00:00
|
|
|
|
internal Gpt4All(ILLModel model, ILogger? logger = null)
|
2023-05-22 19:56:49 +00:00
|
|
|
|
{
|
|
|
|
|
_model = model;
|
2023-06-01 20:01:27 +00:00
|
|
|
|
_logger = logger ?? NullLogger.Instance;
|
2023-05-28 23:57:00 +00:00
|
|
|
|
PromptFormatter = new DefaultPromptFormatter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string FormatPrompt(string prompt)
|
|
|
|
|
{
|
|
|
|
|
if (PromptFormatter == null) return prompt;
|
|
|
|
|
|
|
|
|
|
return PromptFormatter.FormatPrompt(prompt);
|
2023-05-22 19:56:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<ITextPredictionResult> GetPredictionAsync(string text, PredictRequestOptions opts, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
2023-05-28 23:57:00 +00:00
|
|
|
|
ArgumentNullException.ThrowIfNull(text);
|
|
|
|
|
|
2023-05-22 19:56:49 +00:00
|
|
|
|
return Task.Run(() =>
|
|
|
|
|
{
|
2023-06-01 20:01:27 +00:00
|
|
|
|
_logger.LogInformation("Start prediction task");
|
|
|
|
|
|
|
|
|
|
var sw = Stopwatch.StartNew();
|
2023-05-22 19:56:49 +00:00
|
|
|
|
var result = new TextPredictionResult();
|
|
|
|
|
var context = opts.ToPromptContext();
|
2023-05-28 23:57:00 +00:00
|
|
|
|
var prompt = FormatPrompt(text);
|
2023-05-22 19:56:49 +00:00
|
|
|
|
|
2023-06-01 20:01:27 +00:00
|
|
|
|
try
|
2023-05-22 19:56:49 +00:00
|
|
|
|
{
|
2023-06-01 20:01:27 +00:00
|
|
|
|
_model.Prompt(prompt, context, responseCallback: e =>
|
2023-05-22 19:56:49 +00:00
|
|
|
|
{
|
2023-06-01 20:01:27 +00:00
|
|
|
|
if (e.IsError)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogWarning(ResponseErrorMessage, e.Response);
|
|
|
|
|
result.Success = false;
|
|
|
|
|
result.ErrorMessage = e.Response;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
result.Append(e.Response);
|
|
|
|
|
return true;
|
|
|
|
|
}, cancellationToken: cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError(e, "Prompt error");
|
|
|
|
|
result.Success = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sw.Stop();
|
|
|
|
|
_logger.LogInformation("Prediction task completed elapsed={Elapsed}s", sw.Elapsed.TotalSeconds);
|
2023-05-22 19:56:49 +00:00
|
|
|
|
|
|
|
|
|
return (ITextPredictionResult)result;
|
|
|
|
|
}, CancellationToken.None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<ITextPredictionStreamingResult> GetStreamingPredictionAsync(string text, PredictRequestOptions opts, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
2023-05-28 23:57:00 +00:00
|
|
|
|
ArgumentNullException.ThrowIfNull(text);
|
|
|
|
|
|
2023-05-22 19:56:49 +00:00
|
|
|
|
var result = new TextPredictionStreamingResult();
|
|
|
|
|
|
|
|
|
|
_ = Task.Run(() =>
|
|
|
|
|
{
|
2023-06-01 20:01:27 +00:00
|
|
|
|
_logger.LogInformation("Start streaming prediction task");
|
|
|
|
|
var sw = Stopwatch.StartNew();
|
|
|
|
|
|
2023-05-22 19:56:49 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var context = opts.ToPromptContext();
|
2023-05-28 23:57:00 +00:00
|
|
|
|
var prompt = FormatPrompt(text);
|
2023-05-22 19:56:49 +00:00
|
|
|
|
|
2023-05-28 23:57:00 +00:00
|
|
|
|
_model.Prompt(prompt, context, responseCallback: e =>
|
2023-05-22 19:56:49 +00:00
|
|
|
|
{
|
|
|
|
|
if (e.IsError)
|
|
|
|
|
{
|
2023-06-01 20:01:27 +00:00
|
|
|
|
_logger.LogWarning(ResponseErrorMessage, e.Response);
|
2023-05-22 19:56:49 +00:00
|
|
|
|
result.Success = false;
|
|
|
|
|
result.ErrorMessage = e.Response;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
result.Append(e.Response);
|
|
|
|
|
return true;
|
|
|
|
|
}, cancellationToken: cancellationToken);
|
|
|
|
|
}
|
2023-06-01 20:01:27 +00:00
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError(e, "Prompt error");
|
|
|
|
|
result.Success = false;
|
|
|
|
|
}
|
2023-05-22 19:56:49 +00:00
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
result.Complete();
|
2023-06-01 20:01:27 +00:00
|
|
|
|
sw.Stop();
|
|
|
|
|
_logger.LogInformation("Prediction task completed elapsed={Elapsed}s", sw.Elapsed.TotalSeconds);
|
2023-05-22 19:56:49 +00:00
|
|
|
|
}
|
|
|
|
|
}, CancellationToken.None);
|
|
|
|
|
|
|
|
|
|
return Task.FromResult((ITextPredictionStreamingResult)result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
|
|
|
|
_model.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
}
|