Skip to content

Commit

Permalink
Raised up ollama sharp plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Puchaczov committed Jan 28, 2025
1 parent 7929e1e commit 775fa49
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 68 deletions.
19 changes: 18 additions & 1 deletion Musoq.DataSources.Ollama.Tests/OllamaApiPlayground.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void DoSomeRealTests()
var library = new OllamaLibrary();
var entity = new OllamaEntity(
new OllamaApi(),
"llava:13b",
"llama3.2-vision:latest",
0,
CancellationToken.None);

Expand All @@ -25,4 +25,21 @@ public void DoSomeRealTests()
"How would you name this photo(filename)?",
library.ToBase64(File.ReadAllBytes("D:\\Photos\\Piotruś\\iphone\\202403__\\FIIG0678.JPG")));
}

[Ignore]
[TestMethod]
public void DoSomeOtherRealTests()
{
var library = new OllamaLibrary();
var entity = new OllamaEntity(
new OllamaApi(),
"llama3.2-vision:latest",
0,
CancellationToken.None);

var response = library.AskImage(
entity,
"Does the photo contain a cat? reply with \"yes\" or \"no\"",
library.ToBase64(File.ReadAllBytes("C:\\Users\\pucha\\OneDrive\\Pictures\\fotokozia\\jak-ze-starej-fotografii.jpg")));
}
}
4 changes: 2 additions & 2 deletions Musoq.DataSources.Ollama.Tests/OllamaQueryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ private static Mock<IOllamaApi> CreateOpenAiApiMock(string response)
var mockOllamaApi = new Mock<IOllamaApi>();

mockOllamaApi.Setup(x => x.GetCompletionAsync(It.IsAny<OllamaEntity>(), It.IsAny<IList<Message>>()))
.ReturnsAsync(new ConversationContextWithResponse(response, []));
.ReturnsAsync(new CompletionResponse(response));
mockOllamaApi.Setup(x => x.GetImageCompletionAsync(It.IsAny<OllamaEntity>(), It.IsAny<Message>()))
.ReturnsAsync(new ConversationContextWithResponse(response, []));
.ReturnsAsync(new CompletionResponse(response));

return mockOllamaApi;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ private static Mock<IOllamaApi> PrepareOpenAiApi(string response)
It.IsAny<IList<Message>>()))
.Returns<OllamaEntity, IList<Message>>((entity, messages) =>
Task.FromResult(
new ConversationContextWithResponse(response, [])));
new CompletionResponse(response)));
return mock;
}
}
21 changes: 21 additions & 0 deletions Musoq.DataSources.Ollama/CompletionResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace Musoq.DataSources.Ollama;

/// <summary>
/// Completion response
/// </summary>
public class CompletionResponse
{
/// <summary>
/// Initializes a new instance of the <see cref="CompletionResponse"/> class.
/// </summary>
/// <param name="text">The text</param>
public CompletionResponse(string text)
{
Text = text;
}

/// <summary>
/// Gets or sets the text
/// </summary>
public string Text { get; }
}
8 changes: 4 additions & 4 deletions Musoq.DataSources.Ollama/IOllamaApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ public interface IOllamaApi
/// </summary>
/// <param name="entity">The entity</param>
/// <param name="messages">Messages</param>
/// <returns>ConversationContextWithResponse</returns>
Task<ConversationContextWithResponse> GetCompletionAsync(OllamaEntityBase entity, IList<Message> messages);
/// <returns>CompletionResponse</returns>
Task<CompletionResponse> GetCompletionAsync(OllamaEntityBase entity, IList<Message> messages);

/// <summary>
/// Gets the image completion from Ollama API
/// </summary>
/// <param name="entity">The entity</param>
/// <param name="message">Message</param>
/// <returns>ConversationContextWithResponse</returns>
Task<ConversationContextWithResponse> GetImageCompletionAsync(OllamaEntityBase entity, Message message);
/// <returns>CompletionResponse</returns>
Task<CompletionResponse> GetImageCompletionAsync(OllamaEntityBase entity, Message message);
}
4 changes: 2 additions & 2 deletions Musoq.DataSources.Ollama/Musoq.DataSources.Ollama.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>3.2.13</Version>
<Version>3.2.14</Version>
<Authors>Jakub Puchała</Authors>
<Product>Musoq</Product>
<PackageProjectUrl>https://github.com/Puchaczov/Musoq</PackageProjectUrl>
Expand All @@ -27,7 +27,7 @@

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OllamaSharp" Version="2.0.10" />
<PackageReference Include="OllamaSharp" Version="5.0.4" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Musoq.Parser" Version="4.2.0">
<ExcludeAssets>runtime</ExcludeAssets>
Expand Down
65 changes: 39 additions & 26 deletions Musoq.DataSources.Ollama/OllamaApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,49 +30,62 @@ public OllamaApi(string address)
});
}

public async Task<ConversationContextWithResponse> GetImageCompletionAsync(OllamaEntityBase entity, Message message)
public async Task<CompletionResponse> GetImageCompletionAsync(OllamaEntityBase entity, Message message)
{
var completion = await _api.GetCompletion(new GenerateCompletionRequest()
StringBuilder modelResponse = new();
var chatRequest = new ChatRequest
{
Model = entity.Model,
Context = [],
Images = message.Images,
Prompt = message.Content,
Stream = false,
Options = new RequestOptions()
Messages = new List<Message>
{
message
},
Options = new RequestOptions
{
Temperature = entity.Temperature
}
});
},
Stream = true
};

