Skip to content

Commit

Permalink
perf: add csharp ai generator template (#12428)
Browse files Browse the repository at this point in the history
* perf: add csharp ai generator template

* perf: add gitignore

* perf: rename folder

* perf: add ignore file

---------

Co-authored-by: rentu <rentu>
  • Loading branch information
SLdragon committed Sep 20, 2024
1 parent 066da54 commit 3aaafb2
Show file tree
Hide file tree
Showing 36 changed files with 1,598 additions and 0 deletions.
30 changes: 30 additions & 0 deletions templates/csharp/custom-copilot-rag-custom-api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# TeamsFx files
build
appPackage/build
env/.env.*.user
env/.env.local
appsettings.Development.json
appsettings.TestTool.json
.deployment

# User-specific files
*.user

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Notification local store
.notification.localstore.json
.notification.testtoolstore.json

# devTools
devTools/
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Overview of the Chat With Your Data (Using Custom API) template

This template showcases how to build an AI-powered intelligent chatbot that can understand natural language to invoke the API defined in the OpenAPI description document, so you can enable your users to chat with the data provided through API service.
The app template is built using the Teams AI library, which provides the capabilities to build AI-based Teams applications.
## Get started with the template

> **Prerequisites**
>
> To run the template in your local dev machine, you will need:
>
{{#useOpenAI}}
> - an account with [OpenAI](https://platform.openai.com).
{{/useOpenAI}}
{{#useAzureOpenAI}}
> - [Azure OpenAI](https://aka.ms/oai/access) resource
{{/useAzureOpenAI}}

### Debug bot app in Teams App Test Tool
{{#useOpenAI}}
1. Ensure your OpenAI API Key is filled in `appsettings.TestTool.json`.
```
"OpenAI": {
"ApiKey": "<your-openai-api-key>"
}
```
{{/useOpenAI}}
{{#useAzureOpenAI}}
1. Ensure your Azure OpenAI settings are filled in `appsettings.TestTool.json`.
```
"Azure": {
"OpenAIApiKey": "<your-azure-openai-api-key>",
"OpenAIEndpoint": "<your-azure-openai-endpoint>",
"OpenAIDeploymentName": "<your-azure-openai-deployment-name>"
}
```
{{/useAzureOpenAI}}
1. Select `Teams App Test Tool (browser)` in debug dropdown menu.
1. Press F5, or select the Debug > Start Debugging menu in Visual Studio.
1. In Teams App Test Tool from the launched browser, type and send anything to your bot to trigger a response.

**Congratulations**! You are running an application that can now interact with users in Teams App Test Tool:

![custom api template](https://github.com/OfficeDev/TeamsFx/assets/63089166/81f985a1-b81d-4c27-a82a-73a9b65ece1f)

### Debug bot app in Teams Web Client

{{#useOpenAI}}
1. Ensure your OpenAI API Key is filled in `env/.env.local.user`.
```
SECRET_OPENAI_API_KEY="<your-openai-api-key>"
```
{{/useOpenAI}}
{{#useAzureOpenAI}}
1. Ensure your Azure OpenAI settings are filled in `env/.env.local.user`.
```
SECRET_AZURE_OPENAI_API_KEY="<your-azure-openai-api-key>"
AZURE_OPENAI_ENDPOINT="<your-azure-openai-endpoint>"
AZURE_OPENAI_DEPLOYMENT_NAME="<your-azure-openai-deployment-name>"
```
{{/useAzureOpenAI}}
1. In the debug dropdown menu, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel.
1. Right-click your project and select Teams Toolkit > Prepare Teams App Dependencies.
1. If prompted, sign in with a Microsoft 365 account for the Teams organization you want to install the app to.
1. Press F5, or select the Debug > Start Debugging menu in Visual Studio.
1. In the launched browser, select the Add button to load the app in Teams.
1. In the chat bar, type and send anything to your bot to trigger a response.

> For local debugging using Teams Toolkit CLI, you need to do some extra steps described in [Set up your Teams Toolkit CLI for local debugging](https://aka.ms/teamsfx-cli-debugging).

## Extend the template

- Follow [Build a Basic AI Chatbot in Teams](https://aka.ms/teamsfx-basic-ai-chatbot) to extend the template with more AI capabilities.
- Understand more about [build your own data ingestion](https://aka.ms/teamsfx-rag-bot#build-your-own-data-ingestion).

## Additional information and references

- [Teams Toolkit Documentations](https://docs.microsoft.com/microsoftteams/platform/toolkit/teams-toolkit-fundamentals)
- [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli)
- [Teams Toolkit Samples](https://github.com/OfficeDev/TeamsFx-Samples)

## Report an issue

Select Visual Studio > Help > Send Feedback > Report a Problem.
Or, you can create an issue directly in our GitHub repository:
https://github.com/OfficeDev/TeamsFx/issues.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"profiles": {
{{#enableTestToolByDefault}}
// Launch project within Teams App Test Tool
"Teams App Test Tool (browser)": {
"commandName": "Project",
"launchTestTool": true,
"launchUrl": "http://localhost:56150",
},
{{/enableTestToolByDefault}}
// Launch project within Teams
"Microsoft Teams (browser)": {
"commandName": "Project",
"launchUrl": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}",
},
{{^enableTestToolByDefault}}
// Launch project within Teams App Test Tool
"Teams App Test Tool (browser)": {
"commandName": "Project",
"launchTestTool": true,
"launchUrl": "http://localhost:56150",
},
{{/enableTestToolByDefault}}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" Sdk="Microsoft.TeamsFx.Sdk">
<ItemGroup>
<ProjectCapability Include="ProjectConfigurationsDeclaredDimensions" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup>
{{#enableTestToolByDefault}}
<ActiveDebugProfile>Teams App Test Tool (browser)</ActiveDebugProfile>
{{/enableTestToolByDefault}}
{{^enableTestToolByDefault}}
<ActiveDebugProfile>Microsoft Teams (browser)</ActiveDebugProfile>
{{/enableTestToolByDefault}}
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
[
{{#enableTestToolByDefault}}
{
"Name": "Teams App Test Tool (browser)",
"Projects": [
{
"Path": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}",
"Name": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}",
"Action": "StartWithoutDebugging",
"DebugTarget": "Teams App Test Tool (browser)"
},
{
{{#PlaceProjectFileInSolutionDir}}
"Path": "{{ProjectName}}.csproj",
"Name": "{{ProjectName}}.csproj",
{{/PlaceProjectFileInSolutionDir}}
{{^PlaceProjectFileInSolutionDir}}
"Path": "{{ProjectName}}\\{{ProjectName}}.csproj",
"Name": "{{ProjectName}}\\{{ProjectName}}.csproj",
{{/PlaceProjectFileInSolutionDir}}
"Action": "Start",
"DebugTarget": "Teams App Test Tool"
}
]
},
{{/enableTestToolByDefault}}
{
"Name": "Microsoft Teams (browser)",
"Projects": [
{
"Path": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}",
"Name": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}",
"Action": "StartWithoutDebugging",
"DebugTarget": "Microsoft Teams (browser)"
},
{
{{#PlaceProjectFileInSolutionDir}}
"Path": "{{ProjectName}}.csproj",
"Name": "{{ProjectName}}.csproj",
{{/PlaceProjectFileInSolutionDir}}
{{^PlaceProjectFileInSolutionDir}}
"Path": "{{ProjectName}}\\{{ProjectName}}.csproj",
"Name": "{{ProjectName}}\\{{ProjectName}}.csproj",
{{/PlaceProjectFileInSolutionDir}}
"Action": "Start",
"DebugTarget": "Start Project"
}
]
{{#enableTestToolByDefault}}
}
{{/enableTestToolByDefault}}
{{^enableTestToolByDefault}}
},
{
"Name": "Teams App Test Tool (browser)",
"Projects": [
{
"Path": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}",
"Name": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}",
"Action": "StartWithoutDebugging",
"DebugTarget": "Teams App Test Tool (browser)"
},
{
{{#PlaceProjectFileInSolutionDir}}
"Path": "{{ProjectName}}.csproj",
"Name": "{{ProjectName}}.csproj",
{{/PlaceProjectFileInSolutionDir}}
{{^PlaceProjectFileInSolutionDir}}
"Path": "{{ProjectName}}\\{{ProjectName}}.csproj",
"Name": "{{ProjectName}}\\{{ProjectName}}.csproj",
{{/PlaceProjectFileInSolutionDir}}
"Action": "Start",
"DebugTarget": "Teams App Test Tool"
}
]
}
{{/enableTestToolByDefault}}
]
63 changes: 63 additions & 0 deletions templates/csharp/custom-copilot-rag-custom-api/APIActions.cs.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using AdaptiveCards.Templating;
using AdaptiveCards;
using Microsoft.Bot.Builder;
using Microsoft.Teams.AI.AI.Action;
using Microsoft.Teams.AI.AI;
using Microsoft.Teams.AI.State;
using Newtonsoft.Json.Linq;
using Microsoft.Bot.Schema;
using RestSharp;
using OpenAPIClient;

namespace {{SafeProjectName}}
{
public class APIActions
{
private APIClient Client;
public APIActions(string specPath)
{
Client = new APIClient(specPath);
}

private static IMessageActivity RenderCardToMessage(string cardTemplatePath, string data)
{
try
{
var templateString = File.ReadAllText(cardTemplatePath);
AdaptiveCardTemplate template = new AdaptiveCardTemplate(templateString);
var cardBody = template.Expand(data);
Attachment attachment = new Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = JObject.Parse(cardBody)
};

return MessageFactory.Attachment(attachment);
}
catch (Exception ex) {
throw new Exception("Failed to render adaptive card: " + ex.Message);
}
}

private static RequestParams ParseRequestParams(Dictionary<string, object> args)
{
RequestParams requestParam = new RequestParams
{
PathObject = args.ContainsKey("path") ? args["path"] : null,
HeaderObject = args.ContainsKey("header") ? args["header"] : null,
QueryObject = args.ContainsKey("query") ? args["query"] : null,
RequestBody = args.ContainsKey("requestBody") ? args["requestBody"] : null
};
return requestParam;
}

[Action(AIConstants.UnknownActionName)]
public async Task<string> UnknownAction([ActionTurnContext] TurnContext turnContext, [ActionName] string action)
{
await turnContext.SendActivityAsync(MessageFactory.Text("[lights off]"));
return "unknown action";
}
}
}
14 changes: 14 additions & 0 deletions templates/csharp/custom-copilot-rag-custom-api/APIBot.cs.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.Teams.AI.State;
using Microsoft.Teams.AI;

namespace {{SafeProjectName}}
{
public class APIBot : Application<TurnState>
{
public APIBot(ApplicationOptions<TurnState> options, string specPath) : base(options)
{
// Registering action handlers that will be hooked up to the planner.
AI.ImportActions(new APIActions(specPath));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.TraceExtensions;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;

namespace {{SafeProjectName}}
{
public class AdapterWithErrorHandler : CloudAdapter
{
public AdapterWithErrorHandler(BotFrameworkAuthentication auth, ILogger<CloudAdapter> logger)
: base(auth, logger)
{
OnTurnError = async (turnContext, exception) =>
{
// Log any leaked exception from the application.
// NOTE: In production environment, you should consider logging this to
// Azure Application Insights. Visit https://aka.ms/bottelemetry to see how
// to add telemetry capture to your bot.
logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
// Only send error message for user messages, not for other message types so the bot doesn't spam a channel or chat.
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// Send a message to the user
await turnContext.SendActivityAsync($"The bot encountered an unhandled error: {exception.Message}");
await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code.");
// Send a trace activity
await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError");
}
};
}
}
}
Loading

0 comments on commit 3aaafb2

Please sign in to comment.