Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Azure OpenAI Assistant API support for custom-copilot Python template #12153

Merged
merged 5 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/fx-core/src/question/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,12 @@ function llmServiceQuestion(): SingleSelectQuestion {
],
dynamicOptions: (inputs: Inputs) => {
const options: OptionItem[] = [];
if (inputs[QuestionNames.CustomCopilotAssistant] !== "custom-copilot-agent-assistants-api") {
// python tpl supports az oai assistant now. if other languages support az oai assistant, change the condition here.
if (
(inputs[QuestionNames.CustomCopilotAssistant] === "custom-copilot-agent-assistants-api" &&
inputs[QuestionNames.ProgrammingLanguage] === ProgrammingLanguage.PY) ||
inputs[QuestionNames.CustomCopilotAssistant] !== "custom-copilot-agent-assistants-api"
) {
options.push({
id: "llm-service-azure-openai",
label: getLocalizedString("core.createProjectQuestion.llmServiceAzureOpenAIOption.label"),
Expand Down
70 changes: 70 additions & 0 deletions packages/fx-core/tests/question/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,76 @@ describe("scaffold question", () => {
QuestionNames.AppName,
]);
});

it("AI Assistant - Assistants API Python", async () => {
const inputs: Inputs = {
platform: Platform.VSCode,
};
const questions: string[] = [];
const visitor: QuestionTreeVisitor = async (
question: Question,
ui: UserInteraction,
inputs: Inputs,
step?: number,
totalSteps?: number
) => {
questions.push(question.name);
await callFuncs(question, inputs);
if (question.name === QuestionNames.ProjectType) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);

return ok({ type: "success", result: ProjectTypeOptions.customCopilot().id });
} else if (question.name === QuestionNames.Capabilities) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
assert.isTrue(options.length === 3);
return ok({ type: "success", result: CapabilityOptions.customCopilotAssistant().id });
} else if (question.name === QuestionNames.CustomCopilotAssistant) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
assert.isTrue(options.length === 2);
return ok({
type: "success",
result: CustomCopilotAssistantOptions.assistantsApi().id,
});
} else if (question.name === QuestionNames.ProgrammingLanguage) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
assert.isTrue(options.length === 3);
return ok({ type: "success", result: "python" });
} else if (question.name === QuestionNames.LLMService) {
const select = question as SingleSelectQuestion;
const options = await select.dynamicOptions!(inputs);
assert.isTrue(options.length === 2);
return ok({ type: "success", result: "llm-service-azure-openai" });
} else if (question.name === QuestionNames.AzureOpenAIKey) {
return ok({ type: "success", result: "testKey" });
} else if (question.name === QuestionNames.AzureOpenAIEndpoint) {
return ok({ type: "success", result: "testEndppint" });
} else if (question.name === QuestionNames.AzureOpenAIDeploymentName) {
return ok({ type: "success", result: "testAzureOpenAIDeploymentName" });
} else if (question.name === QuestionNames.Folder) {
return ok({ type: "success", result: "./" });
} else if (question.name === QuestionNames.AppName) {
return ok({ type: "success", result: "test001" });
}
return ok({ type: "success", result: undefined });
};
await traverse(createProjectQuestionNode(), inputs, ui, undefined, visitor);
assert.deepEqual(questions, [
QuestionNames.ProjectType,
QuestionNames.Capabilities,
QuestionNames.CustomCopilotAssistant,
QuestionNames.ProgrammingLanguage,
QuestionNames.LLMService,
QuestionNames.AzureOpenAIKey,
QuestionNames.AzureOpenAIEndpoint,
QuestionNames.AzureOpenAIDeploymentName,
QuestionNames.Folder,
QuestionNames.AppName,
]);
});
});

