├── .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 | ![Doodle: what is Generative AI?](../images/doodle-genai.png) 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 | ![Doodle: what is GPT?](../images/doodle-gpt.png) 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 | [![YouTube: Generative AI and prompting 101](https://img.youtube.com/vi/PGI6oxbcYDc/0.jpg)](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 | ![Prebuilt template test](./../../images/genai-01.gif) 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 | ![Custom prompt test](./../../images/genai-02.gif) -------------------------------------------------------------------------------- /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 | ![Doodle: what is Generative AI?](../images/doodle-teamsailib.png) 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 | [![YouTube: Build Clippy for Teams with Azure OpenAI and Teams AI Library](https://img.youtube.com/vi/OZ6qNiuGo1Q/0.jpg)](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 | ![Clippy Chatbot](./../../images/clippyforteams.png) -------------------------------------------------------------------------------- /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 | ![Doodle: what is Assistants API?](../images/doodle-assistants-api.png) 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 | ![Playground screenshot](../images/screen-openai-playground-assistants-api.png) 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 | [![YouTube: Use OpenAI Assistants API to build your own cooking advisor bot on Teams](https://img.youtube.com/vi/OL23O25jQGE/0.jpg)](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 | ![Cooking Advisor Assistant](./../../images/assistants%20api%20final.gif) 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 | ![RAG as a magical library](../images/doodle-rag.png) 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 | [![YouTube: Use OpenAI Assistants API to build your own cooking advisor bot on Teams](https://img.youtube.com/vi/1k4XGgsqfTM/0.jpg)](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 | ![Space AI Search](./../../images/space-ai-search.gif) -------------------------------------------------------------------------------- /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 | ![Azure OpenAI On Your Data doodle](../images/aoai-on-your-data.png) 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 | [![YouTube: Bring Your AI App to Teams with Azure OpenAI Studio's New 'Deploy to a Teams App' Feature](https://github.com/user-attachments/assets/e3860b28-c3ab-46a1-875b-7df48ff3e17a)](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 | ![Coffee Cup Gif](../../images/coffee-cup.gif) -------------------------------------------------------------------------------- /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 | ![Doodle to Code teaser illustration](images/doodle-to-code.png) 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 --------------------------------------------------------------------------------