-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Remove support for embedded Ollama and Llamafile servers (#85)
* refactor: Make argument provider an enum * refactor: Use ExcelAsyncUtil to run task * feat: Remove support for embedded Ollama and Llamafile servers
- Loading branch information
1 parent
3a85d6f
commit 26da547
Showing
15 changed files
with
22 additions
and
628 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
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
118 changes: 4 additions & 114 deletions
118
src/Cellm/Models/Providers/Llamafile/LlamafileRequestHandler.cs
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,129 +1,19 @@ | ||
using System.Diagnostics; | ||
using Cellm.Models.Exceptions; | ||
using Cellm.Models.Local.Utilities; | ||
using Cellm.Models.Providers.OpenAiCompatible; | ||
using Cellm.Models.Providers.OpenAiCompatible; | ||
using MediatR; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Cellm.Models.Providers.Llamafile; | ||
|
||
internal class LlamafileRequestHandler : IProviderRequestHandler<LlamafileRequest, LlamafileResponse> | ||
internal class LlamafileRequestHandler(ISender sender, IOptions<LlamafileConfiguration> llamafileConfiguration) : IProviderRequestHandler<LlamafileRequest, LlamafileResponse> | ||
{ | ||
private record Llamafile(string ModelPath, Uri BaseAddress, Process Process); | ||
|
||
private readonly AsyncLazy<string> _llamafileExePath; | ||
private readonly Dictionary<string, AsyncLazy<Llamafile>> _llamafiles; | ||
private readonly ProcessManager _processManager; | ||
private readonly FileManager _fileManager; | ||
private readonly ServerManager _serverManager; | ||
|
||
private readonly LlamafileConfiguration _llamafileConfiguration; | ||
|
||
private readonly ISender _sender; | ||
private readonly ILogger<LlamafileRequestHandler> _logger; | ||
|
||
public LlamafileRequestHandler( | ||
IOptions<LlamafileConfiguration> llamafileConfiguration, | ||
ISender sender, | ||
HttpClient httpClient, | ||
FileManager fileManager, | ||
ProcessManager processManager, | ||
ServerManager serverManager, | ||
ILogger<LlamafileRequestHandler> logger) | ||
{ | ||
_llamafileConfiguration = llamafileConfiguration.Value; | ||
_sender = sender; | ||
_fileManager = fileManager; | ||
_processManager = processManager; | ||
_serverManager = serverManager; | ||
_logger = logger; | ||
|
||
_llamafileExePath = new AsyncLazy<string>(async () => | ||
{ | ||
var llamafileName = Path.GetFileName(_llamafileConfiguration.LlamafileUrl.Segments.Last()); | ||
return await _fileManager.DownloadFileIfNotExists(_llamafileConfiguration.LlamafileUrl, _fileManager.CreateCellmFilePath(CreateModelFileName($"{llamafileName}.exe"), "Llamafile")); | ||
}); | ||
|
||
_llamafiles = _llamafileConfiguration.Models.ToDictionary(x => x.Key, x => new AsyncLazy<Llamafile>(async () => | ||
{ | ||
// Download Llamafile | ||
var exePath = await _llamafileExePath; | ||
|
||
// Download model | ||
var modelPath = await _fileManager.DownloadFileIfNotExists(x.Value, _fileManager.CreateCellmFilePath(CreateModelFileName(x.Key), "Llamafile")); | ||
|
||
// Start server | ||
var baseAddress = new UriBuilder( | ||
_llamafileConfiguration.BaseAddress.Scheme, | ||
_llamafileConfiguration.BaseAddress.Host, | ||
_serverManager.FindPort(), | ||
_llamafileConfiguration.BaseAddress.AbsolutePath).Uri; | ||
|
||
var process = await StartProcess(exePath, modelPath, baseAddress); | ||
|
||
return new Llamafile(modelPath, baseAddress, process); | ||
})); | ||
} | ||
|
||
public async Task<LlamafileResponse> Handle(LlamafileRequest request, CancellationToken cancellationToken) | ||
{ | ||
// Start server on first call | ||
var llamafile = await _llamafiles[request.Prompt.Options.ModelId ?? _llamafileConfiguration.DefaultModel]; | ||
request.Prompt.Options.ModelId ??= llamafileConfiguration.Value.DefaultModel; | ||
|
||
var openAiResponse = await _sender.Send(new OpenAiCompatibleRequest(request.Prompt, llamafile.BaseAddress), cancellationToken); | ||
var openAiResponse = await sender.Send(new OpenAiCompatibleRequest(request.Prompt, llamafileConfiguration.Value.BaseAddress), cancellationToken); | ||
|
||
return new LlamafileResponse(openAiResponse.Prompt); | ||
} | ||
|
||
private async Task<Process> StartProcess(string exePath, string modelPath, Uri baseAddress) | ||
{ | ||
var processStartInfo = new ProcessStartInfo(exePath); | ||
|
||
processStartInfo.ArgumentList.Add("--server"); | ||
processStartInfo.ArgumentList.Add("--nobrowser"); | ||
processStartInfo.ArgumentList.Add("-m"); | ||
processStartInfo.ArgumentList.Add(modelPath); | ||
processStartInfo.ArgumentList.Add("--host"); | ||
processStartInfo.ArgumentList.Add(baseAddress.Host); | ||
processStartInfo.ArgumentList.Add("--port"); | ||
processStartInfo.ArgumentList.Add(baseAddress.Port.ToString()); | ||
|
||
if (_llamafileConfiguration.Gpu) | ||
{ | ||
processStartInfo.Arguments += $"-ngl {_llamafileConfiguration.GpuLayers} "; | ||
} | ||
|
||
processStartInfo.UseShellExecute = false; | ||
processStartInfo.CreateNoWindow = true; | ||
processStartInfo.RedirectStandardError = true; | ||
processStartInfo.RedirectStandardOutput = true; | ||
|
||
var process = Process.Start(processStartInfo) ?? throw new CellmModelException("Failed to run Llamafile"); | ||
|
||
process.OutputDataReceived += (sender, e) => | ||
{ | ||
if (!string.IsNullOrEmpty(e.Data)) | ||
{ | ||
_logger.LogDebug(e.Data); | ||
} | ||
}; | ||
|
||
process.BeginOutputReadLine(); | ||
process.BeginErrorReadLine(); | ||
|
||
var uriBuilder = new UriBuilder(baseAddress.Scheme, baseAddress.Host, baseAddress.Port, "/health"); | ||
await _serverManager.WaitForServer(uriBuilder.Uri, process); | ||
|
||
// Kill Llamafile when Excel exits or dies | ||
_processManager.AssignProcessToExcel(process); | ||
|
||
return process; | ||
} | ||
|
||
private static string CreateModelFileName(string modelName) | ||
{ | ||
return $"Llamafile-{modelName}"; | ||
} | ||
} | ||
|
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.