-
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.
- Loading branch information
Showing
32 changed files
with
1,906 additions
and
4 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,31 @@ | ||
name: Tests | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
pull_request: | ||
branches: [ main ] | ||
|
||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Setup .NET | ||
uses: actions/setup-dotnet@v3 | ||
with: | ||
dotnet-version: | | ||
6.0.x | ||
7.0.x | ||
8.0.x | ||
- name: Restore dependencies | ||
run: dotnet restore | ||
|
||
- name: Build | ||
run: dotnet build --no-restore | ||
|
||
- name: Test (Unit Only) | ||
run: dotnet test --no-build --verbosity normal --filter "Category!=Integration" |
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 |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Contributing to LocalAI.NET | ||
|
||
## Publishing to NuGet | ||
|
||
### Prerequisites | ||
1. Create a NuGet account at https://www.nuget.org | ||
2. Generate an API key: | ||
- Go to https://www.nuget.org/account/apikeys | ||
- Click "Create" | ||
- Name: "LocalAI.NET.KoboldCpp Publishing" (or your preferred name) | ||
- Expiration: 365 days | ||
- Select "Push new packages and package versions" | ||
- Glob Pattern: "LocalAI.NET.KoboldCpp*" | ||
- Save the generated key securely | ||
|
||
### Publishing Process | ||
1. Update version in `LocalAI.NET.KoboldCpp/LocalAI.NET.KoboldCpp.csproj`: | ||
```xml | ||
<Version>1.0.0</Version> <!-- Change this to new version --> | ||
``` | ||
|
||
2. Clean and pack: | ||
```bash | ||
dotnet clean | ||
dotnet pack -c Release | ||
``` | ||
|
||
3. Push to NuGet: | ||
```bash | ||
dotnet nuget push .\LocalAI.NET.KoboldCpp\bin\Release\LocalAI.NET.KoboldCpp.1.0.0.nupkg --api-key YOUR_API_KEY --source https://api.nuget.org/v3/index.json | ||
``` | ||
Replace: | ||
- `1.0.0` with your new version number | ||
- `YOUR_API_KEY` with your NuGet API key | ||
|
||
4. Wait 15-30 minutes for the package to appear on NuGet.org | ||
|
||
### Version Guidelines | ||
- Use [Semantic Versioning](https://semver.org/): | ||
- MAJOR version for incompatible API changes | ||
- MINOR version for backwards-compatible functionality | ||
- PATCH version for backwards-compatible bug fixes | ||
|
||
## Development Guidelines | ||
|
||
### Code Style | ||
- Use C# latest features and best practices | ||
- Follow Microsoft's [C# Coding Conventions](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions) | ||
- Use meaningful names for variables, methods, and classes | ||
- Add XML documentation comments for public APIs | ||
|
||
### Testing | ||
1. Write unit tests for new features | ||
2. Ensure all tests pass before submitting PR: | ||
```bash | ||
dotnet test | ||
``` | ||
|
||
### Pull Request Process | ||
1. Fork the repository | ||
2. Create a feature branch | ||
3. Make your changes | ||
4. Update documentation and tests | ||
5. Submit a pull request | ||
|
||
## Questions? | ||
Open an issue on GitHub if you have questions or need help. |
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,3 @@ | ||
using Xunit; | ||
|
||
[assembly: CollectionBehavior(DisableTestParallelization = true)] |
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,46 @@ | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace LocalAI.NET.Oobabooga.Tests.Common | ||
{ | ||
public abstract class IntegrationTestBase : TestBase, IAsyncLifetime | ||
{ | ||
protected bool ServerAvailable; | ||
|
||
protected IntegrationTestBase(ITestOutputHelper output) : base(output) | ||
{ | ||
} | ||
|
||
public virtual async Task InitializeAsync() | ||
{ | ||
try | ||
{ | ||
using var httpClient = new HttpClient(); | ||
var response = await httpClient.GetAsync($"{TestConfig.BaseApiUrl}/v1/models"); | ||
ServerAvailable = response.IsSuccessStatusCode; | ||
|
||
if (ServerAvailable) | ||
{ | ||
Output.WriteLine("API endpoint is available"); | ||
} | ||
else | ||
{ | ||
Output.WriteLine("API endpoint is not available"); | ||
throw new SkipTestException("API endpoint is not available"); | ||
} | ||
} | ||
catch (Exception ex) when (ex is not SkipTestException) | ||
{ | ||
Output.WriteLine($"Failed to connect to API endpoint: {ex.Message}"); | ||
throw new SkipTestException("Failed to connect to API endpoint"); | ||
} | ||
} | ||
|
||
public virtual Task DisposeAsync() => Task.CompletedTask; | ||
|
||
protected class SkipTestException : Exception | ||
{ | ||
public SkipTestException(string message) : base(message) { } | ||
} | ||
} | ||
} |
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,74 @@ | ||
using LocalAI.NET.Oobabooga.Providers.OpenAiCompatible; | ||
using Microsoft.Extensions.Logging; | ||
using Newtonsoft.Json; | ||
using WireMock.Server; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace LocalAI.NET.Oobabooga.Tests.Common | ||
{ | ||
public abstract class OobaboogaTestBase : IAsyncLifetime | ||
{ | ||
protected readonly IOpenAiCompatibleProvider Provider; | ||
protected readonly ITestOutputHelper Output; | ||
protected readonly ILogger Logger; | ||
protected bool ServerAvailable; | ||
|
||
protected OobaboogaTestBase(ITestOutputHelper output) | ||
{ | ||
Output = output; | ||
Logger = LoggerFactory | ||
.Create(builder => builder.AddXUnit(output)) | ||
.CreateLogger(GetType()); | ||
|
||
var httpClient = new HttpClient | ||
{ | ||
BaseAddress = new Uri(TestConfig.BaseApiUrl), | ||
Timeout = TimeSpan.FromSeconds(TestConfig.TimeoutSeconds) | ||
}; | ||
|
||
var jsonSettings = new JsonSerializerSettings | ||
{ | ||
NullValueHandling = NullValueHandling.Ignore | ||
}; | ||
|
||
Provider = new OpenAiCompatibleProvider(httpClient, logger: Logger, jsonSettings: jsonSettings); | ||
} | ||
|
||
public async Task InitializeAsync() | ||
{ | ||
try | ||
{ | ||
ServerAvailable = await Provider.IsAvailableAsync(); | ||
if (ServerAvailable) | ||
{ | ||
Output.WriteLine("OpenAI API endpoint is available"); | ||
} | ||
else | ||
{ | ||
Output.WriteLine("OpenAI API endpoint is not available"); | ||
throw new SkipTestException("OpenAI API endpoint is not available"); | ||
} | ||
} | ||
catch (Exception ex) when (ex is not SkipTestException) | ||
{ | ||
Output.WriteLine($"Failed to connect to OpenAI API endpoint: {ex.Message}"); | ||
throw new SkipTestException("Failed to connect to OpenAI API endpoint"); | ||
} | ||
} | ||
|
||
public Task DisposeAsync() | ||
{ | ||
if (Provider is IDisposable disposable) | ||
{ | ||
disposable.Dispose(); | ||
} | ||
return Task.CompletedTask; | ||
} | ||
|
||
private class SkipTestException : Exception | ||
{ | ||
public SkipTestException(string message) : base(message) { } | ||
} | ||
} | ||
} |
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,24 @@ | ||
using Microsoft.Extensions.Logging; | ||
using Xunit.Abstractions; | ||
|
||
namespace LocalAI.NET.Oobabooga.Tests.Common | ||
{ | ||
public abstract class TestBase : IDisposable | ||
{ | ||
protected readonly ILogger Logger; | ||
protected readonly ITestOutputHelper Output; | ||
|
||
protected TestBase(ITestOutputHelper output) | ||
{ | ||
Output = output; | ||
Logger = LoggerFactory | ||
.Create(builder => builder.AddXUnit(output)) | ||
.CreateLogger(GetType()); | ||
} | ||
|
||
public virtual void Dispose() | ||
{ | ||
// Cleanup if needed | ||
} | ||
} | ||
} |
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,12 @@ | ||
namespace LocalAI.NET.Oobabooga.Tests.Common | ||
{ | ||
public static class TestConfig | ||
{ | ||
private const string DefaultHost = "http://127.0.0.1:5000"; | ||
|
||
public static string BaseApiUrl => Environment.GetEnvironmentVariable("OOBABOOGA_BASE_URL") ?? $"{DefaultHost}"; | ||
|
||
// Extended timeout for large models | ||
public static int TimeoutSeconds => 120; | ||
} | ||
} |
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,23 @@ | ||
using WireMock.Server; | ||
using Xunit.Abstractions; | ||
|
||
namespace LocalAI.NET.Oobabooga.Tests.Common | ||
{ | ||
public abstract class UnitTestBase : TestBase | ||
{ | ||
protected readonly WireMockServer Server; | ||
protected readonly string BaseUrl; | ||
|
||
protected UnitTestBase(ITestOutputHelper output) : base(output) | ||
{ | ||
Server = WireMockServer.Start(); | ||
BaseUrl = Server.Urls[0]; | ||
} | ||
|
||
public override void Dispose() | ||
{ | ||
Server?.Dispose(); | ||
base.Dispose(); | ||
} | ||
} | ||
} |
75 changes: 75 additions & 0 deletions
75
LocalAI.NET.Oobabooga.Tests/Integration/OobaboogaIntegrationTests.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 |
---|---|---|
@@ -0,0 +1,75 @@ | ||
using FluentAssertions; | ||
using LocalAI.NET.Oobabooga.Client; | ||
using LocalAI.NET.Oobabooga.Models; | ||
using LocalAI.NET.Oobabooga.Models.Chat; | ||
using LocalAI.NET.Oobabooga.Models.Common; | ||
using LocalAI.NET.Oobabooga.Tests.Common; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace LocalAI.NET.Oobabooga.Tests.Integration | ||
{ | ||
public class OobaboogaIntegrationTests : IntegrationTestBase | ||
{ | ||
private readonly OobaboogaClient _client; | ||
|
||
public OobaboogaIntegrationTests(ITestOutputHelper output) : base(output) | ||
{ | ||
_client = new OobaboogaClient(new OobaboogaOptions | ||
{ | ||
BaseUrl = TestConfig.BaseApiUrl | ||
}, Logger); | ||
} | ||
|
||
[SkippableFact] | ||
[Trait("Category", "Integration")] | ||
public async Task Complete_WithSimplePrompt_ShouldWork() | ||
{ | ||
Skip.If(!ServerAvailable, "API endpoint not available"); | ||
|
||
// Arrange & Act | ||
var response = await _client.CompleteAsync( | ||
"Once upon a time", | ||
new OobaboogaCompletionOptions | ||
{ | ||
MaxTokens = 20, | ||
Temperature = 0.7f, | ||
TopP = 0.9f | ||
}); | ||
|
||
// Assert | ||
response.Should().NotBeNullOrEmpty(); | ||
Output.WriteLine($"Completion response: {response}"); | ||
} | ||
|
||
[Fact] | ||
[Trait("Category", "Integration")] | ||
public async Task ChatComplete_WithInstructTemplate_ShouldWork() | ||
{ | ||
Skip.If(!ServerAvailable, "API endpoint not available"); | ||
|
||
// Arrange | ||
var messages = new List<OobaboogaChatMessage> | ||
{ | ||
new() { Role = "user", Content = "Write a short story" } | ||
}; | ||
|
||
// Act | ||
var response = await _client.ChatCompleteAsync( | ||
messages, | ||
new OobaboogaChatCompletionOptions | ||
{ | ||
Mode = "instruct", | ||
InstructionTemplate = "Alpaca", | ||
MaxTokens = 100 | ||
}); | ||
|
||
// Assert | ||
response.Should().NotBeNull(); | ||
response.Choices.Should().NotBeNull(); | ||
response.Choices.Should().NotBeEmpty("API should return at least one choice"); | ||
response.Choices.First().Message.Should().NotBeNull("Choice should contain a message"); | ||
response.Choices.First().Message.Content.Should().NotBeNullOrEmpty("Message should contain content"); | ||
} | ||
} | ||
} |
Oops, something went wrong.