Skip to content

Commit 01eea85

Browse files
Get Azure Functions working end-to-end
1 parent d8ac209 commit 01eea85

16 files changed

+262
-38
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"recommendations": [
33
"ms-azuretools.vscode-azurefunctions",
4-
"ms-dotnettools.csharp"
4+
"ms-dotnettools.csharp",
5+
"ms-semantic-kernel.semantic-kernel"
56
]
67
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Attach to .NET Functions",
6+
"type": "coreclr",
7+
"request": "attach",
8+
"processId": "${command:azureFunctions.pickProcess}"
9+
}
10+
]
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"azureFunctions.deploySubpath": "bin/Release/net6.0/publish",
3+
"azureFunctions.projectLanguage": "C#",
4+
"azureFunctions.projectRuntime": "~4",
5+
"debug.internalConsoleOptions": "neverOpen",
6+
"azureFunctions.preDeployTask": "publish (functions)"
7+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "clean (functions)",
6+
"command": "dotnet",
7+
"args": [
8+
"clean",
9+
"/property:GenerateFullPaths=true",
10+
"/consoleloggerparameters:NoSummary"
11+
],
12+
"type": "process",
13+
"problemMatcher": "$msCompile"
14+
},
15+
{
16+
"label": "build (functions)",
17+
"command": "dotnet",
18+
"args": [
19+
"build",
20+
"/property:GenerateFullPaths=true",
21+
"/consoleloggerparameters:NoSummary"
22+
],
23+
"type": "process",
24+
"dependsOn": "clean (functions)",
25+
"group": {
26+
"kind": "build",
27+
"isDefault": true
28+
},
29+
"problemMatcher": "$msCompile"
30+
},
31+
{
32+
"label": "clean release (functions)",
33+
"command": "dotnet",
34+
"args": [
35+
"clean",
36+
"--configuration",
37+
"Release",
38+
"/property:GenerateFullPaths=true",
39+
"/consoleloggerparameters:NoSummary"
40+
],
41+
"type": "process",
42+
"problemMatcher": "$msCompile"
43+
},
44+
{
45+
"label": "publish (functions)",
46+
"command": "dotnet",
47+
"args": [
48+
"publish",
49+
"--configuration",
50+
"Release",
51+
"/property:GenerateFullPaths=true",
52+
"/consoleloggerparameters:NoSummary"
53+
],
54+
"type": "process",
55+
"dependsOn": "clean release (functions)",
56+
"problemMatcher": "$msCompile"
57+
},
58+
{
59+
"type": "func",
60+
"dependsOn": "build (functions)",
61+
"options": {
62+
"cwd": "${workspaceFolder}/bin/Debug/net6.0"
63+
},
64+
"command": "host start",
65+
"isBackground": true,
66+
"problemMatcher": "$func-dotnet-watch"
67+
},
68+
{
69+
"label": "build",
70+
"command": "dotnet",
71+
"type": "process",
72+
"args": [
73+
"build",
74+
"${workspaceFolder}/sk-csharp-azure-functions.csproj",
75+
"/property:GenerateFullPaths=true",
76+
"/consoleloggerparameters:NoSummary"
77+
],
78+
"problemMatcher": "$msCompile"
79+
},
80+
{
81+
"label": "publish",
82+
"command": "dotnet",
83+
"type": "process",
84+
"args": [
85+
"publish",
86+
"${workspaceFolder}/sk-csharp-azure-functions.csproj",
87+
"/property:GenerateFullPaths=true",
88+
"/consoleloggerparameters:NoSummary"
89+
],
90+
"problemMatcher": "$msCompile"
91+
},
92+
{
93+
"label": "watch",
94+
"command": "dotnet",
95+
"type": "process",
96+
"args": [
97+
"watch",
98+
"run",
99+
"--project",
100+
"${workspaceFolder}/sk-csharp-azure-functions.csproj"
101+
],
102+
"problemMatcher": "$msCompile"
103+
}
104+
]
105+
}

sk-csharp-azure-functions/Config/KernelSettings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Microsoft.Extensions.Configuration;
55
using Microsoft.Extensions.Logging;
66

