Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions Samples/AppContentSearch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ extendedZipContent:

# AppContentSearch Sample Application

This sample demonstrates how to use App Content Search's **AppContentIndex APIs** in a **WinUI3** notes application. It shows how to create, manage, and semantically search through the index that includes both text content and images. It also shows how to use use the search results to enable retrieval augmented genaration (RAG) scenarios with language models.
This sample demonstrates how to use App Content Search's
**AppContentIndex APIs** in a **WinUI3** notes application.
It shows how to create, manage, and semantically search
through the index that includes both text content and images.
It also shows how to use the search results to enable
retrieval augmented generation (RAG) scenarios with language
models.

> **Note**: This sample is targeted and tested for **Windows App SDK 2.0 Experimental2** and **Visual Studio 2022**. The AppContentSearch APIs are experimental and available in Windows App SDK 2.0 experimental2.
> **Note**: This sample is targeted and tested for
> **Windows App SDK 2.0 Preview1** and
> **Visual Studio 2022**.


## Features
Expand All @@ -42,7 +50,7 @@ This sample demonstrates:

## Building and Running the Sample

* Open the solution file (`AppContentSearch.sln`) in Visual Studio.
* Open the solution file (`NotesApp.sln`) in Visual Studio.
* Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
* Run the application to see the Notes app with integrated search functionality.

Expand Down
22 changes: 14 additions & 8 deletions Samples/AppContentSearch/cs-winui/AI/Provider/FoundryAIProvider.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
// Copyright (c) Microsoft Corporation. All rights reserved.

using Microsoft.AI.Foundry.Local;
using Microsoft.Extensions.AI;
using Notes.ViewModels;
using OpenAI;
using OpenAI.Chat;
using System;
using System.ClientModel;
using System.Collections.Generic;
Expand All @@ -13,6 +8,11 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AI.Foundry.Local;
using Microsoft.Extensions.AI;
using Notes.ViewModels;
using OpenAI;
using OpenAI.Chat;
using Windows.Storage;
using AppChatRole = Notes.ViewModels.ChatRole;
using ExtChatRole = Microsoft.Extensions.AI.ChatRole;
Expand Down Expand Up @@ -143,7 +143,8 @@ public async IAsyncEnumerable<ChatResponseUpdate> SendStreamingRequestAsync(
break;
}

if (!hasNext) break;
if (!hasNext)
break;

