Skip to content
Open
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
53 changes: 53 additions & 0 deletions Samples/AppContentSearch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we put this folder under Samples/WindowsAIFoundry?
Since that's how I discover Windows AI related feature.

page_type: sample
languages:
- csharp
products:
- windows
- windows-app-sdk
name: "AppContentSearch Sample"
urlFragment: AppContentSearchSample
description: "Demonstrates how to use the AppContentSearch APIs in Windows App SDK to index and semantically search text content and images in a WinUI3 notes application."
extendedZipContent:
- path: LICENSE
target: LICENSE
---


# 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.

> **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.


## Features

This sample demonstrates:

- **Creating Index**: Create an index with optional settings.
- **Indexing Content**: Add, update, and remove content from the index
- **Text Content Search**: Query the index for text-based results.
- **Image Content Search**: Query the index for image-based results.
- **Search Results Display**: Display both text and image search results with relevance highlighting and bounding boxes for image matches
- **Retrieval Augmented Generation (RAG)**: Use query search results with language models for retrieval augmented generation (RAG) scenarios.


## Prerequisites

* See [System requirements for Windows app development](https://docs.microsoft.com/windows/apps/windows-app-sdk/system-requirements).
* Make sure that your development environment is set up correctly—see [Install tools for developing apps for Windows 10 and Windows 11](https://docs.microsoft.com/windows/apps/windows-app-sdk/set-up-your-development-environment).
* This sample requires Visual Studio 2022 and .NET 9.


## Building and Running the Sample

* Open the solution file (`AppContentSearch.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.


## Related Documentation and Code Samples

* [Windows App SDK](https://docs.microsoft.com/windows/apps/windows-app-sdk/)
* [AppContentSearch API Documentation](https://learn.microsoft.com/en-us/windows/ai/apis/app-content-search)
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation. All rights reserved.

using Microsoft.Extensions.AI;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace Notes.AI
{
public static class IChatClientExtensions
{
public static async IAsyncEnumerable<string> InferStreaming(this IChatClient client, string system, string prompt, [EnumeratorCancellation] CancellationToken ct = default)
{
await foreach (var messagePart in client.GetStreamingResponseAsync(
[
new ChatMessage(ChatRole.System, system),
new ChatMessage(ChatRole.User, prompt)
],
null,
ct))
{
yield return messagePart.Text ?? string.Empty;
}
}

public static IAsyncEnumerable<string> SummarizeTextAsync(this IChatClient client, string userText, CancellationToken ct = default)
{
return client.InferStreaming("", $"Summarize this text in three to five bullet points:\r {userText}", ct);
}

public static IAsyncEnumerable<string> FixAndCleanUpTextAsync(this IChatClient client, string userText, CancellationToken ct = default)
{
var systemMessage = "Your job is to fix spelling, and clean up the text from the user. Only respond with the updated text. Do not explain anything.";
return client.InferStreaming(systemMessage, userText, ct);
}

public static IAsyncEnumerable<string> AutocompleteSentenceAsync(this IChatClient client, string sentence, CancellationToken ct = default)
{
var systemMessage = "You are an assistant that helps the user complete sentences. Ignore spelling mistakes and just respond with the words that complete the sentence. Do not repeat the begining of the sentence.";
return client.InferStreaming(systemMessage, sentence, ct);
}

public static Task<List<string>> GetTodoItemsFromText(this IChatClient client, string text)
{
return Task.Run(async () =>
{

var system = "Summarize the user text to 2-3 to-do items. Use the format [\"to-do 1\", \"to-do 2\"]. Respond only in one json array format";
string response = string.Empty;

CancellationTokenSource cts = new CancellationTokenSource();
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposable 'CancellationTokenSource' is created but not disposed.

Suggested change
CancellationTokenSource cts = new CancellationTokenSource();
using var cts = new CancellationTokenSource();

Copilot uses AI. Check for mistakes.
await foreach (var partialResult in client.InferStreaming(system, text, cts.Token))
{
response += partialResult;
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String concatenation in loop: use 'StringBuilder'.

Copilot uses AI. Check for mistakes.
if (partialResult.Contains("]"))
{
cts.Cancel();
break;
}
}

var todos = Regex.Matches(response, @"""([^""]*)""", RegexOptions.IgnoreCase | RegexOptions.Multiline)
.Select(m => m.Groups[1].Value)
.Where(t => !t.Contains("todo")).ToList();

return todos;
});
}

public static IAsyncEnumerable<string> AskForContentAsync(this IChatClient client, string content, string question, CancellationToken ct = default)
{
var systemMessage = "You are a helpful assistant answering questions about this content";
return client.InferStreaming($"{systemMessage}: {content}", question, ct);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.

namespace Notes.AI;

internal class LlmPromptTemplate
{
public string? System { get; init; }
public string? User { get; init; }
public string? Assistant { get; init; }
public string[]? Stop { get; init; }
}
Loading
Loading