diff --git a/samples/cs/GettingStarted/Directory.Packages.props b/samples/cs/GettingStarted/Directory.Packages.props
index 78d3d53..ec621b5 100644
--- a/samples/cs/GettingStarted/Directory.Packages.props
+++ b/samples/cs/GettingStarted/Directory.Packages.props
@@ -3,8 +3,8 @@
true
-
-
+
+
diff --git a/samples/cs/GettingStarted/cross-platform/AudioTranscriptionExample/AudioTranscriptionExample.csproj b/samples/cs/GettingStarted/cross-platform/AudioTranscriptionExample/AudioTranscriptionExample.csproj
index 78cb019..144a38d 100644
--- a/samples/cs/GettingStarted/cross-platform/AudioTranscriptionExample/AudioTranscriptionExample.csproj
+++ b/samples/cs/GettingStarted/cross-platform/AudioTranscriptionExample/AudioTranscriptionExample.csproj
@@ -9,7 +9,8 @@
-
+
+
diff --git a/samples/cs/GettingStarted/cross-platform/FoundryLocalWebServer/FoundryLocalWebServer.csproj b/samples/cs/GettingStarted/cross-platform/FoundryLocalWebServer/FoundryLocalWebServer.csproj
index 9312382..4a23db4 100644
--- a/samples/cs/GettingStarted/cross-platform/FoundryLocalWebServer/FoundryLocalWebServer.csproj
+++ b/samples/cs/GettingStarted/cross-platform/FoundryLocalWebServer/FoundryLocalWebServer.csproj
@@ -9,7 +9,8 @@
-
+
+
diff --git a/samples/cs/GettingStarted/cross-platform/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj b/samples/cs/GettingStarted/cross-platform/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj
index 20dcc7c..239e5b4 100644
--- a/samples/cs/GettingStarted/cross-platform/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj
+++ b/samples/cs/GettingStarted/cross-platform/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj
@@ -9,7 +9,8 @@
-
+
+
diff --git a/samples/cs/GettingStarted/nuget.config b/samples/cs/GettingStarted/nuget.config
index 8a62f07..eaea6c3 100644
--- a/samples/cs/GettingStarted/nuget.config
+++ b/samples/cs/GettingStarted/nuget.config
@@ -2,7 +2,7 @@
-
+
diff --git a/samples/cs/GettingStarted/src/AudioTranscriptionExample/Program.cs b/samples/cs/GettingStarted/src/AudioTranscriptionExample/Program.cs
index 15c5c44..51b1a5d 100644
--- a/samples/cs/GettingStarted/src/AudioTranscriptionExample/Program.cs
+++ b/samples/cs/GettingStarted/src/AudioTranscriptionExample/Program.cs
@@ -1,28 +1,32 @@
using Microsoft.AI.Foundry.Local;
-using Microsoft.Extensions.Logging;
var config = new Configuration
{
- AppName = "my-audio-app",
- LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Debug
+ AppName = "foundry_local_samples",
+ LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information
};
-using var loggerFactory = LoggerFactory.Create(builder =>
-{
- builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug);
-});
-var logger = loggerFactory.CreateLogger();
// Initialize the singleton instance.
-await FoundryLocalManager.CreateAsync(config, logger);
+await FoundryLocalManager.CreateAsync(config, Utils.GetAppLogger());
var mgr = FoundryLocalManager.Instance;
+
+// Ensure that any Execution Provider (EP) downloads run and are completed.
+// EP packages include dependencies and may be large.
+// Download is only required again if a new version of the EP is released.
+// For cross platform builds there is no dynamic EP download and this will return immediately.
+await Utils.RunWithSpinner("Registering execution providers", mgr.EnsureEpsDownloadedAsync());
+
+
// Get the model catalog
var catalog = await mgr.GetCatalogAsync();
+
// Get a model using an alias
var model = await catalog.GetModelAsync("whisper-tiny") ?? throw new System.Exception("Model not found");
+
// Download the model (the method skips download if already cached)
await model.DownloadAsync(progress =>
{
@@ -33,26 +37,28 @@ await model.DownloadAsync(progress =>
}
});
+
// Load the model
Console.Write($"Loading model {model.Id}...");
await model.LoadAsync();
Console.WriteLine("done.");
+
// Get a chat client
var audioClient = await model.GetAudioClientAsync();
-// get a cancellation token
-CancellationToken ct = new CancellationToken();
// Get a transcription with streaming outputs
Console.WriteLine("Transcribing audio with streaming output:");
-var response = audioClient.TranscribeAudioStreamingAsync("Recording.mp3", ct);
+var response = audioClient.TranscribeAudioStreamingAsync("Recording.mp3", CancellationToken.None);
await foreach (var chunk in response)
{
Console.Write(chunk.Text);
Console.Out.Flush();
}
+
Console.WriteLine();
+
// Tidy up - unload the model
await model.UnloadAsync();
\ No newline at end of file
diff --git a/samples/cs/GettingStarted/src/FoundryLocalWebServer/Program.cs b/samples/cs/GettingStarted/src/FoundryLocalWebServer/Program.cs
index 7a75288..2be8296 100644
--- a/samples/cs/GettingStarted/src/FoundryLocalWebServer/Program.cs
+++ b/samples/cs/GettingStarted/src/FoundryLocalWebServer/Program.cs
@@ -1,36 +1,36 @@
using Microsoft.AI.Foundry.Local;
-using Microsoft.Extensions.Logging;
using OpenAI;
using System.ClientModel;
var config = new Configuration
{
- AppName = "my-app-name",
- LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Debug,
+ AppName = "foundry_local_samples",
+ LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information,
Web = new Configuration.WebService
{
Urls = "http://127.0.0.1:55588"
}
};
-using var loggerFactory = LoggerFactory.Create(builder =>
-{
- builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug);
-});
-
-var logger = loggerFactory.CreateLogger();
// Initialize the singleton instance.
-await FoundryLocalManager.CreateAsync(config, logger);
+await FoundryLocalManager.CreateAsync(config, Utils.GetAppLogger());
var mgr = FoundryLocalManager.Instance;
+
+// Ensure that any Execution Provider (EP) downloads run and are completed.
+// EP packages include dependencies and may be large.
+// Download is only required again if a new version of the EP is released.
+// For cross platform builds there is no dynamic EP download and this will return immediately.
+await Utils.RunWithSpinner("Registering execution providers", mgr.EnsureEpsDownloadedAsync());
+
+
// Get the model catalog
var catalog = await mgr.GetCatalogAsync();
-// Get a model using an alias
-//var model = await catalog.GetModelAsync("qwen2.5-0.5b") ?? throw new Exception("Model not found");
-var model = await catalog.GetModelVariantAsync("qwen2.5-0.5b-instruct-generic-cpu:3") ?? throw new Exception("Model not found");
+// Get a model using an alias
+var model = await catalog.GetModelAsync("qwen2.5-0.5b") ?? throw new Exception("Model not found");
// Download the model (the method skips download if already cached)
await model.DownloadAsync(progress =>
{
@@ -41,11 +41,13 @@ await model.DownloadAsync(progress =>
}
});
+
// Load the model
Console.Write($"Loading model {model.Id}...");
await model.LoadAsync();
Console.WriteLine("done.");
+
// Start the web service
Console.Write($"Starting web service on {config.Web.Urls}...");
await mgr.StartWebServiceAsync();
@@ -61,7 +63,6 @@ await model.DownloadAsync(progress =>
});
var chatClient = client.GetChatClient(model.Id);
-
var completionUpdates = chatClient.CompleteChatStreaming("Why is the sky blue?");
Console.Write($"[ASSISTANT]: ");
diff --git a/samples/cs/GettingStarted/src/HelloFoundryLocalSdk/Program.cs b/samples/cs/GettingStarted/src/HelloFoundryLocalSdk/Program.cs
index 289f588..6d74900 100644
--- a/samples/cs/GettingStarted/src/HelloFoundryLocalSdk/Program.cs
+++ b/samples/cs/GettingStarted/src/HelloFoundryLocalSdk/Program.cs
@@ -1,28 +1,32 @@
using Microsoft.AI.Foundry.Local;
using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
-using Microsoft.Extensions.Logging;
+using System.Diagnostics;
CancellationToken ct = new CancellationToken();
var config = new Configuration
{
- AppName = "my-app-name",
- LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Debug
+ AppName = "foundry_local_samples",
+ LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information
};
-using var loggerFactory = LoggerFactory.Create(builder =>
-{
- builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug);
-});
-var logger = loggerFactory.CreateLogger();
// Initialize the singleton instance.
-await FoundryLocalManager.CreateAsync(config, logger);
+await FoundryLocalManager.CreateAsync(config, Utils.GetAppLogger());
var mgr = FoundryLocalManager.Instance;
+
+// Ensure that any Execution Provider (EP) downloads run and are completed.
+// EP packages include dependencies and may be large.
+// Download is only required again if a new version of the EP is released.
+// For cross platform builds there is no dynamic EP download and this will return immediately.
+await Utils.RunWithSpinner("Registering execution providers", mgr.EnsureEpsDownloadedAsync());
+
+
// Get the model catalog
var catalog = await mgr.GetCatalogAsync();
+
// List available models
Console.WriteLine("Available models for your hardware:");
var models = await catalog.ListModelsAsync();
@@ -34,21 +38,55 @@
}
}
-// Get a model using an alias
-//var model = await catalog.GetModelAsync("qwen2.5-0.5b") ?? throw new Exception("Model not found");
-var model = await catalog.GetModelVariantAsync("qwen2.5-0.5b-instruct-generic-cpu:3") ?? throw new Exception("Model not found");
-
-// is model cached
-Console.WriteLine($"Is model cached: {await model.IsCachedAsync()}");
// print out cached models
var cachedModels = await catalog.GetCachedModelsAsync();
-Console.WriteLine("Cached models:");
+Console.WriteLine("\nCached models:");
foreach (var cachedModel in cachedModels)
{
Console.WriteLine($"- {cachedModel.Alias} ({cachedModel.Id})");
}
+
+// Get a model using an alias.
+var model = await catalog.GetModelAsync("qwen2.5-0.5b") ?? throw new Exception("Model not found");
+
+// `model.SelectedVariant` indicates which variant will be used by default.
+//
+// Models in Model.Variants are ordered by priority, with the highest priority first.
+// The first downloaded model is selected by default.
+// The highest priority is selected if no models have been downloaded.
+Console.WriteLine("\nThe default selected model variant is: " + model.Id);
+if (model.SelectedVariant != model.Variants.First())
+{
+ Debug.Assert(await model.SelectedVariant.IsCachedAsync());
+ Console.WriteLine("The model variant was selected due to being locally cached.");
+}
+
+
+// OPTIONAL: `model` can be used directly and `model.SelectedVariant` will be used as the default.
+// You can explicitly select or use a specific ModelVariant if you want more control
+// over the device and/or execution provider used.
+// Model and ModelVariant can be used interchangeably in methods such as
+// DownloadAsync, LoadAsync, UnloadAsync and GetChatClientAsync.
+//
+// Choices:
+// - Use a ModelVariant directly from the catalog if you know the variant Id
+// - `var modelVariant = await catalog.GetModelVariantAsync("qwen2.5-0.5b-instruct-generic-gpu:3")`
+//
+// - Get the ModelVariant from Model.Variants
+// - `var modelVariant = model.Variants.First(v => v.Id == "qwen2.5-0.5b-instruct-generic-cpu:4")`
+// - `var modelVariant = model.Variants.First(v => v.Info.Runtime?.DeviceType == DeviceType.GPU)`
+// - optional: update selected variant in `model` using `model.SelectVariant(modelVariant);` if you wish to use
+// `model` in your code.
+
+// For this example we explicitly select the CPU variant, and call SelectVariant so all the following example code
+// uses the `model` instance.
+Console.WriteLine("Selecting CPU variant of model");
+var modelVariant = model.Variants.First(v => v.Info.Runtime?.DeviceType == DeviceType.CPU);
+model.SelectVariant(modelVariant);
+
+
// Download the model (the method skips download if already cached)
await model.DownloadAsync(progress =>
{
diff --git a/samples/cs/GettingStarted/src/Shared/Utils.cs b/samples/cs/GettingStarted/src/Shared/Utils.cs
new file mode 100644
index 0000000..b9c0fcf
--- /dev/null
+++ b/samples/cs/GettingStarted/src/Shared/Utils.cs
@@ -0,0 +1,54 @@
+using Microsoft.Extensions.Logging;
+using System.Text;
+
+internal static class Utils
+{
+ private static readonly ILoggerFactory _loggerFactory;
+
+ static Utils()
+ {
+ _loggerFactory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder =>
+ {
+ builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Information);
+ });
+ }
+
+ ///
+ /// Get a dummy application logger.
+ ///
+ /// ILogger
+ internal static ILogger GetAppLogger()
+ {
+ return _loggerFactory.CreateLogger("FoundryLocalSamples");
+ }
+
+ internal static async Task RunWithSpinner(string msg, T workTask) where T : Task
+ {
+ // Start the spinner
+ using var cts = new CancellationTokenSource();
+ var spinnerTask = ShowSpinner(msg, cts.Token);
+
+ await workTask; // wait for the real work to finish
+ cts.Cancel(); // stop the spinner
+ await spinnerTask; // wait for spinner to exit
+ }
+
+ private static async Task ShowSpinner(string msg, CancellationToken token)
+ {
+ Console.OutputEncoding = Encoding.UTF8;
+
+ var sequence = new[] { '◴','◷','◶','◵' };
+
+ int counter = 0;
+
+ while (!token.IsCancellationRequested)
+ {
+ Console.Write($"{msg}\t{sequence[counter % sequence.Length]}");
+ Console.SetCursorPosition(0, Console.CursorTop);
+ counter++;
+ await Task.Delay(200, token).ContinueWith(_ => { });
+ }
+
+ Console.WriteLine($"\nDone.\n");
+ }
+}
\ No newline at end of file
diff --git a/samples/cs/GettingStarted/windows/AudioTranscriptionExample/AudioTranscriptionExample.csproj b/samples/cs/GettingStarted/windows/AudioTranscriptionExample/AudioTranscriptionExample.csproj
index 7165bd6..9278878 100644
--- a/samples/cs/GettingStarted/windows/AudioTranscriptionExample/AudioTranscriptionExample.csproj
+++ b/samples/cs/GettingStarted/windows/AudioTranscriptionExample/AudioTranscriptionExample.csproj
@@ -5,13 +5,14 @@
enable
enable
- net8.0-windows10.0.26100
+ net9.0-windows10.0.26100
true
ARM64;x64
-
+
+
diff --git a/samples/cs/GettingStarted/windows/FoundryLocalWebServer/FoundryLocalWebServer.csproj b/samples/cs/GettingStarted/windows/FoundryLocalWebServer/FoundryLocalWebServer.csproj
index f72b28d..584e393 100644
--- a/samples/cs/GettingStarted/windows/FoundryLocalWebServer/FoundryLocalWebServer.csproj
+++ b/samples/cs/GettingStarted/windows/FoundryLocalWebServer/FoundryLocalWebServer.csproj
@@ -5,13 +5,14 @@
enable
enable
- net8.0-windows10.0.26100
+ net9.0-windows10.0.26100
true
x64;ARM64
-
+
+
diff --git a/samples/cs/GettingStarted/windows/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj b/samples/cs/GettingStarted/windows/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj
index cacd0c4..adf2100 100644
--- a/samples/cs/GettingStarted/windows/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj
+++ b/samples/cs/GettingStarted/windows/HelloFoundryLocalSdk/HelloFoundryLocalSdk.csproj
@@ -5,13 +5,14 @@
enable
enable
- net8.0-windows10.0.26100
+ net9.0-windows10.0.26100
true
ARM64;x64
+