Skip to content

Commit

Permalink
Merge pull request #166 from JerrettDavis/code-cleanup
Browse files Browse the repository at this point in the history
Documentation Updates and Code Cleanup
  • Loading branch information
awaescher authored Jan 9, 2025
2 parents 9a4b969 + ce3b8b9 commit 9a43aaa
Show file tree
Hide file tree
Showing 16 changed files with 666 additions and 219 deletions.
5 changes: 3 additions & 2 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>

<!-- IDE0130: Namespace does not match folder structure -->
<NoWarn>IDE0130</NoWarn>
<!-- NU5104: A stable release of a package should not have a prerelease depedency. -->
<NoWarn>IDE0130;NU5104</NoWarn>
</PropertyGroup>
</Project>
</Project>
4 changes: 0 additions & 4 deletions src/ByteArrayExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace OllamaSharp;

/// <summary>
Expand Down
292 changes: 233 additions & 59 deletions src/Chat.cs

Large diffs are not rendered by default.

67 changes: 67 additions & 0 deletions src/CollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
namespace OllamaSharp;

/// <summary>
/// Provides extension methods for working with collections.
/// </summary>
internal static class CollectionExtensions
{
/// <summary>
/// Adds the elements of the specified collection to the end of the list if the collection is not <c>null</c>.
/// </summary>
/// <typeparam name="T">The type of elements in the list and collection.</typeparam>
/// <param name="list">The list to which the elements should be added.</param>
/// <param name="items">
/// The collection whose elements should be added to the list.
/// If <c>null</c>, no operations are performed.
/// </param>
/// <example>
/// Example usage:
/// <code>
/// List&lt;int> myList = new List&lt;int> { 1, 2, 3 };
/// IEnumerable&lt;int>? additionalItems = new List&lt;int> { 4, 5, 6 };
/// myList.AddRangeIfNotNull(additionalItems);
/// // myList now contains { 1, 2, 3, 4, 5, 6 }
/// IEnumerable&lt;int>? nullItems = null;
/// myList.AddRangeIfNotNull(nullItems);
/// // myList remains unchanged { 1, 2, 3, 4, 5, 6 }
/// </code>
/// </example>
public static void AddRangeIfNotNull<T>(this List<T> list, IEnumerable<T>? items)
{
if (items is not null)
list.AddRange(items);
}

/// <summary>
/// Executes the specified action for each item in the provided collection.
/// </summary>
/// <typeparam name="T">The type of the elements in the collection.</typeparam>
/// <param name="collection">
/// The enumerable collection whose elements the action will be performed upon.
/// </param>
/// <param name="action">
/// An <see cref="Action{T}"/> delegate to perform on each element of the collection.
/// </param>
/// <example>
/// Example usage:
/// <code>
/// List&lt;string> fruits = new List&lt;string> { "apple", "banana", "cherry" };
/// fruits.ForEachItem(fruit => Console.WriteLine(fruit));
/// // Output:
/// // apple
/// // banana
/// // cherry
/// IEnumerable&lt;int> numbers = new List&lt;int> { 1, 2, 3 };
/// numbers.ForEachItem(number => Console.WriteLine(number * 2));
/// // Output:
/// // 2
/// // 4
/// // 6
/// </code>
/// </example>
public static void ForEachItem<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection)
action(item);
}
}
37 changes: 37 additions & 0 deletions src/Constants/Application.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace OllamaSharp.Constants;

/// <summary>
/// Contains constant values used throughout the application.
/// </summary>
internal static class Application
{
public const string Ollama = "ollama";
public const string KeepAlive = "keep_alive";
public const string Truncate = "truncate";
public const string LoadDuration = "load_duration";
public const string TotalDuration = "total_duration";
public const string PromptEvalDuration = "prompt_eval_duration";
public const string PromptEvalCount = "prompt_eval_count";
public const string EvalDuration = "eval_duration";
public const string EvalCount = "eval_count";
public const string Context = "context";
public const string Done = "done";
public const string Response = "response";
public const string CreatedAt = "created_at";
public const string Model = "model";

public const string Assistant = "assistant";
public const string System = "system";
public const string User = "user";
public const string Tool = "tool";

public const string Length = "length";
public const string Stop = "stop";

public const string Object = "object";
public const string Function = "function";

public const string Json = "json";

public const string NotApplicable = "n/a";
}
26 changes: 26 additions & 0 deletions src/Constants/Endpoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace OllamaSharp.Constants;

