Skip to content

Commit

Permalink
Improve console demos
Browse files Browse the repository at this point in the history
  • Loading branch information
awaescher committed Aug 23, 2024
1 parent 2cc6865 commit 7d26390
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 105 deletions.
48 changes: 36 additions & 12 deletions OllamaApiConsole/Demos/ChatConsole.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using OllamaSharp;
using OllamaSharp.Models.Chat;
using Spectre.Console;

public class ChatConsole : OllamaConsole
Expand All @@ -15,26 +16,49 @@ public override async Task Run()

Ollama.SelectedModel = await SelectModel("Select a model you want to chat with:");


if (!string.IsNullOrEmpty(Ollama.SelectedModel))
{
AnsiConsole.MarkupLine($"You are talking to [blue]{Ollama.SelectedModel}[/] now.");
AnsiConsole.MarkupLine("[gray]Type \"[red]exit[/]\" to leave the chat.[/]");

var chat = Ollama.Chat(stream => AnsiConsole.MarkupInterpolated($"[cyan]{stream?.Message.Content ?? ""}[/]"));
string message;
var keepChatting = true;
var systemPrompt = ReadMultilineInput("Define a system prompt (optional)");

do
{
AnsiConsole.WriteLine();
message = ReadMultilineInput();
AnsiConsole.MarkupLine("");
AnsiConsole.MarkupLine($"You are talking to [blue]{Ollama.SelectedModel}[/] now.");
AnsiConsole.MarkupLine("[gray]Submit your messages by hitting return twice.[/]");
AnsiConsole.MarkupLine("[gray]Type \"[red]/new[/]\" to start over.[/]");
AnsiConsole.MarkupLine("[gray]Type \"[red]/exit[/]\" to leave the chat.[/]");

var chat = Ollama.Chat(stream => AnsiConsole.MarkupInterpolated($"[cyan]{stream?.Message.Content ?? ""}[/]"));

if (!string.IsNullOrEmpty(systemPrompt))
chat.SetMessages([new Message { Role = ChatRole.System, Content = systemPrompt }]);

string message;

do
{
AnsiConsole.WriteLine();
message = ReadMultilineInput();

if (message.Equals("/exit", StringComparison.OrdinalIgnoreCase))
{
keepChatting = false;
break;
}

if (message.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
if (message.Equals("/new", StringComparison.OrdinalIgnoreCase))
{
keepChatting = true;
break;
}

await chat.Send(message);
await chat.Send(message);

AnsiConsole.WriteLine();
} while (!string.IsNullOrEmpty(message));
AnsiConsole.WriteLine();
} while (!string.IsNullOrEmpty(message));
} while (keepChatting);
}
}
}
138 changes: 81 additions & 57 deletions OllamaApiConsole/Demos/ImageChatConsole.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using OllamaSharp;
using OllamaSharp.Models.Chat;
using Spectre.Console;

public class ImageChatConsole : OllamaConsole
Expand All @@ -16,84 +17,107 @@ public override async Task Run()

Ollama.SelectedModel = await SelectModel("Select a model you want to chat with:");


