diff --git a/LLama.Unittest/LLamaContextWithCustomLoggerTests.cs b/LLama.Unittest/LLamaContextWithCustomLoggerTests.cs new file mode 100644 index 000000000..67f95a295 --- /dev/null +++ b/LLama.Unittest/LLamaContextWithCustomLoggerTests.cs @@ -0,0 +1,63 @@ +using LLama.Common; +using LLama.Native; +using Microsoft.Extensions.Logging; + +namespace LLama.Unittest +{ + public sealed class LLamaContextWithCustomLoggerTests + : IDisposable + { + private sealed class CustomLogger : ILogger + { + public IDisposable? BeginScope(TState state) where TState : notnull => default; + + public void Log( + LogLevel logLevel, + EventId eventId, + TState state, + Exception? exception, + Func formatter) + { + } + + public bool IsEnabled(LogLevel logLevel) => true; + } + + private readonly LLamaWeights _weights; + private readonly LLamaContext _context; + + public LLamaContextWithCustomLoggerTests() + { + var @params = new ModelParams(Constants.GenerativeModelPath) + { + ContextSize = 128, + GpuLayerCount = Constants.CIGpuLayerCount, + }; + + // This unit test used to fail when loading the weights with such a naive logger set. + // + // See https://github.com/SciSharp/LLamaSharp/issues/995 + // + // So the unit test here doesn't check that the logger is actually used + // but at least that setting one doesn't crash the weights load. + NativeLogConfig.llama_log_set(new CustomLogger()); + + _weights = LLamaWeights.LoadFromFile(@params); + _context = _weights.CreateContext(@params); + } + + public void Dispose() + { + _weights.Dispose(); + _context.Dispose(); + } + + [Fact] + public void CheckProperties() + { + Assert.Equal(128u, _context.ContextSize); + Assert.Equal(2048, _context.EmbeddingSize); + Assert.Equal(128256, _context.VocabCount); + } + } +} \ No newline at end of file diff --git a/LLama/Native/LLamaLogLevel.cs b/LLama/Native/LLamaLogLevel.cs index 07aca59ed..a381503ac 100644 --- a/LLama/Native/LLamaLogLevel.cs +++ b/LLama/Native/LLamaLogLevel.cs @@ -4,14 +4,26 @@ namespace LLama.Native { /// - /// Severity level of a log message + /// Severity level of a log message. This enum should always be aligned with + /// the one defined on llama.cpp side at + /// https://github.com/ggerganov/llama.cpp/blob/0eb4e12beebabae46d37b78742f4c5d4dbe52dc1/ggml/include/ggml.h#L559 /// public enum LLamaLogLevel { /// - /// Logs that highlight when the current flow of execution is stopped due to a failure. + /// Logs are never written. + /// + None = 0, + + /// + /// Logs that are used for interactive investigation during development. /// - Error = 2, + Debug = 1, + + /// + /// Logs that track the general flow of the application. + /// + Info = 2, /// /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the application execution to stop. @@ -19,28 +31,36 @@ public enum LLamaLogLevel Warning = 3, /// - /// Logs that track the general flow of the application. + /// Logs that highlight when the current flow of execution is stopped due to a failure. /// - Info = 4, + Error = 4, /// - /// Logs that are used for interactive investigation during development. + /// Continue log level is equivalent to None in the way it is used in llama.cpp. /// - Debug = 5, + Continue = 5, } internal static class LLamaLogLevelExtensions { + /// + /// Keeps track of the previous log level to be able to handle the log level . + /// + [ThreadStatic] private static LogLevel _previous; + public static LogLevel ToLogLevel(this LLamaLogLevel llama) { - return (llama) switch + _previous = llama switch { - LLamaLogLevel.Error => LogLevel.Error, - LLamaLogLevel.Warning => LogLevel.Warning, - LLamaLogLevel.Info => LogLevel.Information, + LLamaLogLevel.None => LogLevel.None, LLamaLogLevel.Debug => LogLevel.Debug, + LLamaLogLevel.Info => LogLevel.Information, + LLamaLogLevel.Warning => LogLevel.Warning, + LLamaLogLevel.Error => LogLevel.Error, + LLamaLogLevel.Continue => _previous, _ => throw new ArgumentOutOfRangeException(nameof(llama), llama, null) }; + return _previous; } } -} +} \ No newline at end of file