/// <summary>
/// Provides a collection of constant endpoint URLs used by the API in the OllamaSharp library.
/// </summary>
/// <remarks>
/// <p>
/// This static class contains various string constants that represent API endpoints. These constants are used primarily
/// in API client implementations for making requests to specific functionality provided by the backend API.
/// </p>
/// </remarks>
internal static class Endpoints
{
public const string CreateModel = "api/create";
public const string DeleteModel = "api/delete";
public const string ListLocalModels = "api/tags";
public const string ListRunningModels = "api/ps";
public const string ShowModel = "api/show";
public const string CopyModel = "api/copy";
public const string PullModel = "api/pull";
public const string PushModel = "api/push";
public const string Embed = "api/embed";
public const string Chat = "api/chat";
public const string Version = "api/version";
public const string Generate = "api/generate";
}
12 changes: 12 additions & 0 deletions src/Constants/MimeTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace OllamaSharp.Constants;

/// <summary>
/// Provides predefined MIME type constants to be used across the application.
/// <p>
/// MIME types are used to specify the format of data being sent or received in HTTP requests.
/// </p>
/// </summary>
internal static class MimeTypes
{
public const string Json = "application/json";
}
20 changes: 5 additions & 15 deletions src/HttpRequestMessageExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using OllamaSharp.Models;

Expand All @@ -18,14 +16,8 @@ internal static class HttpRequestMessageExtensions
/// <param name="ollamaRequest">An optional <see cref="OllamaRequest"/> to get additional custom headers from.</param>
public static void ApplyCustomHeaders(this HttpRequestMessage requestMessage, Dictionary<string, string> headers, OllamaRequest? ollamaRequest)
{
foreach (var header in headers)
AddOrUpdateHeaderValue(requestMessage.Headers, header.Key, header.Value);

if (ollamaRequest != null)
{
foreach (var header in ollamaRequest.CustomHeaders)
AddOrUpdateHeaderValue(requestMessage.Headers, header.Key, header.Value);
}
var concatenated = headers.Concat(ollamaRequest?.CustomHeaders ?? []);
concatenated.ForEachItem(header => requestMessage.Headers.AddOrUpdateHeaderValue(header.Key, header.Value));
}

/// <summary>
Expand All @@ -34,11 +26,9 @@ public static void ApplyCustomHeaders(this HttpRequestMessage requestMessage, Di
/// <param name="requestMessageHeaders">The <see cref="HttpRequestHeaders"/> collection to update.</param>
/// <param name="headerKey">The key of the header to add or update.</param>
/// <param name="headerValue">The value of the header to add or update.</param>
private static void AddOrUpdateHeaderValue(HttpRequestHeaders requestMessageHeaders, string headerKey, string headerValue)
private static void AddOrUpdateHeaderValue(this HttpRequestHeaders requestMessageHeaders, string headerKey, string headerValue)
{
if (requestMessageHeaders.Contains(headerKey))
requestMessageHeaders.Remove(headerKey);

requestMessageHeaders.Remove(headerKey);
requestMessageHeaders.Add(headerKey, headerValue);
}
}
}
59 changes: 29 additions & 30 deletions src/MicrosoftAi/AbstractionMapper.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Extensions.AI;
using OllamaSharp.Constants;
using OllamaSharp.Models;
using OllamaSharp.Models.Chat;
using ChatRole = OllamaSharp.Models.Chat.ChatRole;

namespace OllamaSharp.MicrosoftAi;

