chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Data.Entity;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace StructuredDataPlugin;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a database context for the structured data plugin demo.
|
||||
/// Inherits from Entity Framework's DbContext to provide database access and management.
|
||||
/// </summary>
|
||||
internal sealed class ApplicationDbContext : DbContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApplicationDbContext"/> class using configuration settings.
|
||||
/// </summary>
|
||||
/// <param name="config">The configuration object containing connection string information.</param>
|
||||
/// <remarks>
|
||||
/// The connection string is retrieved from the configuration using the pattern "ConnectionStrings:ApplicationDbContext".
|
||||
/// </remarks>
|
||||
public ApplicationDbContext(IConfiguration config) :
|
||||
base(config[$"ConnectionStrings:{nameof(ApplicationDbContext)}"]!)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApplicationDbContext"/> class using a direct connection string.
|
||||
/// </summary>
|
||||
/// <param name="connectionString">The connection string to the database.</param>
|
||||
public ApplicationDbContext(string connectionString)
|
||||
: base(connectionString)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the database model and its relationships.
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder">The builder being used to construct the model for this context.</param>
|
||||
/// <remarks>
|
||||
/// This method:
|
||||
/// - Disables database initialization
|
||||
/// - Maps the Product entity to the "Products" table
|
||||
/// - Calls the base configuration
|
||||
/// </remarks>
|
||||
protected override void OnModelCreating(DbModelBuilder modelBuilder)
|
||||
{
|
||||
Database.SetInitializer<ApplicationDbContext>(null);
|
||||
modelBuilder.Entity<Product>().ToTable("Products");
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace StructuredDataPlugin;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a product entity in the database.
|
||||
/// </summary>
|
||||
public sealed class Product
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique identifier for the product.
|
||||
/// </summary>
|
||||
[Description("The unique identifier for the product.")]
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of the product.
|
||||
/// </summary>
|
||||
[Description("The name of the product.")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The price of the product.
|
||||
/// </summary>
|
||||
[Description("The price of the product in USD.")]
|
||||
public decimal? Price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date the product was created.
|
||||
/// </summary>
|
||||
[Description("The date the product was created")]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
|
||||
public DateTime? DateCreated { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
|
||||
namespace StructuredDataPlugin;
|
||||
|
||||
internal sealed class Program
|
||||
{
|
||||
internal static async Task Main(string[] args)
|
||||
{
|
||||
var serviceCollection = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>((sp) => new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json", optional: true)
|
||||
.AddEnvironmentVariables()
|
||||
.AddUserSecrets<Program>()
|
||||
.Build())
|
||||
.AddTransient<ApplicationDbContext>()
|
||||
.AddTransient<StructuredDataService<ApplicationDbContext>>();
|
||||
|
||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
var config = serviceProvider.GetRequiredService<IConfiguration>();
|
||||
using var structuredDataService = serviceProvider.GetRequiredService<StructuredDataService<ApplicationDbContext>>();
|
||||
|
||||
// Create kernel builder and add OpenAI
|
||||
var kernelBuilder = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: "gpt-4o",
|
||||
apiKey: config["OpenAI:ApiKey"]!);
|
||||
|
||||
// Add the database plugin using the factory with default operations
|
||||
var databasePlugin = StructuredDataPluginFactory.CreateStructuredDataPlugin<ApplicationDbContext, Product>(
|
||||
structuredDataService);
|
||||
|
||||
kernelBuilder.Plugins.Add(databasePlugin);
|
||||
|
||||
// Build the kernel and add the plugin
|
||||
var kernel = kernelBuilder.Build();
|
||||
|
||||
// Create settings for function calling
|
||||
var settings = new OpenAIPromptExecutionSettings
|
||||
{
|
||||
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
|
||||
};
|
||||
|
||||
// Example 1: Inserting new records
|
||||
Console.WriteLine("Creating a new record...");
|
||||
var insertPrompt = "Insert a new product with name 'Book' and price 29.99";
|
||||
var insertResult = await kernel.InvokePromptAsync(insertPrompt, new(settings));
|
||||
Console.WriteLine($"Insert Result: {insertResult}");
|
||||
|
||||
// Example 2: Querying data
|
||||
Console.WriteLine("\nQuerying specific records...");
|
||||
var queryPrompt = "Find all products under $50";
|
||||
var queryResult = await kernel.InvokePromptAsync(queryPrompt, new(settings));
|
||||
Console.WriteLine($"Query Result: {queryResult}");
|
||||
|
||||
// Example 3: Updating records
|
||||
Console.WriteLine("\nUpdating a record...");
|
||||
var updatePrompt = "Update the price of 'Book' to 39.99 and keep its name";
|
||||
var updateResult = await kernel.InvokePromptAsync(updatePrompt, new(settings));
|
||||
Console.WriteLine($"Update Result: {updateResult}");
|
||||
|
||||
// Example 3: Updating records
|
||||
Console.WriteLine("\nDeleting a record...");
|
||||
var deletePrompt = "Delete the product 'Book'";
|
||||
var deleteResult = await kernel.InvokePromptAsync(deletePrompt, new(settings));
|
||||
Console.WriteLine($"Delete Result: {deleteResult}");
|
||||
|
||||
// Example 4: Interactive chat-like interaction
|
||||
Console.WriteLine("\nStarting interactive mode (type 'exit' to quit)");
|
||||
Console.WriteLine("You can try queries like:");
|
||||
Console.WriteLine("- Find all products under $50");
|
||||
Console.WriteLine("- Insert a new product with name 'Table' and price 19.99");
|
||||
Console.WriteLine("- Update the price of 'Table' to 25.99");
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.Write("\nEnter your database query: ");
|
||||
var userInput = Console.ReadLine();
|
||||
|
||||
if (string.IsNullOrEmpty(userInput) || userInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var result = await kernel.InvokePromptAsync(userInput, new(settings));
|
||||
Console.WriteLine($"\nResult: {result}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
# Structured Data Plugin - Demo Application
|
||||
|
||||
This sample demonstrates how to use the Semantic Kernel's Structured Data Plugin to interact with relational databases through Entity Framework Core. The demo shows how to perform database operations using natural language queries, which are translated into appropriate database commands.
|
||||
|
||||
## Semantic Kernel Features Used
|
||||
|
||||
- Structured Data Plugin - Enables natural language interactions with databases
|
||||
- Entity Framework 6 Integration - Provides database access layer
|
||||
- OpenAI Function Calling - Used to parse natural language into structured database operations
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- OpenAI API key
|
||||
- Function Calling enabled model (e.g., gpt-4o)
|
||||
- Relational database (e.g., SQL Server)
|
||||
- .NET 10.0 or higher
|
||||
|
||||
## Database Setup
|
||||
|
||||
1. Create the Products table in your database:
|
||||
|
||||
```sql
|
||||
-- SQL Server example
|
||||
CREATE TABLE Products (
|
||||
Id uniqueidentifier DEFAULT newsequentialid() NOT NULL,
|
||||
Name nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
Price decimal(18,2) NOT NULL,
|
||||
DateCreated datetime DEFAULT getdate() NOT NULL,
|
||||
CONSTRAINT Products_PK PRIMARY KEY (Id)
|
||||
);
|
||||
```
|
||||
|
||||
## Key Components
|
||||
|
||||
### Product Entity
|
||||
|
||||
The demo uses a `Product` entity as an example of structured data. This entity represents items in a database table named "Test1".
|
||||
|
||||
### ApplicationDbContext
|
||||
|
||||
`ApplicationDbContext` is an Entity Framework Core database context that:
|
||||
|
||||
- Inherits from `DbContext`
|
||||
- Configures database connection using either:
|
||||
- Configuration string from IConfiguration
|
||||
- Direct connection string
|
||||
- Disables database initialization
|
||||
- Maps the `Product` entity to the "Test1" table
|
||||
|
||||
### Connection String Setup
|
||||
|
||||
You can configure the connection string using one of these methods:
|
||||
|
||||
1. Using appsettings.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"ApplicationDbContext": "your_connection_string"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Using appsettings.Development.json (for development environment):
|
||||
|
||||
```json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"ApplicationDbContext": "your_connection_string"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Using user secrets (recommended for development):
|
||||
|
||||
```bash
|
||||
dotnet user-secrets set "ConnectionStrings:ApplicationDbContext" "your_connection_string"
|
||||
```
|
||||
|
||||
4. Using environment variables:
|
||||
|
||||
```bash
|
||||
set ConnectionStrings__ApplicationDbContext="your_connection_string"
|
||||
```
|
||||
|
||||
The application uses the following configuration hierarchy (highest to lowest priority):
|
||||
|
||||
1. User Secrets
|
||||
2. Environment Variables
|
||||
3. appsettings.json
|
||||
|
||||
## Usage Examples
|
||||
|
||||
The demo showcases various database operations using natural language:
|
||||
|
||||
1. Inserting new records:
|
||||
|
||||
```csharp
|
||||
var result = await kernel.InvokeAsync("Insert a new product with name 'Sample Product' and price 29.99");
|
||||
```
|
||||
|
||||
2. Querying data:
|
||||
|
||||
```csharp
|
||||
var result = await kernel.InvokeAsync("Find all products under $50");
|
||||
```
|
||||
|
||||
3. Updating records:
|
||||
|
||||
```csharp
|
||||
var result = await kernel.InvokeAsync("Update the price of 'Sample Product' to 39.99");
|
||||
```
|
||||
|
||||
4. Deleting records:
|
||||
|
||||
```csharp
|
||||
var result = await kernel.InvokeAsync("Delete the product named 'Sample Product'");
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The plugin uses OpenAI's function calling feature to parse natural language into structured database operations
|
||||
- Database operations are performed through Entity Framework Core
|
||||
- The demo includes proper error handling and transaction management
|
||||
- Connection strings should be secured and not committed to source control
|
||||
- For production environments, consider using Azure Key Vault or similar secure configuration storage
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Entity Framework Core Documentation](https://learn.microsoft.com/en-us/ef/core/)
|
||||
- [Semantic Kernel Documentation](https://learn.microsoft.com/en-us/semantic-kernel/overview/)
|
||||
- [OpenAI Function Calling](https://platform.openai.com/docs/guides/function-calling)
|
||||
- [Safe Storage of App Secrets in Development](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets)
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<NoWarn>$(NoWarn),VSTHRD111,CA2007,CA5399,SKEXP0050</NoWarn>
|
||||
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Connectors\Connectors.OpenAI\Connectors.OpenAI.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Plugins\Plugins.StructuredData.EntityFramework\Plugins.StructuredData.EntityFramework.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"ApplicationDbContext": "your-connection-string-here"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user