if (!string.IsNullOrEmpty(Ollama.SelectedModel))
{
AnsiConsole.MarkupLine($"You are talking to [blue]{Ollama.SelectedModel}[/] now.");
AnsiConsole.MarkupLine("[gray]Type \"[red]exit[/]\" to leave the chat.[/]");
AnsiConsole.MarkupLine("[gray]To send an image, enter its filename in curly braces,[/]");
AnsiConsole.MarkupLine("[gray]like this {c:/image.jpg}[/]");

var chat = Ollama.Chat(stream => AnsiConsole.MarkupInterpolated($"[cyan]{stream?.Message.Content ?? ""}[/]"));
string message;
var keepChatting = true;
var systemPrompt = ReadMultilineInput("Define a system prompt (optional)");

do
{
AnsiConsole.WriteLine();
message = ReadInput();
AnsiConsole.MarkupLine("");
AnsiConsole.MarkupLine($"You are talking to [blue]{Ollama.SelectedModel}[/] now.");
AnsiConsole.MarkupLine("[gray]To send an image, enter its filename in curly braces,[/]");
AnsiConsole.MarkupLine("[gray]like this {c:/image.jpg}[/]");
AnsiConsole.MarkupLine("[gray]Submit your messages by hitting return twice.[/]");
AnsiConsole.MarkupLine("[gray]Type \"[red]/new[/]\" to start over.[/]");
AnsiConsole.MarkupLine("[gray]Type \"[red]/exit[/]\" to leave the chat.[/]");

var chat = Ollama.Chat(stream => AnsiConsole.MarkupInterpolated($"[cyan]{stream?.Message.Content ?? ""}[/]"));

if (message.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
if (!string.IsNullOrEmpty(systemPrompt))
chat.SetMessages([new Message { Role = ChatRole.System, Content = systemPrompt }]);

var imageMatches = Regex.Matches(message, "{([^}]*)}").Select(m => m.Value);
var imageCount = imageMatches.Count();
var hasImages = imageCount > 0;
string message;

if (hasImages)
do
{
byte[][] imageBytes;
var imagePathsWithCurlyBraces = Regex.Matches(message, "{([^}]*)}").Select(m => m.Value);
var imagePaths = Regex.Matches(message, "{([^}]*)}").Select(m => m.Groups[1].Value);
AnsiConsole.WriteLine();
message = ReadInput();

try
if (message.Equals("/exit", StringComparison.OrdinalIgnoreCase))
{
imageBytes = imagePaths.Select(File.ReadAllBytes).ToArray();
keepChatting = false;
break;
}
catch (IOException ex)

if (message.Equals("/new", StringComparison.OrdinalIgnoreCase))
{
AnsiConsole.MarkupLineInterpolated($"Could not load your {(imageCount == 1 ? "image" : "images")}:");
AnsiConsole.MarkupLineInterpolated($"[red]{Markup.Escape(ex.Message)}[/]");
AnsiConsole.MarkupLine("Please try again");
continue;
keepChatting = true;
break;
}

var imagesBase64 = imageBytes.Select(Convert.ToBase64String);
var imageMatches = Regex.Matches(message, "{([^}]*)}").Select(m => m.Value);
var imageCount = imageMatches.Count();
var hasImages = imageCount > 0;

foreach (var path in imagePathsWithCurlyBraces)
message = message.Replace(path, "");

AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[yellow]Image chat will only work with multimodal models like llava![/]");
AnsiConsole.MarkupLine("[gray]Image paths have been removed from your message, sending this:[/]");
AnsiConsole.MarkupLineInterpolated($"[silver]{Markup.Escape(message)}[/]");
AnsiConsole.WriteLine();
if (imageCount == 1)
AnsiConsole.MarkupLineInterpolated($"[gray]{"Here is the image, that is sent to the chat model in addition to your message."}[/]");
if (hasImages)
{
byte[][] imageBytes;
var imagePathsWithCurlyBraces = Regex.Matches(message, "{([^}]*)}").Select(m => m.Value);
var imagePaths = Regex.Matches(message, "{([^}]*)}").Select(m => m.Groups[1].Value);

try
{
imageBytes = imagePaths.Select(File.ReadAllBytes).ToArray();
}
catch (IOException ex)
{
AnsiConsole.MarkupLineInterpolated($"Could not load your {(imageCount == 1 ? "image" : "images")}:");
AnsiConsole.MarkupLineInterpolated($"[red]{Markup.Escape(ex.Message)}[/]");
AnsiConsole.MarkupLine("Please try again");
continue;
}

var imagesBase64 = imageBytes.Select(Convert.ToBase64String);

foreach (var path in imagePathsWithCurlyBraces)
message = message.Replace(path, "");

AnsiConsole.WriteLine();
AnsiConsole.MarkupLine("[yellow]Image chat will only work with multimodal models like llava![/]");
AnsiConsole.MarkupLine("[gray]Image paths have been removed from your message, sending this:[/]");
AnsiConsole.MarkupLineInterpolated($"[silver]{Markup.Escape(message)}[/]");
AnsiConsole.WriteLine();
if (imageCount == 1)
AnsiConsole.MarkupLineInterpolated($"[gray]{"Here is the image, that is sent to the chat model in addition to your message."}[/]");
else
AnsiConsole.MarkupLineInterpolated($"[gray]{"Here are the images, that are sent to the chat model in addition to your message."}[/]");
AnsiConsole.WriteLine();

foreach (var consoleImage in imageBytes.Select(bytes => new CanvasImage(bytes)))
{
consoleImage.MaxWidth = 40;
AnsiConsole.Write(consoleImage);
}

AnsiConsole.WriteLine();
if (imageCount == 1)
AnsiConsole.MarkupLineInterpolated($"[gray]{"The image was scaled down for the console only, the model gets the full version."}[/]");
else
AnsiConsole.MarkupLineInterpolated($"[gray]{"The images were scaled down for the console only, the model gets full versions."}[/]");
AnsiConsole.WriteLine();

await chat.Send(message, [], imagesBase64);
}
else
AnsiConsole.MarkupLineInterpolated($"[gray]{"Here are the images, that are sent to the chat model in addition to your message."}[/]");
AnsiConsole.WriteLine();

foreach (var consoleImage in imageBytes.Select(bytes => new CanvasImage(bytes)))
{
consoleImage.MaxWidth = 40;
AnsiConsole.Write(consoleImage);
await chat.Send(message);
}

AnsiConsole.WriteLine();
if (imageCount == 1)
AnsiConsole.MarkupLineInterpolated($"[gray]{"The image was scaled down for the console only, the model gets the full version."}[/]");
else
AnsiConsole.MarkupLineInterpolated($"[gray]{"The images were scaled down for the console only, the model gets full versions."}[/]");
AnsiConsole.WriteLine();

await chat.Send(message, [], imagesBase64);
}
else
{
await chat.Send(message);
}

AnsiConsole.WriteLine();
} while (!string.IsNullOrEmpty(message));
} while (!string.IsNullOrEmpty(message));
} while (keepChatting);
}
}
}
80 changes: 51 additions & 29 deletions OllamaApiConsole/Demos/ToolConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,69 @@ public override async Task Run()

