Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Pomocí vyhledávání obsahu aplikace můžete vytvořit sémantický index obsahu v aplikaci. To umožňuje uživatelům najít informace na základě významu, nikoli jenom klíčových slov. Index se dá použít také k vylepšení asistentů umělé inteligence pomocí znalostí specifických pro konkrétní doménu pro lepší přizpůsobení a kontextové výsledky.
Konkrétně se dozvíte, jak používat rozhraní API AppContentIndexer k:
- Vytvoření nebo otevření indexu obsahu v aplikaci
- Přidání textových řetězců do indexu a následné spuštění dotazu
- Správa složitosti dlouhého textového řetězce
- Indexujte data obrázků a vyhledejte relevantní obrázky.
- Povolení scénářů generování posíleného vyhledáváním (RAG)
- Použití AppContentIndexeru na vlákně na pozadí
- Zavření AppContentIndexeru, pokud se už nepoužívá k uvolnění prostředků
Požadavky
Informace o hardwarových požadavcích rozhraní API pro Windows AI a o tom, jak nakonfigurovat zařízení pro úspěšné sestavování aplikací pomocí rozhraní API pro Windows AI, najdete v tématu Začínáme se sestavováním aplikace pomocí rozhraní API pro Windows AI.
Požadavek na identitu balíčku
Aplikace používající AppContentIndexer musí mít identitu balíčku, která je dostupná jenom pro zabalené aplikace (včetně aplikací s externími umístěními). Aby bylo možné povolit sémantické indexování a rozpoznávání textu (OCR), musí aplikace také deklarovat systemaimodels schopnost.
Vytvoření nebo otevření indexu obsahu v aplikaci
Pokud chcete vytvořit sémantický index obsahu v aplikaci, musíte nejprve vytvořit prohledávatelnou strukturu, kterou může vaše aplikace použít k efektivnímu ukládání a načítání obsahu. Tento index funguje jako místní sémantický a lexikální vyhledávací modul pro obsah vaší aplikace.
Pokud chcete použít rozhraní API AppContentIndexer , nejprve volejte GetOrCreateIndex se zadaným názvem indexu. Pokud index s tímto názvem již existuje pro aktuální identitu aplikace a uživatele, otevře se; v opačném případě se vytvoří nový.
public void SimpleGetOrCreateIndexSample()
{
GetOrCreateIndexResult result = AppContentIndexer.GetOrCreateIndex("myindex");
if (!result.Succeeded)
{
throw new InvalidOperationException($"Failed to open index. Status = '{result.Status}', Error = '{result.ExtendedError}'");
}
// If result.Succeeded is true, result.Status will either be CreatedNew or OpenedExisting
if (result.Status == GetOrCreateIndexStatus.CreatedNew)
{
Console.WriteLine("Created a new index");
}
else if(result.Status == GetOrCreateIndexStatus.OpenedExisting)
{
Console.WriteLine("Opened an existing index");
}
using AppContentIndexer indexer = result.Indexer;
// Use indexer...
}
Tento příklad demonstruje, jak řešit případ selhání při otevírání indexu. Pro zjednodušení nemusí jiné ukázky v tomto dokumentu zobrazovat zpracování chyb.
Přidání textových řetězců do indexu a následné spuštění dotazu
Tato ukázka ukazuje, jak přidat některé textové řetězce do indexu vytvořeného pro vaši aplikaci a pak spustit dotaz na tento index, který načte relevantní informace.
// This is some text data that we want to add to the index:
Dictionary<string, string> simpleTextData = new Dictionary<string, string>
{
{"item1", "Here is some information about Cats: Cats are cute and fluffy. Young cats are very playful." },
{"item2", "Dogs are loyal and affectionate animals known for their companionship, intelligence, and diverse breeds." },
{"item3", "Fish are aquatic creatures that breathe through gills and come in a vast variety of shapes, sizes, and colors." },
{"item4", "Broccoli is a nutritious green vegetable rich in vitamins, fiber, and antioxidants." },
{"item5", "Computers are powerful electronic devices that process information, perform calculations, and enable communication worldwide." },
{"item6", "Music is a universal language that expresses emotions, tells stories, and connects people through rhythm and melody." },
};
public void SimpleTextIndexingSample()
{
AppContentIndexer indexer = GetIndexerForApp();
// Add some text data to the index:
foreach (var item in simpleTextData)
{
IndexableAppContent textContent = AppManagedIndexableAppContent.CreateFromString(item.Key, item.Value);
indexer.AddOrUpdate(textContent);
}
}
public void SimpleTextQueryingSample()
{
AppContentIndexer indexer = GetIndexerForApp();
// We search the index using a semantic query:
AppIndexTextQuery queryCursor = indexer.CreateTextQuery("Facts about kittens.");
IReadOnlyList<TextQueryMatch> textMatches = queryCursor.GetNextMatches(5);
// Nothing in the index exactly matches what we queried but item1 is similar to the query so we expect
// that to be the first match.
foreach (var match in textMatches)
{
Console.WriteLine(match.ContentId);
if (match.ContentKind == QueryMatchContentKind.AppManagedText)
{
AppManagedTextQueryMatch textResult = (AppManagedTextQueryMatch)match;
// Only part of the original string may match the query. So we can use TextOffset and TextLength to extract the match.
// In this example, we might imagine that the substring "Cats are cute and fluffy" from "item1" is the top match for the query.
string matchingData = simpleTextData[match.ContentId];
string matchingString = matchingData.Substring(textResult.TextOffset, textResult.TextLength);
Console.WriteLine(matchingString);
}
}
}
QueryMatch obsahuje pouze ContentIdTextOffset/TextLength, nikoli samotný odpovídající text. Jako vývojář aplikace zodpovídáte za odkaz na původní text. Výsledky dotazů se seřadí podle relevance, přičemž nejrelevantnější je nejvyšší výsledek. Indexování probíhá asynchronně, takže dotazy mohou běžet na částečných datech. Stav indexování můžete zkontrolovat, jak je uvedeno níže.
Správa složitosti dlouhého textového řetězce
Ukázka ukazuje, že vývojář aplikace nemusí text rozdělit do menších oddílů pro zpracování modelu. AppContentIndexer spravuje tento aspekt složitosti.
Dictionary<string, string> textFiles = new Dictionary<string, string>
{
{"file1", "File1.txt" },
{"file2", "File2.txt" },
{"file3", "File3.txt" },
};
public void TextIndexingSample2()
{
AppContentIndexer indexer = GetIndexerForApp();
var folderPath = Windows.ApplicationModel.Package.Current.InstalledLocation.Path;
// Add some text data to the index:
foreach (var item in textFiles)
{
string contentId = item.Key;
string filename = item.Value;
// Note that the text here can be arbitrarily large. The AppContentIndexer will take care of chunking the text
// in a way that works effectively with the underlying model. We do not require the app author to break the text
// down into small pieces.
string text = File.ReadAllText(Path.Combine(folderPath, filename));
IndexableAppContent textContent = AppManagedIndexableAppContent.CreateFromString(contentId, text);
indexer.AddOrUpdate(textContent);
}
}
public void TextIndexingSample2_RunQuery()
{
AppContentIndexer indexer = GetIndexerForApp();
var folderPath = Windows.ApplicationModel.Package.Current.InstalledLocation.Path;
// Search the index
AppIndexTextQuery query = indexer.CreateTextQuery("Facts about kittens.");
IReadOnlyList<TextQueryMatch> textMatches = query.GetNextMatches(5);
if (textMatches != null)
{
foreach (var match in textMatches)
{
Console.WriteLine(match.ContentId);
if (match is AppManagedTextQueryMatch textResult)
{
// We load the content of the file that contains the match:
string matchingFilename = textFiles[match.ContentId];
string fileContent = File.ReadAllText(Path.Combine(folderPath, matchingFilename));
// Find the substring within the loaded text that contains the match:
string matchingString = fileContent.Substring(textResult.TextOffset, textResult.TextLength);
Console.WriteLine(matchingString);
}
}
}
}
Textová data pocházejí ze souborů, ale pouze obsah se indexuje, nikoli samotné soubory. AppContentIndexer nemá žádné znalosti o původních souborech a nemonitoruje aktualizace. Pokud se obsah souboru změní, aplikace musí index aktualizovat ručně.
Indexujte data obrázků a vyhledejte relevantní obrázky.
Tato ukázka ukazuje, jak indexovat data obrázků jako SoftwareBitmaps a pak vyhledat relevantní obrázky pomocí textových dotazů.
// We load the image data from a set of known files and send that image data to the indexer.
// The image data does not need to come from files on disk, it can come from anywhere.
Dictionary<string, string> imageFilesToIndex = new Dictionary<string, string>
{
{"item1", "Cat.jpg" },
{"item2", "Dog.jpg" },
{"item3", "Fish.jpg" },
{"item4", "Broccoli.jpg" },
{"item5", "Computer.jpg" },
{"item6", "Music.jpg" },
};
public void SimpleImageIndexingSample()
{
AppContentIndexer indexer = GetIndexerForApp();
// Add some image data to the index.
foreach (var item in imageFilesToIndex)
{
var file = item.Value;
var softwareBitmap = Helpers.GetSoftwareBitmapFromFile(file);
IndexableAppContent imageContent = AppManagedIndexableAppContent.CreateFromBitmap(item.Key, softwareBitmap);
indexer.AddOrUpdate(imageContent);
}
}
public void SimpleImageIndexingSample_RunQuery()
{
AppContentIndexer indexer = GetIndexerForApp();
// We query the index for some data to match our text query.
AppIndexImageQuery query = indexer.CreateImageQuery("cute pictures of kittens");
IReadOnlyList<ImageQueryMatch> imageMatches = query.GetNextMatches(5);
// One of the images that we indexed was a photo of a cat. We expect this to be the first match to match the query.
foreach (var match in imageMatches)
{
Console.WriteLine(match.ContentId);
if (match.ContentKind == QueryMatchContentKind.AppManagedImage)
{
AppManagedImageQueryMatch imageResult = (AppManagedImageQueryMatch)match;
var matchingFileName = imageFilesToIndex[match.ContentId];
// It might be that the match is at a particular region in the image. The result includes
// the subregion of the image that includes the match.
Console.WriteLine($"Matching file: '{matchingFileName}' at location {imageResult.Subregion}");
}
}
}
Povolení scénářů generování posíleného vyhledáváním (RAG)
RAG (Retrieval-Augmented Generation) zahrnuje rozšíření uživatelských dotazů na jazykové modely o další relevantní data, která je možné použít ke generování odpovědí. Dotaz uživatele slouží jako vstup pro sémantické vyhledávání, které identifikuje relevantní informace v indexu. Výsledná data z sémantického vyhledávání se pak začlení do výzvy zadané jazykovému modelu, aby bylo možné vygenerovat přesnější a kontextové odpovědi.
Tato ukázka ukazuje, jak lze rozhraní API AppContentIndexer použít s LLM k přidání kontextových dat do vyhledávacího dotazu uživatele aplikace. Ukázka je obecná, není zadán žádný LLM a v příkladu se dotazují pouze místní data uložená v indexu vytvořeném (žádná externí volání na internet). V této ukázce Helpers.GetUserPrompt()Helpers.GetResponseFromChatAgent() nejsou skutečné funkce a slouží pouze k poskytnutí příkladu.
Pokud chcete povolit scénáře RAG s rozhraním API AppContentIndexer , můžete postupovat podle tohoto příkladu:
public void SimpleRAGScenario()
{
AppContentIndexer indexer = GetIndexerForApp();
// These are some text files that had previously been added to the index.
// The key is the contentId of the item.
Dictionary<string, string> data = new Dictionary<string, string>
{
{"file1", "File1.txt" },
{"file2", "File2.txt" },
{"file3", "File3.txt" },
};
string userPrompt = Helpers.GetUserPrompt();
// We execute a query against the index using the user's prompt string as the query text.
AppIndexTextQuery query = indexer.CreateTextQuery(userPrompt);
IReadOnlyList<TextQueryMatch> textMatches = query.GetNextMatches(5);
StringBuilder promptStringBuilder = new StringBuilder();
promptStringBuilder.AppendLine("Please refer to the following pieces of information when responding to the user's prompt:");
// For each of the matches found, we include the relevant snippets of the text files in the augmented query that we send to the language model
foreach (var match in textMatches)
{
if (match is AppManagedTextQueryMatch textResult)
{
// We load the content of the file that contains the match:
string matchingFilename = data[match.ContentId];
string fileContent = File.ReadAllText(matchingFilename);
// Find the substring within the loaded text that contains the match:
string matchingString = fileContent.Substring(textResult.TextOffset, textResult.TextLength);
promptStringBuilder.AppendLine(matchingString);
promptStringBuilder.AppendLine();
}
}
promptStringBuilder.AppendLine("Please provide a response to the following user prompt:");
promptStringBuilder.AppendLine(userPrompt);
var response = Helpers.GetResponseFromChatAgent(promptStringBuilder.ToString());
Console.WriteLine(response);
}
Použití AppContentIndexeru na vlákně na pozadí
Instance AppContentIndexer není přidružena k určitému vláknu; jedná se o agilní objekt, který může fungovat napříč vlákny. Některé metody AppContentIndexer a jeho souvisejících typů mohou vyžadovat značnou dobu zpracování. Proto je vhodné se vyhnout vyvolání rozhraní AppContentIndexer API přímo z vlákna uživatelského rozhraní aplikace a místo toho použít vlákno na pozadí.
Zavření AppContentIndexeru, pokud se už nepoužívá k uvolnění prostředků
AppContentIndexer implementuje IClosable rozhraní k určení jeho životnosti. Aplikace by měla indexer zavřít, když se už nepoužívá. To umožňuje appContentIndexer uvolnit své základní prostředky.
public void IndexerDisposeSample()
{
var indexer = AppContentIndexer.GetOrCreateIndex("myindex").Indexer;
// use indexer
indexer.Dispose();
// after this point, it would be an error to try to use indexer since it is now Closed.
}
V kódu jazyka IClosable C# je rozhraní zobrazeno jako IDisposable. Kód jazyka using C# může používat vzor pro instance AppContentIndexer .
public void IndexerUsingSample()
{
using var indexer = AppContentIndexer.GetOrCreateIndex("myindex").Indexer;
// use indexer
//indexer.Dispose() is automatically called
}
Pokud ve své aplikaci několikrát otevřete stejný index, musíte zavolat Close u každé instance.
Otevření a zavření indexu je náročná operace, takže byste měli tyto operace ve své aplikaci minimalizovat. Aplikace může například uložit jednu instanci AppContentIndexeru pro aplikaci a tuto instanci používat po celou dobu životnosti aplikace místo neustálého otevírání a zavírání indexu pro každou akci, kterou je potřeba provést.