Skip to content

Commit

Permalink
* Change to recent Google package
Browse files Browse the repository at this point in the history
* Add example about Google
* Add example about using Bing to answer user questions
* Update docs with env vars for Google samples
* Rename search function "SearchAsync" to "search"
* Reorder examples to intro search after template language
* Fix typo
  • Loading branch information
dluc committed Apr 29, 2023
1 parent e8a68da commit 82b43d1
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 106 deletions.
4 changes: 2 additions & 2 deletions dotnet/src/IntegrationTests/WebSkill/WebSkillTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task BingSkillTestAsync(string prompt, string expectedAnswerContain
// Act
SKContext result = await kernel.RunAsync(
prompt,
search["SearchAsync"]
search["Search"]
);

// Assert
Expand All @@ -72,7 +72,7 @@ public async Task WebFileDownloadSkillFileTestAsync()
var download = kernel.ImportSkill(skill, "WebFileDownload");
string fileWhereToSaveWebPage = Path.GetTempFileName();
var contextVariables = new ContextVariables("https://www.microsoft.com");
contextVariables.Set(WebFileDownloadSkill.Parameters.FilePath, fileWhereToSaveWebPage);
contextVariables.Set(WebFileDownloadSkill.FilePathParamName, fileWhereToSaveWebPage);

// Act
await kernel.RunAsync(contextVariables, download["DownloadToFile"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,36 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Customsearch.v1;
using Google.Apis.CustomSearchAPI.v1;
using Google.Apis.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

namespace Microsoft.SemanticKernel.Skills.Web.Google;

/// <summary>
/// Bing API connector.
/// Google search connector.
/// </summary>
public class GoogleConnector : IWebSearchEngineConnector, IDisposable
{
private readonly ILogger _logger;
private readonly CustomsearchService _search;
private readonly string _searchEngineId;
private readonly CustomSearchAPIService _search;
private readonly string? _searchEngineId;

public GoogleConnector(string apiKey, string searchEngineId, ILogger<GoogleConnector>? logger = null)
/// <summary>
/// Google search connector
/// </summary>
/// <param name="apiKey">Google Custom Search API (looks like "ABcdEfG1...")</param>
/// <param name="searchEngineId">Google Search Engine ID (looks like "a12b345...")</param>
/// <param name="logger">Optional logger</param>
public GoogleConnector(
string apiKey,
string searchEngineId,
ILogger<GoogleConnector>? logger = null)
{
this._logger = logger ?? NullLogger<GoogleConnector>.Instance;
this._search = new CustomsearchService(new BaseClientService.Initializer { ApiKey = apiKey });
this._search = new CustomSearchAPIService(new BaseClientService.Initializer { ApiKey = apiKey });
this._searchEngineId = searchEngineId;
this._logger = logger ?? NullLogger<GoogleConnector>.Instance;
}

/// <inheritdoc/>
Expand All @@ -34,7 +43,7 @@ public async Task<string> SearchAsync(string query, CancellationToken cancellati
search.Cx = this._searchEngineId;
search.Q = query;

var results = await search.ExecuteAsync(cancellationToken);
var results = await search.ExecuteAsync(cancellationToken).ConfigureAwait(false);

var first = results.Items?.FirstOrDefault();
this._logger.LogDebug("Result: {Title}, {Link}, {Snippet}", first?.Title, first?.Link, first?.Snippet);
Expand Down
2 changes: 1 addition & 1 deletion dotnet/src/Skills/Skills.Web/Skills.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" VersionOverride="[6.0.0, )" />
<PackageReference Include="System.Text.Json" VersionOverride="[6.0.0, )" />
<PackageReference Include="Google.Apis.Customsearch.v1" VersionOverride="[1.49, )"/>
<PackageReference Include="Google.Apis.CustomSearchAPI.v1" VersionOverride="[1.60.0.3001, )" />
</ItemGroup>

<ItemGroup>
Expand Down
17 changes: 5 additions & 12 deletions dotnet/src/Skills/Skills.Web/WebFileDownloadSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,9 @@ namespace Microsoft.SemanticKernel.Skills.Web;
public class WebFileDownloadSkill : IDisposable
{
/// <summary>
/// Parameter names.
/// <see cref="ContextVariables"/>
/// Skill parameter: where to save file.
/// </summary>
public static class Parameters
{
/// <summary>
/// Where to save file.
/// </summary>
public const string FilePath = "filePath";
}
public const string FilePathParamName = "filePath";

private readonly ILogger _logger;
private readonly HttpClientHandler _httpClientHandler;
Expand All @@ -54,15 +47,15 @@ public WebFileDownloadSkill(ILogger<WebFileDownloadSkill>? logger = null)
[SKFunction("Downloads a file to local storage")]
[SKFunctionName("DownloadToFile")]
[SKFunctionInput(Description = "URL of file to download")]
[SKFunctionContextParameter(Name = Parameters.FilePath, Description = "Path where to save file locally")]
[SKFunctionContextParameter(Name = FilePathParamName, Description = "Path where to save file locally")]
public async Task DownloadToFileAsync(string source, SKContext context)
{
this._logger.LogDebug($"{nameof(this.DownloadToFileAsync)} got called");

if (!context.Variables.Get(Parameters.FilePath, out string filePath))
if (!context.Variables.Get(FilePathParamName, out string filePath))
{
this._logger.LogError($"Missing context variable in {nameof(this.DownloadToFileAsync)}");
string errorMessage = $"Missing variable {Parameters.FilePath}";
string errorMessage = $"Missing variable {FilePathParamName}";
context.Fail(errorMessage);

return;
Expand Down
1 change: 1 addition & 0 deletions dotnet/src/Skills/Skills.Web/WebSearchEngineSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public WebSearchEngineSkill(IWebSearchEngineConnector connector)

[SKFunction("Perform a web search.")]
[SKFunctionInput(Description = "Text to search for")]
[SKFunctionName("search")]
public async Task<string> SearchAsync(string query, SKContext context)
{
string result = await this._connector.SearchAsync(query, context.CancellationToken).ConfigureAwait(false);
Expand Down
63 changes: 28 additions & 35 deletions samples/dotnet/github-skills/GitHubSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,29 @@ namespace GitHubSkills;
public class GitHubSkill
{
/// <summary>
/// Parameter names.
/// <see cref="ContextVariables"/>
/// Name of the repository repositoryBranch which will be downloaded and summarized.
/// </summary>
public static class Parameters
{
/// <summary>
/// Name of the repository repositoryBranch which will be downloaded and summarized.
/// </summary>
public const string RepositoryBranch = "repositoryBranch";

/// <summary>
/// The search string to match against the names of files in the repository.
/// </summary>
public const string SearchPattern = "searchPattern";

/// <summary>
/// Document file path.
/// </summary>
public const string FilePath = "filePath";

/// <summary>
/// Directory to which to extract compressed file's data.
/// </summary>
public const string DestinationDirectoryPath = "destinationDirectoryPath";

/// <summary>
/// Name of the memory collection used to store the code summaries.
/// </summary>
public const string MemoryCollectionName = "memoryCollectionName";
}
public const string RepositoryBranchParamName = "repositoryBranch";

/// <summary>
/// The search string to match against the names of files in the repository.
/// </summary>
public const string SearchPatternParamName = "searchPattern";

/// <summary>
/// Document file path.
/// </summary>
public const string FilePathParamName = "filePath";

/// <summary>
/// Directory to which to extract compressed file's data.
/// </summary>
public const string DestinationDirectoryPathParamName = "destinationDirectoryPath";

/// <summary>
/// Name of the memory collection used to store the code summaries.
/// </summary>
public const string MemoryCollectionNameParamName = "memoryCollectionName";

/// <summary>
/// The max tokens to process in a single semantic function call.
Expand Down Expand Up @@ -110,17 +103,17 @@ public GitHubSkill(IKernel kernel, WebFileDownloadSkill downloadSkill, ILogger<G
[SKFunction("Downloads a repository and summarizes the content")]
[SKFunctionName("SummarizeRepository")]
[SKFunctionInput(Description = "URL of the GitHub repository to summarize")]
[SKFunctionContextParameter(Name = Parameters.RepositoryBranch,
[SKFunctionContextParameter(Name = RepositoryBranchParamName,
Description = "Name of the repository repositoryBranch which will be downloaded and summarized")]
[SKFunctionContextParameter(Name = Parameters.SearchPattern, Description = "The search string to match against the names of files in the repository")]
[SKFunctionContextParameter(Name = SearchPatternParamName, Description = "The search string to match against the names of files in the repository")]
public async Task SummarizeRepositoryAsync(string source, SKContext context)
{
if (!context.Variables.Get(Parameters.RepositoryBranch, out string repositoryBranch) || string.IsNullOrEmpty(repositoryBranch))
if (!context.Variables.Get(RepositoryBranchParamName, out string repositoryBranch) || string.IsNullOrEmpty(repositoryBranch))
{
repositoryBranch = "main";
}

if (!context.Variables.Get(Parameters.SearchPattern, out string searchPattern) || string.IsNullOrEmpty(searchPattern))
if (!context.Variables.Get(SearchPatternParamName, out string searchPattern) || string.IsNullOrEmpty(searchPattern))
{
searchPattern = "*.md";
}
Expand All @@ -133,14 +126,14 @@ public async Task SummarizeRepositoryAsync(string source, SKContext context)
{
var repositoryUri = source.Trim(new char[] { ' ', '/' });
var context1 = new SKContext(new ContextVariables(), NullMemory.Instance, null, context.Log);
context1.Variables.Set(Parameters.FilePath, filePath);
context1.Variables.Set(FilePathParamName, filePath);
await this._downloadSkill.DownloadToFileAsync($"{repositoryUri}/archive/refs/heads/{repositoryBranch}.zip", context1);

ZipFile.ExtractToDirectory(filePath, directoryPath);

await this.SummarizeCodeDirectoryAsync(directoryPath, searchPattern, repositoryUri, repositoryBranch, context);

context.Variables.Set(Parameters.MemoryCollectionName, $"{repositoryUri}-{repositoryBranch}");
context.Variables.Set(MemoryCollectionNameParamName, $"{repositoryUri}-{repositoryBranch}");
}
finally
{
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using RepoUtils;

// ReSharper disable once InconsistentNaming
public static class Example05_CombineLLMPromptsAndNativeCode
public static class Example04_CombineLLMPromptsAndNativeCode
{
public static async Task RunAsync()
{
Expand Down Expand Up @@ -38,18 +38,18 @@ public static async Task RunAsync()

var result1 = await kernel.RunAsync(
ask,
search["SearchAsync"]
search["Search"]
);

var result2 = await kernel.RunAsync(
ask,
search["SearchAsync"],
search["Search"],
sumSkill["Summarize"]
);

var result3 = await kernel.RunAsync(
ask,
search["SearchAsync"],
search["Search"],
sumSkill["Notegen"]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using RepoUtils;

// ReSharper disable once InconsistentNaming
public static class Example06_InlineFunctionDefinition
public static class Example05_InlineFunctionDefinition
{
public static async Task RunAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.CoreSkills;
using Microsoft.SemanticKernel.TemplateEngine;
using RepoUtils;

// ReSharper disable once InconsistentNaming
public static class Example07_TemplateLanguage
public static class Example06_TemplateLanguage
{
/// <summary>
/// Show how to invoke a Native Function written in C#
Expand All @@ -33,9 +34,40 @@ public static async Task RunAsync()
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
Is it weekend time (weekend/not weekend)?
";

// This allows to see the prompt before it's sent to OpenAI
Console.WriteLine("--- Rendered Prompt");
var promptRenderer = new PromptTemplateEngine();
var renderedPrompt = await promptRenderer.RenderAsync(FUNCTION_DEFINITION, kernel.CreateNewContext());
Console.WriteLine(renderedPrompt);

// Run the prompt / semantic function
var kindOfDay = kernel.CreateSemanticFunction(FUNCTION_DEFINITION, maxTokens: 150);

// Show the result
Console.WriteLine("--- Semantic Function result");
var result = await kindOfDay.InvokeAsync();
Console.WriteLine(result);

/* OUTPUT:
--- Rendered Prompt
Today is: Friday, April 28, 2023
Current time is: 11:04:30 PM
Answer to the following questions using JSON syntax, including the data used.
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
Is it weekend time (weekend/not weekend)?
--- Semantic Function result
{
"date": "Friday, April 28, 2023",
"time": "11:04:30 PM",
"period": "night",
"weekend": "weekend"
}
*/
}
}

0 comments on commit 82b43d1

Please sign in to comment.