Skip to content

Commit

Permalink
Merge pull request #28 from Azure/websearch
Browse files Browse the repository at this point in the history
Lesson 4 - Bing Web Search plugin
  • Loading branch information
yortch authored Jan 15, 2025
2 parents 579ec7b + 2a81c1b commit bbe554e
Show file tree
Hide file tree
Showing 23 changed files with 368 additions and 31 deletions.
2 changes: 1 addition & 1 deletion docs/wksp/05-semantic-kernel-workshop/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
This workshop is broken into 2 main sections:

1. [Create simple AI Orchestration using Sematic Kernel](simple-ai-orchestration/index.md)
1. [Create advanced AI Orchestration using Sematik Kernel with agents and planners](advanced-ai-orchestration/index.md)
1. [Create advanced AI Orchestration using Semantic Kernel with agents and planners](advanced-ai-orchestration/index.md)
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ use `bicep` templates which are organized as follows:
* `web.bicep` - bicep templated for web application infrastructure
* core - subdirectory with templates for core infrastructure components
* **ai** - subdirectory for AI related components
* **bing** - subdirectory for Bing Search service
* **host** - subdirectory for container app, environment and registry components
* **monitor** - subdirectory for monitoring components (e.g. application insights)
* **security** - subdirectory for security components (e.g. keyvault)
Expand All @@ -67,19 +68,20 @@ to generate an existing template is to find a template that uses similar compone

You can build, provision all resources and deploy by following these steps:

1. Switch to `workshop/donet` directory.
1. Switch to `workshop/dotnet` directory.
1. Ensure Docker desktop is running (if not using Github Codespace).
1. Run `azd auth login` to login to your Azure account.
1. Run `azd up` to provision Azure resources and deploy this sample to those resources.
You will be prompted for the following parameters:
* Environment name: sk-test
* Select an Azure subscription to use from list
* Select an Azure location to use: e.g. (US) East US 2 (eastus2)
* Enter a value for the infrastructure parameters:
* **openAIApiKey**
* **openAiChatGptDeployment**: e.g. gpt-4o
* **openAiEndpoint**
* **stockServiceApiKey**
1. Open Git bash or WSL (Windows Subsystem for Linux) terminal and run the following commands
1. Run `azd auth login` to login to your Azure account.
1. Run `azd up` to provision Azure resources and deploy this sample to those resources.
You will be prompted for the following parameters:
* Environment name: sk-test
* Select an Azure subscription to use from list
* Select an Azure location to use: e.g. (US) East US 2 (eastus2)
* Enter a value for the infrastructure parameters:
* **openAIApiKey**
* **openAiChatGptDeployment**: e.g. gpt-4o
* **openAiEndpoint**
* **stockServiceApiKey**
1. After the application has been successfully deployed you will see the API and Web Service URLs printed in the console.
Click the Web Service URL to interact with the application in your browser.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ This hands on workshop goes through the following lessons for creating a simple
chatbot as a console application:

1. [Prerequisites](pre-reqs.md)
1. [Lesson 1: Create Simple Semantic Kernel chatbot](lesson1.md)
1. [Lesson 2: Create Simple Semantic Kernel chatbot with history](lesson2.md)
1. [Lesson 3: Create Simple Semantic Kernel chatbot with plugins](lesson3.md)
1. [Lesson 1: Semantic Kernel chatbot](lesson1.md)
1. [Lesson 2: Semantic Kernel chatbot with history](lesson2.md)
1. [Lesson 3: Semantic Kernel chatbot with plugins](lesson3.md)
1. [Lesson 4: Semantic Kernel chatbot with Web Search engine plugin](lesson4.md)

Subsequently the following lessons guide you through converting that chatbot application
into a deployable application with a backend API and Web UI frontend and deploying into Azure:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Lesson 1: Simple Semantic Kernel chatbot
# Lesson 1: Semantic Kernel chatbot

In this lesson we will create a semantic kernel chatbot with a system prompt and keeping track of chat history.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Lesson 2: Simple Semantic Kernel chatbot with history
# Lesson 2: Semantic Kernel chatbot with history

