Skip to content

Commit

Permalink
implement ICompletionService
Browse files Browse the repository at this point in the history
  • Loading branch information
dclipca committed Jan 24, 2025
1 parent f5c5363 commit 96d302d
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 7 deletions.
117 changes: 114 additions & 3 deletions SpongeEngine.LMStudioSharp/LmStudioSharpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
using Microsoft.Extensions.Logging;
using SpongeEngine.LLMSharp.Core;
using SpongeEngine.LLMSharp.Core.Exceptions;
using SpongeEngine.LMStudioSharp.Models.Chat;
using SpongeEngine.LLMSharp.Core.Interfaces;
using SpongeEngine.LLMSharp.Core.Models;
using SpongeEngine.LMStudioSharp.Models.Completion;
using SpongeEngine.LMStudioSharp.Models.Embedding;
using SpongeEngine.LMStudioSharp.Models.Model;
using ChatRequest = SpongeEngine.LMStudioSharp.Models.Chat.ChatRequest;
using ChatResponse = SpongeEngine.LMStudioSharp.Models.Chat.ChatResponse;
using CompletionRequest = SpongeEngine.LMStudioSharp.Models.Completion.CompletionRequest;
using EmbeddingRequest = SpongeEngine.LMStudioSharp.Models.Embedding.EmbeddingRequest;
using EmbeddingResponse = SpongeEngine.LMStudioSharp.Models.Embedding.EmbeddingResponse;

namespace SpongeEngine.LMStudioSharp
{
public class LmStudioSharpClient : LlmClientBase
public class LmStudioSharpClient : LlmClientBase, ICompletionService
{
public override LmStudioClientOptions Options { get; }

Expand Down Expand Up @@ -255,5 +260,111 @@ public class StreamChoice
public string? FinishReason { get; set; }
}
}

public async Task<CompletionResult> CompleteAsync(
LLMSharp.Core.Models.CompletionRequest request,
CancellationToken cancellationToken = default)
{
// Convert LLMSharp Core request to LMStudio request
var lmStudioRequest = new Models.Completion.CompletionRequest
{
Model = request.ModelId,
Prompt = request.Prompt,
MaxTokens = request.MaxTokens ?? -1,
Temperature = request.Temperature,
TopP = request.TopP,
Stop = request.StopSequences.Count > 0 ? request.StopSequences.ToArray() : null,
Stream = false
};

// Apply any additional provider-specific parameters
foreach (var param in request.ProviderParameters)
{
Options.Logger?.LogDebug("Additional provider parameter: {Key}={Value}", param.Key, param.Value);
}

// Call LMStudio API and measure time
var startTime = DateTime.UtcNow;
var response = await CompleteAsync(lmStudioRequest, cancellationToken);
var generationTime = DateTime.UtcNow - startTime;

// Extract the completion text from the first choice
var completionText = response.Choices.FirstOrDefault()?.GetText() ?? string.Empty;

// Convert LMStudio response to LLMSharp Core response
return new CompletionResult
{
Text = completionText,
ModelId = response.Model,
TokenUsage = new CompletionTokenUsage
{
PromptTokens = response.Usage.PromptTokens,
CompletionTokens = response.Usage.CompletionTokens ?? 0,
TotalTokens = response.Usage.TotalTokens
},
FinishReason = response.Choices.FirstOrDefault()?.FinishReason,
GenerationTime = generationTime,
Metadata = new Dictionary<string, object>
{
["provider"] = "LMStudio",
["tokensPerSecond"] = response.Stats.TokensPerSecond,
["timeToFirstToken"] = response.Stats.TimeToFirstToken,
["architecture"] = response.ModelInfo.Architecture,
["quantization"] = response.ModelInfo.Quantization,
["format"] = response.ModelInfo.Format,
["contextLength"] = response.ModelInfo.ContextLength,
["runtime"] = response.Runtime.Name,
["runtimeVersion"] = response.Runtime.Version
}
};
}

public async IAsyncEnumerable<CompletionToken> StreamCompletionAsync(
LLMSharp.Core.Models.CompletionRequest request,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
// Convert LLMSharp Core request to LMStudio request
var lmStudioRequest = new Models.Completion.CompletionRequest
{
Model = request.ModelId,
Prompt = request.Prompt,
MaxTokens = request.MaxTokens ?? -1,
Temperature = request.Temperature,
TopP = request.TopP,
Stop = request.StopSequences.Count > 0 ? request.StopSequences.ToArray() : null,
Stream = true
};

// Apply any additional provider-specific parameters
foreach (var param in request.ProviderParameters)
{
Options.Logger?.LogDebug("Additional provider parameter: {Key}={Value}", param.Key, param.Value);
}

// Stream responses from LMStudio API and track tokens
var totalTokens = 0;
var lastChoice = new StreamResponse.StreamChoice();

await foreach (var token in StreamCompletionAsync(lmStudioRequest, cancellationToken))
{
// Estimate token count - in practice you'd want to use a proper tokenizer here
// This is a rough approximation based on whitespace
var tokenCount = token.Split(new[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries).Length;
totalTokens += tokenCount;

yield return new CompletionToken
{
Text = token,
TokenCount = totalTokens,
FinishReason = lastChoice.FinishReason
};

// Store last choice to get finish reason
if (lastChoice.FinishReason != null)
{
break;
}
}
}
}
}
5 changes: 1 addition & 4 deletions SpongeEngine.LMStudioSharp/SpongeEngine.LMStudioSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<!-- Package Info -->
<PackageId>SpongeEngine.LMStudioSharp</PackageId>
<Title>LMStudioSharp</Title>
<Version>0.3.8.3</Version>
<Version>0.3.8.4</Version>
<Authors>Dan Clipca</Authors>
<Company>Sponge Engine</Company>
<Description>C# client for LM Studio native API.</Description>
Expand Down Expand Up @@ -49,7 +49,4 @@
<ItemGroup>
<None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<Folder Include="Client\" />
</ItemGroup>
</Project>

0 comments on commit 96d302d

Please sign in to comment.