Compare commits

...

1 Commits

Author SHA1 Message Date
Leilei Zhang
c2e0e4553f search 2025-03-29 18:31:20 +08:00
11 changed files with 255 additions and 4 deletions

View File

@@ -706,6 +706,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SemanticSearch", "src\common\SemanticSearch\SemanticSearch.csproj", "{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -2574,14 +2576,18 @@ Global
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|ARM64.Build.0 = Debug|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.ActiveCfg = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.Build.0 = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x86.ActiveCfg = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x86.Build.0 = Debug|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.ActiveCfg = Release|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.Build.0 = Release|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.ActiveCfg = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.Build.0 = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.ActiveCfg = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.Build.0 = Release|x64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Debug|ARM64.ActiveCfg = Debug|ARM64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Debug|ARM64.Build.0 = Debug|ARM64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Debug|x64.ActiveCfg = Debug|x64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Debug|x64.Build.0 = Debug|x64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Release|ARM64.ActiveCfg = Release|ARM64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Release|ARM64.Build.0 = Release|ARM64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Release|x64.ActiveCfg = Release|x64
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2852,6 +2858,7 @@ Global
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{5795CC73-53E2-27F4-3E37-21CB85E9E6A2} = {1AFB6476-670D-4E80-A464-657E01DFF482}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
internal class EmbeddingModel : IEmbeddingModel
{
public float[] ComputeEmbedding(string text)
{
// Placeholder for the actual implementation
return text.Select(c => (float)c % 10).Take(10).ToArray();
}
public bool SupportsSearch => true;
}
}

View File

@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
public static class EmbeddingModelFactory
{
private static IEmbeddingModel? _currentModel;
private static string? _currentModelName;
public static IEmbeddingModel? GetEmbeddingModel()
{
CheckAndUpdateModel();
return _currentModel;
}
public static void CheckAndUpdateModel()
{
string configuredModelName = GetConfiguredModelName();
if (_currentModelName == configuredModelName)
{
return;
}
_currentModel = configuredModelName switch
{
"Mock" => new EmbeddingModel(),
_ => new EmbeddingModel(),
};
_currentModelName = configuredModelName;
}
private static string GetConfiguredModelName()
{
return "Mock";
}
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
public interface IEmbeddingModel
{
float[] ComputeEmbedding(string text);
bool SupportsSearch { get; }
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
public interface IIndexStore
{
void AddData(List<(string Text, float[] Embedding)> data);
List<(string Text, float[] Embedding)> GetData();
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
public interface ISemanticSearchService
{
void IndexData(ModuleName moduleName, List<string> data);
List<string> Search(ModuleName moduleName, string query, int topK = 5, double threshold = 0.7);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
public interface ISimilarityCalculator
{
double ComputeSimilarity(float[] vectorA, float[] vectorB);
}
}

View File

@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
public class InMemoryIndexStore : IIndexStore
{
private readonly List<(string Text, float[] Embedding)> _indexedData = new();
public void AddData(List<(string Text, float[] Embedding)> data)
{
_indexedData.AddRange(data);
}
public List<(string Text, float[] Embedding)> GetData()
{
return _indexedData;
}
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.PowerToys.SemanticSearch
{
public enum ModuleName
{
Settings,
}
}

View File

@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<Description>PowerToys SemanticSearch</Description>
<AssemblyName>PowerToys.SemanticSearch</AssemblyName>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.PowerToys.SemanticSearch;
public abstract class SemanticSearchService
{
private readonly IIndexStore _indexStore;
private readonly IEmbeddingModel _embeddingModel;
private readonly ISimilarityCalculator _similarityCalculator;
protected SemanticSearchService(IIndexStore indexStore, IEmbeddingModel embeddingModel, ISimilarityCalculator similarityCalculator)
{
_indexStore = indexStore;
_embeddingModel = embeddingModel;
_similarityCalculator = similarityCalculator;
}
public virtual void IndexData(List<string> data)
{
var indexedData = data.Select(text => (text, _embeddingModel.ComputeEmbedding(text))).ToList();
_indexStore.AddData(indexedData);
}
public virtual List<string> Search(string query, int topK = 5, double threshold = 0.7)
{
if (!_embeddingModel.SupportsSearch)
{
return new List<string>();
}
var queryEmbedding = _embeddingModel.ComputeEmbedding(query);
var indexedData = _indexStore.GetData();
return indexedData
.Select(entry => (entry.Text, similarity: _similarityCalculator.ComputeSimilarity(queryEmbedding, entry.Embedding)))
.Where(entry => entry.similarity >= threshold)
.OrderByDescending(entry => entry.similarity)
.Take(topK)
.Select(entry => entry.Text)
.ToList();
}
}