├── .DS_Store
├── 01-intro-genai
├── README.md
└── sample
│ └── README.md
├── 02-clippy
├── README.md
└── sample
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
│ ├── .webappignore
│ ├── README.md
│ ├── appPackage
│ ├── color.png
│ ├── manifest.json
│ └── outline.png
│ ├── env
│ ├── .env.dev
│ ├── .env.local.sample
│ ├── .env.local.user.sample
│ └── .env.testtool
│ ├── infra
│ ├── azure.bicep
│ ├── azure.parameters.json
│ └── botRegistration
│ │ ├── azurebot.bicep
│ │ └── readme.md
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── adapter.ts
│ ├── app
│ │ └── app.ts
│ ├── config.ts
│ ├── index.ts
│ └── prompts
│ │ └── chat
│ │ ├── config.json
│ │ └── skprompt.txt
│ ├── teamsapp.local.yml
│ ├── teamsapp.testtool.yml
│ ├── teamsapp.yml
│ ├── tsconfig.json
│ └── web.config
├── 03-assistants-api
├── README.md
└── sample
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
│ ├── .webappignore
│ ├── README.md
│ ├── appPackage
│ ├── color.png
│ ├── manifest.json
│ └── outline.png
│ ├── env
│ ├── .env.dev
│ └── .env.testtool
│ ├── infra
│ ├── azure.bicep
│ ├── azure.parameters.json
│ └── botRegistration
│ │ ├── azurebot.bicep
│ │ └── readme.md
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── app.ts
│ ├── config.ts
│ ├── creator.ts
│ └── index.ts
│ ├── teamsapp.local.yml
│ ├── teamsapp.testtool.yml
│ ├── teamsapp.yml
│ ├── tsconfig.json
│ └── web.config
├── 04-rag
├── README.md
└── sample
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
│ ├── .webappignore
│ ├── README.md
│ ├── appPackage
│ ├── color.png
│ ├── manifest.json
│ └── outline.png
│ ├── env
│ ├── .env.dev
│ ├── .env.testtool.sample
│ └── .env.testtool.user.sample
│ ├── infra
│ ├── azure.bicep
│ ├── azure.parameters.json
│ └── botRegistration
│ │ ├── azurebot.bicep
│ │ └── readme.md
│ ├── src
│ ├── app.py
│ ├── azure_ai_search_data_source.py
│ ├── bot.py
│ ├── config.py
│ ├── indexers
│ │ ├── data
│ │ │ ├── Earth.pdf
│ │ │ ├── Interplanetary_spaceflight.pdf
│ │ │ ├── Jupiter.pdf
│ │ │ ├── Mars.pdf
│ │ │ ├── Mercury.pdf
│ │ │ ├── Neptune.pdf
│ │ │ ├── Pluto.pdf
│ │ │ ├── Saturn.pdf
│ │ │ ├── Star.pdf
│ │ │ ├── Uranus.pdf
│ │ │ └── Venus.pdf
│ │ ├── delete.py
│ │ ├── get_data.py
│ │ └── setup.py
│ ├── prompts
│ │ └── chat
│ │ │ ├── config.json
│ │ │ └── skprompt.txt
│ └── requirements.txt
│ ├── teamsapp.local.yml
│ ├── teamsapp.testtool.yml
│ └── teamsapp.yml
├── 05-on-your-data
├── README.md
└── sample
│ ├── .eslintignore
│ ├── .eslintrc
│ ├── .gitignore
│ ├── .prettierignore
│ ├── .prettierrc
│ ├── .vscode
│ ├── launch.json
│ └── tasks.json
│ ├── .webappignore
│ ├── README.md
│ ├── appPackage
│ ├── color.png
│ ├── manifest.json
│ └── outline.png
│ ├── assets
│ └── example.png
│ ├── data
│ ├── Second-Cup.pdf
│ ├── TimHortons-ca.pdf
│ ├── au-bon-pain.pdf
│ ├── caffe-nero.pdf
│ ├── caribou.pdf
│ ├── coffeebean-and-tea-leaf.pdf
│ ├── costa-uk.pdf
│ ├── dunkin.pdf
│ ├── gloria-jeans.pdf
│ ├── pret.pdf
│ └── starbucks.pdf
│ ├── env
│ ├── .env.dev
│ ├── .env.local.sample
│ ├── .env.local.user.sample
│ └── .env.testtool
│ ├── infra
│ ├── azure.bicep
│ ├── azure.parameters.json
│ └── botRegistration
│ │ ├── azurebot.bicep
│ │ └── readme.md
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── app.ts
│ ├── data
│ │ └── nba.pdf
│ ├── index.ts
│ └── prompts
│ │ └── chat
│ │ └── skprompt.txt
│ ├── teamsapp.local.yml
│ ├── teamsapp.testtool.yml
│ ├── teamsapp.yml
│ ├── tsconfig.json
│ └── web.config
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── LICENSE-CODE
├── README.md
├── SECURITY.md
└── images
├── aoai-on-your-data.png
├── assistants api final.gif
├── clippyforteams.png
├── coffee-cup.gif
├── doodle-assistants-api.png
├── doodle-genai.png
├── doodle-gpt.png
├── doodle-rag.png
├── doodle-teamsailib.png
├── doodle-to-code.png
├── genai-01.gif
├── genai-02.gif
├── screen-openai-playground-assistants-api.png
└── space-ai-search.gif
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/.DS_Store
--------------------------------------------------------------------------------
/01-intro-genai/README.md:
--------------------------------------------------------------------------------
1 | # Generative AI and Prompting 101
2 |
3 | In this section, you'll learn the basic concepts about Generative AI, Large Language Models, such as GPT, and prompting.
4 |
5 | ## What is Generative AI?
6 |
7 | Generative AI refers to a type of AI that can create new content by learning from existing data. It's like having a smart assistant that can write essays, create images, or compose music based on the patterns it has learned from large amounts of data. For example, if you give it a topic, it can write an article, or if you describe an image, it can generate that image for you.
8 |
9 | 
10 |
11 | ## Large Language Models
12 |
13 | LLM stands for **Large Language Model**, which is a type of artificial intelligence model that's designed to understand and generate human-like text. LLMs are trained on vast amounts of data, enabling them to perform a wide range of tasks related to natural language processing (NLP) and generation. They are known for their ability to produce coherent and contextually relevant content, translate languages, summarize text, answer questions, and even assist in creative writing or code generation tasks.
14 |
15 | Model examples:
16 |
17 | - **GPT (Generative Pre-trained Transformer):** This is a series of LLMs that have been trained on diverse datasets to perform a wide range of language-related tasks. They are designed to understand context and generate text that is coherent and contextually relevant.
18 | - **Codex:** While Codex is specialized for understanding and generating code. It has been trained on a mixture of natural language and code from publicly available sources, which allows it to translate natural language prompts into programming code.
19 | - **Dall-E:** It is a modified GPT that generates images from textual descriptions. It uses a version of GPT-3 that's been trained on both text and images, allowing it to create pictures that match the descriptions provided by users.
20 |
21 | 
22 |
23 | ## Prompting
24 |
25 | Prompting is your chat with a language model. It refers to the act of giving an AI system a specific instruction or input that guides it to generate a desired output. A good prompt is clear, specific, and structured in a way that directs the AI towards the intended goal.
26 |
27 | For example, if you're working with a language model and you want it to generate a poem, you wouldn't just say "write a poem." That’s too vague. Instead, you might say, "Write a four-line poem about the ocean at sunset." This gives the model a clear structure and topic to work with.
28 |
29 | Prompting is crucial because the quality of the output you get from an AI model is often directly related to the quality of the input you give it. Think of it as a sophisticated form of human-computer interaction where the computer understands and generates human language.
30 |
31 | ## 🚀 Try it out on your own!
32 |
33 | **Now let's [try this](sample/README.md)!**
34 |
35 | ## 📺 Watch on YouTube
36 |
37 | Watch the video, **Generative AI and prompting 101** on YouTube:
38 |
39 | [](https://youtu.be/PGI6oxbcYDc?si=9AMFTyQFS-BcgFVK)
40 |
41 | [Subscribe us!](https://www.youtube.com/channel/UCV_6HOhwxYLXAGd-JOqKPoQ?sub_confirmation=1)!
42 |
--------------------------------------------------------------------------------
/01-intro-genai/sample/README.md:
--------------------------------------------------------------------------------
1 | # Overview of the Generative AI and prompting with Azure OpenAI
2 |
3 | This sample covers the basics of Generative AI and getting started with Azure OpenAI service. In the sample, you'll also practice prompting and use pre-built templates on Azure OpenAI Studio.
4 |
5 | ## Get started with the sample
6 |
7 | >**Prerequisites**
8 | >
9 | >- An Azure subscription. [Create one for free](https://azure.microsoft.com/en-us/free/ai-services/).
10 | >- Access granted to Azure OpenAI in the desired Azure subscription.
11 | >- Access permissions to [create Azure OpenAI resources and to deploy models](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/role-based-access-control).
12 | >
13 |
14 | ### Create an Azure OpenAI service resource
15 |
16 | 1. Sign in to the [Azure portal](https://portal.azure.com).
17 | 1. Select **Create a resource** and search for **Azure OpenAI**. When you locate the service, select **Create**.
18 | 1. On the Create Azure OpenAI page, provide the following information for the fields on the **Basics** tab and select **Next**:
19 | - **Subscription:** The Azure subscription used in your Azure OpenAI Service onboarding application.
20 | - **Resource group:** The Azure resource group to contain your Azure OpenAI resource. You can create a new group or use a pre-existing group.
21 | - **Region:** The location of your instance. Different locations can introduce latency, but they don't affect the runtime availability of your resource.
22 | - **Name:** A descriptive name for your Azure OpenAI Service resource, such as MyOpenAIResource.
23 | - **Pricing Tier:** The pricing tier for the resource. Currently, only the Standard tier is available for the Azure OpenAI Service. For more info on pricing visit the Azure OpenAI pricing page.
24 | 1. Keep the **Network** tab as default and select **Next**.
25 | 1. Keep the **Tags** tab as default and select **Next**.
26 | 1. Select **Next** to move to the final stage in the process: **Review + submit**.
27 | 1. Confirm your configuration settings, and select **Create**.
28 | 1. The Azure portal displays a notification when the new resource is available. Select **Go to resource**.
29 |
30 | ### Deploy a model in Azure OpenAI
31 |
32 | Before you utilize generative AI, you need to deploy a model. You can select from one of several available models in Azure OpenAI Studio. To use text generation, you'll need to create `gpt-3.5-turbo` model or a higher version.
33 |
34 | To deploy a model, follow these steps:
35 |
36 | 1. In your Azure OpenAI resource, go to the **Overview** tab and select **Go to Azure OpenAI Studio**
37 | 1. Select **Deployments** tab and select **+ Create new deployment**. Configure the following fields, then select **Create**:
38 | - **Select a model:** Select either one of the `gpt-35-turbo`, `gpt-4`, `gpt-4-32k` or `gpt-4o`.
39 | - **Deployment name:** Choose a name carefully. The deployment name is used in your code to call the model by using the client libraries and the REST APIs.
40 | - **Deployment type:** Standard
41 | - **Advanced options (Optional):** Default
42 |
43 | ### Test your model in the Chat Playground
44 |
45 | 1. Select **Chat** tab in the Azure OpenAI Studio.
46 | 1. In the **Prompt** section, select one of the system message templates available under the **Use a system message template**, such as `XBox customer support agent`.
47 | 1. Start testing the template by asking relevant questions, such as "My XBox is showing blue screen".
48 |
49 | 
50 |
51 | 1. In **Use a system message template**, select `Empty Example`.
52 | 1. In **System message**, place the following prompt: *"You are a local tour guide who can help travelers with the best suggestions about Japan"*.
53 | 1. Select **Apply changes**, and start asking questions about traveling to Japan!
54 |
55 | 
--------------------------------------------------------------------------------
/02-clippy/README.md:
--------------------------------------------------------------------------------
1 | # Build Clippy for Teams with Azure OpenAI and Teams AI Library
2 |
3 | In this section, you'll learn about building your own chatbot that channels nostalgic feels of our old friend, Clippy by giving a specific instruction with prompting. You also learn how to use Microsoft Teams AI Library to build an AI bot for Teams!
4 |
5 |
6 | ## Traditional chatbot vs. Generative AI chatbot
7 |
8 | Traditional chatbots and Generative AI chatbots represent two different approaches to automated conversation systems. Here are the key differences:
9 |
10 | **Traditional Chatbots:**
11 |
12 | - **Rule-Based:** They operate on a set of predefined rules and responses. They can't generate new responses but select the closest possible answer from their database
13 | - **Limited Flexibility:** Because they rely on a fixed set of responses, they can struggle with queries outside their programmed knowledge base
14 | - **Specific Use Cases:** Often used in scenarios where the range of possible user queries is limited and predictable
15 |
16 | **Generative AI Chatbots:**
17 |
18 | - **Contextual Intelligence:** These chatbots use large language models to understand and generate responses, providing more engaging and personalized conversations
19 | - **Learning Capabilities:** They can improve over time by learning from interactions, which allows them to handle a wider range of topics
20 | - **Versatility:** They are not limited to predefined templates and can generate original responses, making them suitable for a broader range of applications
21 |
22 | ## Prompt engineering
23 |
24 | Prompt engineering is a fascinating aspect of working with Generative AI chatbots. It involves crafting the input prompts to the AI in a way that guides the chatbot's responses and behavior. This can be particularly useful when aiming to give a chatbot a specific character or personality, such as Microsoft's iconic Clippy.
25 |
26 | Here's how prompt engineering can shape a chatbot's character:
27 |
28 | - **Defining Personality**: By including certain phrases, styles of language, and responses in the prompt, you can influence the chatbot to exhibit traits of a particular character. For Clippy, this might include a helpful but slightly overeager tone.
29 | - **Setting Expectations**: The prompts can set the stage for how the chatbot should interact with users. For example, Clippy was known for popping up with assistance offers, so prompts could be engineered to reflect that proactive nature.
30 | - **Guiding Responses**: Through prompt engineering, you can direct the chatbot to respond in ways that are consistent with the character's known behaviors, ensuring that the chatbot stays 'in character' during interactions.
31 | - **Customizing Interactions**: You can tailor the chatbot's interactions based on the character's backstory or known attributes. Clippy, being a paperclip, might have prompts designed around office-related tasks and help.
32 |
33 | Prompt engineering is not just about the initial input but also about managing the ongoing conversation to maintain the character's persona. For Clippy, this would mean creating prompts that keep the chatbot's interactions aligned with what users would expect from the quirky paperclip assistant.
34 |
35 | ## Intro Microsoft Teams AI Library
36 |
37 | Now let's dive right into the world of AI in Microsoft Teams. You can create your very own AI chatbot right here, in Teams client.
38 |
39 | 
40 |
41 | The **Teams AI Library** is a tool designed to help you create AI-powered apps for Microsoft Teams. It provides a Teams-centric interface to GPT-based language models and user intent engines, simplifying the process of integrating conversational AI into your Teams apps.
42 |
43 | Here's how you can use it to create a Clippy-like bot:
44 |
45 | - **Leverage Prebuilt Templates:** The library offers prebuilt templates that you can use as a starting point for your bot. This allows you to focus on adding your business logic rather than dealing with the complexities of conversational AI
46 | - **Natural Language Modeling:** With GPT-powered language models, the Teams AI Library enables your bot to understand and engage in natural language conversations. You don't need to write extensive conversational logic; the library helps identify user intents and respond appropriately
47 | Since Teams AI library uses OpenAI's GPT model, localization is available.
48 | - **Prompt Engineering:** You can use prompt engineering techniques to guide the conversation and give your bot a specific character, like Clippy. This involves crafting prompts that encourage the bot to respond in a way that's consistent with Clippy's helpful and quirky personality
49 | - **Responsible AI:** The library includes built-in safety features like moderation to ensure that your bot responds appropriately in all interactions
50 | - **Planning Engine:** A planning engine within the library helps the model identify the user's intent and maps that intent to actions that you implement. This means your Clippy bot can proactively offer help and suggestions based on the user's needs
51 | - **Language Support:** The Teams AI Library is available in JavaScript and C# languages, giving you the flexibility to build in the language you're most comfortable with
52 |
53 | ## 🚀 Build Clippy Bot
54 |
55 | **Now let's [build your own Clippy bot](sample/README.md)!**
56 |
57 | ## 📺 Watch on YouTube
58 |
59 | Watch the video, **Build Clippy for Teams with Azure OpenAI and Teams AI Library** on YouTube:
60 |
61 | [](https://youtu.be/OZ6qNiuGo1Q?si=O9xg9MmmWmCJ7fwi)
62 |
63 | [Subscribe us!](https://www.youtube.com/channel/UCV_6HOhwxYLXAGd-JOqKPoQ?sub_confirmation=1)!
--------------------------------------------------------------------------------
/02-clippy/sample/.gitignore:
--------------------------------------------------------------------------------
1 | # TeamsFx files
2 | env/.env.*.user
3 | env/.env.local
4 | .localConfigs
5 | .localConfigs.testTool
6 | .localConfigs
7 | .notification.localstore.json
8 | .notification.testtoolstore.json
9 | appPackage/build
10 |
11 | # dependencies
12 | node_modules/
13 |
14 | # misc
15 | .env
16 | .deployment
17 | .DS_Store
18 |
19 | # build
20 | lib/
21 |
22 | # Dev tool directories
23 | /devTools/
--------------------------------------------------------------------------------
/02-clippy/sample/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "TeamsDevApp.ms-teams-vscode-extension"
4 | ]
5 | }
--------------------------------------------------------------------------------
/02-clippy/sample/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Launch Remote (Edge)",
6 | "type": "msedge",
7 | "request": "launch",
8 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
9 | "presentation": {
10 | "group": "3-remote",
11 | "order": 1
12 | },
13 | "internalConsoleOptions": "neverOpen"
14 | },
15 | {
16 | "name": "Launch Remote (Chrome)",
17 | "type": "chrome",
18 | "request": "launch",
19 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
20 | "presentation": {
21 | "group": "3-remote",
22 | "order": 2
23 | },
24 | "internalConsoleOptions": "neverOpen"
25 | },
26 | {
27 | "name": "Launch App (Edge)",
28 | "type": "msedge",
29 | "request": "launch",
30 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
31 | "cascadeTerminateToConfigurations": [
32 | "Attach to Local Service"
33 | ],
34 | "presentation": {
35 | "group": "all",
36 | "hidden": true
37 | },
38 | "internalConsoleOptions": "neverOpen"
39 | },
40 | {
41 | "name": "Launch App (Chrome)",
42 | "type": "chrome",
43 | "request": "launch",
44 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
45 | "cascadeTerminateToConfigurations": [
46 | "Attach to Local Service"
47 | ],
48 | "presentation": {
49 | "group": "all",
50 | "hidden": true
51 | },
52 | "internalConsoleOptions": "neverOpen"
53 | },
54 | {
55 | "name": "Attach to Local Service",
56 | "type": "node",
57 | "request": "attach",
58 | "port": 9239,
59 | "restart": true,
60 | "presentation": {
61 | "group": "all",
62 | "hidden": true
63 | },
64 | "internalConsoleOptions": "neverOpen"
65 | }
66 | ],
67 | "compounds": [
68 | {
69 | "name": "Debug in Teams (Edge)",
70 | "configurations": [
71 | "Launch App (Edge)",
72 | "Attach to Local Service"
73 | ],
74 | "preLaunchTask": "Start Teams App Locally",
75 | "presentation": {
76 | "group": "2-local",
77 | "order": 1
78 | },
79 | "stopAll": true
80 | },
81 | {
82 | "name": "Debug in Teams (Chrome)",
83 | "configurations": [
84 | "Launch App (Chrome)",
85 | "Attach to Local Service"
86 | ],
87 | "preLaunchTask": "Start Teams App Locally",
88 | "presentation": {
89 | "group": "2-local",
90 | "order": 2
91 | },
92 | "stopAll": true
93 | },
94 | {
95 | "name": "Debug in Test Tool",
96 | "configurations": [
97 | "Attach to Local Service"
98 | ],
99 | "preLaunchTask": "Start Teams App (Test Tool)",
100 | "presentation": {
101 | "group": "1-local",
102 | "order": 1
103 | },
104 | "stopAll": true
105 | }
106 | ]
107 | }
108 |
--------------------------------------------------------------------------------
/02-clippy/sample/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "debug.onTaskErrors": "abort",
3 | "json.schemas": [
4 | {
5 | "fileMatch": [
6 | "/aad.*.json"
7 | ],
8 | "schema": {}
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/02-clippy/sample/.webappignore:
--------------------------------------------------------------------------------
1 | .webappignore
2 | .fx
3 | .deployment
4 | .localConfigs.testTool
5 | .localConfigs
6 | .notification.localstore.json
7 | .notification.testtoolstore.json
8 | .vscode
9 | *.js.map
10 | *.ts.map
11 | *.ts
12 | .git*
13 | .tsbuildinfo
14 | CHANGELOG.md
15 | readme.md
16 | local.settings.json
17 | test
18 | tsconfig.json
19 | .DS_Store
20 | teamsapp.yml
21 | teamsapp.*.yml
22 | /env/
23 | /node_modules/.bin
24 | /node_modules/ts-node
25 | /node_modules/typescript
26 | /appPackage/
27 | /infra/
28 | /devTools/
--------------------------------------------------------------------------------
/02-clippy/sample/README.md:
--------------------------------------------------------------------------------
1 | # Overview of the Clippy Chatbot Sample
2 |
3 | This app template is built on top of [Teams AI library](https://aka.ms/teams-ai-library).
4 | It showcases a bot app that responds to user questions like Clippy. This enables your users to talk with the AI bot in Teams.
5 |
6 | ## Get started with the sample
7 |
8 | > **Prerequisites**
9 | >
10 | > To run the template in your local dev machine, you will need:
11 | >
12 | > - [Node.js](https://nodejs.org/), supported versions: 16, 18.
13 | > - [Teams Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) latest version or [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli).
14 | > - Prepare your own [Azure OpenAI](https://aka.ms/oai/access) resource.
15 |
16 | 1. First, select the Teams Toolkit icon on the left in the VS Code toolbar.
17 | 1. Rename, the file `env/.env.local.sample` to `env/.env.local` and `env/.env.local.user.sample` to `env/.env.local.user`. In `env/.env.local.user`, fill in your Azure OpenAI key in `SECRET_AZURE_OPENAI_API_KEY`, endpoint in `AZURE_OPENAI_ENDPOINT`, and deployment name in `AZURE_OPENAI_DEPLOYMENT_NAME`.
18 | 1. Press F5 to start debugging which launches your app in Teams using a web browser. Select `Debug in Teams`.
19 | 1. You can send any message to get a response from the bot.
20 |
21 | **Congratulations**! You are running an application that can now interact with users in Teams:
22 |
23 | 
--------------------------------------------------------------------------------
/02-clippy/sample/appPackage/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/02-clippy/sample/appPackage/color.png
--------------------------------------------------------------------------------
/02-clippy/sample/appPackage/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
3 | "manifestVersion": "1.16",
4 | "version": "1.0.0",
5 | "id": "${{TEAMS_APP_ID}}",
6 | "packageName": "com.microsoft.teams.extension",
7 | "developer": {
8 | "name": "Teams App, Inc.",
9 | "websiteUrl": "https://www.example.com",
10 | "privacyUrl": "https://www.example.com/privacy",
11 | "termsOfUseUrl": "https://www.example.com/termofuse"
12 | },
13 | "icons": {
14 | "color": "color.png",
15 | "outline": "outline.png"
16 | },
17 | "name": {
18 | "short": "TeamsClippy${{APP_NAME_SUFFIX}}",
19 | "full": "full name for TeamsClippy"
20 | },
21 | "description": {
22 | "short": "short description for TeamsClippy",
23 | "full": "full description for TeamsClippy"
24 | },
25 | "accentColor": "#FFFFFF",
26 | "bots": [
27 | {
28 | "botId": "${{BOT_ID}}",
29 | "scopes": [
30 | "personal",
31 | "team",
32 | "groupchat"
33 | ],
34 | "supportsFiles": false,
35 | "isNotificationOnly": false
36 | }
37 | ],
38 | "composeExtensions": [],
39 | "configurableTabs": [],
40 | "staticTabs": [],
41 | "permissions": [
42 | "identity",
43 | "messageTeamMembers"
44 | ],
45 | "validDomains": []
46 | }
--------------------------------------------------------------------------------
/02-clippy/sample/appPackage/outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/02-clippy/sample/appPackage/outline.png
--------------------------------------------------------------------------------
/02-clippy/sample/env/.env.dev:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that will be committed to git by default.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=dev
5 | APP_NAME_SUFFIX=dev
6 |
7 | # Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups.
8 | AZURE_SUBSCRIPTION_ID=
9 | AZURE_RESOURCE_GROUP_NAME=
10 | RESOURCE_SUFFIX=
11 |
12 | # Generated during provision, you can also add your own variables.
13 | BOT_ID=
14 | TEAMS_APP_ID=
15 | BOT_AZURE_APP_SERVICE_RESOURCE_ID=
16 | BOT_DOMAIN=
--------------------------------------------------------------------------------
/02-clippy/sample/env/.env.local.sample:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=local
5 | APP_NAME_SUFFIX=local
6 |
7 | # Generated during provision, you can also add your own variables.
8 | BOT_ID=
9 | TEAMS_APP_ID=
10 | BOT_DOMAIN=
11 | BOT_ENDPOINT=
12 | TEAMS_APP_TENANT_ID=
13 | BOT_OBJECT_ID=
--------------------------------------------------------------------------------
/02-clippy/sample/env/.env.local.user.sample:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project.
2 |
3 | # If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly
4 | # Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs.
5 | SECRET_BOT_PASSWORD=
6 | SECRET_AZURE_OPENAI_API_KEY=
7 | AZURE_OPENAI_ENDPOINT=
8 | AZURE_OPENAI_DEPLOYMENT_NAME=
9 | TEAMS_APP_UPDATE_TIME=
--------------------------------------------------------------------------------
/02-clippy/sample/env/.env.testtool:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=testtool
5 |
6 | # Environment variables used by test tool
7 | TEAMSAPPTESTER_PORT=56150
8 | TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json
--------------------------------------------------------------------------------
/02-clippy/sample/infra/azure.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | @description('Required when create Azure Bot service')
7 | param botAadAppClientId string
8 |
9 | @secure()
10 | @description('Required by Bot Framework package in your bot project')
11 | param botAadAppClientSecret string
12 |
13 | @secure()
14 | param azureOpenAIKey string
15 |
16 | @secure()
17 | param azureOpenAIEndpoint string
18 |
19 | @secure()
20 | param azureOpenAIDeploymentName string
21 |
22 | param webAppSKU string
23 |
24 | @maxLength(42)
25 | param botDisplayName string
26 |
27 | param serverfarmsName string = resourceBaseName
28 | param webAppName string = resourceBaseName
29 | param location string = resourceGroup().location
30 |
31 | // Compute resources for your Web App
32 | resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = {
33 | kind: 'app'
34 | location: location
35 | name: serverfarmsName
36 | sku: {
37 | name: webAppSKU
38 | }
39 | }
40 |
41 | // Web App that hosts your bot
42 | resource webApp 'Microsoft.Web/sites@2021-02-01' = {
43 | kind: 'app'
44 | location: location
45 | name: webAppName
46 | properties: {
47 | serverFarmId: serverfarm.id
48 | httpsOnly: true
49 | siteConfig: {
50 | alwaysOn: true
51 | appSettings: [
52 | {
53 | name: 'WEBSITE_RUN_FROM_PACKAGE'
54 | value: '1' // Run Azure App Service from a package file
55 | }
56 | {
57 | name: 'WEBSITE_NODE_DEFAULT_VERSION'
58 | value: '~18' // Set NodeJS version to 18.x for your site
59 | }
60 | {
61 | name: 'RUNNING_ON_AZURE'
62 | value: '1'
63 | }
64 | {
65 | name: 'BOT_ID'
66 | value: botAadAppClientId
67 | }
68 | {
69 | name: 'BOT_PASSWORD'
70 | value: botAadAppClientSecret
71 | }
72 | {
73 | name: 'AZURE_OPENAI_API_KEY'
74 | value: azureOpenAIKey
75 | }
76 | {
77 | name: 'AZURE_OPENAI_ENDPOINT'
78 | value: azureOpenAIEndpoint
79 | }
80 | {
81 | name: 'AZURE_OPENAI_DEPLOYMENT_NAME'
82 | value: azureOpenAIDeploymentName
83 | }
84 | ]
85 | ftpsState: 'FtpsOnly'
86 | }
87 | }
88 | }
89 |
90 | // Register your web service as a bot with the Bot Framework
91 | module azureBotRegistration './botRegistration/azurebot.bicep' = {
92 | name: 'Azure-Bot-registration'
93 | params: {
94 | resourceBaseName: resourceBaseName
95 | botAadAppClientId: botAadAppClientId
96 | botAppDomain: webApp.properties.defaultHostName
97 | botDisplayName: botDisplayName
98 | }
99 | }
100 |
101 | // The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details.
102 | output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id
103 | output BOT_DOMAIN string = webApp.properties.defaultHostName
104 |
--------------------------------------------------------------------------------
/02-clippy/sample/infra/azure.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "resourceBaseName": {
6 | "value": "bot${{RESOURCE_SUFFIX}}"
7 | },
8 | "botAadAppClientId": {
9 | "value": "${{BOT_ID}}"
10 | },
11 | "botAadAppClientSecret": {
12 | "value": "${{SECRET_BOT_PASSWORD}}"
13 | },
14 | "azureOpenAIKey": {
15 | "value": "${{SECRET_AZURE_OPENAI_API_KEY}}"
16 | },
17 | "azureOpenAIEndpoint": {
18 | "value": "${{AZURE_OPENAI_ENDPOINT}}"
19 | },
20 | "azureOpenAIDeploymentName": {
21 | "value": "${{AZURE_OPENAI_DEPLOYMENT_NAME}}"
22 | },
23 | "webAppSKU": {
24 | "value": "B1"
25 | },
26 | "botDisplayName": {
27 | "value": "TeamsClippy"
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/02-clippy/sample/infra/botRegistration/azurebot.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | @maxLength(42)
7 | param botDisplayName string
8 |
9 | param botServiceName string = resourceBaseName
10 | param botServiceSku string = 'F0'
11 | param botAadAppClientId string
12 | param botAppDomain string
13 |
14 | // Register your web service as a bot with the Bot Framework
15 | resource botService 'Microsoft.BotService/botServices@2021-03-01' = {
16 | kind: 'azurebot'
17 | location: 'global'
18 | name: botServiceName
19 | properties: {
20 | displayName: botDisplayName
21 | endpoint: 'https://${botAppDomain}/api/messages'
22 | msaAppId: botAadAppClientId
23 | }
24 | sku: {
25 | name: botServiceSku
26 | }
27 | }
28 |
29 | // Connect the bot service to Microsoft Teams
30 | resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = {
31 | parent: botService
32 | location: 'global'
33 | name: 'MsTeamsChannel'
34 | properties: {
35 | channelName: 'MsTeamsChannel'
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/02-clippy/sample/infra/botRegistration/readme.md:
--------------------------------------------------------------------------------
1 | The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again.
--------------------------------------------------------------------------------
/02-clippy/sample/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "teamsclippy",
3 | "version": "1.0.0",
4 | "msteams": {
5 | "teamsAppId": null
6 | },
7 | "description": "Microsoft Teams Toolkit AI Chat Bot Sample with Teams AI Library",
8 | "engines": {
9 | "node": "16 || 18"
10 | },
11 | "author": "Microsoft",
12 | "license": "MIT",
13 | "main": "./lib/src/index.js",
14 | "scripts": {
15 | "dev:teamsfx": "env-cmd --silent -f .localConfigs npm run dev",
16 | "dev:teamsfx:testtool": "env-cmd --silent -f .localConfigs.testTool npm run dev",
17 | "dev:teamsfx:launch-testtool": "env-cmd --silent -f env/.env.testtool teamsapptester start",
18 | "dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register ./src/index.ts",
19 | "build": "tsc --build && shx cp -r ./src/prompts ./lib/src",
20 | "start": "node ./lib/src/index.js",
21 | "test": "echo \"Error: no test specified\" && exit 1",
22 | "watch": "nodemon --exec \"npm run start\""
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com"
27 | },
28 | "dependencies": {
29 | "@microsoft/teams-ai": "^1.1.0",
30 | "botbuilder": "^4.20.0",
31 | "openai": "~4.28.4",
32 | "restify": "^10.0.0"
33 | },
34 | "devDependencies": {
35 | "@types/restify": "^8.5.5",
36 | "@types/node": "^18.0.0",
37 | "env-cmd": "^10.1.0",
38 | "ts-node": "^10.4.0",
39 | "typescript": "^4.4.4",
40 | "nodemon": "^2.0.7",
41 | "shx": "^0.3.3"
42 | }
43 | }
--------------------------------------------------------------------------------
/02-clippy/sample/src/adapter.ts:
--------------------------------------------------------------------------------
1 | // Import required bot services.
2 | // See https://aka.ms/bot-services to learn more about the different parts of a bot.
3 | import {
4 | CloudAdapter,
5 | ConfigurationBotFrameworkAuthentication,
6 | ConfigurationServiceClientCredentialFactory,
7 | } from "botbuilder";
8 |
9 | // This bot's main dialog.
10 | import config from "./config";
11 |
12 | const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(
13 | {},
14 | new ConfigurationServiceClientCredentialFactory({
15 | MicrosoftAppId: config.botId,
16 | MicrosoftAppPassword: process.env.BOT_PASSWORD,
17 | MicrosoftAppType: "MultiTenant",
18 | })
19 | );
20 |
21 | // Create adapter.
22 | // See https://aka.ms/about-bot-adapter to learn more about how bots work.
23 | const adapter = new CloudAdapter(botFrameworkAuthentication);
24 |
25 | // Catch-all for errors.
26 | const onTurnErrorHandler = async (context, error) => {
27 | // This check writes out errors to console log .vs. app insights.
28 | // NOTE: In production environment, you should consider logging this to Azure
29 | // application insights.
30 | console.error(`\n [onTurnError] unhandled error: ${error}`);
31 |
32 | // Only send error message for user messages, not for other message types so the bot doesn't spam a channel or chat.
33 | if (context.activity.type === "message") {
34 | // Send a trace activity, which will be displayed in Bot Framework Emulator
35 | await context.sendTraceActivity(
36 | "OnTurnError Trace",
37 | `${error}`,
38 | "https://www.botframework.com/schemas/error",
39 | "TurnError"
40 | );
41 |
42 | // Send a message to the user
43 | await context.sendActivity("The bot encountered an error or bug.");
44 | await context.sendActivity("To continue to run this bot, please fix the bot source code.");
45 | }
46 | };
47 |
48 | // Set the onTurnError for the singleton CloudAdapter.
49 | adapter.onTurnError = onTurnErrorHandler;
50 |
51 | export default adapter;
52 |
--------------------------------------------------------------------------------
/02-clippy/sample/src/app/app.ts:
--------------------------------------------------------------------------------
1 | import { ActivityTypes, Attachment, CardFactory, MemoryStorage } from "botbuilder";
2 | import * as path from "path";
3 | import config from "../config";
4 |
5 | // See https://aka.ms/teams-ai-library to learn more about the Teams AI library.
6 | import { Application, ActionPlanner, OpenAIModel, PromptManager } from "@microsoft/teams-ai";
7 | import { stat } from "fs";
8 |
9 | // Create AI components
10 | const model = new OpenAIModel({
11 | azureApiKey: config.azureOpenAIKey,
12 | azureDefaultDeployment: config.azureOpenAIDeploymentName,
13 | azureEndpoint: config.azureOpenAIEndpoint,
14 |
15 | useSystemMessages: true,
16 | logRequests: true,
17 | });
18 | const prompts = new PromptManager({
19 | promptsFolder: path.join(__dirname, "../prompts"),
20 | });
21 | const planner = new ActionPlanner({
22 | model,
23 | prompts,
24 | defaultPrompt: "chat",
25 | });
26 |
27 | // Define storage and application
28 | const storage = new MemoryStorage();
29 | const app = new Application({
30 | storage,
31 | ai: {
32 | planner,
33 | },
34 | });
35 |
36 | export default app;
37 |
--------------------------------------------------------------------------------
/02-clippy/sample/src/config.ts:
--------------------------------------------------------------------------------
1 | const config = {
2 | botId: process.env.BOT_ID,
3 | botPassword: process.env.BOT_PASSWORD,
4 | azureOpenAIKey: process.env.AZURE_OPENAI_API_KEY,
5 | azureOpenAIEndpoint: process.env.AZURE_OPENAI_ENDPOINT,
6 | azureOpenAIDeploymentName: process.env.AZURE_OPENAI_DEPLOYMENT_NAME,
7 | };
8 |
9 | export default config;
10 |
--------------------------------------------------------------------------------
/02-clippy/sample/src/index.ts:
--------------------------------------------------------------------------------
1 | // Import required packages
2 | import * as restify from "restify";
3 |
4 | // This bot's adapter
5 | import adapter from "./adapter";
6 |
7 | // This bot's main dialog.
8 | import app from "./app/app";
9 |
10 | // Create HTTP server.
11 | const server = restify.createServer();
12 | server.use(restify.plugins.bodyParser());
13 |
14 | server.listen(process.env.port || process.env.PORT || 3978, () => {
15 | console.log(`\nBot Started, ${server.name} listening to ${server.url}`);
16 | });
17 |
18 | // Listen for incoming server requests.
19 | server.post("/api/messages", async (req, res) => {
20 | // Route received a request to adapter for processing
21 | await adapter.process(req, res as any, async (context) => {
22 | // Dispatch to application for routing
23 | await app.run(context);
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/02-clippy/sample/src/prompts/chat/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": 1.1,
3 | "description": "A bot that can chat with users",
4 | "type": "completion",
5 | "completion": {
6 | "completion_type": "chat",
7 | "include_history": true,
8 | "include_input": true,
9 | "max_input_tokens": 2800,
10 | "max_tokens": 1000,
11 | "temperature": 0.9,
12 | "top_p": 0.0,
13 | "presence_penalty": 0.6,
14 | "frequency_penalty": 0.0
15 | }
16 | }
--------------------------------------------------------------------------------
/02-clippy/sample/src/prompts/chat/skprompt.txt:
--------------------------------------------------------------------------------
1 | You are Clippy, an AI assistant designed to help people answer questions about Microsoft products. Clippy is fun, helpful and a little quircky. Clippy starts with "Hi, I'm Clippy" in it's greeting. Clippy loves all Microsoft products and loves helping users make the most of them. Clippy loves jokes, and finished each of its response with a joke related to Microsoft products (and acknowledges the joke with "ha!").
2 |
3 | Here is an adaptive card template for showing Clippy's answer to a user
4 |
5 | {
6 | "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
7 | "type": "AdaptiveCard",
8 | "version": "1.5",
9 | "body": [
10 | {
11 | "type": "ColumnSet",
12 | "columns": [
13 | {
14 | "type": "Column",
15 | "width": 10,
16 | "items": [
17 | {
18 | "type": "Image",
19 | "url": "https://github-production-user-asset-6210df.s3.amazonaws.com/36196437/263676753-bf71c902-d693-4c89-837d-7f851af38673.png",
20 | "size": "Medium",
21 | "horizontalAlignment": "Right"
22 | }
23 | ]
24 | },
25 | {
26 | "type": "Column",
27 | "width": 80,
28 | "items": [
29 | {
30 | "type": "TextBlock",
31 | "text": "It looks like you are trying to forcast sales for your business!",
32 | "wrap": true,
33 | "style": "heading",
34 | "fontType": "Monospace",
35 | "size": "Large",
36 | "color": "Accent",
37 | "weight": "Bolder"
38 | },
39 | {
40 | "type": "TextBlock",
41 | "text": "You can use Microsoft Excel to make forcasts based on prior data and your assumptions. Here's how:",
42 | "wrap": true,
43 | "fontType": "Monospace"
44 | }
45 | ]
46 | }
47 | ]
48 | }
49 | ]
50 | }
51 |
52 | Use the template to create an Adaptive Card.
53 | Always replace the TextBlock text with the real data.
54 | The first TextBlock will cover one-sentence summary of user's question starting with "It looks like you are trying to ..."
55 | The second TextBlock will cover the answer to the user's question.
56 |
57 | AdaptiveCard:
--------------------------------------------------------------------------------
/02-clippy/sample/teamsapp.local.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.5/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.5
5 |
6 | provision:
7 | # Creates a Teams app
8 | - uses: teamsApp/create
9 | with:
10 | # Teams app name
11 | name: TeamsClippy${{APP_NAME_SUFFIX}}
12 | # Write the information of created resources into environment file for
13 | # the specified environment variable(s).
14 | writeToEnvironmentFile:
15 | teamsAppId: TEAMS_APP_ID
16 |
17 | # Create or reuse an existing Microsoft Entra application for bot.
18 | - uses: aadApp/create
19 | with:
20 | # The Microsoft Entra application's display name
21 | name: TeamsClippy${{APP_NAME_SUFFIX}}
22 | generateClientSecret: true
23 | signInAudience: AzureADMultipleOrgs
24 | writeToEnvironmentFile:
25 | # The Microsoft Entra application's client id created for bot.
26 | clientId: BOT_ID
27 | # The Microsoft Entra application's client secret created for bot.
28 | clientSecret: SECRET_BOT_PASSWORD
29 | # The Microsoft Entra application's object id created for bot.
30 | objectId: BOT_OBJECT_ID
31 |
32 | # Create or update the bot registration on dev.botframework.com
33 | - uses: botFramework/create
34 | with:
35 | botId: ${{BOT_ID}}
36 | name: TeamsClippy
37 | messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages
38 | description: ""
39 | channels:
40 | - name: msteams
41 |
42 | # Validate using manifest schema
43 | - uses: teamsApp/validateManifest
44 | with:
45 | # Path to manifest template
46 | manifestPath: ./appPackage/manifest.json
47 |
48 | # Build Teams app package with latest env value
49 | - uses: teamsApp/zipAppPackage
50 | with:
51 | # Path to manifest template
52 | manifestPath: ./appPackage/manifest.json
53 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
54 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
55 | # Validate app package using validation rules
56 | - uses: teamsApp/validateAppPackage
57 | with:
58 | # Relative path to this file. This is the path for built zip file.
59 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
60 |
61 | # Apply the Teams app manifest to an existing Teams app in
62 | # Teams Developer Portal.
63 | # Will use the app id in manifest file to determine which Teams app to update.
64 | - uses: teamsApp/update
65 | with:
66 | # Relative path to this file. This is the path for built zip file.
67 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
68 |
69 | deploy:
70 | # Run npm command
71 | - uses: cli/runNpmCommand
72 | name: install dependencies
73 | with:
74 | args: install --no-audit
75 |
76 | # Generate runtime environment variables
77 | - uses: file/createOrUpdateEnvironmentFile
78 | with:
79 | target: ./.localConfigs
80 | envs:
81 | BOT_ID: ${{BOT_ID}}
82 | BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}}
83 | AZURE_OPENAI_API_KEY: ${{SECRET_AZURE_OPENAI_API_KEY}}
84 | AZURE_OPENAI_ENDPOINT: ${{AZURE_OPENAI_ENDPOINT}}
85 | AZURE_OPENAI_DEPLOYMENT_NAME: ${{AZURE_OPENAI_DEPLOYMENT_NAME}}
86 |
--------------------------------------------------------------------------------
/02-clippy/sample/teamsapp.testtool.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.5/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.5
5 |
6 | deploy:
7 | # Install development tool(s)
8 | - uses: devTool/install
9 | with:
10 | testTool:
11 | version: ~0.2.1
12 | symlinkDir: ./devTools/teamsapptester
13 |
14 | # Run npm command
15 | - uses: cli/runNpmCommand
16 | with:
17 | args: install --no-audit
18 |
19 | # Generate runtime environment variables
20 | - uses: file/createOrUpdateEnvironmentFile
21 | with:
22 | target: ./.localConfigs.testTool
23 | envs:
24 | AZURE_OPENAI_API_KEY: ${{SECRET_AZURE_OPENAI_API_KEY}}
25 | AZURE_OPENAI_ENDPOINT: ${{AZURE_OPENAI_ENDPOINT}}
26 | AZURE_OPENAI_DEPLOYMENT_NAME: ${{AZURE_OPENAI_DEPLOYMENT_NAME}}
27 | TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}}
--------------------------------------------------------------------------------
/02-clippy/sample/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "target": "es2017",
5 | "module": "commonjs",
6 | "outDir": "./lib",
7 | "rootDir": "./",
8 | "sourceMap": true,
9 | "incremental": true,
10 | "tsBuildInfoFile": "./lib/.tsbuildinfo",
11 | "esModuleInterop": true
12 | }
13 | }
--------------------------------------------------------------------------------
/02-clippy/sample/web.config:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/03-assistants-api/README.md:
--------------------------------------------------------------------------------
1 | # Build your own cooking assistant with OpenAI Assistants API
2 |
3 | In this section, you'll learn about OpenAI's Assistants API and build your own cooking assistant bot that suggests recipes based on what you have in the fridge!
4 |
5 | ## What is Assistants API?
6 |
7 | [OpenAI's **Assistants API**](https://platform.openai.com/docs/assistants/overview) lets you build AI agent-like applications that can understand and generate human-like text, and it is customizable and versatile with your own instructions, model, tools, and files.
8 |
9 | > **Note:** The OpenAI Assistants API is a paid service, where developers are billed based on the usage of tokens for the Assistant API at the chosen language model's per-token input/output rates. Please check the latest information on OpenAI's [pricing page](https://openai.com/api/pricing/) for the most up-to-date details!
10 |
11 | Assistants API has some main components-
12 |
13 | - **Models**: You can choose from a range of GPT-3.5 and GPT-4 models.
14 |
15 | And these are the additional tools features that enhance the functionality of the API. They can be either OpenAI-hosted or custom-built by you. The OpenAI-hosted tools include:
16 |
17 | - **Code Interpreter**: It allows the API to write & run Python code.
18 | - **File Search (was Retrieval)**: It allows the API to access external knowledge sources from outside its model, such as proprietary product information or documents provided by your users.
19 | - **Function calling**: It refers to custom operations that you can define to perform any task that is not supported by the OpenAI-hosted tools, like, accessing your own databases, APIs, or services. When it invokes functions, the API will pause execution during a Run phase, and you can supply the results of the function callback to continue the Run execution.
20 |
21 | The typical integration flow of the Assistants API involves creating an Assistant with custom instructions and a chosen model, adding files, enabling tools, and then creating a Thread to handle the conversation with the user. Messages are added to the Thread as the user interacts with the Assistant, and the Assistant generates responses by calling the model and the tools.
22 |
23 | 
24 |
25 | ### Example: Cooking Assistant
26 |
27 | For example, you can create a cooking assistant. You can give specific instruction to make the chatbot acts as a personal cooking assistant that suggests cuisine recipes based on what's in your fridge.
28 |
29 | Let's say, when a user asks a question like, "I have some Bok choy, fresh ginger, and tofu in fridge. Can you suggest some Chinese recipes?", the assistant replies with some yummy recipe suggestions!
30 |
31 | To define your assistant, you need to give **instructions** in Assistants API to guide its behavior. In this case, you can provide an instruction like:
32 | *You are a cooking advisor, who can help users with recipes around the world, based on ingredients*.
33 |
34 | The API processes your request; When a conversation is started, the API creates a Thread, and creates messages to the Thread, as soon as the user asks questions. This is how it maintains stateful conversations.
35 |
36 | Finally, it generates a response; The API runs the Assistant on the Thread to trigger responses to generate a human-like reply message with some dish suggestions.
37 |
38 | The user can keep the conversation with the agent in the Thread.
39 |
40 | ## Use-cases and scenarios
41 |
42 | - **Content writer**: You can leverage the API to assist users in drafting emails, articles, blog posts, or social media updates.
43 | - **Personal assistant**: It can help with tasks like scheduling appointments & setting reminders.
44 | - **Travel guide**: It suggests you some interesting places to visit, based on your preferences.
45 | - **Virtual tutor**: such as a math tutor who can walk you through some equations.
46 |
47 | These are just a few examples. The possibilities with Assistants API are limited only by your imagination!
48 |
49 | You can explore the capabilities of the API with the web-based [Playground on OpenAI's Developer Platform website](https://platform.openai.com/playground?mode=assistant).
50 |
51 | 
52 |
53 | It lets you export the configuration to apply on your own applications, including Microsoft Teams apps! Teams Toolkit extension for Visual Studio & VS Code can make your life easier, when want to integrate the API to create your own AI Assistant Bot that lives in Teams!
54 |
55 | ## 🚀 Build Cooking Assistant bot
56 |
57 | **Now let's [build your own Cooking Assistant](sample/README.md)!**
58 |
59 | ## 📺 Watch on YouTube
60 |
61 | Watch the video, **Use OpenAI Assistants API to build your own cooking advisor bot on Teams** on YouTube:
62 |
63 | [](https://youtu.be/OL23O25jQGE?si=JK9y3U-UDSZYTyiu)
64 |
65 | [Subscribe us!](https://www.youtube.com/channel/UCV_6HOhwxYLXAGd-JOqKPoQ?sub_confirmation=1)!
66 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/.gitignore:
--------------------------------------------------------------------------------
1 | # TeamsFx files
2 | env/.env.*.user
3 | env/.env.local
4 | appPackage/build
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # misc
10 | .env
11 | .deployment
12 | .DS_Store
13 |
14 | # build
15 | lib/
16 |
17 | # devTools
18 | devTools/
19 |
20 | # Local data
21 | .localConfigs.testTool
22 | .localConfigs
23 | .notification.localstore.json
24 | .notification.testtoolstore.json
25 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "TeamsDevApp.ms-teams-vscode-extension"
4 | ]
5 | }
--------------------------------------------------------------------------------
/03-assistants-api/sample/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Launch Remote (Edge)",
6 | "type": "msedge",
7 | "request": "launch",
8 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
9 | "presentation": {
10 | "group": "3-remote",
11 | "order": 1
12 | },
13 | "internalConsoleOptions": "neverOpen"
14 | },
15 | {
16 | "name": "Launch Remote (Chrome)",
17 | "type": "chrome",
18 | "request": "launch",
19 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
20 | "presentation": {
21 | "group": "3-remote",
22 | "order": 2
23 | },
24 | "internalConsoleOptions": "neverOpen"
25 | },
26 | {
27 | "name": "Launch App (Edge)",
28 | "type": "msedge",
29 | "request": "launch",
30 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
31 | "cascadeTerminateToConfigurations": [
32 | "Attach to Local Service"
33 | ],
34 | "presentation": {
35 | "group": "all",
36 | "hidden": true
37 | },
38 | "internalConsoleOptions": "neverOpen"
39 | },
40 | {
41 | "name": "Launch App (Chrome)",
42 | "type": "chrome",
43 | "request": "launch",
44 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
45 | "cascadeTerminateToConfigurations": [
46 | "Attach to Local Service"
47 | ],
48 | "presentation": {
49 | "group": "all",
50 | "hidden": true
51 | },
52 | "internalConsoleOptions": "neverOpen"
53 | },
54 | {
55 | "name": "Attach to Local Service",
56 | "type": "node",
57 | "request": "attach",
58 | "port": 9239,
59 | "restart": true,
60 | "presentation": {
61 | "group": "all",
62 | "hidden": true
63 | },
64 | "internalConsoleOptions": "neverOpen"
65 | }
66 | ],
67 | "compounds": [
68 | {
69 | "name": "Debug (Edge)",
70 | "configurations": [
71 | "Launch App (Edge)",
72 | "Attach to Local Service"
73 | ],
74 | "preLaunchTask": "Start Teams App Locally",
75 | "presentation": {
76 | "group": "2-local",
77 | "order": 1
78 | },
79 | "stopAll": true
80 | },
81 | {
82 | "name": "Debug (Chrome)",
83 | "configurations": [
84 | "Launch App (Chrome)",
85 | "Attach to Local Service"
86 | ],
87 | "preLaunchTask": "Start Teams App Locally",
88 | "presentation": {
89 | "group": "2-local",
90 | "order": 2
91 | },
92 | "stopAll": true
93 | },
94 | {
95 | "name": "Debug in Test Tool",
96 | "configurations": [
97 | "Attach to Local Service"
98 | ],
99 | "preLaunchTask": "Start Teams App (Test Tool)",
100 | "presentation": {
101 | "group": "1-local",
102 | "order": 1
103 | },
104 | "stopAll": true
105 | }
106 | ]
107 | }
108 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "debug.onTaskErrors": "abort",
3 | "json.schemas": [
4 | {
5 | "fileMatch": [
6 | "/aad.*.json"
7 | ],
8 | "schema": {}
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/03-assistants-api/sample/.webappignore:
--------------------------------------------------------------------------------
1 | .webappignore
2 | .fx
3 | .deployment
4 | .localConfigs
5 | .notification.localstore.json
6 | .vscode
7 | *.js.map
8 | *.ts.map
9 | *.ts
10 | .git*
11 | .tsbuildinfo
12 | CHANGELOG.md
13 | readme.md
14 | local.settings.json
15 | test
16 | tsconfig.json
17 | .DS_Store
18 | teamsapp.yml
19 | teamsapp.*.yml
20 | /env/
21 | /node_modules/.bin
22 | /node_modules/ts-node
23 | /node_modules/typescript
24 | /appPackage/
25 | /infra/
--------------------------------------------------------------------------------
/03-assistants-api/sample/README.md:
--------------------------------------------------------------------------------
1 | # Overview of the Cooking Advisor with the Assistants API Sample
2 |
3 | This app template is built on top of [Teams AI library](https://aka.ms/teams-ai-library) and [OpenAI Assistants API](https://platform.openai.com/docs/assistants/overview).
4 | It showcases how to build an intelligent chat bot in Teams capable of helping users accomplish a specific task using natural language right in the Teams conversations, such as solving a math problem.
5 |
6 | ## Get started with the Cooking Advisor with the Assistants API Sample
7 |
8 | > **Prerequisites**
9 | >
10 | > To run the Cooking Assistant in your local dev machine, you will need:
11 | >
12 | > - [Node.js](https://nodejs.org/), supported versions: 16, 18
13 | > - A [Microsoft 365 account for development](https://docs.microsoft.com/microsoftteams/platform/toolkit/accounts)
14 | > - [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-cli)
15 | > - An account with [OpenAI](https://platform.openai.com/).
16 |
17 | ### Create your own OpenAI Assistant
18 |
19 | Developer's can create their own assistants using one of the options below.
20 |
21 |
22 | Option 1: Create your Assistant using OpenAI Platform
23 |
24 | Before running or debugging your bot, please follow these steps to setup your own [OpenAI Assistant](https://platform.openai.com/docs/assistants/overview):
25 |
26 | 1. Go to [OpenAI Platform](https://platform.openai.com) and select `Assistants` from the left-hand side menu, then select `+Create`. Fill the details as the following:
27 |
28 | - **Name:** Cooking Advisor
29 | - **Instructions:** You are a cooking advisor who can help users with recipes around the world
30 | - **Model:** gpt-3.5-turbo (or higher)
31 | - **Functions:** Select `+Functions` to create new, copy the following snippet in the function and `Save`:
32 |
33 | ```json
34 | {
35 | "name": "get_recipes",
36 | "description": "gets food recipes",
37 | "parameters": {
38 | "type": "object",
39 | "properties": {
40 | "meal": {
41 | "type": "string",
42 | "description": "The meal name"
43 | },
44 | "language": {
45 | "type": "string",
46 | "description": "language of the prompt"
47 | }
48 | },
49 | "required": [
50 | "meal", "language"
51 | ]
52 | }
53 | }
54 | ```
55 |
56 | - Finally, select `Playground` on top of the panel to test your Cooking Advisor Assistant.
57 |
58 | Some of the example questions you can use to test your assistant in the Playground:
59 |
60 | - "Can you help me cook ramen?"
61 | - "How can I make homemade pasta?"
62 |
63 | Copy the **Assistant ID** that is available right under your Assistant's name.
64 |
65 |
66 | Option 2: Create your Assistant using CLI
67 |
68 | > This app template provides script `src/creator.ts` to help create assistant. You can change the instructions and settings in the script to customize the assistant.
69 | >
70 | > After creation, you can change and manage your assistants on [OpenAI](https://platform.openai.com/assistants).
71 |
72 | 1. Open terminal and run command `npm install` to install all dependency packages
73 | ```
74 | > npm install
75 | ```
76 |
77 | 1. After `npm install` completed, run command `npm run assistant:create -- `
78 | ```
79 | > npm run assistant:create -- xxxxxx
80 | ```
81 |
82 | 1. The above command will output something like "*Created a new assistant with an ID of: **asst_xxx...***"
83 |
84 |
85 |
86 | #### Update the environment variables in the source code
87 |
88 | 1. Create `.en.testtool.user` under the **env** folder. Fill in both OpenAI API Key and the created Assistant ID into `env/.env.testtool.user`:
89 | ```
90 | SECRET_OPENAI_API_KEY=
91 | SECRET_OPENAI_ASSISTANT_ID=
92 | ```
93 |
94 | ### Run Teams Bot locally
95 |
96 | 1. In Visual Studio Code, select `Run and Debug` from the left side panel and select `Debug in Test Tool`.
97 | 1. When Teams App Test Tool in the browser, you can start testing your Cooking Advisor.
98 |
99 | **Congratulations**! You are running an application that can now interact with users:
100 |
101 | 
102 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/appPackage/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/03-assistants-api/sample/appPackage/color.png
--------------------------------------------------------------------------------
/03-assistants-api/sample/appPackage/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
3 | "manifestVersion": "1.16",
4 | "version": "1.0.0",
5 | "id": "${{TEAMS_APP_ID}}",
6 | "packageName": "com.microsoft.teams.extension",
7 | "developer": {
8 | "name": "Teams App, Inc.",
9 | "websiteUrl": "https://www.example.com",
10 | "privacyUrl": "https://www.example.com/termofuse",
11 | "termsOfUseUrl": "https://www.example.com/privacy"
12 | },
13 | "icons": {
14 | "color": "color.png",
15 | "outline": "outline.png"
16 | },
17 | "name": {
18 | "short": "AssistantBot${{APP_NAME_SUFFIX}}",
19 | "full": "full name for AssistantBot"
20 | },
21 | "description": {
22 | "short": "short description for AssistantBot",
23 | "full": "full description for AssistantBot"
24 | },
25 | "accentColor": "#FFFFFF",
26 | "bots": [
27 | {
28 | "botId": "${{BOT_ID}}",
29 | "scopes": [
30 | "personal"
31 | ],
32 | "supportsFiles": false,
33 | "isNotificationOnly": false
34 | }
35 | ],
36 | "composeExtensions": [],
37 | "configurableTabs": [],
38 | "staticTabs": [],
39 | "permissions": [
40 | "identity"
41 | ],
42 | "validDomains": []
43 | }
--------------------------------------------------------------------------------
/03-assistants-api/sample/appPackage/outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/03-assistants-api/sample/appPackage/outline.png
--------------------------------------------------------------------------------
/03-assistants-api/sample/env/.env.dev:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that will be committed to git by default.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=dev
5 | APP_NAME_SUFFIX=dev
6 |
7 | # Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups.
8 | AZURE_SUBSCRIPTION_ID=
9 | AZURE_RESOURCE_GROUP_NAME=
10 | RESOURCE_SUFFIX=
11 |
12 | # Generated during provision, you can also add your own variables.
13 | BOT_ID=
14 | TEAMS_APP_ID=
15 | BOT_AZURE_APP_SERVICE_RESOURCE_ID=
16 | BOT_DOMAIN=
--------------------------------------------------------------------------------
/03-assistants-api/sample/env/.env.testtool:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=testtool
5 |
6 | # Environment variables used by test tool
7 | TEAMSAPPTESTER_PORT=56150
8 | TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json
--------------------------------------------------------------------------------
/03-assistants-api/sample/infra/azure.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | @description('Required when create Azure Bot service')
7 | param botAadAppClientId string
8 |
9 | @secure()
10 | @description('Required by Bot Framework package in your bot project')
11 | param botAadAppClientSecret string
12 |
13 | @secure()
14 | param openAIKey string
15 |
16 | @secure()
17 | param openAIAssistantId string
18 |
19 | param webAppSKU string
20 |
21 | @maxLength(42)
22 | param botDisplayName string
23 |
24 | param serverfarmsName string = resourceBaseName
25 | param webAppName string = resourceBaseName
26 | param location string = resourceGroup().location
27 |
28 | // Compute resources for your Web App
29 | resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = {
30 | kind: 'app'
31 | location: location
32 | name: serverfarmsName
33 | sku: {
34 | name: webAppSKU
35 | }
36 | }
37 |
38 | // Web App that hosts your bot
39 | resource webApp 'Microsoft.Web/sites@2021-02-01' = {
40 | kind: 'app'
41 | location: location
42 | name: webAppName
43 | properties: {
44 | serverFarmId: serverfarm.id
45 | httpsOnly: true
46 | siteConfig: {
47 | alwaysOn: true
48 | appSettings: [
49 | {
50 | name: 'WEBSITE_RUN_FROM_PACKAGE'
51 | value: '1' // Run Azure App Service from a package file
52 | }
53 | {
54 | name: 'WEBSITE_NODE_DEFAULT_VERSION'
55 | value: '~18' // Set NodeJS version to 18.x for your site
56 | }
57 | {
58 | name: 'RUNNING_ON_AZURE'
59 | value: '1'
60 | }
61 | {
62 | name: 'BOT_ID'
63 | value: botAadAppClientId
64 | }
65 | {
66 | name: 'BOT_PASSWORD'
67 | value: botAadAppClientSecret
68 | }
69 | {
70 | name: 'OPENAI_API_KEY'
71 | value: openAIKey
72 | }
73 | {
74 | name: 'OPENAI_ASSISTANT_ID'
75 | value: openAIAssistantId
76 | }
77 | ]
78 | ftpsState: 'FtpsOnly'
79 | }
80 | }
81 | }
82 |
83 | // Register your web service as a bot with the Bot Framework
84 | module azureBotRegistration './botRegistration/azurebot.bicep' = {
85 | name: 'Azure-Bot-registration'
86 | params: {
87 | resourceBaseName: resourceBaseName
88 | botAadAppClientId: botAadAppClientId
89 | botAppDomain: webApp.properties.defaultHostName
90 | botDisplayName: botDisplayName
91 | }
92 | }
93 |
94 | // The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details.
95 | output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id
96 | output BOT_DOMAIN string = webApp.properties.defaultHostName
97 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/infra/azure.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "resourceBaseName": {
6 | "value": "bot${{RESOURCE_SUFFIX}}"
7 | },
8 | "botAadAppClientId": {
9 | "value": "${{BOT_ID}}"
10 | },
11 | "botAadAppClientSecret": {
12 | "value": "${{SECRET_BOT_PASSWORD}}"
13 | },
14 | "openAIKey": {
15 | "value": "${{SECRET_OPENAI_API_KEY}}"
16 | },
17 | "openAIAssistantId": {
18 | "value": "${{SECRET_OPENAI_ASSISTANT_ID}}"
19 | },
20 | "webAppSKU": {
21 | "value": "B1"
22 | },
23 | "botDisplayName": {
24 | "value": "AssistantBot"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/03-assistants-api/sample/infra/botRegistration/azurebot.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | @maxLength(42)
7 | param botDisplayName string
8 |
9 | param botServiceName string = resourceBaseName
10 | param botServiceSku string = 'F0'
11 | param botAadAppClientId string
12 | param botAppDomain string
13 |
14 | // Register your web service as a bot with the Bot Framework
15 | resource botService 'Microsoft.BotService/botServices@2021-03-01' = {
16 | kind: 'azurebot'
17 | location: 'global'
18 | name: botServiceName
19 | properties: {
20 | displayName: botDisplayName
21 | endpoint: 'https://${botAppDomain}/api/messages'
22 | msaAppId: botAadAppClientId
23 | }
24 | sku: {
25 | name: botServiceSku
26 | }
27 | }
28 |
29 | // Connect the bot service to Microsoft Teams
30 | resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = {
31 | parent: botService
32 | location: 'global'
33 | name: 'MsTeamsChannel'
34 | properties: {
35 | channelName: 'MsTeamsChannel'
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/infra/botRegistration/readme.md:
--------------------------------------------------------------------------------
1 | The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again.
--------------------------------------------------------------------------------
/03-assistants-api/sample/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "assistantbot",
3 | "version": "1.0.0",
4 | "msteams": {
5 | "teamsAppId": null
6 | },
7 | "description": "Microsoft Teams Toolkit AI Assistant Bot Sample",
8 | "engines": {
9 | "node": "16 || 18"
10 | },
11 | "author": "Microsoft",
12 | "license": "MIT",
13 | "main": "./lib/src/index.js",
14 | "scripts": {
15 | "dev:teamsfx": "env-cmd --silent -f .localConfigs npm run dev",
16 | "dev:teamsfx:testtool": "env-cmd --silent -f .localConfigs.testTool npm run dev",
17 | "dev:teamsfx:launch-testtool": "env-cmd --silent -f env/.env.testtool teamsapptester start",
18 | "dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register ./src/index.ts",
19 | "build": "tsc --build",
20 | "start": "node ./lib/src/index.js",
21 | "test": "echo \"Error: no test specified\" && exit 1",
22 | "watch": "nodemon --exec \"npm run start\"",
23 | "assistant:create": "node -r ts-node/register ./src/creator.ts"
24 | },
25 | "repository": {
26 | "type": "git",
27 | "url": "https://github.com"
28 | },
29 | "dependencies": {
30 | "@microsoft/teams-ai": "1.0.0-preview.1",
31 | "botbuilder": "^4.20.0",
32 | "restify": "^10.0.0"
33 | },
34 | "devDependencies": {
35 | "@types/restify": "^8.5.5",
36 | "@types/node": "^14.0.0",
37 | "env-cmd": "^10.1.0",
38 | "ts-node": "^10.4.0",
39 | "typescript": "^4.4.4",
40 | "nodemon": "^2.0.7",
41 | "shx": "^0.3.3"
42 | }
43 | }
--------------------------------------------------------------------------------
/03-assistants-api/sample/src/app.ts:
--------------------------------------------------------------------------------
1 | import { MemoryStorage } from "botbuilder";
2 |
3 | // See https://aka.ms/teams-ai-library to learn more about the Teams AI library.
4 | import { Application, AssistantsPlanner, AI } from "@microsoft/teams-ai";
5 |
6 | import config from "./config";
7 |
8 | // See README.md to prepare your own OpenAI Assistant
9 | if (!config.openAIKey || !config.openAIAssistantId) {
10 | throw new Error(
11 | "Missing OPENAI_API_KEY or OPENAI_ASSISTANT_ID. See README.md to prepare your own OpenAI Assistant."
12 | );
13 | }
14 |
15 | // Create AI components
16 | // Use OpenAI
17 | const planner = new AssistantsPlanner({
18 | apiKey: config.openAIKey,
19 | assistant_id: config.openAIAssistantId,
20 | });
21 |
22 | // Define storage and application
23 | const storage = new MemoryStorage();
24 | const app = new Application({
25 | storage,
26 | ai: {
27 | planner,
28 | },
29 | });
30 |
31 | app.conversationUpdate("membersAdded", async (context) => {
32 | await context.sendActivity("I'm an assistant bot. How can I help you today?");
33 | });
34 |
35 | app.message("/reset", async (context, state) => {
36 | state.deleteConversationState();
37 | await context.sendActivity("Ok lets start this over.");
38 | });
39 |
40 | app.ai.action(AI.HttpErrorActionName, async (context, state, data) => {
41 | await context.sendActivity("An AI request failed. Please try again later.");
42 | return AI.StopCommandName;
43 | });
44 |
45 | interface recipeData{
46 | meal?: string;
47 | language: string;
48 | ingredients?: string[];
49 | }
50 |
51 | app.ai.action('get_recipes', async(context, state, recipe) =>{
52 | if(recipe.ingredients != null){
53 | await context.sendActivity(`Getting delicious recipes for your ingredients ${recipe.ingredients} in ${recipe.language} language`);
54 | return 'recipe sent!';
55 | }
56 | else if(recipe.meal != ""){
57 | await context.sendActivity(`Getting a delicious recipe for ${recipe.meal} in ${recipe.language} language`);
58 | return 'recipe sent!';
59 | }
60 | else{
61 | await context.sendActivity("At least give me some ingredients to start with :)");
62 | return 'recipe not found';
63 | }
64 |
65 | });
66 |
67 | export default app;
68 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/src/config.ts:
--------------------------------------------------------------------------------
1 | const config = {
2 | botId: process.env.BOT_ID,
3 | botPassword: process.env.BOT_PASSWORD,
4 | openAIKey: process.env.OPENAI_API_KEY,
5 | openAIAssistantId: process.env.OPENAI_ASSISTANT_ID,
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/src/creator.ts:
--------------------------------------------------------------------------------
1 | import { AssistantsPlanner } from "@microsoft/teams-ai";
2 |
3 | const openAIKey = process.argv[2];
4 | if (!openAIKey) {
5 | throw new Error("Missing input OpenAI Key");
6 | }
7 |
8 | // Create new Assistant
9 | (async () => {
10 | const assistant = await AssistantsPlanner.createAssistant(openAIKey, {
11 | name: "Cooking Advisor",
12 | instructions: "You are a cooking advisor who can help users with recipes around the world",
13 | tools: [{ type: "function",
14 | function:{
15 | name: "get_recipes",
16 | description: "gets food recipes",
17 | parameters: {
18 | type: "object",
19 | properties: {
20 | meal: {
21 | type: "string",
22 | description: "The meal name"
23 | },
24 | language: {
25 | type: "string",
26 | description: "language of the prompt"
27 | }
28 | },
29 | required: ["meal", "language"]
30 | }
31 | }
32 | }],
33 | model: "gpt-3.5-turbo",
34 | });
35 |
36 | console.log(`Created a new assistant with an ID of: ${assistant.id}`);
37 | })();
38 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/src/index.ts:
--------------------------------------------------------------------------------
1 | // Import required packages
2 | import * as restify from "restify";
3 |
4 | // Import required bot services.
5 | // See https://aka.ms/bot-services to learn more about the different parts of a bot.
6 | import {
7 | CloudAdapter,
8 | ConfigurationBotFrameworkAuthentication,
9 | ConfigurationServiceClientCredentialFactory,
10 | } from "botbuilder";
11 |
12 | // This bot's main dialog.
13 | import app from "./app";
14 | import config from "./config";
15 |
16 | const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(
17 | {},
18 | new ConfigurationServiceClientCredentialFactory({
19 | MicrosoftAppId: config.botId,
20 | MicrosoftAppPassword: process.env.BOT_PASSWORD,
21 | MicrosoftAppType: "MultiTenant",
22 | })
23 | );
24 |
25 | // Create adapter.
26 | // See https://aka.ms/about-bot-adapter to learn more about how bots work.
27 | const adapter = new CloudAdapter(botFrameworkAuthentication);
28 |
29 | // Catch-all for errors.
30 | const onTurnErrorHandler = async (context, error) => {
31 | // This check writes out errors to console log .vs. app insights.
32 | // NOTE: In production environment, you should consider logging this to Azure
33 | // application insights.
34 | console.error(`\n [onTurnError] unhandled error: ${error}`);
35 |
36 | // Send a trace activity, which will be displayed in Bot Framework Emulator
37 | await context.sendTraceActivity(
38 | "OnTurnError Trace",
39 | `${error}`,
40 | "https://www.botframework.com/schemas/error",
41 | "TurnError"
42 | );
43 |
44 | // Send a message to the user
45 | await context.sendActivity("The bot encountered an error or bug.");
46 | await context.sendActivity("To continue to run this bot, please fix the bot source code.");
47 | };
48 |
49 | // Set the onTurnError for the singleton CloudAdapter.
50 | adapter.onTurnError = onTurnErrorHandler;
51 |
52 | // Create HTTP server.
53 | const server = restify.createServer();
54 | server.use(restify.plugins.bodyParser());
55 |
56 | server.listen(process.env.port || process.env.PORT || 3978, () => {
57 | console.log(`\nBot Started, ${server.name} listening to ${server.url}`);
58 | });
59 |
60 | // Listen for incoming server requests.
61 | server.post("/api/messages", async (req, res) => {
62 | // Route received a request to adapter for processing
63 | await adapter.process(req, res as any, async (context) => {
64 | // Dispatch to application for routing
65 | await app.run(context);
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/teamsapp.local.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/1.0.0/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: 1.0.0
5 |
6 | provision:
7 | # Creates a Teams app
8 | - uses: teamsApp/create
9 | with:
10 | # Teams app name
11 | name: AssistantBot${{APP_NAME_SUFFIX}}
12 | # Write the information of created resources into environment file for
13 | # the specified environment variable(s).
14 | writeToEnvironmentFile:
15 | teamsAppId: TEAMS_APP_ID
16 |
17 | # Create or reuse an existing Microsoft Entra application for bot.
18 | - uses: botAadApp/create
19 | with:
20 | # The Microsoft Entra application's display name
21 | name: AssistantBot${{APP_NAME_SUFFIX}}
22 | writeToEnvironmentFile:
23 | # The Microsoft Entra application's client id created for bot.
24 | botId: BOT_ID
25 | # The Microsoft Entra application's client secret created for bot.
26 | botPassword: SECRET_BOT_PASSWORD
27 |
28 | # Create or update the bot registration on dev.botframework.com
29 | - uses: botFramework/create
30 | with:
31 | botId: ${{BOT_ID}}
32 | name: AssistantBot
33 | messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages
34 | description: ""
35 | channels:
36 | - name: msteams
37 |
38 | # Validate using manifest schema
39 | - uses: teamsApp/validateManifest
40 | with:
41 | # Path to manifest template
42 | manifestPath: ./appPackage/manifest.json
43 |
44 | # Build Teams app package with latest env value
45 | - uses: teamsApp/zipAppPackage
46 | with:
47 | # Path to manifest template
48 | manifestPath: ./appPackage/manifest.json
49 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
50 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
51 | # Validate app package using validation rules
52 | - uses: teamsApp/validateAppPackage
53 | with:
54 | # Relative path to this file. This is the path for built zip file.
55 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
56 |
57 | # Apply the Teams app manifest to an existing Teams app in
58 | # Teams Developer Portal.
59 | # Will use the app id in manifest file to determine which Teams app to update.
60 | - uses: teamsApp/update
61 | with:
62 | # Relative path to this file. This is the path for built zip file.
63 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
64 |
65 | deploy:
66 | # Run npm command
67 | - uses: cli/runNpmCommand
68 | name: install dependencies
69 | with:
70 | args: install --no-audit
71 |
72 | # Generate runtime environment variables
73 | - uses: file/createOrUpdateEnvironmentFile
74 | with:
75 | target: ./.localConfigs
76 | envs:
77 | BOT_ID: ${{BOT_ID}}
78 | BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}}
79 | OPENAI_API_KEY: ${{SECRET_OPENAI_API_KEY}}
80 | OPENAI_ASSISTANT_ID: ${{SECRET_OPENAI_ASSISTANT_ID}}
--------------------------------------------------------------------------------
/03-assistants-api/sample/teamsapp.testtool.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.3/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.3
5 |
6 | deploy:
7 | # Install development tool(s)
8 | - uses: devTool/install
9 | with:
10 | testTool:
11 | version: ~0.1.0-beta
12 | symlinkDir: ./devTools/teamsapptester
13 |
14 | # Run npm command
15 | - uses: cli/runNpmCommand
16 | with:
17 | args: install --no-audit
18 |
19 | # Generate runtime environment variables
20 | - uses: file/createOrUpdateEnvironmentFile
21 | with:
22 | target: ./.localConfigs.testTool
23 | envs:
24 | OPENAI_API_KEY: ${{SECRET_OPENAI_API_KEY}}
25 | OPENAI_ASSISTANT_ID: ${{SECRET_OPENAI_ASSISTANT_ID}}
26 | TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}}
27 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/teamsapp.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/1.0.0/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: 1.0.0
5 |
6 | environmentFolderPath: ./env
7 |
8 | # Triggered when 'teamsfx provision' is executed
9 | provision:
10 | # Creates a Teams app
11 | - uses: teamsApp/create
12 | with:
13 | # Teams app name
14 | name: AssistantBot${{APP_NAME_SUFFIX}}
15 | # Write the information of created resources into environment file for
16 | # the specified environment variable(s).
17 | writeToEnvironmentFile:
18 | teamsAppId: TEAMS_APP_ID
19 |
20 | # Create or reuse an existing Microsoft Entra application for bot.
21 | - uses: botAadApp/create
22 | with:
23 | # The Microsoft Entra application's display name
24 | name: AssistantBot${{APP_NAME_SUFFIX}}
25 | writeToEnvironmentFile:
26 | # The Microsoft Entra application's client id created for bot.
27 | botId: BOT_ID
28 | # The Microsoft Entra application's client secret created for bot.
29 | botPassword: SECRET_BOT_PASSWORD
30 |
31 | - uses: arm/deploy # Deploy given ARM templates parallelly.
32 | with:
33 | # AZURE_SUBSCRIPTION_ID is a built-in environment variable,
34 | # if its value is empty, TeamsFx will prompt you to select a subscription.
35 | # Referencing other environment variables with empty values
36 | # will skip the subscription selection prompt.
37 | subscriptionId: ${{AZURE_SUBSCRIPTION_ID}}
38 | # AZURE_RESOURCE_GROUP_NAME is a built-in environment variable,
39 | # if its value is empty, TeamsFx will prompt you to select or create one
40 | # resource group.
41 | # Referencing other environment variables with empty values
42 | # will skip the resource group selection prompt.
43 | resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}}
44 | templates:
45 | - path: ./infra/azure.bicep # Relative path to this file
46 | # Relative path to this yaml file.
47 | # Placeholders will be replaced with corresponding environment
48 | # variable before ARM deployment.
49 | parameters: ./infra/azure.parameters.json
50 | # Required when deploying ARM template
51 | deploymentName: Create-resources-for-bot
52 | # Teams Toolkit will download this bicep CLI version from github for you,
53 | # will use bicep CLI in PATH if you remove this config.
54 | bicepCliVersion: v0.9.1
55 |
56 | # Validate using manifest schema
57 | - uses: teamsApp/validateManifest
58 | with:
59 | # Path to manifest template
60 | manifestPath: ./appPackage/manifest.json
61 | # Build Teams app package with latest env value
62 | - uses: teamsApp/zipAppPackage
63 | with:
64 | # Path to manifest template
65 | manifestPath: ./appPackage/manifest.json
66 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
67 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
68 | # Validate app package using validation rules
69 | - uses: teamsApp/validateAppPackage
70 | with:
71 | # Relative path to this file. This is the path for built zip file.
72 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
73 | # Apply the Teams app manifest to an existing Teams app in
74 | # Teams Developer Portal.
75 | # Will use the app id in manifest file to determine which Teams app to update.
76 | - uses: teamsApp/update
77 | with:
78 | # Relative path to this file. This is the path for built zip file.
79 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
80 |
81 | # Triggered when 'teamsfx deploy' is executed
82 | deploy:
83 | # Run npm command
84 | - uses: cli/runNpmCommand
85 | name: install dependencies
86 | with:
87 | args: install
88 | - uses: cli/runNpmCommand
89 | name: build app
90 | with:
91 | args: run build --if-present
92 | # Deploy your application to Azure App Service using the zip deploy feature.
93 | # For additional details, refer to https://aka.ms/zip-deploy-to-app-services.
94 | - uses: azureAppService/zipDeploy
95 | with:
96 | # Deploy base folder
97 | artifactFolder: .
98 | # Ignore file location, leave blank will ignore nothing
99 | ignoreFile: .webappignore
100 | # The resource id of the cloud resource to be deployed to.
101 | # This key will be generated by arm/deploy action automatically.
102 | # You can replace it with your existing Azure Resource id
103 | # or add it to your environment variable file.
104 | resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}}
105 |
106 | # Triggered when 'teamsfx publish' is executed
107 | publish:
108 | # Validate using manifest schema
109 | - uses: teamsApp/validateManifest
110 | with:
111 | # Path to manifest template
112 | manifestPath: ./appPackage/manifest.json
113 | # Build Teams app package with latest env value
114 | - uses: teamsApp/zipAppPackage
115 | with:
116 | # Path to manifest template
117 | manifestPath: ./appPackage/manifest.json
118 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
119 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
120 | # Validate app package using validation rules
121 | - uses: teamsApp/validateAppPackage
122 | with:
123 | # Relative path to this file. This is the path for built zip file.
124 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
125 | # Apply the Teams app manifest to an existing Teams app in
126 | # Teams Developer Portal.
127 | # Will use the app id in manifest file to determine which Teams app to update.
128 | - uses: teamsApp/update
129 | with:
130 | # Relative path to this file. This is the path for built zip file.
131 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
132 | # Publish the app to
133 | # Teams Admin Center (https://admin.teams.microsoft.com/policies/manage-apps)
134 | # for review and approval
135 | - uses: teamsApp/publishAppPackage
136 | with:
137 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
138 | # Write the information of created resources into environment file for
139 | # the specified environment variable(s).
140 | writeToEnvironmentFile:
141 | publishedAppId: TEAMS_APP_PUBLISHED_APP_ID
142 | projectId: 4543cfbb-97b4-4afc-86bd-b5e702ebeb5f
143 |
--------------------------------------------------------------------------------
/03-assistants-api/sample/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "target": "es2017",
5 | "module": "commonjs",
6 | "outDir": "./lib",
7 | "rootDir": "./",
8 | "sourceMap": true,
9 | "incremental": true,
10 | "tsBuildInfoFile": "./lib/.tsbuildinfo",
11 | "esModuleInterop": true
12 | }
13 | }
--------------------------------------------------------------------------------
/03-assistants-api/sample/web.config:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/04-rag/README.md:
--------------------------------------------------------------------------------
1 | # Intro to Retrieval-Augmented Generation
2 |
3 | In this section, you'll learn the concept of Retrieval-Augmented Generation (RAG) and its applications.
4 |
5 | ## What is RAG?
6 |
7 | Retrieval-Augmented Generation, short for RAG, is a way for AI to pull in information from a variety of data sources outside of its training data to give better and more informed responses with the generative models.
8 |
9 | - **Retrieval system**: This component searches an external knowledge base to find relevant information.
10 | - **Generative model**: This part of RAG uses the retrieved information to generate responses that are accurate and informative.
11 |
12 | The key advantage of RAG is that it allows the generative model to produce responses that are not only based on its training data but also supplemented with up-to-date information from the knowledge base. This results in more accurate, relevant, and contextually appropriate outputs.
13 |
14 | 
15 |
16 | Imagine you're writing a science-fiction story about a distant planet, but instead of making it all up, you can ask the chatbot with very specific knowledge about the particular planet, and generate the content that you desire.
17 |
18 | Think as the chatbot have the access to a private library that contains books, research papers, and all kinds of information about the universe. It can combine the creativity of Generative AI with the depth of existing knowledge.
19 |
20 | So, **Retrieval**, is when you ask about this planet, GenAI goes into this library and pulls out books about planets, stars, and space travel to gather information.
21 |
22 | Once the relevant information is retrieved, it synthesizes this information, combining it with its own generative capabilities to craft a story. This is the **Augmented Generation** part.
23 |
24 | In reality, when you build a RAG-based app, the data source can be a collection of plain text (such as `.txt`, `.csv` content), or the data come from an API (such as data from `json`, `xml`), or structured database. Or possibly indexed data from a vector search.
25 |
26 | ## 🚀 Retrieve your custom data
27 |
28 | **Now [let's build a custom bot using Azure AI and Teams Toolkit](sample/README.md)!**
29 |
30 | ## 📺 Watch on YouTube
31 |
32 | Watch the video, **Use OpenAI Assistants API to build your own cooking advisor bot on Teams** on YouTube:
33 |
34 | [](https://youtu.be/1k4XGgsqfTM?si=909QFuvEcSfwo7rh)
35 |
36 | [Subscribe us!](https://www.youtube.com/channel/UCV_6HOhwxYLXAGd-JOqKPoQ?sub_confirmation=1)
--------------------------------------------------------------------------------
/04-rag/sample/.gitignore:
--------------------------------------------------------------------------------
1 | # TeamsFx files
2 | env/.env.*.user
3 | env/.env.local
4 | env/.env.testtool
5 | .env
6 | appPackage/build
7 |
8 | # python virtual environment
9 | .venv/
10 | __pycache__/
11 |
12 | # others
13 | .deployment/
14 | node_modules/
15 |
16 | # Dev tool directories
17 | /devTools/
--------------------------------------------------------------------------------
/04-rag/sample/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "TeamsDevApp.ms-teams-vscode-extension",
4 | "ms-python.python"
5 | ]
6 | }
--------------------------------------------------------------------------------
/04-rag/sample/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Launch Remote in Teams (Edge)",
6 | "type": "msedge",
7 | "request": "launch",
8 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
9 | "presentation": {
10 | "group": "group 1: Teams",
11 | "order": 3
12 | },
13 | "internalConsoleOptions": "neverOpen"
14 | },
15 | {
16 | "name": "Launch Remote in Teams (Chrome)",
17 | "type": "chrome",
18 | "request": "launch",
19 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
20 | "presentation": {
21 | "group": "group 1: Teams",
22 | "order": 3
23 | },
24 | "internalConsoleOptions": "neverOpen"
25 | },
26 | {
27 | "name": "Launch App (Edge)",
28 | "type": "msedge",
29 | "request": "launch",
30 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
31 | "presentation": {
32 | "group": "all",
33 | "hidden": true
34 | },
35 | "internalConsoleOptions": "neverOpen"
36 | },
37 | {
38 | "name": "Launch App (Chrome)",
39 | "type": "chrome",
40 | "request": "launch",
41 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
42 | "presentation": {
43 | "group": "all",
44 | "hidden": true
45 | },
46 | "internalConsoleOptions": "neverOpen"
47 | },
48 | {
49 | "name": "Start Python",
50 | "type": "debugpy",
51 | "program": "${workspaceFolder}/src/app.py",
52 | "request": "launch",
53 | "cwd": "${workspaceFolder}/src/",
54 | "console": "integratedTerminal",
55 | },
56 | {
57 | "name": "Start Test Tool",
58 | "type": "node",
59 | "request": "launch",
60 | "program": "${workspaceFolder}/devTools/teamsapptester/node_modules/@microsoft/teams-app-test-tool/cli.js",
61 | "args": [
62 | "start",
63 | ],
64 | "cwd": "${workspaceFolder}",
65 | "console": "integratedTerminal",
66 | "internalConsoleOptions": "neverOpen"
67 | }
68 | ],
69 | "compounds": [
70 | {
71 | "name": "Debug in Teams (Edge)",
72 | "configurations": [
73 | "Launch App (Edge)",
74 | "Start Python"
75 | ],
76 | "cascadeTerminateToConfigurations": [
77 | "Start Python"
78 | ],
79 | "preLaunchTask": "Start Teams App Locally",
80 | "presentation": {
81 | "group": "2-local",
82 | "order": 1
83 | },
84 | "stopAll": true
85 | },
86 | {
87 | "name": "Debug in Teams (Chrome)",
88 | "configurations": [
89 | "Launch App (Chrome)",
90 | "Start Python"
91 | ],
92 | "cascadeTerminateToConfigurations": [
93 | "Start Python"
94 | ],
95 | "preLaunchTask": "Start Teams App Locally",
96 | "presentation": {
97 | "group": "2-local",
98 | "order": 2
99 | },
100 | "stopAll": true
101 | },
102 | {
103 | "name": "Debug in Test Tool (Preview)",
104 | "configurations": [
105 | "Start Python",
106 | "Start Test Tool",
107 | ],
108 | "cascadeTerminateToConfigurations": [
109 | "Start Test Tool"
110 | ],
111 | "preLaunchTask": "Deploy (Test Tool)",
112 | "presentation": {
113 | "group": "1-local",
114 | "order": 1
115 | },
116 | "stopAll": true
117 | }
118 | ]
119 | }
--------------------------------------------------------------------------------
/04-rag/sample/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "debug.onTaskErrors": "abort",
3 | "json.schemas": [
4 | {
5 | "fileMatch": [
6 | "/aad.*.json"
7 | ],
8 | "schema": {}
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/04-rag/sample/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // This file is automatically generated by Teams Toolkit.
2 | // The teamsfx tasks defined in this file require Teams Toolkit version >= 5.0.0.
3 | // See https://aka.ms/teamsfx-tasks for details on how to customize each task.
4 | {
5 | "version": "2.0.0",
6 | "tasks": [
7 | {
8 | // Check all required prerequisites.
9 | // See https://aka.ms/teamsfx-tasks/check-prerequisites to know the details and how to customize the args.
10 | "label": "Validate prerequisites (Test Tool)",
11 | "type": "teamsfx",
12 | "command": "debug-check-prerequisites",
13 | "args": {
14 | "prerequisites": [
15 | "nodejs", // Check if Node.js is installed and the version is >= 12.
16 | "portOccupancy" // Validate available ports to ensure those debug ones are not occupied.
17 | ],
18 | "portOccupancy": [
19 | 3978, // app service port
20 | 56150, // test tool port
21 | ]
22 | }
23 | },
24 | {
25 | // Build project.
26 | // See https://aka.ms/teamsfx-tasks/deploy to know the details and how to customize the args.
27 | "label": "Deploy (Test Tool)",
28 | "dependsOn": [
29 | "Validate prerequisites (Test Tool)"
30 | ],
31 | "type": "teamsfx",
32 | "command": "deploy",
33 | "args": {
34 | "env": "testtool",
35 | }
36 | },
37 | {
38 | "label": "Start Teams App Locally",
39 | "dependsOn": [
40 | "Validate prerequisites",
41 | "Start local tunnel",
42 | "Provision",
43 | "Deploy"
44 | ],
45 | "dependsOrder": "sequence"
46 | },
47 | {
48 | // Check all required prerequisites.
49 | // See https://aka.ms/teamsfx-tasks/check-prerequisites to know the details and how to customize the args.
50 | "label": "Validate prerequisites",
51 | "type": "teamsfx",
52 | "command": "debug-check-prerequisites",
53 | "args": {
54 | "prerequisites": [
55 | "m365Account", // Sign-in prompt for Microsoft 365 account, then validate if the account enables the sideloading permission.
56 | "portOccupancy" // Validate available ports to ensure those debug ones are not occupied.
57 | ],
58 | "portOccupancy": [
59 | 3978 // app service port
60 | ]
61 | }
62 | },
63 | {
64 | // Start the local tunnel service to forward public URL to local port and inspect traffic.
65 | // See https://aka.ms/teamsfx-tasks/local-tunnel for the detailed args definitions.
66 | "label": "Start local tunnel",
67 | "type": "teamsfx",
68 | "command": "debug-start-local-tunnel",
69 | "args": {
70 | "type": "dev-tunnel",
71 | "ports": [
72 | {
73 | "portNumber": 3978,
74 | "protocol": "http",
75 | "access": "public",
76 | "writeToEnvironmentFile": {
77 | "endpoint": "BOT_ENDPOINT", // output tunnel endpoint as BOT_ENDPOINT
78 | "domain": "BOT_DOMAIN" // output tunnel domain as BOT_DOMAIN
79 | }
80 | }
81 | ],
82 | "env": "local"
83 | },
84 | "isBackground": true,
85 | "problemMatcher": "$teamsfx-local-tunnel-watch"
86 | },
87 | {
88 | // Create the debug resources.
89 | // See https://aka.ms/teamsfx-tasks/provision to know the details and how to customize the args.
90 | "label": "Provision",
91 | "type": "teamsfx",
92 | "command": "provision",
93 | "args": {
94 | "env": "local"
95 | }
96 | },
97 | {
98 | // Build project.
99 | // See https://aka.ms/teamsfx-tasks/deploy to know the details and how to customize the args.
100 | "label": "Deploy",
101 | "type": "teamsfx",
102 | "command": "deploy",
103 | "args": {
104 | "env": "local"
105 | }
106 | }
107 | ]
108 | }
--------------------------------------------------------------------------------
/04-rag/sample/.webappignore:
--------------------------------------------------------------------------------
1 | .venv/
2 | .vscode/
3 | appPackage/
4 | devTools/
5 | infra/
6 | .env
7 | env/
8 | __pycache__/
9 | README.md
10 | teamsapp.yml
11 | teamsapp.local.yml
12 | teamsapp.testtool.yml
13 | .gitignore
14 |
15 | indexers/
--------------------------------------------------------------------------------
/04-rag/sample/README.md:
--------------------------------------------------------------------------------
1 | # Overview of the Space AI Search sample
2 |
3 | This template showcases the Space AI Search sample that responds to user questions like an AI assistant according to your space data from Azure AI Search. This enables your users to talk with the AI assistant in Teams to find information.
4 |
5 | The app template is built using the Teams AI library, which provides the capabilities to build AI-based Teams applications.
6 |
7 | ## Get started with the Space AI Search sample
8 |
9 | > **Prerequisites**
10 | >
11 | > To run the sample in your local dev machine, you will need:
12 | >
13 | > - [Python](https://www.python.org/), version 3.8 to 3.11.
14 | > - [Python extension](https://code.visualstudio.com/docs/languages/python), version v2024.0.1 or higher.
15 | > - [Teams Toolkit Visual Studio Code Extension](https://aka.ms/teams-toolkit) latest version or [Teams Toolkit CLI](https://aka.ms/teamsfx-cli).
16 | > - An account with [Azure OpenAI](https://aka.ms/oai/access).
17 | > - An [Azure AI Search service](https://learn.microsoft.com/en-us/azure/search/search-what-is-azure-search) and an [Azure OpenAI Service](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource).
18 | > - [Node.js](https://nodejs.org/) (supported versions: 16, 18) for local debug in Test Tool.
19 |
20 | ### Configurations
21 | 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.
22 | 1. In **env** folder, create a file **env/.env.testtool**, and paste the following snippet in the file
23 | ```
24 | TEAMSFX_ENV=testtool
25 | TEAMSAPPTESTER_PORT=56150
26 | TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json
27 | ```
28 | 1.In **env** folder, create a file **env/.env.testtool.user**, and paste the following snippet in the file and fill the required environment variables:
29 | ```
30 | SECRET_BOT_PASSWORD=
31 | SECRET_AZURE_OPENAI_API_KEY=''
32 | AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=''
33 | AZURE_OPENAI_ENDPOINT=''
34 | AZURE_OPENAI_EMBEDDING_DEPLOYMENT=''
35 |
36 | SECRET_AZURE_SEARCH_KEY=''
37 | AZURE_SEARCH_ENDPOINT=''
38 | ```
39 |
40 | ### Setting up index and documents
41 | 1. Open the terminal in the project root and use command `python src/indexers/setup.py` to create index and upload documents in `src/indexers/data`.
42 | 1. You will see the following information indicated the success of setup:
43 | ```
44 | Create index succeeded. If it does not exist, wait for 5 seconds...
45 | Upload new documents succeeded. If they do not exist, wait for several seconds...
46 | setup finished
47 | ```
48 | 1. Once you're done using the sample it's good practice to delete the index. You can do so with the command `python src/indexers/delete.py`.
49 |
50 | ### Conversation with Space AI Search
51 | 1. Select the Teams Toolkit icon on the left in the VS Code toolbar.
52 | 1. Press F5 to start debugging which launches your app in Teams App Test Tool using a web browser. Select `Debug in Test Tool (Preview)`.
53 | 1. Type "Hi" or similar and you will receive a welcome message from the bot, or send any message to get a response.
54 |
55 | **Congratulations**! You are running the Space AI Search that can now interact with users:
56 |
57 | 
--------------------------------------------------------------------------------
/04-rag/sample/appPackage/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/appPackage/color.png
--------------------------------------------------------------------------------
/04-rag/sample/appPackage/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
3 | "manifestVersion": "1.16",
4 | "version": "1.0.0",
5 | "id": "${{TEAMS_APP_ID}}",
6 | "packageName": "com.microsoft.teams.extension",
7 | "developer": {
8 | "name": "Teams App, Inc.",
9 | "websiteUrl": "https://www.example.com",
10 | "privacyUrl": "https://www.example.com/privacy",
11 | "termsOfUseUrl": "https://www.example.com/termofuse"
12 | },
13 | "icons": {
14 | "color": "color.png",
15 | "outline": "outline.png"
16 | },
17 | "name": {
18 | "short": "space-ai-search${{APP_NAME_SUFFIX}}",
19 | "full": "full name for space-ai-search"
20 | },
21 | "description": {
22 | "short": "short description for space-ai-search",
23 | "full": "full description for space-ai-search"
24 | },
25 | "accentColor": "#FFFFFF",
26 | "bots": [
27 | {
28 | "botId": "${{BOT_ID}}",
29 | "scopes": [
30 | "personal",
31 | "team",
32 | "groupchat"
33 | ],
34 | "supportsFiles": false,
35 | "isNotificationOnly": false
36 | }
37 | ],
38 | "composeExtensions": [],
39 | "configurableTabs": [],
40 | "staticTabs": [],
41 | "permissions": [
42 | "identity",
43 | "messageTeamMembers"
44 | ],
45 | "validDomains": []
46 | }
47 |
--------------------------------------------------------------------------------
/04-rag/sample/appPackage/outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/appPackage/outline.png
--------------------------------------------------------------------------------
/04-rag/sample/env/.env.dev:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that will be committed to git by default.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=dev
5 | APP_NAME_SUFFIX=dev
6 |
7 | # Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups.
8 | AZURE_SUBSCRIPTION_ID=
9 | AZURE_RESOURCE_GROUP_NAME=
10 | RESOURCE_SUFFIX=
11 |
12 | # Generated during provision, you can also add your own variables.
13 | BOT_ID=
14 | TEAMS_APP_ID=
15 | TEAMS_APP_TENANT_ID=
16 | BOT_AZURE_APP_SERVICE_RESOURCE_ID=
17 | BOT_DOMAIN=
--------------------------------------------------------------------------------
/04-rag/sample/env/.env.testtool.sample:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=testtool
5 |
6 | # Environment variables used by test tool
7 | TEAMSAPPTESTER_PORT=56150
8 | TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json
--------------------------------------------------------------------------------
/04-rag/sample/env/.env.testtool.user.sample:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project.
2 |
3 | # If you're adding a secret value, add SECRET_ prefix to the name so Teams Toolkit can handle them properly
4 | # Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs.
5 | SECRET_BOT_PASSWORD=
6 | SECRET_AZURE_OPENAI_API_KEY=''
7 | AZURE_OPENAI_MODEL_DEPLOYMENT_NAME=''
8 | AZURE_OPENAI_ENDPOINT=''
9 | AZURE_OPENAI_EMBEDDING_DEPLOYMENT=''
10 |
11 | SECRET_AZURE_SEARCH_KEY=''
12 | AZURE_SEARCH_ENDPOINT=''
--------------------------------------------------------------------------------
/04-rag/sample/infra/azure.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | @description('Required when create Azure Bot service')
7 | param botAadAppClientId string
8 |
9 | @secure()
10 | @description('Required by Bot Framework package in your bot project')
11 | param botAadAppClientSecret string
12 |
13 | @secure()
14 | @description('Required in your bot project to access Azure OpenAI service. You can get it from Azure Portal > OpenAI > Keys > Key1 > Resource Management > Endpoint')
15 | param azureOpenaiKey string
16 | param azureOpenaiModelDeploymentName string
17 | param azureOpenaiEndpoint string
18 | param azureOpenaiEmbeddingDeployment string
19 |
20 | @secure()
21 | @description('Required in your bot project to access Azure Search service. You can get it from Azure Portal > Azure Search > Keys > Admin Key')
22 | param azureSearchKey string
23 | param azureSearchEndpoint string
24 |
25 | param webAppSKU string
26 | param linuxFxVersion string
27 |
28 | @maxLength(42)
29 | param botDisplayName string
30 |
31 | param serverfarmsName string = resourceBaseName
32 | param webAppName string = resourceBaseName
33 | param location string = resourceGroup().location
34 | param pythonVersion string = linuxFxVersion
35 |
36 | // Compute resources for your Web App
37 | resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = {
38 | kind: 'app,linux'
39 | location: location
40 | name: serverfarmsName
41 | sku: {
42 | name: webAppSKU
43 | }
44 | properties:{
45 | reserved: true
46 | }
47 | }
48 |
49 | // Web App that hosts your bot
50 | resource webApp 'Microsoft.Web/sites@2021-02-01' = {
51 | kind: 'app,linux'
52 | location: location
53 | name: webAppName
54 | properties: {
55 | serverFarmId: serverfarm.id
56 | siteConfig: {
57 | alwaysOn: true
58 | appCommandLine: 'gunicorn --bind 0.0.0.0 --worker-class aiohttp.worker.GunicornWebWorker --timeout 600 app:app'
59 | linuxFxVersion: pythonVersion
60 | appSettings: [
61 | {
62 | name: 'WEBSITES_CONTAINER_START_TIME_LIMIT'
63 | value: '600'
64 | }
65 | {
66 | name: 'SCM_DO_BUILD_DURING_DEPLOYMENT'
67 | value: 'true'
68 | }
69 | {
70 | name: 'BOT_ID'
71 | value: botAadAppClientId
72 | }
73 | {
74 | name: 'BOT_PASSWORD'
75 | value: botAadAppClientSecret
76 | }
77 | {
78 | name: 'AZURE_OPENAI_API_KEY'
79 | value: azureOpenaiKey
80 | }
81 | {
82 | name: 'AZURE_OPENAI_MODEL_DEPLOYMENT_NAME'
83 | value: azureOpenaiModelDeploymentName
84 | }
85 | {
86 | name: 'AZURE_OPENAI_ENDPOINT'
87 | value: azureOpenaiEndpoint
88 | }
89 | {
90 | name: 'AZURE_OPENAI_EMBEDDING_DEPLOYMENT'
91 | value: azureOpenaiEmbeddingDeployment
92 | }
93 | {
94 | name: 'AZURE_SEARCH_KEY'
95 | value: azureSearchKey
96 | }
97 | {
98 | name: 'AZURE_SEARCH_ENDPOINT'
99 | value: azureSearchEndpoint
100 | }
101 | ]
102 | ftpsState: 'FtpsOnly'
103 | }
104 | }
105 | }
106 |
107 | // Register your web service as a bot with the Bot Framework
108 | module azureBotRegistration './botRegistration/azurebot.bicep' = {
109 | name: 'Azure-Bot-registration'
110 | params: {
111 | resourceBaseName: resourceBaseName
112 | botAadAppClientId: botAadAppClientId
113 | botAppDomain: webApp.properties.defaultHostName
114 | botDisplayName: botDisplayName
115 | }
116 | }
117 |
118 | // The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details.
119 | output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id
120 | output BOT_DOMAIN string = webApp.properties.defaultHostName
121 |
--------------------------------------------------------------------------------
/04-rag/sample/infra/azure.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "resourceBaseName": {
6 | "value": "bot${{RESOURCE_SUFFIX}}"
7 | },
8 | "botAadAppClientId": {
9 | "value": "${{BOT_ID}}"
10 | },
11 | "botAadAppClientSecret": {
12 | "value": "${{SECRET_BOT_PASSWORD}}"
13 | },
14 | "azureOpenaiKey": {
15 | "value": "${{SECRET_AZURE_OPENAI_API_KEY}}"
16 | },
17 | "azureOpenaiModelDeploymentName" : {
18 | "value": "${{AZURE_OPENAI_MODEL_DEPLOYMENT_NAME}}"
19 | },
20 | "azureOpenaiEndpoint" : {
21 | "value": "${{AZURE_OPENAI_ENDPOINT}}"
22 | },
23 | "azureOpenaiEmbeddingDeployment" : {
24 | "value": "${{AZURE_OPENAI_EMBEDDING_DEPLOYMENT}}"
25 | },
26 | "azureSearchKey": {
27 | "value": "${{SECRET_AZURE_SEARCH_KEY}}"
28 | },
29 | "azureSearchEndpoint": {
30 | "value": "${{AZURE_SEARCH_ENDPOINT}}"
31 | },
32 | "webAppSKU": {
33 | "value": "B1"
34 | },
35 | "botDisplayName": {
36 | "value": "AISearch-py"
37 | },
38 | "linuxFxVersion": {
39 | "value": "PYTHON|3.11"
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/04-rag/sample/infra/botRegistration/azurebot.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | @maxLength(42)
7 | param botDisplayName string
8 |
9 | param botServiceName string = resourceBaseName
10 | param botServiceSku string = 'F0'
11 | param botAadAppClientId string
12 | param botAppDomain string
13 |
14 | // Register your web service as a bot with the Bot Framework
15 | resource botService 'Microsoft.BotService/botServices@2021-03-01' = {
16 | kind: 'azurebot'
17 | location: 'global'
18 | name: botServiceName
19 | properties: {
20 | displayName: botDisplayName
21 | endpoint: 'https://${botAppDomain}/api/messages'
22 | msaAppId: botAadAppClientId
23 | }
24 | sku: {
25 | name: botServiceSku
26 | }
27 | }
28 |
29 | // Connect the bot service to Microsoft Teams
30 | resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = {
31 | parent: botService
32 | location: 'global'
33 | name: 'MsTeamsChannel'
34 | properties: {
35 | channelName: 'MsTeamsChannel'
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/04-rag/sample/infra/botRegistration/readme.md:
--------------------------------------------------------------------------------
1 | The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again.
--------------------------------------------------------------------------------
/04-rag/sample/src/app.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) Microsoft Corporation. All rights reserved.
3 | Licensed under the MIT License.
4 | """
5 |
6 | import asyncio
7 | from http import HTTPStatus
8 | from aiohttp import web
9 | from botbuilder.core.integration import aiohttp_error_middleware
10 |
11 | from bot import bot_app
12 |
13 | routes = web.RouteTableDef()
14 |
15 | @routes.post("/api/messages")
16 | async def on_messages(req: web.Request) -> web.Response:
17 | res = await bot_app.process(req)
18 |
19 | if res is not None:
20 | return res
21 |
22 | return web.Response(status=HTTPStatus.OK)
23 |
24 | app = web.Application(middlewares=[aiohttp_error_middleware])
25 | app.add_routes(routes)
26 |
27 | from config import Config
28 |
29 | if __name__ == "__main__":
30 | web.run_app(app, host="localhost", port=Config.PORT)
--------------------------------------------------------------------------------
/04-rag/sample/src/azure_ai_search_data_source.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import Optional, List
3 | from azure.search.documents.indexes.models import _edm as EDM
4 | from azure.search.documents.models import VectorQuery, VectorizedQuery
5 | from teams.ai.embeddings import AzureOpenAIEmbeddings, AzureOpenAIEmbeddingsOptions
6 | from teams.state.memory import Memory
7 | from teams.state.state import TurnContext
8 | from teams.ai.tokenizers import Tokenizer
9 | from teams.ai.data_sources import DataSource
10 |
11 | from config import Config
12 |
13 | async def get_embedding_vector(text: str):
14 | embeddings = AzureOpenAIEmbeddings(AzureOpenAIEmbeddingsOptions(
15 | azure_api_key=Config.AZURE_OPENAI_API_KEY,
16 | azure_endpoint=Config.AZURE_OPENAI_ENDPOINT,
17 | azure_deployment=Config.AZURE_OPENAI_EMBEDDING_DEPLOYMENT
18 | ))
19 |
20 | result = await embeddings.create_embeddings(text)
21 | if (result.status != 'success' or not result.output):
22 | raise Exception(f"Failed to generate embeddings for description: {text}")
23 |
24 | return result.output[0]
25 |
26 | @dataclass
27 | class Doc:
28 | docId: Optional[str] = None
29 | docTitle: Optional[str] = None
30 | description: Optional[str] = None
31 | descriptionVector: Optional[List[float]] = None
32 |
33 | @dataclass
34 | class AzureAISearchDataSourceOptions:
35 | name: str
36 | indexName: str
37 | azureAISearchApiKey: str
38 | azureAISearchEndpoint: str
39 |
40 | from azure.core.credentials import AzureKeyCredential
41 | from azure.search.documents import SearchClient
42 | import json
43 |
44 | @dataclass
45 | class Result:
46 | def __init__(self, output, length, too_long):
47 | self.output = output
48 | self.length = length
49 | self.too_long = too_long
50 |
51 | class AzureAISearchDataSource(DataSource):
52 | def __init__(self, options: AzureAISearchDataSourceOptions):
53 | self.name = options.name
54 | self.options = options
55 | self.searchClient = SearchClient(
56 | options.azureAISearchEndpoint,
57 | options.indexName,
58 | AzureKeyCredential(options.azureAISearchApiKey)
59 | )
60 |
61 | def name(self):
62 | return self.name
63 |
64 | async def render_data(self, _context: TurnContext, memory: Memory, tokenizer: Tokenizer, maxTokens: int):
65 | query = memory.get('temp.input')
66 | embedding = await get_embedding_vector(query)
67 | vector_query = VectorizedQuery(vector=embedding, k_nearest_neighbors=2, fields="descriptionVector")
68 |
69 | if not query:
70 | return Result('', 0, False)
71 |
72 | selectedFields = [
73 | 'docTitle',
74 | 'description',
75 | 'descriptionVector',
76 | ]
77 |
78 | searchResults = self.searchClient.search(
79 | search_text=query,
80 | select=selectedFields,
81 | vector_queries=[vector_query],
82 | )
83 |
84 | if not searchResults:
85 | return Result('', 0, False)
86 |
87 | usedTokens = 0
88 | doc = ''
89 | for result in searchResults:
90 | tokens = len(tokenizer.encode(json.dumps(result["description"])))
91 |
92 | if usedTokens + tokens > maxTokens:
93 | break
94 |
95 | doc += json.dumps(result["description"])
96 | usedTokens += tokens
97 |
98 | return Result(doc, usedTokens, usedTokens > maxTokens)
--------------------------------------------------------------------------------
/04-rag/sample/src/bot.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from dataclasses import dataclass
3 | import json
4 | import os
5 | import sys
6 | import traceback
7 | from typing import Generic, TypeVar
8 |
9 | from botbuilder.core import MemoryStorage, TurnContext
10 | from teams import Application, ApplicationOptions, TeamsAdapter
11 | from teams.ai import AIOptions
12 | from teams.ai.models import AzureOpenAIModelOptions, OpenAIModel, OpenAIModelOptions
13 | from teams.ai.planners import ActionPlanner, ActionPlannerOptions
14 | from teams.ai.prompts import PromptManager, PromptManagerOptions
15 | from teams.ai.actions import ActionTypes
16 | from teams.state import TurnState
17 |
18 | from azure_ai_search_data_source import AzureAISearchDataSource, AzureAISearchDataSourceOptions
19 | from config import Config
20 |
21 | config = Config()
22 |
23 | # Create AI components
24 | model: OpenAIModel
25 |
26 | model = OpenAIModel(
27 | AzureOpenAIModelOptions(
28 | api_key=config.AZURE_OPENAI_API_KEY,
29 | default_model=config.AZURE_OPENAI_MODEL_DEPLOYMENT_NAME,
30 | endpoint=config.AZURE_OPENAI_ENDPOINT,
31 | )
32 | )
33 |
34 | prompts = PromptManager(PromptManagerOptions(prompts_folder=f"{os.getcwd()}/prompts"))
35 |
36 | prompts.add_data_source(
37 | AzureAISearchDataSource(
38 | AzureAISearchDataSourceOptions(
39 | name='azure-ai-search',
40 | indexName='space-facts-index',
41 | azureAISearchApiKey=config.AZURE_SEARCH_KEY,
42 | azureAISearchEndpoint=config.AZURE_SEARCH_ENDPOINT,
43 | )
44 | )
45 | )
46 |
47 | planner = ActionPlanner(
48 | ActionPlannerOptions(model=model, prompts=prompts, default_prompt="chat")
49 | )
50 |
51 | # Define storage and application
52 | storage = MemoryStorage()
53 | bot_app = Application[TurnState](
54 | ApplicationOptions(
55 | bot_app_id=config.APP_ID,
56 | storage=storage,
57 | adapter=TeamsAdapter(config),
58 | ai=AIOptions(planner=planner),
59 | )
60 | )
61 |
62 | @bot_app.conversation_update("membersAdded")
63 | async def on_members_added(context: TurnContext, state: TurnState):
64 | await context.send_activity("How can I help you today?")
65 |
66 | @bot_app.error
67 | async def on_error(context: TurnContext, error: Exception):
68 | # This check writes out errors to console log .vs. app insights.
69 | # NOTE: In production environment, you should consider logging this to Azure
70 | # application insights.
71 | print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
72 | traceback.print_exc()
73 |
74 | # Send a message to the user
75 | await context.send_activity("The bot encountered an error or bug.")
--------------------------------------------------------------------------------
/04-rag/sample/src/config.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) Microsoft Corporation. All rights reserved.
3 | Licensed under the MIT License.
4 | """
5 |
6 | import os
7 |
8 | from dotenv import load_dotenv
9 |
10 | load_dotenv()
11 |
12 | class Config:
13 | """Bot Configuration"""
14 |
15 | PORT = 3978
16 | APP_ID = os.environ.get("BOT_ID", "")
17 | APP_PASSWORD = os.environ.get("BOT_PASSWORD", "")
18 | AZURE_OPENAI_API_KEY = os.environ["AZURE_OPENAI_API_KEY"] # Azure OpenAI API key
19 | AZURE_OPENAI_MODEL_DEPLOYMENT_NAME = os.environ["AZURE_OPENAI_MODEL_DEPLOYMENT_NAME"] # Azure OpenAI model deployment name
20 | AZURE_OPENAI_ENDPOINT = os.environ["AZURE_OPENAI_ENDPOINT"] # Azure OpenAI endpoint
21 | AZURE_OPENAI_EMBEDDING_DEPLOYMENT = os.environ["AZURE_OPENAI_EMBEDDING_DEPLOYMENT"] # Azure OpenAI embedding deployment
22 | AZURE_SEARCH_KEY = os.environ["AZURE_SEARCH_KEY"] # Azure Search key
23 | AZURE_SEARCH_ENDPOINT = os.environ["AZURE_SEARCH_ENDPOINT"] # Azure Search endpoint
24 |
25 |
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Earth.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Earth.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Interplanetary_spaceflight.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Interplanetary_spaceflight.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Jupiter.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Jupiter.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Mars.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Mars.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Mercury.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Mercury.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Neptune.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Neptune.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Pluto.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Pluto.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Saturn.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Saturn.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Star.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Star.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Uranus.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Uranus.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/data/Venus.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/04-rag/sample/src/indexers/data/Venus.pdf
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/delete.py:
--------------------------------------------------------------------------------
1 | import os
2 | from azure.core.credentials import AzureKeyCredential
3 | from azure.search.documents.indexes import SearchIndexClient
4 |
5 | from dotenv import load_dotenv
6 |
7 | load_dotenv(f'{os.getcwd()}/env/.env.testtool.user')
8 |
9 | def delete_index(client: SearchIndexClient, name: str):
10 | client.delete_index(name)
11 | print(f"Index {name} deleted")
12 |
13 | index = 'contoso-electronics'
14 | search_api_key = os.getenv('SECRET_AZURE_SEARCH_KEY')
15 | search_api_endpoint = os.getenv('AZURE_SEARCH_ENDPOINT')
16 | credentials = AzureKeyCredential(search_api_key)
17 |
18 | search_index_client = SearchIndexClient(search_api_endpoint, credentials)
19 | delete_index(search_index_client, index)
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/get_data.py:
--------------------------------------------------------------------------------
1 | import os
2 | import PyPDF2
3 | async def get_doc_data(embeddings):
4 | file_names = [
5 | "Earth", "Jupiter", "Mars", "Mercury", "Neptune",
6 | "Pluto", "Saturn", "Uranus", "Venus", "Star", "Interplanetary_spaceflight"
7 | ]
8 | docs = []
9 | for name in file_names:
10 | file_path = os.path.join(os.getcwd(), f"src/indexers/data/{name}.pdf")
11 | with open(file_path, 'rb') as file: # Correct mode 'rb' for binary read
12 | reader = PyPDF2.PdfReader(file)
13 | raw_description = reader.pages[0].extract_text() or ""
14 | doc = {
15 | "docId": str(file_names.index(name) + 1),
16 | "docTitle": name,
17 | "description": raw_description,
18 | "descriptionVector": await get_embedding_vector(raw_description, embeddings=embeddings),
19 | }
20 | docs.append(doc)
21 | return docs
22 |
23 |
24 | async def get_embedding_vector(text: str, embeddings):
25 | result = await embeddings.create_embeddings(text)
26 | if (result.status != 'success' or not result.output):
27 | if result.status == 'error':
28 | raise Exception(f"Failed to generate embeddings for description: <{text[:200]+'...'}>\n\nError: {result.output}")
29 | raise Exception(f"Failed to generate embeddings for description: <{text[:200]+'...'}>")
30 |
31 | return result.output[0]
--------------------------------------------------------------------------------
/04-rag/sample/src/indexers/setup.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import os
3 | from dataclasses import dataclass
4 | from typing import List, Optional
5 |
6 | from azure.core.credentials import AzureKeyCredential
7 | from azure.search.documents import SearchClient
8 | from azure.search.documents.indexes import SearchIndexClient
9 | from azure.search.documents.indexes.models import (
10 | SearchIndex,
11 | SimpleField,
12 | SearchableField,
13 | SearchField,
14 | SearchFieldDataType,
15 | ComplexField,
16 | CorsOptions,
17 | VectorSearch,
18 | VectorSearchProfile,
19 | HnswAlgorithmConfiguration
20 | )
21 | from teams.ai.embeddings import AzureOpenAIEmbeddings, AzureOpenAIEmbeddingsOptions
22 |
23 | from get_data import get_doc_data
24 |
25 | from dotenv import load_dotenv
26 |
27 | load_dotenv(f'{os.getcwd()}/env/.env.testtool.user')
28 |
29 | @dataclass
30 | class Doc:
31 | docId: Optional[str] = None
32 | docTitle: Optional[str] = None
33 | description: Optional[str] = None
34 | descriptionVector: Optional[List[float]] = None
35 |
36 | async def upsert_documents(client: SearchClient, documents: list[Doc]):
37 | return client.merge_or_upload_documents(documents)
38 |
39 | async def create_index_if_not_exists(client: SearchIndexClient, name: str):
40 | doc_index = SearchIndex(
41 | name=name,
42 | fields = [
43 | SimpleField(name="docId", type=SearchFieldDataType.String, key=True),
44 | SimpleField(name="docTitle", type=SearchFieldDataType.String),
45 | SearchableField(name="description", type=SearchFieldDataType.String, searchable=True),
46 | SearchField(name="descriptionVector", type=SearchFieldDataType.Collection(SearchFieldDataType.Single), searchable=True, vector_search_dimensions=1536, vector_search_profile_name='my-vector-config'),
47 | ],
48 | scoring_profiles=[],
49 | cors_options=CorsOptions(allowed_origins=["*"]),
50 | vector_search = VectorSearch(
51 | profiles=[VectorSearchProfile(name="my-vector-config", algorithm_configuration_name="my-algorithms-config")],
52 | algorithms=[HnswAlgorithmConfiguration(name="my-algorithms-config")],
53 | )
54 | )
55 |
56 | client.create_or_update_index(doc_index)
57 |
58 | async def setup(search_api_key, search_api_endpoint):
59 | index = 'space-facts-index'
60 |
61 | credentials = AzureKeyCredential(search_api_key)
62 |
63 | search_index_client = SearchIndexClient(search_api_endpoint, credentials)
64 | await create_index_if_not_exists(search_index_client, index)
65 |
66 | print("Create index succeeded. If it does not exist, wait for 5 seconds...")
67 | await asyncio.sleep(5)
68 |
69 | search_client = SearchClient(search_api_endpoint, index, credentials)
70 |
71 | embeddings = AzureOpenAIEmbeddings(AzureOpenAIEmbeddingsOptions(
72 | azure_api_key=os.getenv('SECRET_AZURE_OPENAI_API_KEY'),
73 | azure_endpoint=os.getenv('AZURE_OPENAI_ENDPOINT'),
74 | azure_deployment=os.getenv('AZURE_OPENAI_EMBEDDING_DEPLOYMENT')
75 | ))
76 | data = await get_doc_data(embeddings=embeddings)
77 | await upsert_documents(search_client, data)
78 |
79 | print("Upload new documents succeeded. If they do not exist, wait for several seconds...")
80 |
81 | search_api_key = os.getenv('SECRET_AZURE_SEARCH_KEY')
82 | search_api_endpoint = os.getenv('AZURE_SEARCH_ENDPOINT')
83 | asyncio.run(setup(search_api_key, search_api_endpoint))
84 | print("setup finished")
85 |
86 |
--------------------------------------------------------------------------------
/04-rag/sample/src/prompts/chat/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": 1.1,
3 | "description": "Chat with Teams RAG",
4 | "type": "completion",
5 | "completion": {
6 | "completion_type": "chat",
7 | "include_history": true,
8 | "include_input": true,
9 | "max_input_tokens": 4096,
10 | "max_tokens": 1000,
11 | "temperature": 0.9,
12 | "top_p": 0.0,
13 | "presence_penalty": 0.6,
14 | "frequency_penalty": 0.0,
15 | "stop_sequences": []
16 | },
17 | "augmentation": {
18 | "augmentation_type": "none",
19 | "data_sources": {
20 | "azure-ai-search": 2500
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/04-rag/sample/src/prompts/chat/skprompt.txt:
--------------------------------------------------------------------------------
1 | This is a conversation with an AI assistant specialized in the vast and intriguing universe of planets and space.
2 | Encourage the AI to provide vivid and captivating explanations that spark curiosity and enhance learning.
3 | Brighten the conversation with emojis! They add a playful and visually engaging element that makes learning about space more fun.
4 | At the end of each response, share a fascinating fun fact about space or planets. These snippets aim to amaze and provide extra tidbits of knowledge!
--------------------------------------------------------------------------------
/04-rag/sample/src/requirements.txt:
--------------------------------------------------------------------------------
1 | python-dotenv
2 | aiohttp
3 | azure-search
4 | azure-search-documents
5 | teams-ai~=1.0.1
--------------------------------------------------------------------------------
/04-rag/sample/teamsapp.local.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.3/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.3
5 |
6 | provision:
7 | # Creates a Teams app
8 | - uses: teamsApp/create
9 | with:
10 | # Teams app name
11 | name: space-ai-search-${{TEAMSFX_ENV}}
12 | # Write the information of created resources into environment file for
13 | # the specified environment variable(s).
14 | writeToEnvironmentFile:
15 | teamsAppId: TEAMS_APP_ID
16 |
17 | # Create or reuse an existing Microsoft Entra application for bot.
18 | - uses: aadApp/create
19 | with:
20 | # The Microsoft Entra application's display name
21 | name: space-ai-search${{APP_NAME_SUFFIX}}
22 | generateClientSecret: true
23 | signInAudience: AzureADMultipleOrgs
24 | writeToEnvironmentFile:
25 | # The Microsoft Entra application's client id created for bot.
26 | clientId: BOT_ID
27 | # The Microsoft Entra application's client secret created for bot.
28 | clientSecret: SECRET_BOT_PASSWORD
29 | # The Microsoft Entra application's object id created for bot.
30 | objectId: BOT_OBJECT_ID
31 |
32 | # Create or update the bot registration on dev.botframework.com
33 | - uses: botFramework/create
34 | with:
35 | botId: ${{BOT_ID}}
36 | name: space-ai-search
37 | messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages
38 | description: ""
39 | channels:
40 | - name: msteams
41 |
42 | # Validate using manifest schema
43 | - uses: teamsApp/validateManifest
44 | with:
45 | # Path to manifest template
46 | manifestPath: ./appPackage/manifest.json
47 |
48 | # Build Teams app package with latest env value
49 | - uses: teamsApp/zipAppPackage
50 | with:
51 | # Path to manifest template
52 | manifestPath: ./appPackage/manifest.json
53 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
54 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
55 | # Validate app package using validation rules
56 | - uses: teamsApp/validateAppPackage
57 | with:
58 | # Relative path to this file. This is the path for built zip file.
59 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
60 |
61 | # Apply the Teams app manifest to an existing Teams app in
62 | # Teams Developer Portal.
63 | # Will use the app id in manifest file to determine which Teams app to update.
64 | - uses: teamsApp/update
65 | with:
66 | # Relative path to this file. This is the path for built zip file.
67 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
68 |
69 | deploy:
70 | # Generate runtime environment variables
71 | - uses: file/createOrUpdateEnvironmentFile
72 | with:
73 | target: ./.env
74 | envs:
75 | BOT_ID: ${{BOT_ID}}
76 | BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}}
77 | AZURE_OPENAI_API_KEY: ${{SECRET_AZURE_OPENAI_API_KEY}}
78 | AZURE_OPENAI_MODEL_DEPLOYMENT_NAME: ${{AZURE_OPENAI_MODEL_DEPLOYMENT_NAME}}
79 | AZURE_OPENAI_ENDPOINT: ${{AZURE_OPENAI_ENDPOINT}}
80 | AZURE_OPENAI_EMBEDDING_DEPLOYMENT: ${{AZURE_OPENAI_EMBEDDING_DEPLOYMENT}}
81 | AZURE_SEARCH_KEY: ${{SECRET_AZURE_SEARCH_KEY}}
82 | AZURE_SEARCH_ENDPOINT: ${{AZURE_SEARCH_ENDPOINT}}
83 |
--------------------------------------------------------------------------------
/04-rag/sample/teamsapp.testtool.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.3/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.3
5 |
6 | deploy:
7 | # Install development tool(s)
8 | - uses: devTool/install
9 | with:
10 | testTool:
11 | version: ~0.2.1-beta
12 | symlinkDir: ./devTools/teamsapptester
13 |
14 | # Generate runtime environment variables
15 | - uses: file/createOrUpdateEnvironmentFile
16 | with:
17 | target: ./.env
18 | envs:
19 | TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}}
20 | BOT_ID: ""
21 | BOT_PASSWORD: ""
22 | AZURE_OPENAI_API_KEY: ${{SECRET_AZURE_OPENAI_API_KEY}}
23 | AZURE_OPENAI_MODEL_DEPLOYMENT_NAME: ${{AZURE_OPENAI_MODEL_DEPLOYMENT_NAME}}
24 | AZURE_OPENAI_ENDPOINT: ${{AZURE_OPENAI_ENDPOINT}}
25 | AZURE_OPENAI_EMBEDDING_DEPLOYMENT: ${{AZURE_OPENAI_EMBEDDING_DEPLOYMENT}}
26 | AZURE_SEARCH_KEY: ${{SECRET_AZURE_SEARCH_KEY}}
27 | AZURE_SEARCH_ENDPOINT: ${{AZURE_SEARCH_ENDPOINT}}
28 |
--------------------------------------------------------------------------------
/04-rag/sample/teamsapp.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.3/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.3
5 |
6 | environmentFolderPath: ./env
7 |
8 | # Triggered when 'teamsfx provision' is executed
9 | provision:
10 | # Creates a Teams app
11 | - uses: teamsApp/create
12 | with:
13 | # Teams app name
14 | name: space-ai-search-${{TEAMSFX_ENV}}
15 | # Write the information of created resources into environment file for
16 | # the specified environment variable(s).
17 | writeToEnvironmentFile:
18 | teamsAppId: TEAMS_APP_ID
19 |
20 | # Create or reuse an existing Microsoft Entra application for bot.
21 | - uses: aadApp/create
22 | with:
23 | # The Microsoft Entra application's display name
24 | name: space-ai-search${{APP_NAME_SUFFIX}}
25 | generateClientSecret: true
26 | signInAudience: AzureADMultipleOrgs
27 | writeToEnvironmentFile:
28 | # The Microsoft Entra application's client id created for bot.
29 | clientId: BOT_ID
30 | # The Microsoft Entra application's client secret created for bot.
31 | clientSecret: SECRET_BOT_PASSWORD
32 | # The Microsoft Entra application's object id created for bot.
33 | objectId: BOT_OBJECT_ID
34 |
35 | - uses: arm/deploy # Deploy given ARM templates parallelly.
36 | with:
37 | # AZURE_SUBSCRIPTION_ID is a built-in environment variable,
38 | # if its value is empty, TeamsFx will prompt you to select a subscription.
39 | # Referencing other environment variables with empty values
40 | # will skip the subscription selection prompt.
41 | subscriptionId: ${{AZURE_SUBSCRIPTION_ID}}
42 | # AZURE_RESOURCE_GROUP_NAME is a built-in environment variable,
43 | # if its value is empty, TeamsFx will prompt you to select or create one
44 | # resource group.
45 | # Referencing other environment variables with empty values
46 | # will skip the resource group selection prompt.
47 | resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}}
48 | templates:
49 | - path: ./infra/azure.bicep # Relative path to this file
50 | # Relative path to this yaml file.
51 | # Placeholders will be replaced with corresponding environment
52 | # variable before ARM deployment.
53 | parameters: ./infra/azure.parameters.json
54 | # Required when deploying ARM template
55 | deploymentName: Create-resources-for-tab
56 | # Teams Toolkit will download this bicep CLI version from github for you,
57 | # will use bicep CLI in PATH if you remove this config.
58 | bicepCliVersion: v0.9.1
59 |
60 | # Validate using manifest schema
61 | - uses: teamsApp/validateManifest
62 | with:
63 | # Path to manifest template
64 | manifestPath: ./appPackage/manifest.json
65 | # Build Teams app package with latest env value
66 | - uses: teamsApp/zipAppPackage
67 | with:
68 | # Path to manifest template
69 | manifestPath: ./appPackage/manifest.json
70 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
71 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
72 | # Validate app package using validation rules
73 | - uses: teamsApp/validateAppPackage
74 | with:
75 | # Relative path to this file. This is the path for built zip file.
76 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
77 | # Apply the Teams app manifest to an existing Teams app in
78 | # Teams Developer Portal.
79 | # Will use the app id in manifest file to determine which Teams app to update.
80 | - uses: teamsApp/update
81 | with:
82 | # Relative path to this file. This is the path for built zip file.
83 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
84 |
85 | # Triggered when 'teamsfx deploy' is executed
86 | deploy:
87 | # Deploy your application to Azure App Service using the zip deploy feature.
88 | # For additional details, refer to https://aka.ms/zip-deploy-to-app-services.
89 | - uses: azureAppService/zipDeploy
90 | with:
91 | # Deploy base folder
92 | artifactFolder: ./src
93 | # Ignore file location, leave blank will ignore nothing
94 | ignoreFile: .webappignore
95 | # The resource id of the cloud resource to be deployed to.
96 | # This key will be generated by arm/deploy action automatically.
97 | # You can replace it with your existing Azure Resource id
98 | # or add it to your environment variable file.
99 | resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}}
100 |
101 | # Triggered when 'teamsapp publish' is executed
102 | publish:
103 | # Validate using manifest schema
104 | - uses: teamsApp/validateManifest
105 | with:
106 | # Path to manifest template
107 | manifestPath: ./appPackage/manifest.json
108 | # Build Teams app package with latest env value
109 | - uses: teamsApp/zipAppPackage
110 | with:
111 | # Path to manifest template
112 | manifestPath: ./appPackage/manifest.json
113 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
114 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
115 | # Validate app package using validation rules
116 | - uses: teamsApp/validateAppPackage
117 | with:
118 | # Relative path to this file. This is the path for built zip file.
119 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
120 | # Apply the Teams app manifest to an existing Teams app in
121 | # Teams Developer Portal.
122 | # Will use the app id in manifest file to determine which Teams app to update.
123 | - uses: teamsApp/update
124 | with:
125 | # Relative path to this file. This is the path for built zip file.
126 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
127 | # Publish the app to
128 | # Teams Admin Center (https://admin.teams.microsoft.com/policies/manage-apps)
129 | # for review and approval
130 | - uses: teamsApp/publishAppPackage
131 | with:
132 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
133 | # Write the information of created resources into environment file for
134 | # the specified environment variable(s).
135 | writeToEnvironmentFile:
136 | publishedAppId: TEAMS_APP_PUBLISHED_APP_ID
137 | projectId: 0213a39c-54c8-4bcd-8985-3b0da9a50a9f
138 |
--------------------------------------------------------------------------------
/05-on-your-data/README.md:
--------------------------------------------------------------------------------
1 | # Bring your AI app to Teams with Azure OpenAI Studio's new 'Deploy to a Teams App' feature
2 |
3 | In this section, you'll learn about the practical smart bot development with Azure OpenAI On Your Data.
4 |
5 | ## What is Azure OpenAI On Your Data?
6 |
7 | [**Azure OpenAI On Your Data**](https://learn.microsoft.com/azure/ai-services/openai/concepts/use-your-data) transforms how you interact with your enterprise data, seamlessly integrates and analyzes your data using advanced AI models, such as GPT-35-Turbo and GPT-4, without needing to train or fine-tune models.
8 |
9 | You can access Azure OpenAI On Your Data using the web-based interface in the [Azure OpenAI Studio](https://oai.azure.com/), where you can integrate your own data into AI models by simply uploading your datasets.
10 |
11 | 
12 |
13 | ### Data types
14 |
15 | Azure OpenAI On Your Data supports the following file types:
16 | - .txt
17 | - .md
18 | - .html
19 | - .docx
20 | - .pptx
21 | - .pdf
22 |
23 | There's an upload limit, and there are some caveats about document structure and how it might affect the quality of responses from the model, so you may need to tweak your data with the [data preparation script](https://github.com/microsoft/sample-app-aoai-chatGPT/tree/main/scripts#data-preparation)!
24 |
25 | ### Search Types
26 |
27 | You can have Azure OpenAI On Your Data to search your data source with the following search types
28 |
29 | - [**Keyword search**](https://learn.microsoft.com/azure/search/search-lucene-query-architecture)
30 | - [**Semantic search**](https://learn.microsoft.com/azure/search/semantic-search-overview)
31 | - [**Vector search**](https://learn.microsoft.com/en-us/azure/search/vector-search-overview) using Ada [embedding](https://learn.microsoft.com/azure/ai-services/openai/concepts/understand-embeddings) models (available in [selected regions](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#embeddings-models))
32 |
33 | ### Deploy to Teams
34 |
35 | One of the standout features is the **Deploy to Teams** option. With just a few clicks, you can deploy your AI models directly into Microsoft Teams, enhancing your collaboration and productivity.
36 |
37 | So, whether you're looking to personalize your AI models with your own data or bring AI capabilities directly into your Teams workspace, Azure OpenAI Studio has got you covered 💪
38 |
39 | ## 🚀 Try by yourself
40 |
41 | **Now [let's build a custom bot using your data on Azure OpenAI Studio](sample/README.md)!**
42 |
43 | ## 📺 Watch on YouTube
44 |
45 | Watch the video, **Bring Your AI App to Teams with Azure OpenAI Studio's New 'Deploy to a Teams App' Feature** on YouTube:
46 |
47 | [](https://www.youtube.com/watch?v=xAXlFGSH1II)
48 |
49 | [Subscribe us!](https://www.youtube.com/channel/UCV_6HOhwxYLXAGd-JOqKPoQ?sub_confirmation=1)
50 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/.eslintignore:
--------------------------------------------------------------------------------
1 | bin
2 | build
3 | demo-packages
4 | dist
5 | manifest
6 | node_modules
7 | package-lock.json
8 | docs/assets/main.js
--------------------------------------------------------------------------------
/05-on-your-data/sample/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "root": true,
4 | "env": {
5 | "browser": true,
6 | "node": true,
7 | "es2015": true,
8 | "mocha": true,
9 | "jest": true
10 | },
11 | "extends": [
12 | "eslint:recommended",
13 | "plugin:@typescript-eslint/recommended",
14 | "plugin:import/typescript",
15 | "plugin:import/recommended",
16 | "plugin:jsdoc/recommended",
17 | "plugin:prettier/recommended" // Recommended to be last
18 | ],
19 | "plugins": [
20 | "@typescript-eslint",
21 | "jsdoc",
22 |
23 | "mocha",
24 | "only-warn",
25 | "prettier"
26 | // "react"
27 | ],
28 | "parserOptions": {
29 | "ecmaVersion": 2015,
30 | // Allows for the parsing of modern ECMAScript features
31 | "sourceType": "module" // Allows for the use of imports
32 | // "ecmaFeatures": {
33 | // "jsx": true
34 | // }
35 | },
36 | "rules": {
37 | // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
38 | "@typescript-eslint/ban-types": "off",
39 | "@typescript-eslint/explicit-function-return-type": "off",
40 | "@typescript-eslint/explicit-member-accessibility": "off",
41 | "@typescript-eslint/explicit-module-boundary-types": "off",
42 | "@typescript-eslint/interface-name-prefix": "off",
43 | "@typescript-eslint/no-empty-function": "off",
44 | "@typescript-eslint/no-explicit-any": "off",
45 | "@typescript-eslint/no-namespace": "off",
46 | "no-async-promise-executor": "off",
47 | "no-constant-condition": "off",
48 | "no-undef": "off", // Disabled due to conflicts with @typescript/eslint
49 | "no-unused-vars": "off", // Disabled due to conflicts with @typescript/eslint
50 | "prettier/prettier": "error"
51 | },
52 | "overrides": [
53 | {
54 | "files": ["bin/*.js", "lib/*.js"]
55 | }
56 | ],
57 | "ignorePatterns": ["node_modules/*"]
58 | }
59 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/.gitignore:
--------------------------------------------------------------------------------
1 | .zip
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | lerna-debug.log*
10 |
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13 |
14 | # Runtime data
15 | pids
16 | *.pid
17 | *.seed
18 | *.pid.lock
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 | /**/lib
23 | lib
24 |
25 | # Coverage directory used by tools like istanbul
26 | coverage
27 | *.lcov
28 |
29 | # nyc test coverage
30 | .nyc_output
31 |
32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
33 | .grunt
34 |
35 | # Bower dependency directory (https://bower.io/)
36 | bower_components
37 |
38 | # node-waf configuration
39 | .lock-wscript
40 |
41 | # Compiled binary addons (https://nodejs.org/api/addons.html)
42 | build/Release
43 |
44 | # Dependency directories
45 | node_modules/
46 | jspm_packages/
47 |
48 | # TypeScript v1 declaration files
49 | typings/
50 |
51 | # TypeScript cache
52 | *.tsbuildinfo
53 |
54 | # Optional npm cache directory
55 | .npm
56 |
57 | # Optional eslint cache
58 | .eslintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variables file
76 | .env
77 | .env.test
78 |
79 | # parcel-bundler cache (https://parceljs.org/)
80 | .cache
81 |
82 | # Next.js build output
83 | .next
84 |
85 | # Nuxt.js build / generate output
86 | .nuxt
87 | dist
88 |
89 | # Gatsby files
90 | .cache/
91 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
92 | # https://nextjs.org/blog/next-9-1#public-directory-support
93 | # public
94 |
95 | # vuepress build output
96 | .vuepress/dist
97 |
98 | # Serverless directories
99 | .serverless/
100 |
101 | # FuseBox cache
102 | .fusebox/
103 |
104 | # DynamoDB Local files
105 | .dynamodb/
106 |
107 | # TernJS port file
108 | .tern-port
109 |
110 | # Teams Toolkit
111 | env/.env.*.user
112 | env/.env.local
113 | appPackage/build
114 | .deployment
115 | devTools/
116 | build
117 | config.json
--------------------------------------------------------------------------------
/05-on-your-data/sample/.prettierignore:
--------------------------------------------------------------------------------
1 | bin
2 | build
3 | demo-packages
4 | dist
5 | manifest
6 | node_modules
7 | package-lock.json
--------------------------------------------------------------------------------
/05-on-your-data/sample/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "always",
3 | "endOfLine": "auto",
4 | "printWidth": 120,
5 | "semi": true,
6 | "singleAttributePerLine": false,
7 | "singleQuote": true,
8 | "tabWidth": 4,
9 | "trailingComma": "none",
10 | "useTabs": false
11 | }
12 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Launch Remote (Edge)",
6 | "type": "msedge",
7 | "request": "launch",
8 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
9 | "presentation": {
10 | "group": "remote",
11 | "order": 1
12 | },
13 | "internalConsoleOptions": "neverOpen"
14 | },
15 | {
16 | "name": "Launch Remote (Chrome)",
17 | "type": "chrome",
18 | "request": "launch",
19 | "url": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
20 | "presentation": {
21 | "group": "remote",
22 | "order": 2
23 | },
24 | "internalConsoleOptions": "neverOpen"
25 | },
26 | {
27 | "name": "Launch App (Edge)",
28 | "type": "msedge",
29 | "request": "launch",
30 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
31 | "cascadeTerminateToConfigurations": [
32 | "Attach to Local Service"
33 | ],
34 | "presentation": {
35 | "group": "all",
36 | "hidden": true
37 | },
38 | "internalConsoleOptions": "neverOpen"
39 | },
40 | {
41 | "name": "Launch App (Chrome)",
42 | "type": "chrome",
43 | "request": "launch",
44 | "url": "https://teams.microsoft.com/l/app/${{local:TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&${account-hint}",
45 | "cascadeTerminateToConfigurations": [
46 | "Attach to Local Service"
47 | ],
48 | "presentation": {
49 | "group": "all",
50 | "hidden": true
51 | },
52 | "internalConsoleOptions": "neverOpen"
53 | },
54 | {
55 | "name": "Attach to Local Service",
56 | "type": "node",
57 | "request": "attach",
58 | "port": 9239,
59 | "restart": true,
60 | "presentation": {
61 | "group": "all",
62 | "hidden": true
63 | },
64 | "internalConsoleOptions": "neverOpen"
65 | },
66 | ],
67 | "compounds": [
68 | {
69 | "name": "Debug in Teams (Edge)",
70 | "configurations": [
71 | "Launch App (Edge)",
72 | "Attach to Local Service"
73 | ],
74 | "preLaunchTask": "Start Teams App Locally",
75 | "presentation": {
76 | "group": "all",
77 | "order": 1
78 | },
79 | "stopAll": true
80 | },
81 | {
82 | "name": "Debug in Test Tool",
83 | "configurations": [
84 | "Attach to Local Service"
85 | ],
86 | "preLaunchTask": "Start Teams App (Test Tool)",
87 | "presentation": {
88 | "group": "2-local",
89 | "order": 1
90 | },
91 | "stopAll": true
92 | },
93 | {
94 | "name": "Debug in Teams (Chrome)",
95 | "configurations": [
96 | "Launch App (Chrome)",
97 | "Attach to Local Service"
98 | ],
99 | "preLaunchTask": "Start Teams App Locally",
100 | "presentation": {
101 | "group": "all",
102 | "order": 2
103 | },
104 | "stopAll": true
105 | }
106 | ]
107 | }
108 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/.webappignore:
--------------------------------------------------------------------------------
1 | .webappignore
2 | .fx
3 | .deployment
4 | .localConfigs
5 | .notification.localstore.json
6 | .vscode
7 | *.js.map
8 | *.ts.map
9 | *.ts
10 | .git*
11 | .tsbuildinfo
12 | CHANGELOG.md
13 | readme.md
14 | local.settings.json
15 | .env
16 | test
17 | tsconfig.json
18 | .DS_Store
19 | teamsapp.yml
20 | teamsapp.*.yml
21 | /env/
22 | /node_modules/.bin
23 | /node_modules/ts-node
24 | /node_modules/typescript
25 | /appPackage/
26 | /infra/
--------------------------------------------------------------------------------
/05-on-your-data/sample/README.md:
--------------------------------------------------------------------------------
1 | # Deploy to a Teams App using Azure OpenAI Studio On Your Data
2 |
3 | This sample shows how to create a custom engine copilot that uses the Azure OpenAI Chat Completions API **Azure OpenAI On Your Data** feature to facilitate RAG (retrieval augmented generation) and test it on Microsoft Teams.
4 |
5 | You can integrate your data from Azure AI Search, Azure Blob Storage, URL/web address, Azure Cosmos DB for MongoDB vCore, uploaded files, and Elasticsearch. Then, you can deploy to a standalone Teams app (preview) directly from Azure OpenAI Studio, enabling you to bring conversational experience to your users in Teams to improve operational efficiency and democratize access of information. The source code of this app is powered by Teams AI library that helps you utilize the AI features and connect with your data from Azure.
6 |
7 | This guide will show you how to set up your custom engine copilot for Teams using Azure OpenAI Studio and Teams Toolkit.
8 |
9 | ## Pre-requisites
10 |
11 | - [Visual Studio Code](https://code.visualstudio.com)
12 | - [Teams Toolkit](https://marketplace.visualstudio.com/items?itemName=TeamsDevApp.ms-teams-vscode-extension)
13 | - [Node.js](https://nodejs.org/en)
14 | - [Microsoft Teams](https://www.microsoft.com/microsoft-teams/download-app)
15 | - [Microsoft 365 developer account](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/prepare-your-o365-tenant)
16 | - [Azure OpenAI](https://oai.azure.com/portal) with `text-embedding-ada-002` and `gpt-35-turbo` or higher deployed
17 | - [Microsoft Edge](https://www.microsoft.com/edge) (recommended) or [Google Chrome](https://www.google.com/chrome/)
18 | - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
19 | - [Cognitive Services OpenAI User](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/role-based-access-control#:~:text=to%20a%20role.-,Cognitive%20Services%20OpenAI%20User,-If%20a%20user)
20 |
21 | ## Setting up your AI app in Azure OpenAI Studio
22 |
23 | 1. Open [Azure OpenAI Studio](https://oai.azure.com/portal) and select **Chat** from the menu. Locate the `Prompt` tab under the Setup and replace the **System Message** with the following lines. Select **Apply Changes**:
24 |
25 | ```
26 | You are an AI assistant named Coffee Cup that helps people find information about nutrition of coffee options using given data.
27 | Always introduce yourself in the beginning, use emojis where appropriate.
28 | ```
29 |
30 | 1. To ingest your data, select `Add your data` tab, select **Add a data source**, then **Upload files (preview)**.
31 | 1. Select your subscription, Azure Blob Storage, Azure AI Search. If you don't these resources created earlier, select the option to create new.
32 | 1. Enter an index name, such as `coffee-shops`.
33 | 1. Check the box for "Add vector search to this search resource." and select your embedding model and select **Next**.
34 | 1. Drag and drop the files from `src/data/` folder and select **Next**.
35 | 1. Select the search type as `Vector` and then **Next**.
36 | 1. Select the authentication type as **API key** and then **Next**.
37 | 1. Finally, select **Save and close**.
38 | 1. Once the data ingestion is complete, ask similar questions to the following examples:
39 | - *What are my options for cold brew?*
40 | - *How about iced latte?*
41 | - *Can you share the options for cappuccino with almond milk?*
42 |
43 | 1. After testing your data, click **Deploy to** and then **A new Teams app(preview)**.
44 | 1. Enter the name of your Teams app such as "CoffeeCup".
45 | 1. Click `download` to download your Teams app as a zip file.
46 | 1. Open the location of where you downloaded the zip file and extract the zip file.
47 |
48 | ### Chat with your AI app on Microsoft Teams
49 |
50 | Note: Testing this sample requires that you are logged into Azure CLI and you have [Cognitive Services OpenAI User role assigned to you](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/role-based-access-control#add-role-assignment-to-an-azure-openai-resource) per the prerequisites.
51 |
52 | 1. Go to Visual Studio Code.
53 | 1. Select `File > Open Folder`.
54 | 1. Go to the location where you extracted your Teams app folder and select it.
55 | 1. If you chose `API key` in data connection, manually copy and paste your Azure AI Search key in `src\prompts\chat\config.json` file. Your **Azure AI Search Key** can be found in Azure OpenAI Studio Playground by clicking the `View code` button and looking under **Azure Search Resource Key**. If you chose `system assigned managed identity`, you can skip this step. Learn more about different data connection options in the [Data connection section](https://review.learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data?tabs=ai-search%2Ccopilot&branch=pr-en-us-277392#data-connection).
56 | 1. Open the Visual Studio Code terminal by selecting `View > Terminal` and log into Azure CLI selecting the Azure account that you assigned Cognitive Service OpenAI User role to. Use the following command to log in:
57 |
58 | ```bash
59 | az login
60 | ```
61 |
62 | 1. To debug your app, press the `F5` key or from the left pane, select `RUN AND DEBUG ▷` (Ctrl+Shift+D) and then select `Debug in (Edge)` or `Debug in (Chrome)` from the dropdown list. Select `Run > Start Debugging` (F5). A webpage opens where you can chat with your custom copilot.
63 |
64 | **Note:** The citation experience is only available in Teams, make sure to debug in Edge or Chrome instead of the Test Tool.
65 |
66 | 
--------------------------------------------------------------------------------
/05-on-your-data/sample/appPackage/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/appPackage/color.png
--------------------------------------------------------------------------------
/05-on-your-data/sample/appPackage/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.15/MicrosoftTeams.schema.json",
3 | "version": "1.1.0",
4 | "manifestVersion": "1.15",
5 | "id": "${{TEAMS_APP_ID}}",
6 | "packageName": "com.package.name",
7 | "name": {
8 | "short": "coffeecup-${{TEAMSFX_ENV}}",
9 | "full": "coffeecup"
10 | },
11 | "developer": {
12 | "name": "Microsoft",
13 | "mpnId": "",
14 | "websiteUrl": "https://www.example.com",
15 | "privacyUrl": "https://www.example.com/privacy",
16 | "termsOfUseUrl": "https://www.example.com/terms-of-use"
17 | },
18 | "description": {
19 | "short": "Custom copilot to chat with your data via RAG through Azure OpenAI On Your Data",
20 | "full": "Custom copilot to chat with your data via RAG (retrieval augmentation generation) through Azure OpenAI On Your Data supported data sources: Azure AI Search, Azure Blob Storage, URL/web address, Azure Cosmos DB for MongoDB vCore, uploaded files, and Elasticsearch."
21 | },
22 | "icons": {
23 | "outline": "outline.png",
24 | "color": "color.png"
25 | },
26 | "accentColor": "#FFFFFF",
27 | "staticTabs": [
28 | {
29 | "entityId": "conversations",
30 | "scopes": [
31 | "personal"
32 | ]
33 | },
34 | {
35 | "entityId": "about",
36 | "scopes": [
37 | "personal"
38 | ]
39 | }
40 | ],
41 | "bots": [
42 | {
43 | "botId": "${{BOT_ID}}",
44 | "scopes": [
45 | "personal"
46 | ],
47 | "isNotificationOnly": false,
48 | "supportsCalling": false,
49 | "supportsVideo": false,
50 | "supportsFiles": false
51 | }
52 | ],
53 | "validDomains": []
54 | }
--------------------------------------------------------------------------------
/05-on-your-data/sample/appPackage/outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/appPackage/outline.png
--------------------------------------------------------------------------------
/05-on-your-data/sample/assets/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/assets/example.png
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/Second-Cup.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/Second-Cup.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/TimHortons-ca.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/TimHortons-ca.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/au-bon-pain.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/au-bon-pain.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/caffe-nero.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/caffe-nero.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/caribou.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/caribou.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/coffeebean-and-tea-leaf.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/coffeebean-and-tea-leaf.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/costa-uk.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/costa-uk.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/dunkin.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/dunkin.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/gloria-jeans.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/gloria-jeans.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/pret.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/pret.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/data/starbucks.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/data/starbucks.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/env/.env.dev:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that will be committed to git by default.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=dev
5 |
6 | # Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups.
7 | AZURE_SUBSCRIPTION_ID=
8 | AZURE_RESOURCE_GROUP_NAME=
9 | RESOURCE_SUFFIX=
10 |
11 | # Generated during provision, you can also add your own variables.
12 | BOT_ID=
13 | BOT_PASSWORD=
14 | APP_NAME_SUFFIX=dev
15 | TEAMS_APP_ID=
16 | TEAMS_APP_TENANT_ID=
17 | BOT_AZURE_APP_SERVICE_RESOURCE_ID=
18 | BOT_DOMAIN=
19 | AZURE_OPENAI_ENDPOINT=
20 | AZURE_OPENAI_DEPLOYMENT=
--------------------------------------------------------------------------------
/05-on-your-data/sample/env/.env.local.sample:
--------------------------------------------------------------------------------
1 | BOT_ENDPOINT=
2 | BOT_DOMAIN=
3 | TEAMSFX_ENV=local
4 | APP_NAME_SUFFIX=local
5 | TEAMS_APP_ID=
6 | TEAMS_APP_TENANT_ID=
7 | BOT_ID=
8 | AZURE_OPENAI_ENDPOINT=
9 | AZURE_OPENAI_DEPLOYMENT=
10 | BOT_OBJECT_ID=
--------------------------------------------------------------------------------
/05-on-your-data/sample/env/.env.local.user.sample:
--------------------------------------------------------------------------------
1 | SECRET_BOT_PASSWORD=
2 | TEAMS_APP_UPDATE_TIME=
--------------------------------------------------------------------------------
/05-on-your-data/sample/env/.env.testtool:
--------------------------------------------------------------------------------
1 | # This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment.
2 |
3 | # Built-in environment variables
4 | TEAMSFX_ENV=testtool
5 |
6 | # Environment variables used by test tool
7 | TEAMSAPPTESTER_PORT=56150
--------------------------------------------------------------------------------
/05-on-your-data/sample/infra/azure.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | param azureOpenAIEndpoint string = ''
7 | param azureOpenAIDeployment string = ''
8 | param webAppSKU string
9 |
10 | @maxLength(42)
11 | param botDisplayName string
12 |
13 | param serverfarmsName string = resourceBaseName
14 | param webAppName string = resourceBaseName
15 | param location string = resourceGroup().location
16 | param identityName string = resourceBaseName
17 |
18 | resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
19 | location: location
20 | name: identityName
21 | }
22 |
23 | // Compute resources for your Web App
24 | resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = {
25 | kind: 'app'
26 | location: location
27 | name: serverfarmsName
28 | sku: {
29 | name: webAppSKU
30 | }
31 | }
32 |
33 | // Web App that hosts your bot
34 | resource webApp 'Microsoft.Web/sites@2021-02-01' = {
35 | kind: 'app'
36 | location: location
37 | name: webAppName
38 | properties: {
39 | serverFarmId: serverfarm.id
40 | httpsOnly: true
41 | siteConfig: {
42 | alwaysOn: true
43 | appSettings: [
44 | {
45 | name: 'WEBSITE_RUN_FROM_PACKAGE'
46 | value: '1' // Run Azure App Service from a package file
47 | }
48 | {
49 | name: 'WEBSITE_NODE_DEFAULT_VERSION'
50 | value: '~18' // Set NodeJS version to 18.x for your site
51 | }
52 | {
53 | name: 'RUNNING_ON_AZURE'
54 | value: '1'
55 | }
56 | {
57 | name: 'BOT_ID'
58 | value: identity.properties.clientId
59 | }
60 | {
61 | name: 'BOT_TENANT_ID'
62 | value: identity.properties.tenantId
63 | }
64 | {
65 | name: 'BOT_TYPE'
66 | value: 'UserAssignedMSI'
67 | }
68 | {
69 | name: 'AZURE_OPENAI_ENDPOINT'
70 | value: azureOpenAIEndpoint
71 | }
72 | {
73 | name: 'AZURE_OPENAI_DEPLOYMENT'
74 | value: azureOpenAIDeployment
75 | }
76 | {
77 | name: 'AZURE_CLIENT_ID'
78 | value: identity.properties.clientId
79 | }
80 | ]
81 | ftpsState: 'FtpsOnly'
82 | }
83 | }
84 | identity: {
85 | type: 'UserAssigned'
86 | userAssignedIdentities: {
87 | '${identity.id}': {}
88 | }
89 | }
90 | }
91 |
92 | // Register your web service as a bot with the Bot Framework
93 | module azureBotRegistration './botRegistration/azurebot.bicep' = {
94 | name: 'Azure-Bot-registration'
95 | params: {
96 | resourceBaseName: resourceBaseName
97 | identityClientId: identity.properties.clientId
98 | identityResourceId: identity.id
99 | identityTenantId: identity.properties.tenantId
100 | botAppDomain: webApp.properties.defaultHostName
101 | botDisplayName: botDisplayName
102 | }
103 | }
104 |
105 | // The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details.
106 | output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id
107 | output BOT_DOMAIN string = webApp.properties.defaultHostName
108 | output BOT_ID string = identity.properties.clientId
109 | output BOT_TENANT_ID string = identity.properties.tenantId
110 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/infra/azure.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "resourceBaseName": {
6 | "value": "coffeecup-${{RESOURCE_SUFFIX}}"
7 | },
8 | "webAppSKU": {
9 | "value": "B1"
10 | },
11 | "botDisplayName": {
12 | "value": "coffeecup"
13 | },
14 | "azureOpenAIEndpoint": {
15 | "value": "${{AZURE_OPENAI_ENDPOINT}}"
16 | },
17 | "azureOpenAIDeployment": {
18 | "value": "${{AZURE_OPENAI_DEPLOYMENT}}"
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/05-on-your-data/sample/infra/botRegistration/azurebot.bicep:
--------------------------------------------------------------------------------
1 | @maxLength(20)
2 | @minLength(4)
3 | @description('Used to generate names for all resources in this file')
4 | param resourceBaseName string
5 |
6 | @maxLength(42)
7 | param botDisplayName string
8 |
9 | param botServiceName string = resourceBaseName
10 | param botServiceSku string = 'F0'
11 | param botAppDomain string
12 | param identityResourceId string
13 | param identityClientId string
14 | param identityTenantId string
15 |
16 | // Register your web service as a bot with the Bot Framework
17 | resource botService 'Microsoft.BotService/botServices@2021-03-01' = {
18 | kind: 'azurebot'
19 | location: 'global'
20 | name: botServiceName
21 | properties: {
22 | displayName: botDisplayName
23 | endpoint: 'https://${botAppDomain}/api/messages'
24 | msaAppId: identityClientId
25 | msaAppMSIResourceId: identityResourceId
26 | msaAppTenantId:identityTenantId
27 | msaAppType:'UserAssignedMSI'
28 | }
29 | sku: {
30 | name: botServiceSku
31 | }
32 | }
33 |
34 | // Connect the bot service to Microsoft Teams
35 | resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = {
36 | parent: botService
37 | location: 'global'
38 | name: 'MsTeamsChannel'
39 | properties: {
40 | channelName: 'MsTeamsChannel'
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/infra/botRegistration/readme.md:
--------------------------------------------------------------------------------
1 | The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again.
--------------------------------------------------------------------------------
/05-on-your-data/sample/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "teams-azureopenai-demo",
3 | "version": "1.0.0",
4 | "description": "Sample bot demonstrating using Azure AI Search for RAG.",
5 | "author": "Microsoft",
6 | "license": "MIT",
7 | "main": "./lib/index.js",
8 | "engines": {
9 | "node": ">=18.0.0"
10 | },
11 | "scripts": {
12 | "dev:teamsfx": "env-cmd --silent -f .env npm run dev",
13 | "dev:teamsfx:testtool": "env-cmd --silent -f .env npm run dev",
14 | "dev:teamsfx:launch-testtool": "env-cmd --silent -f env/.env.testtool teamsapptester start",
15 | "dev": "nodemon --watch ./src --exec node --inspect=9239 --signal SIGINT -r ts-node/register ./src/index.ts",
16 | "build": "tsc --build && copyfiles -u 3 src/prompts/chat/config.json lib/prompts/chat/",
17 | "clean": "rimraf node_modules lib",
18 | "lint": "eslint **/src/**/*.{j,t}s{,x} --fix --no-error-on-unmatched-pattern",
19 | "start": "tsc --build && node ./lib/index.js",
20 | "test": "echo \"Error: no test specified\" && exit 1",
21 | "watch": "nodemon --watch ./src -e ts --exec \"yarn start\""
22 | },
23 | "repository": {
24 | "type": "git",
25 | "url": "https://github.com/microsoft/teams-ai"
26 | },
27 | "dependencies": {
28 | "@azure/identity": "^4.3.0",
29 | "@azure/search-documents": "12.0.0",
30 | "@microsoft/teams-ai": "~1.3.1",
31 | "@microsoft/teamsfx": "^2.3.2",
32 | "botbuilder": "^4.22.3",
33 | "dotenv": "^16.4.1",
34 | "openai": "4.28.4",
35 | "replace": "~1.2.0",
36 | "restify": "~11.1.0",
37 | "vectra": "^0.7.6"
38 | },
39 | "devDependencies": {
40 | "@types/debug": "^4.1.12",
41 | "@types/jsonwebtoken": "^8.5.0",
42 | "@types/node": "^20.14.10",
43 | "@types/restify": "8.5.12",
44 | "@typescript-eslint/eslint-plugin": "^6.21.0",
45 | "@typescript-eslint/parser": "^6.21.0",
46 | "copyfiles": "^2.4.1",
47 | "debug": "^4.3.5",
48 | "env-cmd": "^10.1.0",
49 | "eslint": "^8.57.0",
50 | "nodemon": "~3.0.1",
51 | "prettier": "^3.3.3",
52 | "rimraf": "^5.0.9",
53 | "ts-node": "^10.9.2",
54 | "typescript": "^5.5.3"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/src/app.ts:
--------------------------------------------------------------------------------
1 | import { OpenAIModel, PromptManager, ActionPlanner, Application, TurnState, TeamsAdapter, FeedbackLoopData } from '@microsoft/teams-ai';
2 | import { DefaultAzureCredential, getBearerTokenProvider } from '@azure/identity';
3 | import { ConfigurationServiceClientCredentialFactory, MemoryStorage, TurnContext } from 'botbuilder';
4 | import axios from 'axios';
5 | import path from 'path';
6 | import debug from 'debug';
7 |
8 | const error = debug('azureopenai:app:error');
9 | error.log = console.log.bind(console);
10 |
11 | interface ConversationState {}
12 | type ApplicationTurnState = TurnState;
13 |
14 | // Create AI components
15 | const model = new OpenAIModel({
16 | // Azure OpenAI Support
17 | azureDefaultDeployment: process.env.AZURE_OPENAI_DEPLOYMENT!,
18 | azureEndpoint: process.env.AZURE_OPENAI_ENDPOINT!,
19 | azureApiVersion: '2024-02-15-preview',
20 | azureADTokenProvider: getBearerTokenProvider(
21 | new DefaultAzureCredential(),
22 | 'https://cognitiveservices.azure.com/.default'
23 | ),
24 |
25 | // Request logging
26 | logRequests: true,
27 | useSystemMessages: true
28 | });
29 |
30 | const prompts = new PromptManager({
31 | promptsFolder: path.join(__dirname, '../src/prompts')
32 | });
33 |
34 | const planner = new ActionPlanner({
35 | model,
36 | prompts,
37 | defaultPrompt: 'chat'
38 | });
39 |
40 | // Define storage and application
41 | const storage = new MemoryStorage();
42 | export const app = new Application({
43 | storage,
44 | ai: {
45 | planner: planner,
46 | enable_feedback_loop: true
47 | },
48 | adapter: new TeamsAdapter(
49 | {},
50 | new ConfigurationServiceClientCredentialFactory({
51 | MicrosoftAppId: process.env.BOT_ID,
52 | MicrosoftAppPassword: process.env.BOT_PASSWORD,
53 | MicrosoftAppTenantId: process.env.BOT_TENANT_ID,
54 | MicrosoftAppType: process.env.BOT_TYPE
55 | })
56 | )
57 | });
58 |
59 | app.conversationUpdate('membersAdded', async (context: TurnContext) => {
60 | await context.sendActivity(
61 | "Welcome! I'm a conversational bot that can tell you about your data. You can also type `/clear` to clear the conversation history."
62 | );
63 | });
64 |
65 | app.message('/clear', async (context: TurnContext, state: TurnState) => {
66 | state.deleteConversationState();
67 | await context.sendActivity("New chat session started: Previous messages won't be used as context for new queries.");
68 | });
69 |
70 | app.error(async (context: TurnContext, err: any) => {
71 | // This check writes out errors to console log .vs. app insights.
72 | // NOTE: In production environment, you should consider logging this to Azure
73 | // application insights.
74 | error(`[onTurnError] unhandled error: ${err}`);
75 |
76 | if (err instanceof axios.AxiosError) {
77 | error(err.toJSON());
78 | error(err.response?.data);
79 | } else {
80 | error(err);
81 | }
82 |
83 | // Send a trace activity, which will be displayed in Bot Framework Emulator
84 | await context.sendTraceActivity(
85 | 'OnTurnError Trace',
86 | `${err}`,
87 | 'https://www.botframework.com/schemas/error',
88 | 'TurnError'
89 | );
90 |
91 | // Send a message to the user
92 | await context.sendActivity('The bot encountered an error or bug.');
93 | await context.sendActivity('To continue to run this bot, please fix the bot source code.');
94 | });
95 |
96 | app.feedbackLoop(async (_context: TurnContext, _state: TurnState, feedbackLoopData: FeedbackLoopData ) => {
97 | if (feedbackLoopData.actionValue.reaction === 'like') {
98 | console.log('👍');
99 | } else {
100 | console.log('👎');
101 | }
102 | });
103 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/src/data/nba.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/05-on-your-data/sample/src/data/nba.pdf
--------------------------------------------------------------------------------
/05-on-your-data/sample/src/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | // Import required packages
5 | import { config } from 'dotenv';
6 | import * as path from 'path';
7 | import debug from 'debug';
8 | import * as restify from 'restify';
9 | import { app } from './app';
10 | import { TeamsAdapter } from '@microsoft/teams-ai';
11 | import { Request, Response, TurnContext } from 'botbuilder';
12 |
13 | const ENV_FILE = path.join(__dirname, '..', '.env');
14 | config({ path: ENV_FILE });
15 |
16 | const log = debug('azureopenai:server');
17 | log.log = console.log.bind(console);
18 |
19 | // Create HTTP server.
20 | const server = restify.createServer();
21 | const port = process.env.port || process.env.PORT || 3978;
22 |
23 | server.use(restify.plugins.bodyParser());
24 |
25 | server.listen(port, () => {
26 | log(`listening on ${port} 🚀`);
27 | log('To test your bot in Teams, sideload the app manifest.json within Teams Apps.');
28 | log(`\nBot Started, ${server.name} listening to ${server.url}`);
29 | });
30 |
31 | server.post('/api/messages', async (req, res) => {
32 | if (!req.headers.authorization && process.env.RUNNING_ON_AZURE === "1") {
33 | return res.send(401, 'unauthorized');
34 | }
35 |
36 | // Route received a request to adapter for processing
37 | await (app.adapter as TeamsAdapter).process(req, res, async (context: TurnContext) => {
38 | if (context.activity.conversation.tenantId !== process.env.BOT_TENANT_ID && process.env.RUNNING_ON_AZURE === "1") {
39 | return res.send(401, 'invalid tenant');
40 | }
41 |
42 | // Dispatch to application for routing
43 | await app.run(context);
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/src/prompts/chat/skprompt.txt:
--------------------------------------------------------------------------------
1 | # Note
2 | // To update the model instructions directing how your custom copilot should behave when generating a response,
3 | // please update the role_information parameter located in the src\prompts\chat\config.json file.
4 | // The skprompt.txt file is not used by Azure OpenAI On Your Data.
5 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/teamsapp.local.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.5/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.5
5 |
6 | additionalMetadata:
7 | sampleTag: TeamsAI-Samples:datasource-azureopenai
8 |
9 | provision:
10 | - uses: teamsApp/create # Creates a Teams app
11 | with:
12 | name: coffeecup (${{TEAMSFX_ENV}}) # Teams app name
13 | writeToEnvironmentFile: # Write the information of installed dependencies into environment file for the specified environment variable(s).
14 | teamsAppId: TEAMS_APP_ID
15 |
16 | # Create or reuse an existing Microsoft Entra application for bot.
17 | - uses: aadApp/create
18 | with:
19 | # The Microsoft Entra application's display name
20 | name: coffeecup (${{APP_NAME_SUFFIX}})
21 | generateClientSecret: true
22 | signInAudience: AzureADMultipleOrgs
23 | writeToEnvironmentFile:
24 | # The Microsoft Entra application's client id created for bot.
25 | clientId: BOT_ID
26 | # The Microsoft Entra application's client secret created for bot.
27 | clientSecret: SECRET_BOT_PASSWORD
28 | # The Microsoft Entra application's object id created for bot.
29 | objectId: BOT_OBJECT_ID
30 |
31 | - uses: botFramework/create # Create or update the bot registration on dev.botframework.com
32 | with:
33 | botId: ${{BOT_ID}}
34 | name: coffeecup (${{APP_NAME_SUFFIX}})
35 | messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages
36 | description: ''
37 | channels:
38 | - name: msteams
39 |
40 | - uses: teamsApp/validateManifest # Validate using manifest schema
41 | with:
42 | manifestPath: ./appPackage/manifest.json # Path to manifest template
43 |
44 | - uses: teamsApp/zipAppPackage # Build Teams app package with latest env value
45 | with:
46 | manifestPath: ./appPackage/manifest.json # Path to manifest template
47 | outputZipPath: ./build/appPackage/appPackage.${{TEAMSFX_ENV}}.zip
48 | outputJsonPath: ./build/appPackage/manifest.${{TEAMSFX_ENV}}.json
49 |
50 | - uses: teamsApp/update # Apply the Teams app manifest to an existing Teams app in Teams Developer Portal. Will use the app id in manifest file to determine which Teams app to update.
51 | with:
52 | appPackagePath: ./build/appPackage/appPackage.${{TEAMSFX_ENV}}.zip # Relative path to this file. This is the path for built zip file.
53 |
54 | deploy:
55 | # Install any dependencies and build the web app using NPM
56 | - uses: cli/runNpmCommand
57 | name: install dependencies
58 | with:
59 | args: install --no-audit --workspaces=false
60 | # Provides the Teams Toolkit .env file values to the apps runtime so they can be accessed with `process.env`.
61 | - uses: file/createOrUpdateEnvironmentFile
62 | with:
63 | target: ./.env
64 | envs:
65 | BOT_ID: ${{BOT_ID}}
66 | BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}}
67 | BOT_TENANT_ID: ${{TEAMS_APP_TENANT_ID}}
68 | BOT_TYPE: 'MultiTenant'
69 | AZURE_TENANT_ID: ${{TEAMS_APP_TENANT_ID}}
70 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/teamsapp.testtool.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.5/yaml.schema.json
2 | # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file
3 | # Visit https://aka.ms/teamsfx-actions for details on actions
4 | version: v1.5
5 |
6 | additionalMetadata:
7 | sampleTag: TeamsAI-Samples:datasource-azureopenai
8 |
9 | deploy:
10 | # Install development tool(s)
11 | - uses: devTool/install
12 | with:
13 | testTool:
14 | version: ~0.1.0-beta
15 | symlinkDir: ./devTools/teamsapptester
16 |
17 | # Run npm command
18 | - uses: cli/runNpmCommand
19 | with:
20 | args: install --no-audit --workspaces=false
21 |
22 | # Provides the Teams Toolkit .env file values to the apps runtime so they can be accessed with `process.env`.
23 | - uses: file/createOrUpdateEnvironmentFile
24 | with:
25 | target: ./.env
26 | envs: # These values need to be empty when using the test tool to prevent 401 errors with the bot.
27 | BOT_ID: ""
28 | BOT_PASSWORD: ""
29 | BOT_TENANT_ID: ""
30 | AZURE_TENANT_ID: ""
--------------------------------------------------------------------------------
/05-on-your-data/sample/teamsapp.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.5/yaml.schema.json
2 | #
3 | # The teamsapp.yml composes automation tasks for Teams Toolkit when running other environment configurations.
4 | # This file is used when selecting the Provision, Deploy, or Publish menu items in the Teams Toolkit for Visual Studio Code window
5 | # or with the TeamsFx CLI commands.
6 | # i.e. `teamsfx provision --env {environment name}` or `teamsfx deploy --env {environment name}`.
7 | #
8 | # You can customize this file. Visit https://aka.ms/teamsfx-v5.0-guide for more info about Teams Toolkit project files.
9 | version: v1.5
10 |
11 | additionalMetadata:
12 | sampleTag: TeamsAI-Samples:datasource-azureopenai
13 |
14 | environmentFolderPath: ./env
15 |
16 | # Defines what the `provision` lifecycle step does with Teams Toolkit.
17 | # Runs with the Provision menu or CLI using `teamsfx provision --env {environment name}`.
18 | provision:
19 | # Automates the creation of a Teams app registration and saves the App ID to an environment file.
20 | - uses: teamsApp/create
21 | with:
22 | name: TeamsAOAI-${{TEAMSFX_ENV}}
23 | writeToEnvironmentFile:
24 | teamsAppId: TEAMS_APP_ID
25 |
26 | # Automates the creation of infrastructure defined in ARM templates to host the bot.
27 | # The created resource IDs are saved to an environment file.
28 | - uses: arm/deploy
29 | with:
30 | subscriptionId: ${{AZURE_SUBSCRIPTION_ID}}
31 | resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}}
32 | templates:
33 | - path: ./infra/azure.bicep
34 | parameters: ./infra/azure.parameters.json
35 | deploymentName: Create-resources-for-bot
36 | bicepCliVersion: v0.9.1
37 |
38 | # Optional: Automates schema and error checking of the Teams app manifest and outputs the results in the console.
39 | - uses: teamsApp/validateManifest
40 | with:
41 | manifestPath: ./appPackage/manifest.json
42 |
43 | # Automates creating a final app package (.zip) by replacing any variables in the manifest.json file for the current environment.
44 | - uses: teamsApp/zipAppPackage
45 | with:
46 | manifestPath: ./appPackage/manifest.json
47 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
48 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
49 |
50 | # Optional: Automates an app package check for errors that would prevent the app from being published and reports any problems.
51 | - uses: teamsApp/validateAppPackage
52 | with:
53 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
54 |
55 | # Automates updating the Teams app manifest in Teams Developer Portal using the App ID from the mainfest file.
56 | # This action ensures that any manifest changes are reflected when launching the app again in Teams.
57 | - uses: teamsApp/update
58 | with:
59 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
60 |
61 | # Defines what the `deploy` lifecycle step does with Teams Toolkit.
62 | # Runs with the Deploy menu or CLI using `teamsfx deploy --env {environment name}`.
63 | deploy:
64 | # Install any dependencies and build the web app using NPM
65 | - uses: cli/runNpmCommand
66 | name: install dependencies
67 | with:
68 | args: install --workspaces=false
69 |
70 | - uses: cli/runNpmCommand
71 | name: build app
72 | with:
73 | args: run build --if-present
74 |
75 | # Deploy to an Azure App Service using the zip file created in the provision step.
76 | - uses: azureAppService/zipDeploy
77 | with:
78 | artifactFolder: .
79 | ignoreFile: .webappignore
80 | # This example uses the env var thats generated by the arm/deploy action.
81 | # You can replace it with an existing Azure Resource ID or other
82 | # custom environment variable.
83 | resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}}
84 |
85 | # Defines what the `publish` lifecycle step does with Teams Toolkit.
86 | # Runs with the Deploy menu or CLI using `teamsfx publish --env {environment name}`.
87 | publish:
88 | # Optional: Automates schema and error checking of the Teams app manifest and outputs the results in the console.
89 | - uses: teamsApp/validateManifest
90 | with:
91 | manifestPath: ./appPackage/manifest.json
92 |
93 | # Automates creating a final app package (.zip) by replacing any variables in the manifest.json file for the current environment.
94 | - uses: teamsApp/zipAppPackage
95 | with:
96 | manifestPath: ./appPackage/manifest.json
97 | outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
98 | outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json
99 |
100 | # Optional: Automates an app package check for errors that would prevent the app from being published and reports any problems.
101 | - uses: teamsApp/validateAppPackage
102 | with:
103 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
104 |
105 | # Automates updating the Teams app manifest in Teams Developer Portal using the App ID from the mainfest file.
106 | # This action ensures that any manifest changes are reflected when launching the app again in Teams.
107 | - uses: teamsApp/update
108 | with:
109 | appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip
110 | projectId: 2918afbf-1c1c-41b1-8721-52cfc2394441
111 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "forceConsistentCasingInFileNames": true,
5 | "incremental": true,
6 | "module": "commonjs",
7 | "outDir": "./lib",
8 | "rootDir": "./src",
9 | "sourceMap": true,
10 | "strict": true,
11 | "target": "es2017",
12 | "tsBuildInfoFile": "./lib/.tsbuildinfo",
13 | "esModuleInterop": true,
14 | "resolveJsonModule": true,
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/05-on-your-data/sample/web.config:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 | # Contributing
3 |
4 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
5 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
6 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
7 |
8 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
9 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
10 | provided by the bot. You will only need to do this once across all repos using our CLA.
11 |
12 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
13 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
14 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
15 |
16 | # Legal Notices
17 |
18 | Microsoft and any contributors grant you a license to the Microsoft documentation and other content
19 | in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode),
20 | see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the
21 | [LICENSE-CODE](LICENSE-CODE) file.
22 |
23 | Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation
24 | may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries.
25 | The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks.
26 | Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653.
27 |
28 | Privacy information can be found at https://privacy.microsoft.com/en-us/
29 |
30 | Microsoft and any contributors reserve all other rights, whether under their respective copyrights, patents,
31 | or trademarks, whether by implication, estoppel or otherwise.
32 |
--------------------------------------------------------------------------------
/LICENSE-CODE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Doodle to Code: A Practical guide to getting started with Generative AI
3 |
4 | Learn the fundamentals of Generative AI and related technologies from doodles and apply the knowledge by coding. Each content comes with a video, conceptual doodles, and hands-on projects to build a practical app with conversational AI. Optimize your knowledge and enhance your skills!
5 |
6 | 
7 |
8 | ## 🌱 Prerequisites
9 |
10 | For coding exercises, it is recommended to use [Visual Studio Code](https://code.visualstudio.com/) for the best experience.
11 |
12 | To use Azure AI Services, you generally need to have an [Azure account](https://azure.microsoft.com/free/), which allows you to access and manage various Azure services, including AI tools.
13 |
14 | Additionally, some exercises use a bot on Microsoft Teams as an example. You can start developing on Teams and access the sandbox for free, but first you need to get:
15 | - A [Microsoft 365 account](https://developer.microsoft.com/microsoft-365/dev-program) with custom app upload permission
16 | - A [Microsoft 365 tenant](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/prepare-your-o365-tenant)
17 |
18 | ## Topics
19 |
20 | Aside from the first topic, which covers the basics of generative AI, all other topics are standalone projects. You can start with any topic you like!
21 |
22 | | # | Topics | Descriptions |
23 | |---|--------------|--------------|
24 | | 01 | [Generative AI and Prompting 101](01-intro-genai/README.md) | Explore the basic concepts of Large Language Model (LLM) such as GPT, and prompt engineering. Also learn how to use Azure OpenAI services. |
25 | | 02 | [Personalize AI chatbot using prompts](02-clippy/README.md) | Master the art of prompt engineering to build Clippy for Teams using Azure OpenAI and Teams AI Library. |
26 | | 03 | [OpenAI Assistants API](03-assistants-api/README.md) | Learn OpenAI Assistants API and build your own cooking advisor bot on Teams. |
27 | | 04 | [Intro to Retrieval-Augmented Generation (RAG)](04-rag/README.md) | Import your custom data using Azure AI Search and build a RAG-based AI assistant in Python using Teams Toolkit. |
28 | | 05 | [Deploy to a Teams app using Azure OpenAI Studio](05-on-your-data/README.md) | Bring your AI app to Teams using Azure OpenAI Studio's 'Deploy to a Teams App' feature. |
29 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/images/aoai-on-your-data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/aoai-on-your-data.png
--------------------------------------------------------------------------------
/images/assistants api final.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/assistants api final.gif
--------------------------------------------------------------------------------
/images/clippyforteams.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/clippyforteams.png
--------------------------------------------------------------------------------
/images/coffee-cup.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/coffee-cup.gif
--------------------------------------------------------------------------------
/images/doodle-assistants-api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/doodle-assistants-api.png
--------------------------------------------------------------------------------
/images/doodle-genai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/doodle-genai.png
--------------------------------------------------------------------------------
/images/doodle-gpt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/doodle-gpt.png
--------------------------------------------------------------------------------
/images/doodle-rag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/doodle-rag.png
--------------------------------------------------------------------------------
/images/doodle-teamsailib.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/doodle-teamsailib.png
--------------------------------------------------------------------------------
/images/doodle-to-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/doodle-to-code.png
--------------------------------------------------------------------------------
/images/genai-01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/genai-01.gif
--------------------------------------------------------------------------------
/images/genai-02.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/genai-02.gif
--------------------------------------------------------------------------------
/images/screen-openai-playground-assistants-api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/screen-openai-playground-assistants-api.png
--------------------------------------------------------------------------------
/images/space-ai-search.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/doodle-to-code/ba94f33fe1dddba2aa2f54ffb479379ee3cc8c08/images/space-ai-search.gif
--------------------------------------------------------------------------------