if (!string.IsNullOrEmpty(Ollama.SelectedModel))
{
AnsiConsole.MarkupLineInterpolated($"You are talking to [blue]{Ollama.SelectedModel}[/] now.");
AnsiConsole.MarkupLineInterpolated($"When asked for the weather or the news for a given location, it will try to use a predefined tool.");
AnsiConsole.MarkupLineInterpolated($"If any tool is used, the intended usage information is printed.");
AnsiConsole.MarkupLine("[gray]Type \"[red]exit[/]\" to leave the chat.[/]");

var chat = Ollama.Chat(stream => AnsiConsole.MarkupInterpolated($"[cyan]{stream?.Message.Content ?? ""}[/]"));
string message;
var keepChatting = true;
var systemPrompt = ReadMultilineInput("Define a system prompt (optional)");

do
{
AnsiConsole.WriteLine();
message = ReadMultilineInput();
AnsiConsole.MarkupLine("");
AnsiConsole.MarkupLineInterpolated($"You are talking to [blue]{Ollama.SelectedModel}[/] now.");
AnsiConsole.MarkupLine("When asked for the weather or the news for a given location, it will try to use a predefined tool.");
AnsiConsole.MarkupLine("If any tool is used, the intended usage information is printed.");
AnsiConsole.MarkupLine("[gray]Submit your messages by hitting return twice.[/]");
AnsiConsole.MarkupLine("[gray]Type \"[red]/new[/]\" to start over.[/]");
AnsiConsole.MarkupLine("[gray]Type \"[red]/exit[/]\" to leave the chat.[/]");

if (message.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
var chat = Ollama.Chat(stream => AnsiConsole.MarkupInterpolated($"[cyan]{stream?.Message.Content ?? ""}[/]"));

try
{
await chat.SendAs(ChatRole.User, message, GetTools());
}
catch (OllamaException ex)
{
AnsiConsole.MarkupLineInterpolated($"[red]{ex.Message}[/]");
}
if (!string.IsNullOrEmpty(systemPrompt))
chat.SetMessages([new Message { Role = ChatRole.System, Content = systemPrompt }]);

var toolCalls = chat.Messages.LastOrDefault()?.ToolCalls ?? [];
if (toolCalls.Any())
string message;

do
{
AnsiConsole.MarkupLine("\n[purple]Tools used:[/]");
AnsiConsole.WriteLine();
message = ReadMultilineInput();

foreach (var tool in toolCalls.Where(t => t.Function != null))
if (message.Equals("/exit", StringComparison.OrdinalIgnoreCase))
{
AnsiConsole.MarkupLineInterpolated($" - [purple]{tool.Function!.Name}[/]");
keepChatting = false;
break;
}

foreach (var argument in tool.Function.Arguments ?? [])
AnsiConsole.MarkupLineInterpolated($" - [purple]{argument.Key}[/]: [purple]{argument.Value}[/]");
if (message.Equals("/new", StringComparison.OrdinalIgnoreCase))
{
keepChatting = true;
break;
}

try
{
await chat.SendAs(ChatRole.User, message, GetTools());
}
catch (OllamaException ex)
{
AnsiConsole.MarkupLineInterpolated($"[red]{ex.Message}[/]");
}

var toolCalls = chat.Messages.LastOrDefault()?.ToolCalls ?? [];
if (toolCalls.Any())
{
AnsiConsole.MarkupLine("\n[purple]Tools used:[/]");

foreach (var tool in toolCalls.Where(t => t.Function != null))
{
AnsiConsole.MarkupLineInterpolated($" - [purple]{tool.Function!.Name}[/]");

foreach (var argument in tool.Function.Arguments ?? [])
AnsiConsole.MarkupLineInterpolated($" - [purple]{argument.Key}[/]: [purple]{argument.Value}[/]");
}
}
}

AnsiConsole.WriteLine();
} while (!string.IsNullOrEmpty(message));
AnsiConsole.WriteLine();
} while (!string.IsNullOrEmpty(message));
} while (keepChatting);
}
}

Expand Down
13 changes: 6 additions & 7 deletions OllamaApiConsole/OllamaConsole.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Text;
using OllamaSharp;
using Spectre.Console;

Expand Down Expand Up @@ -29,19 +30,17 @@ public static string ReadMultilineInput(string prompt = "", string additionalInf
if (!string.IsNullOrEmpty(additionalInformation))
AnsiConsole.MarkupLine(additionalInformation);

AnsiConsole.MarkupLineInterpolated($"Type \"[red]-[/]\" and hit [red]{"[Return]"}[/] to submit.");

var builder = new StringBuilder();
var input = "";

while (!input.TrimEnd().EndsWith('-'))
while (!string.IsNullOrEmpty(input) || builder.Length == 0)
{
AnsiConsole.Markup("[blue]> [/]");
input += Console.ReadLine() + Environment.NewLine;
input = Console.ReadLine();
builder.AppendLine(input);
}

input = input.TrimEnd();

return input.EndsWith('-') ? input.Substring(0, input.Length - 1) : input;
return builder.ToString().TrimEnd();
}

protected async Task<string> SelectModel(string prompt, string additionalInformation = "")
Expand Down

0 comments on commit 7d26390

Please sign in to comment.