7+
#pragma warning disable CA1812
78
internal class KernelSettings
89
{
910
public const string DefaultConfigFile = "config/appsettings.json";

sk-csharp-azure-functions/Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<LangVersion>11</LangVersion>
1010
<Nullable>enable</Nullable>
1111
<ImplicitUsings>disable</ImplicitUsings>
12+
<NoWarn>CS1591,CA1852,CA1050</NoWarn>
1213
</PropertyGroup>
1314

1415
<PropertyGroup>

sk-csharp-azure-functions/ExecuteFunctionEndpoint.cs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22

33
using System.Net;
44
using System.Text.Json;
5-
using System.Linq;
65
using Microsoft.Azure.Functions.Worker.Http;
76
using Microsoft.Azure.Functions.Worker;
87
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
98
using Microsoft.SemanticKernel;
109
using Microsoft.SemanticKernel.Orchestration;
1110
using Microsoft.SemanticKernel.KernelExtensions;
1211
using Models;
13-
using Tavis.UriTemplates;
1412

1513
public class ExecuteFunctionEndpoint
1614
{
@@ -31,26 +29,42 @@ public ExecuteFunctionEndpoint(IKernel kernel)
3129
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ExecuteFunctionResponse), Description = "Includes the AI response")]
3230
public async Task<HttpResponseData> ExecuteFunctionAsync(
3331
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "skills/{skillName}/functions/{functionName}")]
34-
HttpRequestData req,
32+
HttpRequestData requestData,
3533
FunctionContext executionContext, string skillName, string functionName)
3634
{
37-
var funcReq = await JsonSerializer.DeserializeAsync<ExecuteFunctionRequest>(req.Body, s_jsonOptions).ConfigureAwait(false);
35+
#pragma warning disable CA1062
36+
var functionRequest = await JsonSerializer.DeserializeAsync<ExecuteFunctionRequest>(requestData.Body, s_jsonOptions).ConfigureAwait(false);
37+
#pragma warning disable CA1062
38+
if (functionRequest == null)
39+
{
40+
return await CreateResponseAsync(requestData, HttpStatusCode.BadRequest, new ErrorResponse() { Message = $"Invalid request body {functionRequest}" }).ConfigureAwait(false);
41+
}
3842

3943
// note: using skills from the repo
4044
var skillsDirectory = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "skills");
4145
var skill = _kernel.ImportSemanticSkillFromDirectory(skillsDirectory, skillName);
42-
var skfunction = skill[functionName];
46+
47+
var function = skill[functionName];
48+
if (function == null)
49+
{
50+
return await CreateResponseAsync(requestData, HttpStatusCode.NotFound, new ErrorResponse() { Message = $"Unable to load {skillName}.{functionName}" }).ConfigureAwait(false);
51+
}
4352

4453
var context = new ContextVariables();
45-
foreach (var v in funcReq.Variables)
54+
foreach (var v in functionRequest.Variables)
4655
{
4756
context.Set(v.Key, v.Value);
4857
}
4958

50-
var result = await _kernel.RunAsync(context, skfunction);
59+
var result = await _kernel.RunAsync(context, function).ConfigureAwait(false);
5160

52-
var rep = req.CreateResponse(HttpStatusCode.OK);
53-
await rep.WriteAsJsonAsync(new ExecuteFunctionResponse() { Response = result.ToString() }).ConfigureAwait(false);
54-
return rep;
61+
return await CreateResponseAsync(requestData, HttpStatusCode.OK, new ExecuteFunctionResponse() { Response = result.ToString() }).ConfigureAwait(false);
62+
}
63+
64+
private static async Task<HttpResponseData> CreateResponseAsync(HttpRequestData requestData, HttpStatusCode statusCode, object responseBody)
65+
{
66+
var responseData = requestData.CreateResponse(statusCode);
67+
await responseData.WriteAsJsonAsync(responseBody).ConfigureAwait(false);
68+
return responseData;
5569
}
5670
}

sk-csharp-azure-functions/HealthEndpoint.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

33
using System.Net;
4-
using KernelHttpServer.Model;
54
using Microsoft.Azure.Functions.Worker;
65
using Microsoft.Azure.Functions.Worker.Http;
76
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
87
using Microsoft.SemanticKernel;
9-
using Microsoft.SemanticKernel.Memory;
10-
8+
using Models;
119

1210
// This endpoint exists as a convenience for the UI to check if the function it is dependent
1311
// on is running. You won't need this endpoint in a typical app.
14-
namespace KernelHttpServer;
1512