if (cancellationToken.IsCancellationRequested)
{
Expand Down Expand Up @@ -175,7 +176,9 @@ private bool HasCachedModels()
{
try
{
#pragma warning disable CA2000 // Dispose objects before losing scope
var foundryManager = new FoundryLocalManager();
#pragma warning restore CA2000 // Dispose objects before losing scope
var cached = foundryManager.ListCachedModelsAsync().GetAwaiter().GetResult();
return cached.Count > 0;
}
Expand All @@ -187,15 +190,18 @@ private bool HasCachedModels()

private async Task EnsureFoundryClientAsync(CancellationToken ct)
{
if (_foundryClient != null && _foundryChatClient != null) return;
if (_foundryClient != null && _foundryChatClient != null)
return;

var settings = ApplicationData.Current.LocalSettings;
string alias = (settings.Values[FoundryModelKey] as string)?.Trim() ?? "";
if (string.IsNullOrWhiteSpace(alias))
{
try
{
#pragma warning disable CA2000 // Dispose objects before losing scope
var foundryManager = new FoundryLocalManager();
#pragma warning restore CA2000 // Dispose objects before losing scope

var cached = await foundryManager.ListCachedModelsAsync();
if (cached.Count != 0)
Expand Down Expand Up @@ -269,4 +275,4 @@ private ChatResponseUpdate Append(SessionEntryViewModel entry, string text, Chat

return list;
}
}
}
6 changes: 3 additions & 3 deletions Samples/AppContentSearch/cs-winui/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Windows.AI.Search.Experimental.AppContentIndex;
using Microsoft.Windows.Search.AppContentIndex;
using Notes.Controls;
using Notes.Pages;
using Notes.ViewModels;
Expand Down Expand Up @@ -98,10 +98,10 @@ private async Task InitializeAppContentIndexerAsync()
GetOrCreateIndexResult? getOrCreateResult = null;
await Task.Run(() =>
{
getOrCreateResult = Microsoft.Windows.AI.Search.Experimental.AppContentIndex.AppContentIndexer.GetOrCreateIndex("NotesIndex");
getOrCreateResult = AppContentIndexer.GetOrCreateIndex("NotesIndex");
if (getOrCreateResult == null)
{
throw new Exception("GetOrCreateIndexResult is null");
throw new InvalidOperationException("GetOrCreateIndexResult is null");
}
if (!getOrCreateResult.Succeeded)
{
Expand Down
35 changes: 1 addition & 34 deletions Samples/AppContentSearch/cs-winui/Notes.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,13 @@
<Content Remove="Assets\mockText.txt" />
</ItemGroup>

<!-- <ItemGroup>
<ProjectReference Include="..\..\product\APIs\Projection\Microsoft.Windows.AI.Search.Projection\Microsoft.Windows.AI.Search.Projection.csproj" />
<ProjectReference Include="..\..\product\APIs\Projection\Microsoft.Windows.AI.Text.Projection\Microsoft.Windows.AI.Text.Projection.csproj" />
</ItemGroup> -->

<ItemGroup>
<None Remove="Assets\Notes.ico" />
<None Remove="Controls\AttachmentView.xaml" />
<None Remove="Controls\ChatSessionView.xaml" />
<None Remove="Controls\SearchView.xaml" />
</ItemGroup>

<!-- <ItemGroup>
<AdditionalFiles Include="NativeMethods.txt" />
</ItemGroup> -->

<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
Expand Down Expand Up @@ -76,7 +67,7 @@
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.3.0-preview.1.25114.11" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4948" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="2.0.0-experimental3" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="2.0.0-preview1" />
<PackageReference Include="OpenAI" Version="2.2.0-beta.2" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -119,30 +110,6 @@
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<!-- <ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="C:\.tools\.nuget\packages\microsoft.windowsappsdk.packages\1.8.250515001-experimental2\buildTransitive\..\include\WindowsAppSDK-VersionInfo.cs" />
</ItemGroup> -->
<ItemGroup>
<PRIResource Remove="Assets\Icon\**" />
</ItemGroup>
Expand Down
16 changes: 7 additions & 9 deletions Samples/AppContentSearch/cs-winui/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,17 @@
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:systemai="http://schemas.microsoft.com/appx/manifest/systemai/windows10"
IgnorableNamespaces="uap rescap systemai">

IgnorableNamespaces="uap rescap systemai"
xmlns:systemai="http://schemas.microsoft.com/appx/manifest/systemai/windows10">
<Identity
Name="8e8c755b-914d-4f6c-89b6-95af1fc4fbaa"
Publisher="CN=nikol"
Version="1.0.1.0" />

<mp:PhoneIdentity PhoneProductId="8e8c755b-914d-4f6c-89b6-95af1fc4fbaa" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
Name="ai-powered-notes-winui3-sample"
Publisher="CN=AppContentSearchSample"
Version="1.0.0.0" />

<Properties>
<DisplayName>Notes</DisplayName>
<PublisherDisplayName>nikol</PublisherDisplayName>
<PublisherDisplayName>AppContentSearchSample</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>

Expand Down
10 changes: 5 additions & 5 deletions Samples/AppContentSearch/cs-winui/Utils/AttachmentProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.

using Microsoft.Windows.AI.Search.Experimental.AppContentIndex;
using Notes.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Windows.Search.AppContentIndex;
using Notes.Models;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;
Expand All @@ -14,7 +14,7 @@ namespace Notes
{
public static class AttachmentProcessor
{
public static EventHandler<AttachmentProcessedEventArgs>? AttachmentProcessed;
internal static EventHandler<AttachmentProcessedEventArgs>? AttachmentProcessed;

private readonly static List<Attachment> _toBeProcessed = new();
private static bool _isProcessing = false;
Expand Down Expand Up @@ -46,7 +46,7 @@ public async static Task RemoveAttachment(Attachment attachment)
{
await Task.Run(() =>
{
MainWindow.AppContentIndexer.Remove(attachment.Id.ToString());
MainWindow.AppContentIndexer.RemoveContentItem(attachment.Id.ToString());
});
Debug.WriteLine($"Deleted image from index: {attachment.Filename}");
}
Expand Down
18 changes: 9 additions & 9 deletions Samples/AppContentSearch/cs-winui/Utils/Utils.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.

using Microsoft.Windows.AI.Search.Experimental.AppContentIndex;
using Notes.ViewModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Windows.Search.AppContentIndex;
using Notes.ViewModels;
using Windows.Foundation;
using Windows.Storage;

Expand Down Expand Up @@ -149,7 +149,7 @@ await Task.Run(() =>
AppManagedImageQueryMatch? imageMatch = match as AppManagedImageQueryMatch;
if (imageMatch != null)
{
Debug.WriteLine($"Image match: {imageMatch.ContentId}, Subregion: {imageMatch.Subregion}");
Debug.WriteLine($"Image match: {imageMatch.ContentId}, Region of interest: {imageMatch.RegionOfInterest}");
var searchResult = new SearchResult
{
ContentType = ContentType.Image,
Expand Down Expand Up @@ -184,18 +184,18 @@ await Task.Run(() =>
var attachmentsFolder = await GetAttachmentsFolderAsync();
searchResult.Path = attachmentsFolder.Path + "\\" + image.RelativePath;

// Capture bounding box if present (Subregion is IReference<Rect>)
// Capture bounding box if present (Region of interest is IReference<Rect>)
try
{
if (imageMatch.Subregion != null)
if (imageMatch.RegionOfInterest != null)
{
var rect = imageMatch.Subregion.Value;
var rect = imageMatch.RegionOfInterest.Value;
searchResult.BoundingBox = rect;
}
}
catch (Exception ex)
{
Debug.WriteLine("Failed to read image Subregion: " + ex.Message);
Debug.WriteLine("Failed to read image Region of interest: " + ex.Message);
}
results.Add(searchResult);
}
Expand Down Expand Up @@ -266,4 +266,4 @@ public enum ContentSubType
Gif = 3,
Bmp = 4
}
}
}
18 changes: 9 additions & 9 deletions Samples/AppContentSearch/cs-winui/ViewModels/NoteViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.

using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.Windows.AI.Search.Experimental.AppContentIndex;
using Notes.Models;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.Windows.Search.AppContentIndex;
using Notes.Models;
using Windows.Graphics.Imaging;
using Windows.Storage;

Expand Down Expand Up @@ -220,7 +220,7 @@ public async Task RemoveNoteFromIndexAsync()
{
await Task.Run(() =>
{
MainWindow.AppContentIndexer.Remove(Note.Id.ToString());
MainWindow.AppContentIndexer.RemoveContentItem(Note.Id.ToString());
});
Debug.WriteLine($"Deleted note from index: {Note.Filename}");
}
Expand All @@ -247,7 +247,7 @@ public async static Task ManualDeleteIndex()
{
await Task.Run(() =>
{
MainWindow.AppContentIndexer.RemoveAll();
MainWindow.AppContentIndexer.RemoveAllContentItems();
});
Debug.WriteLine($"Deleted Index");
}
Expand Down Expand Up @@ -327,7 +327,7 @@ private async Task SaveContentToFileDeleteAndReIndex()

await Task.Run(() =>
{
MainWindow.AppContentIndexer.Remove(Note.Id.ToString());
MainWindow.AppContentIndexer.RemoveContentItem(Note.Id.ToString());
});
Debug.WriteLine($"Deleted note {Note.Title}");

Expand Down
Loading