Expand Down Expand Up @@ -53,7 +52,7 @@ public static ChatRequest ToOllamaSharpChatRequest(IList<ChatMessage> chatMessag
{
var request = new ChatRequest
{
Format = Equals(options?.ResponseFormat, ChatResponseFormat.Json) ? "json" : null,
Format = Equals(options?.ResponseFormat, ChatResponseFormat.Json) ? Application.Json : null,
KeepAlive = null,
Messages = ToOllamaSharpMessages(chatMessages, serializerOptions),
Model = options?.ModelId ?? "", // will be set OllamaApiClient.SelectedModel if not set
Expand Down Expand Up @@ -167,17 +166,17 @@ private static Tool ToOllamaSharpTool(AIFunctionMetadata functionMetadata)
Name = functionMetadata.Name,
Parameters = new Parameters
{
Properties = functionMetadata.Parameters.ToDictionary(p => p.Name, p => new Models.Chat.Property
Properties = functionMetadata.Parameters.ToDictionary(p => p.Name, p => new Property
{
Description = p.Description,
Enum = GetPossibleValues(p.Schema as JsonObject),
Type = ToFunctionTypeString(p.Schema as JsonObject)
}),
Required = functionMetadata.Parameters.Where(p => p.IsRequired).Select(p => p.Name),
Type = "object"
Type = Application.Object
}
},
Type = "function"
Type = Application.Function
};
}

Expand Down Expand Up @@ -238,7 +237,7 @@ private static IEnumerable<Message> ToOllamaSharpMessages(IList<ChatMessage> cha
CallId = frc.CallId,
Result = jsonResult,
}, serializerOptions),
Role = Models.Chat.ChatRole.Tool,
Role = ChatRole.Tool,
};
}
}
Expand Down Expand Up @@ -282,15 +281,15 @@ private static Message.ToolCall ToOllamaSharpToolCall(FunctionCallContent functi
/// </summary>
/// <param name="role">The chat role to map.</param>
/// <returns>A <see cref="OllamaSharp.Models.Chat.ChatRole"/> object containing the mapped role.</returns>
private static Models.Chat.ChatRole ToOllamaSharpRole(Microsoft.Extensions.AI.ChatRole role)
private static ChatRole ToOllamaSharpRole(Microsoft.Extensions.AI.ChatRole role)
{
return role.Value switch
{
"assistant" => Models.Chat.ChatRole.Assistant,
"system" => Models.Chat.ChatRole.System,
"user" => Models.Chat.ChatRole.User,
"tool" => Models.Chat.ChatRole.Tool,
_ => new Models.Chat.ChatRole(role.Value),
Application.Assistant => ChatRole.Assistant,
Application.System => ChatRole.System,
Application.User => ChatRole.User,
Application.Tool => ChatRole.Tool,
_ => new ChatRole(role.Value),
};
}

Expand All @@ -299,17 +298,17 @@ private static Models.Chat.ChatRole ToOllamaSharpRole(Microsoft.Extensions.AI.Ch
/// </summary>
/// <param name="role">The chat role to map.</param>
/// <returns>A <see cref="Microsoft.Extensions.AI.ChatRole"/> object containing the mapped role.</returns>
private static Microsoft.Extensions.AI.ChatRole ToAbstractionRole(OllamaSharp.Models.Chat.ChatRole? role)
private static Microsoft.Extensions.AI.ChatRole ToAbstractionRole(ChatRole? role)
{
if (role is null)
return new Microsoft.Extensions.AI.ChatRole("unknown");

return role.ToString() switch
{
"assistant" => Microsoft.Extensions.AI.ChatRole.Assistant,
"system" => Microsoft.Extensions.AI.ChatRole.System,
"user" => Microsoft.Extensions.AI.ChatRole.User,
"tool" => Microsoft.Extensions.AI.ChatRole.Tool,
Application.Assistant => Microsoft.Extensions.AI.ChatRole.Assistant,
Application.System => Microsoft.Extensions.AI.ChatRole.System,
Application.User => Microsoft.Extensions.AI.ChatRole.User,
Application.Tool => Microsoft.Extensions.AI.ChatRole.Tool,
_ => new Microsoft.Extensions.AI.ChatRole(role.ToString()!),
};
}
Expand Down Expand Up @@ -352,7 +351,7 @@ public static ChatMessage ToChatMessage(Message message)
if (toolCall.Function is { } function)
{
var id = Guid.NewGuid().ToString().Substring(0, 8);
contents.Add(new FunctionCallContent(id, function.Name ?? "n/a", function.Arguments) { RawRepresentation = toolCall });
contents.Add(new FunctionCallContent(id, function.Name ?? Application.NotApplicable, function.Arguments) { RawRepresentation = toolCall });
}
}
}
Expand All @@ -376,10 +375,10 @@ private static AdditionalPropertiesDictionary ParseOllamaChatResponseProps(ChatD

return new AdditionalPropertiesDictionary
{
["load_duration"] = TimeSpan.FromMilliseconds(response.LoadDuration / NANOSECONDS_PER_MILLISECOND),
["total_duration"] = TimeSpan.FromMilliseconds(response.TotalDuration / NANOSECONDS_PER_MILLISECOND),
["prompt_eval_duration"] = TimeSpan.FromMilliseconds(response.PromptEvalDuration / NANOSECONDS_PER_MILLISECOND),
["eval_duration"] = TimeSpan.FromMilliseconds(response.EvalDuration / NANOSECONDS_PER_MILLISECOND)
[Application.LoadDuration] = TimeSpan.FromMilliseconds(response.LoadDuration / NANOSECONDS_PER_MILLISECOND),
[Application.TotalDuration] = TimeSpan.FromMilliseconds(response.TotalDuration / NANOSECONDS_PER_MILLISECOND),
[Application.PromptEvalDuration] = TimeSpan.FromMilliseconds(response.PromptEvalDuration / NANOSECONDS_PER_MILLISECOND),
[Application.EvalDuration] = TimeSpan.FromMilliseconds(response.EvalDuration / NANOSECONDS_PER_MILLISECOND)
};
}