1613
public class HealthEndpoint
1714
{
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Text.Json.Serialization;
4+
5+
namespace Models;
6+
7+
internal class ErrorResponse
8+
{
9+
[JsonPropertyName("message")]
10+
public string Message { get; set; } = string.Empty;
11+
}

sk-csharp-azure-functions/Models/ExecuteFunctionRequest.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Copyright (c) Microsoft. All rights reserved.
2+
23
using System.Text.Json.Serialization;
34

45
namespace Models;
56

7+
#pragma warning disable CA1812
68
internal class ExecuteFunctionRequest
79
{
810
[JsonPropertyName("variables")]
@@ -16,9 +18,4 @@ internal class ExecuteFunctionVariable
1618

1719
[JsonPropertyName("value")]
1820
public string Value { get; set; } = string.Empty;
19-
20-
public Boolean AssertValid()
21-
{
22-
return true;
23-
}
2421
}

sk-csharp-azure-functions/Models/HealthResponse.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Models;
66

7-
public class HealthResponse
7+
internal class HealthResponse
88
{
99
[JsonPropertyName("message")]
1010
public string Message { get; set; } = string.Empty;

sk-csharp-azure-functions/README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,81 @@
11
# Semantic Kernel Azure Functions Starter
2+
3+
The `sk-csharp-azure-functions` Azure Functions application demonstrates how to execute a semantic function.
4+
5+
## Prerequisites
6+
7+
- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) is required to run this starter.
8+
- Install the recommended extensions
9+
- [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp)
10+
- [Semantic Kernel Tools](https://marketplace.visualstudio.com/items?itemName=ms-semantic-kernel.semantic-kernel)
11+
12+
## Configuring the starter
13+
14+
The starter can be configured in two ways:
15+
16+
1. Using .NET Secret Manager
17+
1. Using appsettings.json
18+
19+
For Debugging the console application alone, we suggest using .NET [Secret Manager](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets) to avoid the risk of leaking secrets into the repository, branches and pull requests.
20+
21+
### Using .NET [Secret Manager](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets)
22+
23+
Configure an OpenAI endpoint
24+
25+
```powershell
26+
cd sk-csharp-azure-functions
27+
dotnet user-secrets set "serviceType" "OpenAI"
28+
dotnet user-secrets set "serviceId" "text-davinci-003"
29+
dotnet user-secrets set "deploymentOrModelId" "text-davinci-003"
30+
dotnet user-secrets set "apiKey" "... your OpenAI key ..."
31+
```
32+
33+
Configure an Azure OpenAI endpoint
34+
35+
```powershell
36+
cd sk-csharp-azure-functions
37+
dotnet user-secrets set "serviceType" "AzureOpenAI"
38+
dotnet user-secrets set "serviceId" "text-davinci-003"
39+
dotnet user-secrets set "deploymentOrModelId" "text-davinci-003"
40+
dotnet user-secrets set "endpoint" "https:// ... your endpoint ... .openai.azure.com/"
41+
dotnet user-secrets set "apiKey" "... your Azure OpenAI key ..."
42+
```
43+
44+
Configure the Semantic Kernel logging level
45+
46+
```powershell
47+
dotnet user-secrets set "LogLevel" 0
48+
```
49+
50+
Log levels:
51+
52+
- 0 = Trace
53+
- 1 = Debug
54+
- 2 = Information
55+
- 3 = Warning
56+
- 4 = Error
57+
- 5 = Critical
58+
- 6 = None
59+
60+
### Using appsettings.json
61+
62+
Configure an OpenAI endpoint
63+
64+
1. Copy [settings.json.openai-example](./config/appsettings.json.openai-example) to `./config/appsettings.json`
65+
1. Edit the file to add your OpenAI endpoint configuration
66+
67+
Configure an Azure OpenAI endpoint
68+
69+
1. Copy [settings.json.azure-example](./config/appsettings.json.azure-example) to `./config/appsettings.json`
70+
1. Edit the file to add your Azure OpenAI endpoint configuration
71+
72+
## Running the starter
73+
74+
To run the Azure Functions application just hit `F5`.
75+
76+
To build and run the Azure Functions application from a terminal use the following commands:
77+
78+
```powershell
79+
dotnet build
80+
func start --csharp
81+
```

sk-csharp-hello-world/.vscode/extensions.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
{
2-
// See https://go.microsoft.com/fwlink/?LinkId=827846
3-
// for the documentation about the extensions.json format
42
"recommendations": [
53
"ms-dotnettools.csharp",
64
"ms-semantic-kernel.semantic-kernel"

0 commit comments

Comments
 (0)