In this lesson we will add chat history to our chat agent.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Lesson 3: Simple Semantic Kernel chat agent with plugins
# Lesson 3: Semantic Kernel chatbot with plugins

In this lesson we will a semantic kernel plugins to be able to retrieve stock pricing.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Lesson 4: Semantic Kernel chatbot with Web Search engine plugin

In this lesson we will add a Web Search Engine plugin that uses Bing Search to our semantic kernel chatbot.

1. Ensure all [pre-requisites](pre-reqs.md) are met and installed (including updating the `BingSearchService` `apiKey` value in the `appSettings.json` file using the key from **Bing Search Service v7** in Azure (https://portal.azure.com)).

1. Switch to Lesson 4 directory:

```bash
cd ../Lesson4
```

1. Start by copying `appsettings.json` from Lesson 1:

```bash
cp ../Lesson1/appsettings.json .
```

1. Run program and ask what the sentiment on Microsoft stock is:

```bash
dotnet run
```

At the prompt enter

```bash
What is the sentiment on Microsoft stock?
```

Assistant will give a generic response:

```txt
Assistant > The sentiment on Microsoft (ticker symbol: MSFT) largely hinges on factors like:
- Tech innovation (e.g., AI, Azure cloud service, and gaming)
- Quarterly earnings reports
- Overall market conditions
- How much caffeine traders have consumed
```

1. Notice it does not provide a specific answer. We can add the Web Search Engine plugin to be able to provide a better answer.

1. Next locate **TODO: Step 1** in `Program.cs` and add the following import lines:

```csharp
using Microsoft.SemanticKernel.Plugins.Web;
using Microsoft.SemanticKernel.Plugins.Web.Bing;
```

1. Next locate **TODO: Step 2** in `Program.cs` and provide the following lines to initialize and register the `WebSearchEnginePlugin`:

```csharp
var bingApiKey = AISettingsProvider.GetSettings().BingSearchService.ApiKey;
if (!string.IsNullOrEmpty(bingApiKey))
{
var bingConnector = new BingConnector(bingApiKey);
var bing = new WebSearchEnginePlugin(bingConnector);
kernel.ImportPluginFromObject(bing, "bing");
}
```
1. Re-run the program and ask what the sentiment on Microsoft stock is:
```bash
dotnet run
User > What is the sentiment on Microsoft stock?
```
Assistant response:
```txt
Assistant > Ah, Microsoft stock seems to be the belle of the ball with mixed but leaning-positive vibes. Let me serve up the sentiment soup:
- **Positives:** There's more excitement than usual, with higher-than-average media sentiment compared to other tech companies. Plus, analysts are dishing out 12-month price targets like cocktails, with an average around $489.55 and some saying it could go as high as $600—a nice little pie in the sky for investors! 🍰🚀
- **Concerns:** Clouds (pun intended!) aren't all silver-lining for Microsoft, as they've got capacity constraints in their cloud services. Choppy waters ahead, perhaps? 🌩️
- **Buzz:** Oh, it's trending alright! Tons of people are searching, sharing, and probably debating MSFT more than their weekend plans.
Feeling FOMO or ready to YOLO-invest? Don’t forget to watch that ticker—MSFT!
```
Expect to see a more specific response. With the Web Search Engine plugin, you can now tap into any web search, so your agent will leverage that plugin to find information not available via other plugins or within the LLM being used.
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,28 @@ cd intelligent-app-workshop
1. Update `appsettings.json` deploymentName field with your model deployment name.
1. Use the **Deployment Name** value (e.g. gpt-4o) as the **deploymentName** value within the `OpenAI` element in the `appsettings.json` file.
1. Create Azure Bing Search v7 Service in Azure and retrieve the API Key to update newly created `appsettings.json`. This value will be needed for [Lesson 4](lesson4.md).
1. Create Bing Search Service (from Azure Portal):
1. Go to the [Azure Portal](https://portal.azure.com).
1. Click on [Create A Resource](https://ms.portal.azure.com/#create/hub)
1. On the search bar type **Bing Search** and hit enter
1. Locate **Bing Search v7** and click **Create**
1. On the **Create a Bing Search Resource** page, provide the following information for the fields on the Basics tab:
* Subscription: The Azure subscription to used for your service.
* Resource group: The Azure resource group to contain your Bing service resource. You can create a new group or use a pre-existing group.
* Name: A descriptive and unique name for your Bing Search Service resource, such as `bing-search-myid`.
* Region: Global (default).
* Pricing Tier: The pricing tier for the resource. The `F1` tier is free and recommended for testing purposes.
1. Click **Next**.
1. On the **Tags** tab click **Next**
1. Click **Create**.
1. Get the Bing Search API Key and update `appsettings.json` file:
1. Go to the [Azure Portal](https://portal.azure.com).
1. On the search bar type **Bing Reources** and hit enter
1. Locate the **Bing Service** created above and click on it.
1. Expand **RESOURCE MANAGEMENT** and click on **Keys and Endpoint**
1. Copy the value from **Key 1** and paste it as the **ApiKey** value within the `BingSearchService` element in the `appsettings.json` file.
1. Additionally, we need to obtain an API Key to be able to get stock prices from [polygon.io](https://polygon.io/dashboard/login). You can sign up for a free API Key by creating a login. This value will be needed for [Lesson 3](lesson3.md).
1. Once logged in, from the [polygon.io Dashboard](https://polygon.io/dashboard) locate the **Keys** section. Copy the default key value and paste it as the **apiKey** value within the `StockService` element in the `appsettings.json` file.
Expand Down
7 changes: 4 additions & 3 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ nav:
- Module 5 - Hands-on AI Orchestration using Semantic Kernel Workshop:
- wksp/05-semantic-kernel-workshop/simple-ai-orchestration/index.md
- Pre-requisites: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/pre-reqs.md
- Lesson 1 - Simple Semantic Kernel chatbot: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/lesson1.md
- Lesson 2 - Simple Semantic Kernel chatbot with history: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/lesson2.md
- Lesson 3 - Simple Semantic Kernel chatbot with plugins: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/lesson3.md
- Lesson 1 - Semantic Kernel chatbot: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/lesson1.md
- Lesson 2 - Semantic Kernel chatbot with history: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/lesson2.md
- Lesson 3 - Semantic Kernel chatbot with plugins: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/lesson3.md
- Lesson 4 - Semantic Kernel chatbot with Web Search engine plugin: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/lesson4.md
- Build a deployable web application:
- wksp/05-semantic-kernel-workshop/simple-ai-orchestration/create-deployable-app/index.md
- Create Backend API: wksp/05-semantic-kernel-workshop/simple-ai-orchestration/create-deployable-app/backend-api.md
Expand Down
12 changes: 12 additions & 0 deletions workshop/dotnet/App/backend/Extensions/ServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
// Add import required for StockService
using Core.Utilities.Services;
using Microsoft.SemanticKernel;
// Add imports for Bing Search plugin
using Microsoft.SemanticKernel.Plugins.Web;
using Microsoft.SemanticKernel.Plugins.Web.Bing;

namespace Extensions;

Expand All @@ -27,6 +30,15 @@ public static void AddSkServices(this IServiceCollection services)
StockDataPlugin stockDataPlugin = new(new StocksService(httpClient));
kernel.Plugins.AddFromObject(stockDataPlugin);

// Initialize Bing Search plugin
var bingApiKey = AISettingsProvider.GetSettings().BingSearchService.ApiKey;
if (!string.IsNullOrEmpty(bingApiKey))
{
var bingConnector = new BingConnector(bingApiKey);
var bing = new WebSearchEnginePlugin(bingConnector);
kernel.ImportPluginFromObject(bing, "bing");
}

return kernel;
});
}
Expand Down
4 changes: 2 additions & 2 deletions workshop/dotnet/Core.Utilities/Config/AISettingsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

namespace Core.Utilities.Config;

internal static class AISettingsProvider
public static class AISettingsProvider
{
internal static AppSettings GetSettings()
public static AppSettings GetSettings()
{
IConfigurationRoot config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true)
Expand Down
3 changes: 2 additions & 1 deletion workshop/dotnet/Core.Utilities/Core.Utilities.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NoWarn>SKEXP0110;SKEXP0001;SKEXP0101</NoWarn>
<NoWarn>SKEXP0110;SKEXP0001;SKEXP0101</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand All @@ -14,5 +14,6 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Microsoft.SemanticKernel" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Web" />
</ItemGroup>
</Project>
7 changes: 6 additions & 1 deletion workshop/dotnet/Core.Utilities/Models/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ namespace Core.Utilities.Models;

public record AppSettings (
OpenAI OpenAI,
StockService StockService
StockService StockService,
BingSearchService BingSearchService
);

public record OpenAI (
Expand All @@ -15,4 +16,8 @@ string ApiKey

public record StockService (
string ApiKey
);

public record BingSearchService (
string ApiKey
);
1 change: 0 additions & 1 deletion workshop/dotnet/Core.Utilities/Plugins/StockDataPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Core.Utilities.Services;
using Core.Utilities.Models;
using Core.Utilities.Extensions;

using Microsoft.SemanticKernel;
Expand Down
2 changes: 1 addition & 1 deletion workshop/dotnet/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>SKEXP0110;SKEXP0001;SKEXP0101</NoWarn>
<NoWarn>SKEXP0110;SKEXP0001;SKEXP0101;SKEXP0050</NoWarn>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

Expand Down
1 change: 1 addition & 0 deletions workshop/dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.32.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Agents.Core" Version="1.19.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Plugins.Web" Version="1.32.0-alpha" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.8.1" />
<PackageVersion Include="xunit" Version="2.4.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.3" />
Expand Down
8 changes: 8 additions & 0 deletions workshop/dotnet/Lessons/Lesson4/Lesson4.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
74 changes: 74 additions & 0 deletions workshop/dotnet/Lessons/Lesson4/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Core.Utilities.Config;
// Add import for Plugins
using Core.Utilities.Plugins;
// Add import required for StockService
using Core.Utilities.Services;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
// TODO: Step 1 - Add imports for Bing Search plugin

// Add ChatCompletion import
using Microsoft.SemanticKernel.ChatCompletion;
// Temporarily added to enable Semantic Kernel tracing
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;


// Initialize the kernel with chat completion
IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion();
// Enable tracing
//builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace));
Kernel kernel = builder.Build();

// Initialize Time plugin and registration in the kernel
kernel.Plugins.AddFromObject(new TimeInformationPlugin());

// Initialize Stock Data Plugin and register it in the kernel
HttpClient httpClient = new();
StockDataPlugin stockDataPlugin = new(new StocksService(httpClient));
kernel.Plugins.AddFromObject(stockDataPlugin);

// TODO: Step 2 - Initialize Bing Search plugin


// Get chatCompletionService and initialize chatHistory with system prompt
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone");
// Remove the promptExecutionSettings and kernelArgs initialization code
// Add system prompt
OpenAIPromptExecutionSettings promptExecutionSettings = new()
{
// Add Auto invoke kernel functions as the tool call behavior
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};

// Initialize kernel arguments
KernelArguments kernelArgs = new(promptExecutionSettings);

// Execute program.
const string terminationPhrase = "quit";
string? userInput;
do
{
Console.Write("User > ");
userInput = Console.ReadLine();

if (userInput != null && userInput != terminationPhrase)
{
Console.Write("Assistant > ");
// Initialize fullMessage variable and add user input to chat history
string fullMessage = "";
chatHistory.AddUserMessage(userInput);

// Step 4 - Provide promptExecutionSettings and kernel arguments
await foreach (var chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory, promptExecutionSettings, kernel))
{
Console.Write(chatUpdate.Content);
fullMessage += chatUpdate.Content ?? "";
}
chatHistory.AddAssistantMessage(fullMessage);

Console.WriteLine();
}
}
while (userInput != terminationPhrase);
8 changes: 8 additions & 0 deletions workshop/dotnet/Solutions/Lesson4/Lesson4.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Loading

0 comments on commit bbe554e

Please sign in to comment.