Expand All @@ -394,8 +393,8 @@ private static AdditionalPropertiesDictionary ParseOllamaEmbedResponseProps(Embe

return new AdditionalPropertiesDictionary
{
["load_duration"] = TimeSpan.FromMilliseconds((response.LoadDuration ?? 0) / NANOSECONDS_PER_MILLISECOND),
["total_duration"] = TimeSpan.FromMilliseconds((response.TotalDuration ?? 0) / NANOSECONDS_PER_MILLISECOND)
[Application.LoadDuration] = TimeSpan.FromMilliseconds((response.LoadDuration ?? 0) / NANOSECONDS_PER_MILLISECOND),
[Application.TotalDuration] = TimeSpan.FromMilliseconds((response.TotalDuration ?? 0) / NANOSECONDS_PER_MILLISECOND)
};
}

Expand All @@ -409,8 +408,8 @@ private static AdditionalPropertiesDictionary ParseOllamaEmbedResponseProps(Embe
return ollamaDoneReason switch
{
null => null,
"length" => ChatFinishReason.Length,
"stop" => ChatFinishReason.Stop,
Application.Length => ChatFinishReason.Length,
Application.Stop => ChatFinishReason.Stop,
_ => new ChatFinishReason(ollamaDoneReason),
};
}
Expand Down Expand Up @@ -451,10 +450,10 @@ public static EmbedRequest ToOllamaEmbedRequest(IEnumerable<string> values, Embe

if (options?.AdditionalProperties is { } requestProps)
{
if (requestProps.TryGetValue("keep_alive", out long keepAlive))
if (requestProps.TryGetValue(Application.KeepAlive, out long keepAlive))
request.KeepAlive = keepAlive;

if (requestProps.TryGetValue("truncate", out bool truncate))
if (requestProps.TryGetValue(Application.Truncate, out bool truncate))
request.Truncate = truncate;
}

Expand Down
Loading

0 comments on commit 9a43aaa

Please sign in to comment.