describe("copilot plugin enabled", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,49 @@ It showcases how to build an AI agent in Teams capable of helping users accompli
> - [Python](https://www.python.org/), version 3.8 or higher
> - [Python extension](https://code.visualstudio.com/docs/languages/python), version v2024.0.1 or higher
> - [Teams Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) version 5.0.0 and higher or [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli)
{{#useAzureOpenAI}}
> - An account with [Azure OpenAI](https://aka.ms/oai/access).
{{/useAzureOpenAI}}
{{#useOpenAI}}
> - An account with [OpenAI](https://platform.openai.com/).
{{/useOpenAI}}
> - A [Microsoft 365 account for development](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts).

{{#useAzureOpenAI}}
> Please make sure you are using model version 0613 or newer (0613, 1106, 0125) or gpt-4 turbo or gpt-35 turbo. Lower versions do NOT support assistants.
{{/useAzureOpenAI}}

### Configurations
1. Open the command box and enter `Python: Create Environment` to create and activate your desired virtual environment. Remember to select `src/requirements.txt` as dependencies to install when creating the virtual environment.
{{#useAzureOpenAI}}
1. In file *env/.env.local.user*, fill in your Azure OpenAI key `SECRET_AZURE_OPENAI_API_KEY`, deployment name `AZURE_OPENAI_MODEL_DEPLOYMENT_NAME` and endpoint `AZURE_OPENAI_ENDPOINT`.
{{/useAzureOpenAI}}
{{#useOpenAI}}
1. In file *env/.env.local.user*, fill in your OpenAI key `SECRET_OPENAI_API_KEY`.
1. In this template, default model name is `gpt-3.5-turbo`. If you want to use a different model from OpenAI, fill in your model name in [src/config.py](./src/config.py).
{{/useOpenAI}}

### Create your own OpenAI Assistant

{{#useOpenAI}}
Before running or debugging your bot, please follow these steps to setup your own [OpenAI Assistant](https://platform.openai.com/docs/assistants/overview).
{{/useOpenAI}}
{{#useAzureOpenAI}}
Before running or debugging your bot, please follow these steps to setup your own [Azure OpenAI Assistant](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/assistant).
{{/useAzureOpenAI}}

**If you haven't setup any Assistant yet**

> This app template provides script `src/utils/creator.py` to help create assistant. You can change the instructions and settings in the script to customize the assistant.
>
{{#useOpenAI}}
> After creation, you can change and manage your assistants on [OpenAI](https://platform.openai.com/assistants).
{{/useOpenAI}}
{{#useAzureOpenAI}}
> After creation, you can change and manage your assistants on [Azure OpenAI Studio](https://oai.azure.com/).
{{/useAzureOpenAI}}

{{#useOpenAI}}
1. Run command `python src/utils/creator.py`. Remember to fill in your **OpenAI key** in *env/.env.local.user* first.
```
> python src/utils/creator.py
Expand All @@ -48,6 +73,31 @@ Before running or debugging your bot, please follow these steps to setup your ow
SECRET_OPENAI_API_KEY=<your-openai-api-key>
OPENAI_ASSISTANT_ID=<your-openai-assistant-id>
```
{{/useOpenAI}}
{{#useAzureOpenAI}}
1. Run command `python src/utils/creator.py`. Remember to fill in your **Azure OpenAI key** in *env/.env.local.user* first.
```
> python src/utils/creator.py
```
1. The above command will output something like "*Created a new assistant with an ID of: **asst_xxx...***".
1. Fill in both Azure OpenAI API Key, endpoint, deployment name and the created Assistant ID into `env/.env.local.user`.
```
SECRET_AZURE_OPENAI_API_KEY=<your-azure-openai-api-key>
AZURE_OPENAI_ENDPOINT=<your-azure-openai-endpoint>
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=<your-azure-openai-model-delopyment-name>
AZURE_OPENAI_ASSISTANT_ID=<your-azure-openai-assistant-id>
```

**If you already have an Assistant created**

1. Fill in both Azure OpenAI API Key, endpoint, deployment name and the created Assistant ID into `env/.env.local.user`.
```
SECRET_AZURE_OPENAI_API_KEY=<your-azure-openai-api-key>
AZURE_OPENAI_ENDPOINT=<your-azure-openai-endpoint>
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=<your-azure-openai-model-delopyment-name>
AZURE_OPENAI_ASSISTANT_ID=<your-azure-openai-assistant-id>
```
{{/useAzureOpenAI}}

### Conversation with bot
1. Select the Teams Toolkit icon on the left in the VS Code toolbar.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,33 @@

# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs.
SECRET_BOT_PASSWORD=
{{#useOpenAI}}
{{#openAIKey}}
SECRET_OPENAI_API_KEY='{{{openAIKey}}}'
{{/openAIKey}}
{{^openAIKey}}
SECRET_OPENAI_API_KEY=
{{/openAIKey}}
OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
{{/useOpenAI}}
{{#useAzureOpenAI}}
{{#azureOpenAIKey}}
SECRET_AZURE_OPENAI_API_KEY='{{{azureOpenAIKey}}}'
{{/azureOpenAIKey}}
{{^azureOpenAIKey}}
SECRET_AZURE_OPENAI_API_KEY=
{{/azureOpenAIKey}}
{{#azureOpenAIDeploymentName}}
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME='{{{azureOpenAIDeploymentName}}}'
{{/azureOpenAIDeploymentName}}
{{^azureOpenAIDeploymentName}}
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=
{{/azureOpenAIDeploymentName}}
{{#azureOpenAIEndpoint}}
AZURE_OPENAI_ENDPOINT='{{{azureOpenAIEndpoint}}}'
{{/azureOpenAIEndpoint}}
{{^azureOpenAIEndpoint}}
AZURE_OPENAI_ENDPOINT=
{{/azureOpenAIEndpoint}}
AZURE_OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
{{/useAzureOpenAI}}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,33 @@
# If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly
# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs.
SECRET_BOT_PASSWORD=
{{#useOpenAI}}
{{#openAIKey}}
SECRET_OPENAI_API_KEY='{{{openAIKey}}}'
{{/openAIKey}}
{{^openAIKey}}
SECRET_OPENAI_API_KEY=
{{/openAIKey}}
OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
{{/useOpenAI}}
{{#useAzureOpenAI}}
{{#azureOpenAIKey}}
SECRET_AZURE_OPENAI_API_KEY='{{{azureOpenAIKey}}}'
{{/azureOpenAIKey}}
{{^azureOpenAIKey}}
SECRET_AZURE_OPENAI_API_KEY=
{{/azureOpenAIKey}}
{{#azureOpenAIDeploymentName}}
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME='{{{azureOpenAIDeploymentName}}}'
{{/azureOpenAIDeploymentName}}
{{^azureOpenAIDeploymentName}}
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=
{{/azureOpenAIDeploymentName}}
{{#azureOpenAIEndpoint}}
AZURE_OPENAI_ENDPOINT='{{{azureOpenAIEndpoint}}}'
{{/azureOpenAIEndpoint}}
{{^azureOpenAIEndpoint}}
AZURE_OPENAI_ENDPOINT=
{{/azureOpenAIEndpoint}}
AZURE_OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
{{/useAzureOpenAI}}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,33 @@

# If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly
# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs.
{{#useOpenAI}}
{{#openAIKey}}
SECRET_OPENAI_API_KEY='{{{openAIKey}}}'
{{/openAIKey}}
{{^openAIKey}}
SECRET_OPENAI_API_KEY=
{{/openAIKey}}
OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
{{/useOpenAI}}
{{#useAzureOpenAI}}
{{#azureOpenAIKey}}
SECRET_AZURE_OPENAI_API_KEY='{{{azureOpenAIKey}}}'
{{/azureOpenAIKey}}
{{^azureOpenAIKey}}
SECRET_AZURE_OPENAI_API_KEY=
{{/azureOpenAIKey}}
{{#azureOpenAIDeploymentName}}
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME='{{{azureOpenAIDeploymentName}}}'
{{/azureOpenAIDeploymentName}}
{{^azureOpenAIDeploymentName}}
AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=
{{/azureOpenAIDeploymentName}}
{{#azureOpenAIEndpoint}}
AZURE_OPENAI_ENDPOINT='{{{azureOpenAIEndpoint}}}'
{{/azureOpenAIEndpoint}}
{{^azureOpenAIEndpoint}}
AZURE_OPENAI_ENDPOINT=
{{/azureOpenAIEndpoint}}
AZURE_OPENAI_ASSISTANT_ID= # See README.md for how to fill in this value.
{{/useAzureOpenAI}}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@ param botAadAppClientId string
@description('Required by Bot Framework package in your bot project')
param botAadAppClientSecret string

{{#useAzureOpenAI}}
@secure()
@description('Required in your bot project to access Azure OpenAI service. You can get it from Azure Portal > OpenAI > Keys > Key1 > Resource Management > Endpoint')
param azureOpenaiKey string
param azureOpenaiModelDeploymentName string
param azureOpenaiEndpoint string
{{/useAzureOpenAI}}
{{#useOpenAI}}
@secure()
@description('Required in your bot project to access OpenAI service. You can get it from OpenAI > API > API Key')
param openaiKey string
{{/useOpenAI}}
param assistantId string

param webAppSKU string
Expand Down Expand Up @@ -67,6 +76,7 @@ resource webApp 'Microsoft.Web/sites@2021-02-01' = {
name: 'BOT_PASSWORD'
value: botAadAppClientSecret
}
{{#useOpenAI}}
{
name: 'OPENAI_API_KEY'
value: openaiKey
Expand All @@ -75,6 +85,25 @@ resource webApp 'Microsoft.Web/sites@2021-02-01' = {
name: 'OPENAI_ASSISTANT_ID'
value: assistantId
}
{{/useOpenAI}}
{{#useAzureOpenAI}}
{
name: 'AZURE_OPENAI_API_KEY'
value: azureOpenaiKey
}
{
name: 'AZURE_OPENAI_MODEL_DEPLOYMENT_NAME'
value: azureOpenaiModelDeploymentName
}
{
name: 'AZURE_OPENAI_ENDPOINT'
value: azureOpenaiEndpoint
}
{
name: 'AZURE_OPENAI_ASSISTANT_ID'
value: assistantId
}
{{/useAzureOpenAI}}
]
ftpsState: 'FtpsOnly'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,28 @@
"botAadAppClientSecret": {
"value": "${{SECRET_BOT_PASSWORD}}"
},
{{#useOpenAI}}
"openaiKey": {
"value": "${{SECRET_OPENAI_API_KEY}}"
},
"assistantId": {
"value": "${{OPENAI_ASSISTANT_ID}}"
},
{{/useOpenAI}}
{{#useAzureOpenAI}}
"azureOpenaiKey": {
"value": "${{SECRET_AZURE_OPENAI_API_KEY}}"
},
"azureOpenaiModelDeploymentName" : {
"value": "${{AZURE_OPENAI_MODEL_DEPLOYMENT_NAME}}"
},
"azureOpenaiEndpoint" : {
"value": "${{AZURE_OPENAI_ENDPOINT}}"
},
"assistantId": {
"value": "${{AZURE_OPENAI_ASSISTANT_ID}}"
},
{{/useAzureOpenAI}}
"webAppSKU": {
"value": "B1"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,27 @@
from botbuilder.core import MemoryStorage, TurnContext
from teams import Application, ApplicationOptions, TeamsAdapter
from teams.ai import AIOptions
from teams.ai.planners import AssistantsPlanner, OpenAIAssistantsOptions
from teams.ai.planners import AssistantsPlanner, OpenAIAssistantsOptions, AzureOpenAIAssistantsOptions
from teams.state import TurnState

from config import Config

config = Config()

{{#useOpenAI}}
planner = AssistantsPlanner[TurnState](
OpenAIAssistantsOptions(api_key=config.OPENAI_API_KEY, assistant_id=config.OPENAI_ASSISTANT_ID)
)
{{/useOpenAI}}
{{#useAzureOpenAI}}
planner = AssistantsPlanner[TurnState](
AzureOpenAIAssistantsOptions(
api_key=config.AZURE_OPENAI_API_KEY,
endpoint=config.AZURE_OPENAI_ENDPOINT,
default_model=config.AZURE_OPENAI_MODEL_DEPLOYMENT_NAME,
assistant_id=config.AZURE_OPENAI_ASSISTANT_ID)
)
{{/useAzureOpenAI}}

# Define storage and application
storage = MemoryStorage()
Expand Down
Loading
Loading