await foreach (var token in _api.ChatAsync(chatRequest, entity.CancellationToken))
{
if (token is null)
continue;

if (token.Done)
break;

modelResponse.Append(token.Message.Content);
}

return completion;
return new CompletionResponse(modelResponse.ToString());
}

public async Task<ConversationContextWithResponse> GetCompletionAsync(OllamaEntityBase entity, IList<Message> messages)
public async Task<CompletionResponse> GetCompletionAsync(OllamaEntityBase entity, IList<Message> messages)
{
TaskCompletionSource<ConversationContextWithResponse> completionSource = new();
var stringResponse = new StringBuilder();

await _api.SendChat(new ChatRequest()
StringBuilder modelResponse = new();
var chatRequest = new ChatRequest
{
Model = entity.Model,
Messages = messages,
Options = new RequestOptions()
Options = new RequestOptions
{
Temperature = entity.Temperature,
Temperature = entity.Temperature
},
Stream = true
}, stream =>
};

await foreach (var token in _api.ChatAsync(chatRequest, entity.CancellationToken))
{
if (!stream.Done)
{
stringResponse.Append(stream.Message.Content);
return;
}
if (token is null)
continue;

if (token.Done)
break;

completionSource.SetResult(new ConversationContextWithResponse(stringResponse.ToString(), []));
}, entity.CancellationToken);
modelResponse.Append(token.Message.Content);
}

return completionSource.Task.Result;
return new CompletionResponse(modelResponse.ToString());
}
}
4 changes: 2 additions & 2 deletions Musoq.DataSources.Ollama/OllamaEntityBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public abstract class OllamaEntityBase
/// <summary>
/// Initializes a new instance of the <see cref="api"/> class with the specified parameters.
/// </summary>
protected OllamaEntityBase(IOllamaApi api, string? model, float temperature, CancellationToken cancellationToken)
protected OllamaEntityBase(IOllamaApi api, string model, float temperature, CancellationToken cancellationToken)
{
Api = api;
Model = model;
Expand All @@ -24,7 +24,7 @@ protected OllamaEntityBase(IOllamaApi api, string? model, float temperature, Can
/// <summary>
/// Gets the optional model name to use for generating text.
/// </summary>
public string? Model { get; }
public string Model { get; }

/// <summary>
/// Gets the temperature to control the randomness of the generated text.
Expand Down
20 changes: 7 additions & 13 deletions Musoq.DataSources.Ollama/OllamaLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Musoq.Plugins;
using Musoq.Plugins.Attributes;
using Newtonsoft.Json;
using OllamaSharp;
using OllamaSharp.Models.Chat;
using SharpToken;

Expand Down Expand Up @@ -213,7 +212,7 @@ public bool IsQuestionApplicableToImage([InjectSpecificSource(typeof(OllamaEntit
var youAreImageDescriberDescribeTheImage = $"You are image based question answerer. Return only answer for the following question: {question}. You must respond with json {{ result: boolean }}. Do not comment or explain anything.";
return api.GetImageCompletionAsync(
entity,
new(ChatRole.User, youAreImageDescriberDescribeTheImage, [imageBase64]));
new Message(ChatRole.User, youAreImageDescriberDescribeTheImage, [imageBase64]));
});

var response = describeImageResultTask.Result;
Expand Down Expand Up @@ -280,29 +279,24 @@ public int CountTokens(string content)
return encoding.CountTokens(content);
}

private static async Task<string> DoAsynchronously(Func<Task<ConversationContextWithResponse>> func)
private static async Task<string> DoAsynchronously(Func<Task<CompletionResponse>> func)
{
var result = func();

try
{
var completion = await result;

return completion.Response ?? string.Empty;
return completion.Text;
}
catch (Exception)
catch (Exception exc)
{
return "ERROR";
return exc.Message;
}
}

private class ExtractedEntities
private class ExtractedEntities(string[] entities)
{
public ExtractedEntities(string[] entities)
{
Entities = entities;
}

public string[] Entities { get; set; }
public string[] Entities { get; } = entities;
}
}
28 changes: 11 additions & 17 deletions Musoq.DataSources.Ollama/OllamaSingleRowSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,15 @@ public OllamaSingleRowSource(RuntimeContext runtimeContext, OllamaRequestInfo op
_cancellationToken = runtimeContext.EndWorkToken;
}

public override IEnumerable<IObjectResolver> Rows
{
get
{
return new IObjectResolver[]
{
new EntityResolver<OllamaEntity>(
new OllamaEntity(
_openAiApi,
_openAiRequestInfo.Model,
_openAiRequestInfo.Temperature,
_cancellationToken),
OllamaSchemaHelper.NameToIndexMap,
OllamaSchemaHelper.IndexToMethodAccessMap)
};
}
}
public override IEnumerable<IObjectResolver> Rows =>
[
new EntityResolver<OllamaEntity>(
new OllamaEntity(
_openAiApi,
_openAiRequestInfo.Model,
_openAiRequestInfo.Temperature,
_cancellationToken),
OllamaSchemaHelper.NameToIndexMap,
OllamaSchemaHelper.IndexToMethodAccessMap)
];
}

0 comments on commit 775fa49

Please sign in to comment.