├── .devcontainer └── devcontainer.json ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── deploy-to-az-static-web-apps.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── docs ├── assets │ ├── Skills │ │ ├── AdvisorSkill │ │ │ ├── InvestmentAdvise │ │ │ │ ├── config.json │ │ │ │ └── skprompt.txt │ │ │ └── PortfolioAllocation │ │ │ │ ├── config.json │ │ │ │ └── skprompt.txt │ │ └── UserProfileSkill.cs │ ├── images │ │ ├── 00-intro │ │ │ ├── feedback-qr.png │ │ │ ├── sk-samples.png │ │ │ ├── sk-skills.png │ │ │ └── sk.png │ │ ├── 01-design-thinking │ │ │ ├── dt-1.png │ │ │ └── dt-2.png │ │ ├── 1.png │ │ ├── agents-block-diagram.png │ │ ├── ai_application.png │ │ ├── aml-finetune.png │ │ ├── aml-miyagi-dolly.png │ │ ├── basic-arch.png │ │ ├── copilot-stack.png │ │ ├── embeddings.png │ │ ├── favicon.ico │ │ ├── favicon.png │ │ ├── gpt-capabilities.PNG │ │ ├── gpt4-capabilities.PNG │ │ ├── miyagi-dark-bg.png │ │ ├── miyagi.png │ │ ├── plugin.png │ │ ├── prompt-flow-basic.png │ │ ├── sk-memory-orchestration.png │ │ ├── sk-round-trip.png │ │ ├── ui-annotations.png │ │ ├── use-cases-slide.png │ │ ├── video_recording.png │ │ ├── wavenet-animation.gif │ │ ├── wip-architecture.png │ │ ├── wip-azure.png │ │ ├── wip-dreambooth.png │ │ ├── wip-ui.png │ │ └── workshop-gbb.png │ ├── overrides │ │ └── main.html │ └── workshop.pdf ├── index.md └── wksp │ ├── 00-intro │ ├── agenda-and-outcomes.md │ ├── architecture-overview.md │ ├── index.md │ ├── pre-reqs.md │ ├── samples-walk-through.md │ └── semantic-kernel-overview.md │ ├── 01-design-thinking │ ├── design-thinking-canvas.md │ ├── heart-framework.md │ ├── index.md │ └── jobs-to-be-done.md │ ├── 02-fork-and-get-hands-on │ └── index.md │ ├── 03-inner-loop │ └── index.md │ ├── 04-Semantic-Kernel-Basics │ └── index.md │ ├── 05-semantic-kernel-workshop │ ├── create-deployable-app │ │ ├── azd-infra.md │ │ ├── backend-api.md │ │ ├── index.md │ │ └── web-app.md │ ├── images │ │ ├── architecture.png │ │ ├── bing-grounding-connection.jpg │ │ ├── connected-resources.jpg │ │ ├── model-deployments.jpg │ │ ├── open-ai-connection.jpg │ │ ├── public-port.jpg │ │ └── upgrade-connection.jpg │ ├── index.md │ ├── lesson1.md │ ├── lesson2.md │ ├── lesson3.md │ ├── lesson4.md │ ├── lesson5.md │ ├── lesson6.md │ └── pre-reqs.md │ ├── 06-use-cases │ ├── generation.md │ ├── index.md │ └── synthesis.md │ ├── 07-custom-copilot │ ├── extend-copilot-ai-doc-intel.md │ └── index.md │ ├── appendix │ ├── design-patterns.md │ ├── patterns.csv │ ├── samples.csv │ ├── samples.md │ ├── security.csv │ └── security.md │ └── other │ └── feedback.md ├── mkdocs.yml ├── requirements.txt ├── setup.py └── workshop ├── dotnet ├── App │ ├── Directory.Build.props │ ├── Dockerfile │ └── backend │ │ ├── Controllers │ │ ├── ChatController.cs │ │ └── PluginInfoController.cs │ │ ├── Extensions │ │ └── ServiceExtensions.cs │ │ ├── Program.cs │ │ └── backend.csproj ├── Core.Utilities.Tests │ ├── Core.Utilities.Tests.csproj │ ├── Core.Utilities.Tests.sln │ └── Services │ │ └── StocksServiceTest.cs ├── Core.Utilities │ ├── Config │ │ ├── AISettingsProvider.cs │ │ └── KernelBuilderProvider.cs │ ├── Core.Utilities.csproj │ ├── Extensions │ │ └── ModelExtensionMethods.cs │ ├── Models │ │ ├── AggregateStockResponse.cs │ │ ├── AppSettings.cs │ │ ├── ChatMessage.cs │ │ ├── ChatRequest.cs │ │ ├── ChatResponse.cs │ │ ├── PluginFunctionMetadata.cs │ │ └── Stocks.cs │ ├── Plugins │ │ ├── StockDataPlugin.cs │ │ └── TimeInformationPlugin.cs │ └── Services │ │ └── StocksService.cs ├── Directory.Build.props ├── Directory.Packages.props ├── Lessons │ ├── Directory.Build.props │ ├── Lesson1 │ │ ├── Lesson1.csproj │ │ └── Program.cs │ ├── Lesson2 │ │ ├── Lesson2.csproj │ │ └── Program.cs │ ├── Lesson3 │ │ ├── Lesson3.csproj │ │ └── Program.cs │ ├── Lesson4 │ │ ├── Lesson4.csproj │ │ └── Program.cs │ ├── Lesson5 │ │ ├── Lesson5.csproj │ │ └── Program.cs │ ├── Lesson6 │ │ ├── Lesson6.csproj │ │ └── Program.cs │ └── appsettings.json.example ├── Solutions │ ├── Directory.Build.props │ ├── Lesson1 │ │ ├── Lesson1.csproj │ │ └── Program.cs │ ├── Lesson2 │ │ ├── Lesson2.csproj │ │ └── Program.cs │ ├── Lesson3 │ │ ├── Lesson3.csproj │ │ ├── Lesson3.sln │ │ └── Program.cs │ ├── Lesson4 │ │ ├── Lesson4.csproj │ │ └── Program.cs │ ├── Lesson5 │ │ ├── Lesson5.csproj │ │ └── Program.cs │ ├── Lesson6 │ │ ├── Lesson6.csproj │ │ └── Program.cs │ └── Solutions.sln ├── azure.yaml ├── dotnet.sln └── infra │ ├── abbreviations.json │ ├── app │ ├── api.bicep │ ├── user-assigned-identity.bicep │ └── web.bicep │ ├── core │ ├── ai │ │ └── cognitiveservices.bicep │ ├── bing │ │ └── bing-search.bicep │ ├── host │ │ ├── container-app-upsert.bicep │ │ ├── container-app.bicep │ │ ├── container-apps-environment.bicep │ │ ├── container-apps.bicep │ │ └── container-registry.bicep │ ├── monitor │ │ ├── applicationinsights-dashboard.bicep │ │ ├── applicationinsights.bicep │ │ ├── loganalytics.bicep │ │ └── monitoring.bicep │ ├── security │ │ ├── keyvault-access.bicep │ │ ├── keyvault-secret.bicep │ │ ├── keyvault-secrets.bicep │ │ ├── keyvault.bicep │ │ ├── registry-access.bicep │ │ ├── role.bicep │ │ └── subscription-role.bicep │ └── storage │ │ └── storage-account.bicep │ ├── main.bicep │ └── main.parameters.json ├── frontend ├── .dockerignore ├── .github │ └── workflows │ │ └── azure-container-apps-deploy.yml ├── Dockerfile ├── README.md ├── package.json ├── public │ └── index.html ├── server.js ├── src │ ├── App.tsx │ └── index.tsx └── tsconfig.json └── pre-reqs ├── azure.yaml └── infra ├── abbreviations.json ├── main.bicep ├── main.parameters.json └── modules └── cognitive-services.bicep /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/devcontainers/base:ubuntu", 3 | "features": { 4 | "ghcr.io/devcontainers/features/dotnet:1": { 5 | "version": "9.0" 6 | }, 7 | "ghcr.io/azure/azure-dev/azd:latest": {}, 8 | "ghcr.io/devcontainers/features/azure-cli:latest": {} 9 | }, 10 | "customizations": { 11 | "vscode": { 12 | "extensions": [ 13 | "ms-dotnettools.csdevkit", 14 | "EditorConfig.EditorConfig", 15 | "GitHub.copilot" 16 | ] 17 | } 18 | }, 19 | "hostRequirements": { 20 | "memory": "8gb" 21 | }, 22 | "remoteUser": "vscode", 23 | "runArgs": ["--dns=8.8.8.8", "--dns=1.1.1.1"] 24 | } 25 | -------------------------------------------------------------------------------- /.github/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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | > Please provide us with the following information: 5 | > --------------------------------------------------------------- 6 | 7 | ### This issue is for a: (mark with an `x`) 8 | ``` 9 | - [ ] bug report -> please search issues before submitting 10 | - [ ] feature request 11 | - [ ] documentation issue or request 12 | - [ ] regression (a behavior that used to work and stopped in a new release) 13 | ``` 14 | 15 | ### Minimal steps to reproduce 16 | > 17 | 18 | ### Any log messages given by the failure 19 | > 20 | 21 | ### Expected/desired behavior 22 | > 23 | 24 | ### OS and Version? 25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) 26 | 27 | ### Versions 28 | > 29 | 30 | ### Mention any other details that might be useful 31 | 32 | > --------------------------------------------------------------- 33 | > Thanks! We'll be in touch soon. 34 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | * ... 4 | 5 | ## Does this introduce a breaking change? 6 | 7 | ``` 8 | [ ] Yes 9 | [ ] No 10 | ``` 11 | 12 | ## Pull Request Type 13 | What kind of change does this Pull Request introduce? 14 | 15 | 16 | ``` 17 | [ ] Bugfix 18 | [ ] Feature 19 | [ ] Code style update (formatting, local variables) 20 | [ ] Refactoring (no functional changes, no api changes) 21 | [ ] Documentation content changes 22 | [ ] Other... Please describe: 23 | ``` 24 | 25 | ## How to Test 26 | * Get the code 27 | 28 | ``` 29 | git clone [repo-address] 30 | cd [repo-name] 31 | git checkout [branch-name] 32 | npm install 33 | ``` 34 | 35 | * Test the code 36 | 37 | ``` 38 | ``` 39 | 40 | ## What to Check 41 | Verify that the following are valid 42 | * ... 43 | 44 | ## Other Information 45 | -------------------------------------------------------------------------------- /.github/workflows/deploy-to-az-static-web-apps.yml: -------------------------------------------------------------------------------- 1 | # This Action builds the documentation site in mkdocs 2 | # and pushes it to Azure from where it is deployed 3 | # to https://iappwksp.com 4 | 5 | name: deploy-to-az-static-web-apps.yml 6 | 7 | on: 8 | push: 9 | branches: 10 | - 'main' 11 | pull_request: 12 | types: [opened, synchronize, reopened, closed] 13 | branches: 14 | - live 15 | permissions: 16 | contents: write 17 | pull-requests: write # this permission is required in order to allow PR comment with staging URL 18 | jobs: 19 | build_and_deploy_job: 20 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') 21 | runs-on: ubuntu-latest 22 | env: 23 | ENABLE_PDF_EXPORT: 1 # Makes PDF export an option, default disabled, when building locally 24 | ENABLE_GIT_COMMITTERS: True # Makes git-committers an option, default disabled, when building locally 25 | name: Build and Deploy to Azure 26 | steps: 27 | - uses: actions/checkout@v3 28 | with: 29 | fetch-depth: 0 30 | submodules: true 31 | - uses: actions/setup-python@v4 32 | with: 33 | python-version: '3.11' 34 | - run: pip install git+https://${{ secrets.MIYAGI_DOCS_GH_ACTION_TKN }}@github.com/Azure/intelligent-app-workshop.git 35 | - run: pip install -r requirements.txt 36 | - run: mkdocs build 37 | - name: Upload to Azure 38 | id: builddeploy 39 | uses: Azure/static-web-apps-deploy@v1 40 | with: 41 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} 42 | repo_token: ${{ secrets.MIYAGI_DOCS_GH_ACTION_TKN }} # Used for GitHub integrations (i.e. PR comments) 43 | action: "upload" 44 | production_branch: "main" 45 | ###### Repository/Build Configurations ###### 46 | app_location: "" # App source code path relative to repository root 47 | api_location: "" # Api source code path relative to repository root - optional 48 | output_location: "site" # Built app content directory, relative to app_location - optional 49 | ###### End of Repository/Build Configurations ###### 50 | 51 | close_pull_request_job: 52 | if: github.event_name == 'pull_request' && github.event.action == 'closed' 53 | runs-on: ubuntu-latest 54 | name: Close Pull Request Job 55 | steps: 56 | - name: Close Pull Request 57 | id: closepullrequest 58 | uses: Azure/static-web-apps-deploy@v1 59 | with: 60 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} 61 | action: "close" 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | node_modules/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | 52 | # Scrapy stuff: 53 | .scrapy 54 | 55 | # PyBuilder 56 | target/ 57 | 58 | # IPython Notebook 59 | .ipynb_checkpoints 60 | 61 | # pyenv 62 | .python-version 63 | 64 | # virtualenv 65 | venv/ 66 | ENV/ 67 | 68 | # MkDocs documentation 69 | site*/ 70 | .vscode/ 71 | 72 | # Build results 73 | [Dd]ebug/ 74 | [Dd]ebugPublic/ 75 | [Rr]elease/ 76 | [Rr]eleases/ 77 | x64/ 78 | x86/ 79 | [Aa][Rr][Mm]/ 80 | [Aa][Rr][Mm]64/ 81 | bld/ 82 | [Bb]in/ 83 | [Oo]bj/ 84 | [Ll]og/ 85 | [Ll]ogs/ 86 | 87 | # Frontend/react/npm files 88 | appsettings.json 89 | .env 90 | package-lock.json 91 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [project-title] Changelog 2 | 3 | 4 | # x.y.z (yyyy-mm-dd) 5 | 6 | *Features* 7 | * ... 8 | 9 | *Bug Fixes* 10 | * ... 11 | 12 | *Breaking Changes* 13 | * ... 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to [project-title] 2 | 3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 5 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 6 | 7 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 8 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 9 | provided by the bot. You will only need to do this once across all repos using our CLA. 10 | 11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 14 | 15 | - [Code of Conduct](#coc) 16 | - [Issues and Bugs](#issue) 17 | - [Feature Requests](#feature) 18 | - [Submission Guidelines](#submit) 19 | 20 | ## Code of Conduct 21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 22 | 23 | ## Found an Issue? 24 | If you find a bug in the source code or a mistake in the documentation, you can help us by 25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can 26 | [submit a Pull Request](#submit-pr) with a fix. 27 | 28 | ## Want a Feature? 29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub 30 | Repository. If you would like to *implement* a new feature, please submit an issue with 31 | a proposal for your work first, to be sure that we can use it. 32 | 33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). 34 | 35 | ## Submission Guidelines 36 | 37 | ### Submitting an Issue 38 | Before you submit an issue, search the archive, maybe your question was already answered. 39 | 40 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 41 | Help us to maximize the effort we can spend fixing issues and adding new 42 | features, by not reporting duplicate issues. Providing the following information will increase the 43 | chances of your issue being dealt with quickly: 44 | 45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 46 | * **Version** - what version is affected (e.g. 0.1.2) 47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you 48 | * **Browsers and Operating System** - is this a problem with all browsers? 49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps 50 | * **Related Issues** - has a similar issue been reported before? 51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 52 | causing the problem (line of code or commit) 53 | 54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new]. 55 | 56 | ### Submitting a Pull Request (PR) 57 | Before you submit your Pull Request (PR) consider the following guidelines: 58 | 59 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR 60 | that relates to your submission. You don't want to duplicate effort. 61 | 62 | * Make your changes in a new git fork: 63 | 64 | * Commit your changes using a descriptive commit message 65 | * Push your fork to GitHub: 66 | * In GitHub, create a pull request 67 | * If we suggest changes then: 68 | * Make the required updates. 69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): 70 | 71 | ```shell 72 | git rebase master -i 73 | git push -f 74 | ``` 75 | 76 | That's it! Thank you for your contribution! 77 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Envisioning Workshop: Build Your Own Custom Copilot 2 | 3 | [![Open in Visual Studio Code](https://img.shields.io/static/v1?logo=visualstudiocode&label=&message=Open%20in%20VS%20Code&labelColor=2c2c32&color=007acc&logoColor=007acc)](https://github.dev/Azure/intelligent-app-workshop) 4 | [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA-222.svg)](https://creativecommons.org/licenses/by-sa/4.0/) 5 | 6 | Welcome to this envisioning workshop designed to help you build your own custom Copilot using [Microsoft's Copilot stack](https://developer.microsoft.com/en-us/copilot). This workshop aims to rethink user experience, architecture, and app development by leveraging reasoning engines (Foundation models and Language Models) and semantic memory systems. 7 | 8 | ## Workshop Overview 9 | 10 | In this comprehensive workshop, you will: 11 | 12 | - Utilize Azure AI Foundry for reasoning engines, Prompt Flow for LLMOps, AI Search for semantic retrieval systems, and Semantic Kernel for orchestration. 13 | - Work with [Miyagi](https://github.com/Azure-Samples/miyagi) codebase during the hands-on experiential workshop 14 | - Explore advanced capabilities such as AutoGen and GraphRag 15 | 16 | ## Objectives 17 | 18 | This workshop will guide you through the entire lifecycle of app development, including: 19 | 20 | 1. Identifying user needs 21 | 2. Developing a fully functional, production-grade app 22 | 3. Deploying your app on Azure with advanced capabilities 23 | 24 | By the end of this workshop, you will have a deeper understanding of how to leverage Microsoft's tools and technologies to create intelligent applications. 25 | 26 | 27 |

28 | 29 | ![wip-azure](docs/assets/images/wip-azure.png) 30 | 31 | 32 | 33 | ### Disclaimer 34 | 35 | This software is provided for demonstration purposes only. It is not intended to be relied upon for any purpose. The creators of this software make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the software or the information, products, services, or related graphics contained in the software for any purpose. Any reliance you place on such information is therefore strictly at your own risk. 36 | 37 | ### License 38 | 39 | This software is provided for demonstration purposes only. It is not intended to be relied upon for any purpose. The software is provided “as is” and without any warranties, express or implied. The software is not intended to be used for any commercial purpose. The software is provided solely for demonstration purposes and should not be used for any other purpose. The software is provided without any warranty of any kind, either express or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. The software is provided “as is” and without any warranty of any kind. The user assumes all risk and responsibility for the use of the software. -------------------------------------------------------------------------------- /docs/assets/Skills/AdvisorSkill/InvestmentAdvise/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": 1, 3 | "type": "completion", 4 | "description": "Gives financial advise on how to allocate portfolio, given a risk tolerance and a set of assets", 5 | "completion": { 6 | "max_tokens": 512, 7 | "temperature": 0.9, 8 | "top_p": 1.0, 9 | "presence_penalty": 1.0, 10 | "frequency_penalty": 1.0 11 | }, 12 | "input": { 13 | "parameters": [ 14 | { 15 | "name": "portfolio", 16 | "description": "Asset portfolio as JSON text", 17 | "defaultValue": "" 18 | }, 19 | { 20 | "name": "user", 21 | "description": "User information as JSON text", 22 | "defaultValue": "" 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/assets/Skills/AdvisorSkill/InvestmentAdvise/skprompt.txt: -------------------------------------------------------------------------------- 1 | System: ONLY USE JSON PROPERTIES IN THIS LIST: 2 | [JSON PROPERTY LIST] 3 | portfolio 4 | [END LIST] 5 | 6 | [CONTENT] 7 | { 8 | {{$stocks}} 9 | } 10 | [END CONTENT] 11 | 12 | EMIT WELL FORMED JSON ALWAYS. 13 | BE BRIEF AND TO THE POINT. 14 | 15 | This is a chat between systems that respond in valid JSON. You are a financial advisor JSON service that only emits 16 | valid financial advise in parsable JSON. For gptRecommendation attribute, use the voice of {{$voice}} and be creative but limit to a sentence less than 20 words. 17 | Provide advice based on the given portfolio allocation and user information such as a age, income, and risk. 18 | For someone who is {{UserProfilePlugin.GetUserAge $userId}} years old, with {{UserProfilePlugin.GetAnnualHouseholdIncome $userId}} as household income, and with a risk tolerance of {{$risk}}, what recommendation would {{$voice}} give. 19 | Return well-formed JSON with a "gptRecommendation" property containing {{$voice}}'s' recommendation in a creative and funny tone. 20 | Example: {"portfolio":[{"symbol":"MSFT","gptRecommendation":"Booyah! Hold on, steady growth! Diversify, though!"},{"symbol":"PEP","gptRecommendation":"Buy, buy, buy! Solid dividends, sweet stability!"}]} 21 | 22 | Zeitgeist to consider: 23 | current inflation and mortgage rates: {{$bingResults}} 24 | 25 | wisdom of crowds opinions: {{recall "investment advise"} 26 | 27 | +++++ -------------------------------------------------------------------------------- /docs/assets/Skills/AdvisorSkill/PortfolioAllocation/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": 1, 3 | "type": "completion", 4 | "description": "Gives financial advise on how to allocate portfolio, given a risk tolerance and a set of assets", 5 | "completion": { 6 | "max_tokens": 512, 7 | "temperature": 0.4, 8 | "top_p": 1.0, 9 | "presence_penalty": 0.0, 10 | "frequency_penalty": 0.0 11 | }, 12 | "input": { 13 | "parameters": [ 14 | { 15 | "name": "portfolio", 16 | "description": "Asset portfolio as JSON text", 17 | "defaultValue": "" 18 | }, 19 | { 20 | "name": "user", 21 | "description": "User information as JSON text", 22 | "defaultValue": "" 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/assets/Skills/AdvisorSkill/PortfolioAllocation/skprompt.txt: -------------------------------------------------------------------------------- 1 | ONLY USE JSON PROPERTIES IN THIS LIST: 2 | [JSON PROPERTY LIST] 3 | portfolio 4 | [END LIST] 5 | 6 | [CONTENT] 7 | { 8 | {{$portfolio}} 9 | } 10 | [END CONTENT] 11 | 12 | EMIT WELL FORMED JSON ALWAYS. 13 | BE BRIEF AND TO THE POINT. 14 | 15 | This is a chat between systems that respond in valid JSON. You are a financial advisor JSON service that only emits 16 | valid financial advise in parsable JSON. For gptRecommendation attribute, provide advice based on the given portfolio allocation and user information such as a age, income, and risk. 17 | For someone who is {{UserProfilePlugin.GetUserAge $userId}} years old, with {{UserProfilePlugin.GetAnnualHouseholdIncome $userId}} as household income, and with a risk tolerance of {{$risk}}, what is an ideal advice on the given portfolio allocation? 18 | Your advice should be one of the following outputs: "Buy", "Sell", or "Hold" as show in the example below. 19 | Return well-formed JSON with an "gptRecommendation" property containing your recommendation. 20 | Example: {"portfolio":[{"name":"Stocks","gptRecommendation":""},{"name":"Bonds","gptRecommendation":""},{"name":"Cash","gptRecommendation":""},{"name":"Home Equity","gptRecommendation":""}]} 21 | 22 | +++++ 23 | 24 | -------------------------------------------------------------------------------- /docs/assets/Skills/UserProfileSkill.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | 3 | using System.ComponentModel; 4 | using Microsoft.SemanticKernel.Orchestration; 5 | using Microsoft.SemanticKernel.SkillDefinition; 6 | 7 | namespace GBB.Miyagi.RecommendationService.plugins; 8 | 9 | /// 10 | /// UserProfilePlugin shows a native skill example to look user info given userId. 11 | /// 12 | /// 13 | /// Usage: kernel.ImportSkill("UserProfilePlugin", new UserProfilePlugin()); 14 | /// Examples: 15 | /// SKContext["userId"] = "000" 16 | /// {{UserProfilePlugin.GetUserAge $userId }} => {userProfile} 17 | /// 18 | public class UserProfilePlugin 19 | { 20 | /// 21 | /// Name of the context variable used for UserId. 22 | /// 23 | public const string UserId = "UserId"; 24 | 25 | private const string DefaultUserId = "40"; 26 | private const int DefaultAnnualHouseholdIncome = 150000; 27 | private const int Normalize = 81; 28 | 29 | /// 30 | /// Lookup User's age for a given UserId. 31 | /// 32 | /// 33 | /// SKContext[UserProfilePlugin.UserId] = "000" 34 | /// 35 | /// Contains the context variables. 36 | [SKFunction] 37 | [SKName("GetUserAge")] 38 | [Description("Given a userId, get user age")] 39 | public string GetUserAge( 40 | [Description("Unique identifier of a user")] 41 | string userId, 42 | SKContext context) 43 | { 44 | // userId = context.Variables.ContainsKey(UserId) ? context[UserId] : DefaultUserId; 45 | userId = string.IsNullOrEmpty(userId) ? DefaultUserId : userId; 46 | context.Log.LogDebug("Returning hard coded age for {0}", userId); 47 | 48 | int age; 49 | 50 | if (int.TryParse(userId, out var parsedUserId)) 51 | age = parsedUserId > 100 ? parsedUserId % Normalize : parsedUserId; 52 | else 53 | age = int.Parse(DefaultUserId); 54 | 55 | // invoke a service to get the age of the user, given the userId 56 | return age.ToString(); 57 | } 58 | 59 | /// 60 | /// Lookup User's annual income given UserId. 61 | /// 62 | /// 63 | /// SKContext[UserProfilePlugin.UserId] = "000" 64 | /// 65 | /// Contains the context variables. 66 | [SKFunction] 67 | [SKName("GetAnnualHouseholdIncome")] 68 | [Description("Given a userId, get user annual household income")] 69 | public string GetAnnualHouseholdIncome( 70 | [Description("Unique identifier of a user")] 71 | string userId, 72 | SKContext context) 73 | { 74 | // userId = context.Variables.ContainsKey(UserId) ? context[UserId] : DefaultUserId; 75 | userId = string.IsNullOrEmpty(userId) ? DefaultUserId : userId; 76 | context.Log.LogDebug("Returning userId * randomMultiplier for {0}", userId); 77 | 78 | var random = new Random(); 79 | var randomMultiplier = random.Next(1000, 8000); 80 | 81 | // invoke a service to get the annual household income of the user, given the userId 82 | var annualHouseholdIncome = int.TryParse(userId, out var parsedUserId) 83 | ? parsedUserId * randomMultiplier 84 | : DefaultAnnualHouseholdIncome; 85 | 86 | return annualHouseholdIncome.ToString(); 87 | } 88 | } -------------------------------------------------------------------------------- /docs/assets/images/00-intro/feedback-qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/00-intro/feedback-qr.png -------------------------------------------------------------------------------- /docs/assets/images/00-intro/sk-samples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/00-intro/sk-samples.png -------------------------------------------------------------------------------- /docs/assets/images/00-intro/sk-skills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/00-intro/sk-skills.png -------------------------------------------------------------------------------- /docs/assets/images/00-intro/sk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/00-intro/sk.png -------------------------------------------------------------------------------- /docs/assets/images/01-design-thinking/dt-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/01-design-thinking/dt-1.png -------------------------------------------------------------------------------- /docs/assets/images/01-design-thinking/dt-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/01-design-thinking/dt-2.png -------------------------------------------------------------------------------- /docs/assets/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/1.png -------------------------------------------------------------------------------- /docs/assets/images/agents-block-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/agents-block-diagram.png -------------------------------------------------------------------------------- /docs/assets/images/ai_application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/ai_application.png -------------------------------------------------------------------------------- /docs/assets/images/aml-finetune.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/aml-finetune.png -------------------------------------------------------------------------------- /docs/assets/images/aml-miyagi-dolly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/aml-miyagi-dolly.png -------------------------------------------------------------------------------- /docs/assets/images/basic-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/basic-arch.png -------------------------------------------------------------------------------- /docs/assets/images/copilot-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/copilot-stack.png -------------------------------------------------------------------------------- /docs/assets/images/embeddings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/embeddings.png -------------------------------------------------------------------------------- /docs/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/favicon.ico -------------------------------------------------------------------------------- /docs/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/favicon.png -------------------------------------------------------------------------------- /docs/assets/images/gpt-capabilities.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/gpt-capabilities.PNG -------------------------------------------------------------------------------- /docs/assets/images/gpt4-capabilities.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/gpt4-capabilities.PNG -------------------------------------------------------------------------------- /docs/assets/images/miyagi-dark-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/miyagi-dark-bg.png -------------------------------------------------------------------------------- /docs/assets/images/miyagi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/miyagi.png -------------------------------------------------------------------------------- /docs/assets/images/plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/plugin.png -------------------------------------------------------------------------------- /docs/assets/images/prompt-flow-basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/prompt-flow-basic.png -------------------------------------------------------------------------------- /docs/assets/images/sk-memory-orchestration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/sk-memory-orchestration.png -------------------------------------------------------------------------------- /docs/assets/images/sk-round-trip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/sk-round-trip.png -------------------------------------------------------------------------------- /docs/assets/images/ui-annotations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/ui-annotations.png -------------------------------------------------------------------------------- /docs/assets/images/use-cases-slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/use-cases-slide.png -------------------------------------------------------------------------------- /docs/assets/images/video_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/video_recording.png -------------------------------------------------------------------------------- /docs/assets/images/wavenet-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/wavenet-animation.gif -------------------------------------------------------------------------------- /docs/assets/images/wip-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/wip-architecture.png -------------------------------------------------------------------------------- /docs/assets/images/wip-azure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/wip-azure.png -------------------------------------------------------------------------------- /docs/assets/images/wip-dreambooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/wip-dreambooth.png -------------------------------------------------------------------------------- /docs/assets/images/wip-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/wip-ui.png -------------------------------------------------------------------------------- /docs/assets/images/workshop-gbb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/images/workshop-gbb.png -------------------------------------------------------------------------------- /docs/assets/overrides/main.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block scripts %} 4 | 5 | {{ super() }} 6 | 7 | 14 | {% endblock %} 15 | 16 | 17 | {% block site_meta %} 18 | 19 | 20 | 21 | 22 | {% if page.meta and page.meta.description %} 23 | 24 | {% elif config.site_description %} 25 | 26 | {% endif %} 27 | 28 | 29 | {% if page.meta and page.meta.author %} 30 | 31 | {% elif config.site_author %} 32 | 33 | {% endif %} 34 | 35 | 36 | {% if page and page.meta and page.meta.canonical_url %} 37 | 38 | {% elif page.canonical_url %} 39 | 40 | {% endif %} 41 | 42 | 43 | {% if page.previous_page %} 44 | 45 | {% endif %} 46 | 47 | 48 | {% if page.next_page %} 49 | 50 | {% endif %} 51 | 52 | 53 | 54 | 55 | 56 | 60 | {% endblock %} 61 | 62 | {% block extrahead %} 63 | {% if page and page.meta and page.meta.canonical_url %} 64 | 65 | {% endif %} 66 | {% endblock %} -------------------------------------------------------------------------------- /docs/assets/workshop.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/assets/workshop.pdf -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Home 2 | 3 | Inspired by Github Copilot's impact on developer productivity, this experiential workshop is designed to demonstrate how you can infuse similar intelligence and product experience into traditional software systems. Using [Microsoft's Copilot stack](https://developer.microsoft.com/en-us/copilot) and practical [use cases](https://iappwksp.com/wksp/05-use-cases/#use-cases), this workshop will guide you in envisioning and creating intelligent systems and agents that integrate foundation models throughout your workflows and applications, resulting in improved productivity and hyper-personalized user experiences. 4 | 5 | [Sign up for updates](https://forms.office.com/r/rLds2s8RH1){ :target="_blank" .md-button .md-button--primary } 6 | 7 | !!! note "" 8 | 9 | :tv: For a preview, catch the [recording on :simple-youtube: Cosmos DB Live TV](https://www.youtube.com/watch?v=V8dlEvXdGEM&t=144s). For an overview on mental models, see [this video from Semantic Kernel's Channel](https://www.youtube.com/watch?v=EueJTTuluVQ&t=750s). 10 | 11 | 12 | ## Workshop Overview 13 | 14 | In this comprehensive workshop, you will: 15 | 16 | - Utilize Azure AI Foundry for reasoning engines, Prompt Flow for LLMOps, AI Search for semantic retrieval systems, and Semantic Kernel for orchestration. 17 | - Work with [Miyagi](https://github.com/Azure-Samples/miyagi) codebase during the hands-on experiential workshop. 18 | - Explore advanced capabilities such as AutoGen and GraphRaG. 19 | 20 | 21 | ## Topics for the Workshop 22 | 23 | ???+ info "Pre-requisite" 24 | 25 | Please complete the [Getting Started with AOAI module](https://learn.microsoft.com/en-us/training/modules/get-started-openai/) to get the most out of this workshop. 26 | 27 | 1. **Brief Overview of Gen AI Capabilities and Use Cases**: Explore the art of the possible with multi-agent and advanced retrieval systems using samples like [Miyagi](https://github.com/Azure-Samples/miyagi) and [Holmes](https://github.com/Azure-Samples/holmes). Engage in interactive demonstrations to envision potential applications with reasoning engines and semantic memory systems. 28 | 1. **Design Thinking Session (Optional)**: Participate in a collaborative brainstorming activity to identify your unique use cases, focusing on addressing user needs and alleviating pain points, ensuring the workshop is relevant to you. 29 | 1. **AI Studio and Prompt Flow**: Quickly get started with your own copilot, grounded by your proprietary data in AI Search using our AI Studio experience. Customize it with Prompt Flow and deploy it to a production endpoint, including LLMOps integration. 30 | 1. **AI Orchestration SDKs**: Enhance your custom copilot by integrating it with existing APIs and incorporating advanced orchestration and multi-turn LLM interactions using SDKs like Semantic Kernel and LangChain. 31 | 1. **Multi-Agent and Advanced Retrieval**: Further develop your solution by leveraging multi-agent capabilities for reliable outputs and complex inference tasks with AutoGen, Assistants API, and GraphRag. 32 | 1. **Other Use Cases**: Explore AI Document Intelligence and Vision model capabilities for automating business workflows. 33 | 34 |

35 |

36 | 37 | [See full agenda](wksp/00-intro/agenda-and-outcomes.md){ .md-button } 38 | 39 | 40 | 41 | ### Disclaimer 42 | 43 | This software is provided for demonstration purposes only. It is not intended to be relied upon for any purpose. The creators of this software make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the software or the information, products, services, or related graphics contained in the software for any purpose. Any reliance you place on such information is therefore strictly at your own risk. 44 | 45 | ### License 46 | 47 | This software is provided for demonstration purposes only. It is not intended to be relied upon for any purpose. The software is provided “as is” and without any warranties, express or implied. The software is not intended to be used for any commercial purpose. The software is provided solely for demonstration purposes and should not be used for any other purpose. The software is provided without any warranty of any kind, either express or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. The software is provided “as is” and without any warranty of any kind. The user assumes all risk and responsibility for the use of the software. 48 | -------------------------------------------------------------------------------- /docs/wksp/00-intro/agenda-and-outcomes.md: -------------------------------------------------------------------------------- 1 | # Agenda & Outcomes 2 | 3 | [Sign up for updates](https://forms.office.com/r/rLds2s8RH1){ :target="_blank" .md-button .md-button--primary } 4 | 5 | ## Agenda 6 | 7 | 1. Introduction to Intelligent App Development with Copilot stack 8 | 1. Unveiling the Art of the Possible: Inspiring Walkthroughs 9 | - [Miyagi](https://github.com/Azure-Samples/miyagi) 10 | - [Semantic Kernel Samples](https://github.com/microsoft/semantic-kernel#check-out-our-other-repos) 11 | - [Reddog](https://github.com/Azure/reddog-solutions) 12 | 1. Comprehensive Architecture Overview 13 | 1. Essential Pre-requisites 14 | 1. Unearthing Customer Needs and Pain Points (Design Thinking session to personalize the workshop for your organization needs and use cases) 15 | 1. Crafting AI-Driven Design and User Experience 16 | 1. First steps to integrate AI into cloud-native and Azure backing services and data processing 17 | 1. Empowering Development with AI Capabilities (inner-loop), including leveraging Github CoPilot 18 | 1. Learn LLM capabilities and Prompt Engineering 19 | 1. In-context learning (ICL) 20 | 1. Prompt Engineering techniques 21 | 1. Advanced Retrieval augmented generation (RaG) 22 | 1. Integrating vector databases 23 | 1. Prompt Flow 24 | 1. Agents with Semantic Kernel, Autogen, and TaskWeaver 25 | 1. Deep-dive into AI orchestration primitives through use cases with Miyagi and Reddog 26 | 1. Exploring Agents and Agent-like Orchestration 27 | 1. Tradeoffs with AI orchestrators (Semantic Kernel, Langchain, Guidance, TypeChat, PromptFlow etc.) 28 | 1. Copilot Studio and Power Platform 29 | 1. AI Studio and Prompt Flow 30 | 1. AI Content Safety Studio 31 | 1. Fine-tuning OSS models with proprietary training data to improve task specific accuracy and latency 32 | 1. Streamlined Deployment and Monitoring of AI-Infused Apps 33 | 1. (Optional) First Principles of Large Language Models for application developers 34 | 1. High Level Overview of AI and ML 35 | 1. Overview and History of NLP, NLU, and NLG 36 | 1. Autoregressive Models 37 | 1. NLP: RNNs to Transformers 38 | 1. Computer Vision: CNNs to Vision Transformers (ViT) 39 | 1. Audio: Wav2Vec2, Whisper 40 | 1. Multimodal: VisualBERT, CLIP 41 | 1. Reliability & Responsible AI for developers 42 | 1. Ensuring Reliability and Controllability of LLM Output 43 | 1. Grounding 44 | 1. Alignment 45 | 1. Retrieval augmented generation (RaG) 46 | 1. Hands-on Project: Constructing a Semantic Kernel Plugin and integrating it with an Existing App using Miyagi 47 | 1. Reliability and controllability of LLM output 48 | 1. Embracing "Everything as Code": Automation, Deployment, and Operationalization for production 49 | 1. Architecture Design Session: Crafting a customized PoC for your unique use case(s) 50 | 1. Conclusion and Next Steps with MVP 51 | 52 | ## Outcomes 53 | 54 | Upon completing this workshop, participants will: 55 | 56 | - Comprehend the transformative potential of Azure AI services and Copilot Stack in revolutionizing every facet of AI app development. 57 | - Acquire hands-on experience in AI-driven design and user experience techniques 58 | - Learn to effortlessly integrate foundation models into backend services, data processing, and frontend development 59 | - Build an AI-infused app from the ground up during the hands-on project 60 | - Implement Agents using Assistants API, Code Interpretor, and Retrieval intefaces. 61 | 62 | -------------------------------------------------------------------------------- /docs/wksp/00-intro/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | In this hands-on workshop, we will explore how to use Microsoft's Copilot Stack to develop your own AI-infused, enterprise-grade applications that improve productivity and create hyper-personalized product experiences. 4 | 5 | We will also highlight the emergent capabilities that are advantageous to adopt, as well as the limitations that can be mitigated through engineering, particularly in the areas of orchestration and retrieval. Additionally, we will showcase the capabilities within the Copilot Stack that enable you to achieve this. 6 | 7 | 8 | ![gpt-capabilities](../../assets/images/gpt-capabilities.PNG) 9 | 10 | ## Overview 11 | 12 | This workshop offers a methodical, hands-on approach that starts with the basics and gradually introduces you to advanced capabilities. It covers a broad range of topics, including the latest frameworks, methodologies, and architectures in AI-driven app development, along with production-grade deployment options on Azure. We will begin with Azure AI Foundry and Prompt Flow to demonstrate how easy it is to get started. From there, we will dive deeper into SDK-based development, utilizing AI orchestration libraries (Semantic Kernel, Langchain, Llamaindex) integrated with Azure AI's LLMOps tooling, the multi-agent framework with AutoGen with Assistants API, and advanced retrieval systems using GraphRag. Once you are well-versed in these capabilities, the next step is to identify customer needs and work backwards to determine how these technologies can be integrated into the development process to address those needs effectively. 13 | 14 | ### Who is this for 15 | 16 | This workshop is designed for: 17 | 18 | - Developers and Architects with a foundational understanding of app development who want to incorporate AI into their applications. 19 | - Product managers and designers interested in leveraging AI to enhance user experiences. 20 | - Anyone curious about the potential of AI in app development. 21 | 22 | ### Disclaimer 23 | 24 | This software is provided for demonstration purposes only. It is not intended to be relied upon for any purpose. The creators of this software make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the software or the information, products, services, or related graphics contained in the software for any purpose. Any reliance you place on such information is therefore strictly at your own risk. 25 | 26 | ### License 27 | 28 | This software is provided for demonstration purposes only. It is not intended to be relied upon for any purpose. The software is provided “as is” and without any warranties, express or implied. The software is not intended to be used for any commercial purpose. The software is provided solely for demonstration purposes and should not be used for any other purpose. The software is provided without any warranty of any kind, either express or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. The software is provided “as is” and without any warranty of any kind. The user assumes all risk and responsibility for the use of the software. -------------------------------------------------------------------------------- /docs/wksp/00-intro/pre-reqs.md: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | 3 | !!! note "Mandatory pre-requisite" 4 | 5 | Please signup for [Azure OpenAI (AOAI)](https://aka.ms/oai/access) and complete [Getting started with AOAI module](https://learn.microsoft.com/en-us/training/modules/get-started-openai/) 6 | 7 | Before attending the Intelligent App Development Workshop, please ensure you have the following prerequisites in place: 8 | 9 | 1. **Basic programming knowledge**: Familiarity with at least one programming language (e.g., Python, JavaScript, Java, or C#) and basic understanding of software development concepts. 10 | 1. **Azure account**: A Microsoft Azure account with an active subscription. If you don't have one, sign up for a [free trial](https://azure.microsoft.com/en-us/free/). 11 | 1. 1. **Azure OpenAI**: Ability to provision an [Azure AIFoundry](https://azure.microsoft.com/en-us/products/ai-foundry/) resource is required. 12 | 1. **Development environment**: A computer with your preferred development environment installed, such as Visual Studio Code, PyCharm, or another IDE that supports the programming language you'll be using in the workshop. 13 | 1. **Git**: Familiarity with Git and GitHub for version control. Ensure you have [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) installed on your computer. 14 | 15 | ??? note "Optional" 16 | The following prerequisites are optional but recommended to get the most out of the workshop: 17 | 18 | 1. **Azure CLI**: Install the [Azure Command-Line Interface (CLI)](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) to interact with Azure services and manage resources from the command line. 19 | 20 | 2. **Azure Functions Core Tools**: Install the [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash#v2) to create, test, and deploy Azure Functions from your local development environment. 21 | 22 | 3. **Docker**: Install [Docker Desktop](https://www.docker.com/products/docker-desktop) to build and run containerized applications. 23 | 24 | 4. **Hugging Face Transformers**: Familiarity with the [Hugging Face Transformers](https://huggingface.co/transformers/) library for Natural Language Processing tasks using pre-trained models is recommended but not mandatory. 25 | 26 | 5. **Cognitive Services SDKs**: Install the SDKs for the Azure Cognitive Services you'll be using in the workshop, such as the [Azure OpenAI SDK](https://pypi.org/project/azure-cognitiveservices-openai/), based on your programming language and the services used during the workshop. 27 | 28 | By ensuring you have completed these prerequisites, you'll be well-prepared to dive into the Intelligent App Development Workshop and make the most of the hands-on learning experience. 29 | -------------------------------------------------------------------------------- /docs/wksp/00-intro/samples-walk-through.md: -------------------------------------------------------------------------------- 1 | # Samples Walk Through 2 | 3 | ## [Miyagi](https://github.com/Azure-Samples/miyagi) 4 | 5 | ### Frontend 6 | 7 | ![ui](../../assets/images/wip-ui.png) 8 | 9 | 10 | ### Plugin 11 | 12 | ![plugin](../../assets/images/plugin.png) 13 | 14 | ### AzureML Prompt flow example 15 | ![pf](../../assets/images/prompt-flow-basic.png) 16 | 17 | ### Fine-tuned Model 18 | 19 | ![fine-tune](../../assets/images/aml-finetune.png) 20 | 21 | ![aml](../../assets/images/aml-miyagi-dolly.png) 22 | 23 | For a preview, catch the [recording on :simple-youtube: Cosmos DB Live TV](https://www.youtube.com/watch?v=V8dlEvXdGEM&t=144s) 24 | 25 | ## [Semantic Kernel Samples](https://github.com/microsoft/semantic-kernel#sample-apps-) 26 | 27 | ![sk-samples](../../assets/images/00-intro/sk-samples.png) -------------------------------------------------------------------------------- /docs/wksp/00-intro/semantic-kernel-overview.md: -------------------------------------------------------------------------------- 1 | # Semantic Kernel Overview 2 | 3 | Semantic Kernel (SK) is a lightweight SDK enabling integration of AI Large Language Models (LLMs) with conventional programming languages. The SK extensible programming model combines natural language semantic functions, traditional code native functions, and embeddings-based memory unlocking new potential and adding value to applications with AI. 4 | 5 | SK supports prompt templating, function chaining, vectorized memory, and intelligent planning capabilities out of the box. 6 | 7 | *[Source](https://github.com/microsoft/semantic-kernel#semantic-kernel) 8 | 9 | ![sk](../../assets/images/00-intro/sk.png) 10 | 11 | ## [Skills](https://github.com/microsoft/semantic-kernel/tree/main/samples/skills) 12 | 13 | ![sk](../../assets/images/00-intro/sk-skills.png) 14 | 15 | Coming Soon: Sample skills notebooks video walkthrough -------------------------------------------------------------------------------- /docs/wksp/01-design-thinking/design-thinking-canvas.md: -------------------------------------------------------------------------------- 1 | # Design Thinking Canvas 2 | 3 | In this module, we will leverage the Design Thinking Canvas to identify customer needs and pain points, and explore how AI-driven solutions can address them effectively. This will also ensure that the workshop is more relevant as we get more hands-on in the coming hours and days. 4 | 5 | !!! Tip 6 | Use [John Maeda's Design Thinking Skills](https://devblogs.microsoft.com/semantic-kernel/recipes/#recipe-6-design-thinking-x-ai-yes) to jump start your design thinking session. 7 | 8 | ## Figma Template 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/wksp/01-design-thinking/heart-framework.md: -------------------------------------------------------------------------------- 1 | # HEART Framework (Optional) 2 | 3 | In this module, we will leverage the HEART Framework to identify customer needs and pain points, and explore how AI-driven solutions can address them effectively. This will also ensure that the workshop is more relevant as we get more hands-on in the coming hours and days. 4 | 5 | ## Figma Template 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/wksp/01-design-thinking/index.md: -------------------------------------------------------------------------------- 1 | # Design Thinking Session to make this workshop more relevant and useful 2 | 3 | In this module, we'll be using a Figma template to facilitate a design thinking session focused on identifying customer needs and pain points, and explore how AI-driven solutions can address them effectively. This will also ensure that the workshop is more relevant as we get more hands-on in the coming hours and days. 4 | 5 | ## Overview 6 | 7 | 1. Introduction to Design Thinking & HEART Framework 8 | 2. Understanding Semantic Kernel 9 | 3. Setting up the Figma Template 10 | 4. Design Thinking Activities 11 | - Empathize 12 | - Define 13 | - Ideate 14 | - Prototype 15 | - Test 16 | 5. Integrating AI and Semantic Kernel Skills 17 | 6. Conclusion and Next Steps 18 | 19 | ### Introduction to Design Thinking & HEART Framework 20 | 21 | Design Thinking is a human-centered, iterative approach to problem-solving that focuses on deeply understanding users' needs and developing innovative solutions to address them. It consists of five stages: Empathize, Define, Ideate, Prototype, and Test. 22 | 23 | 24 | The HEART framework is a methodology to improve the user experience (UX) of software. The framework helps a company evaluate any aspect of its user experience according to five user-centered metrics. These metrics, which form the acronym HEART, are: 25 | 26 | 1. Happiness 27 | 1. Engagement 28 | 1. Adoption 29 | 1. Retention 30 | 1. Task success 31 | 32 | ### Understanding Semantic Kernel 33 | 34 | Semantic Kernel is a framework that helps developers build AI-driven applications by orchestrating and chaining AI skills. It allows for the seamless integration of AI components into the user experience and backend workflows. 35 | 36 | ### Setting up the Figma Template 37 | 38 | 1. Sign up for a free [Figma](https://www.figma.com/) account if you don't already have one. 39 | 2. Duplicate the provided Design Thinking template to your Figma workspace. 40 | 3. Invite your team members to collaborate on the template in real-time. 41 | 42 | ### Design Thinking Activities 43 | 44 | #### Empathize 45 | 46 | - Conduct user interviews, surveys, or observations to understand users' needs, motivations, and pain points. 47 | - Create empathy maps and personas to represent different user segments. 48 | 49 | #### Define 50 | 51 | - Analyze and synthesize your findings to define the problem statement. 52 | - Prioritize user needs and pain points to focus on the most critical issues. 53 | 54 | #### Ideate 55 | 56 | - Generate a wide range of ideas to address the defined problem. 57 | - Use brainstorming, mind mapping, or other ideation techniques to encourage creative thinking. 58 | 59 | #### Prototype 60 | 61 | - Create low-fidelity prototypes of your proposed solutions. 62 | - Use wireframes, mockups, or simple interactive models to visualize the user experience. 63 | 64 | #### Test 65 | 66 | - Validate your prototypes with real users through usability testing, interviews, or other feedback mechanisms. 67 | - Iterate on your designs based on user feedback and insights. 68 | 69 | ### Integrating AI and Semantic Kernel Skills 70 | 71 | - Identify areas in your design where AI can add value, such as personalization, automation, or enhanced user experiences. 72 | - Explore how Semantic Kernel skills can be integrated into your solution to enable AI-driven features and capabilities. 73 | 74 | 75 | ### Conclusion and Next Steps 76 | 77 | - Reflect on the insights gained through the design thinking process and how they can inform your application's development. 78 | - Plan the next steps for implementing your AI-infused solution using Semantic Kernel and other AI technologies. 79 | 80 | By completing this module, you will have a deeper understanding of your users' needs and pain points and a solid foundation for incorporating AI-driven solutions into your application using Semantic Kernel. 81 | 82 | ![overview](../../assets/images/01-design-thinking/dt-2.png) -------------------------------------------------------------------------------- /docs/wksp/01-design-thinking/jobs-to-be-done.md: -------------------------------------------------------------------------------- 1 | # Jobs to be done Canvas (Optional) 2 | 3 | In this module, we will leverage the Jobs to Be Done (JTBD) Figma Canvas, an interactive, dynamic tool designed to guide us through the intricacies of developing AI-infused product experiences. The canvas provides a structured approach to uncovering customer needs, desires, and motivations, ensuring that our applications are always user-centered and purpose-driven. Using the JTBD methodology, we'll map out the critical job steps, pain points, and opportunities for innovation, translating these insights into actionable strategies as we make progress with the workshop. 4 | 5 | !!! Tip "Learn more" 6 | [Primer on the framework](https://jobs-to-be-done.com/jobs-to-be-done-a-framework-for-customer-needs-c883cbf61c90) 7 | 8 | ## Figma Template 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/wksp/02-fork-and-get-hands-on/index.md: -------------------------------------------------------------------------------- 1 | # Fork the repos and get hands-on 2 | 3 | 1. Visit [Miyagi](https://github.com/Azure-Samples/miyagi) and fork the repo to your GitHub account. 4 | 1. Either clone the repo to your local machine or open it in GitHub Codespaces. 5 | 1. Open the config file `config.json` and update the variables 6 | 7 | 8 | Coming Soon 9 | 10 | [Sign up for updates](https://forms.office.com/r/rLds2s8RH1){ :target="_blank" .md-button .md-button--primary } -------------------------------------------------------------------------------- /docs/wksp/03-inner-loop/index.md: -------------------------------------------------------------------------------- 1 | # Developer inner-loop 2 | 3 | Explore the developer inner-loop for AI-infused apps through the Miyagi codebase example. 4 | 5 | ??? note "(Optional) Legacy app modernization" 6 | Showcase how GitHub Copilot X can be used to modernize legacy apps. 7 | 8 | 1. Start with CICS COBOL app 9 | 1. Use GitHub Copilot X to modernize the app 10 | 1. Deploy the app to Azure 11 | 1. Add a SK skill to the app to make it AI-infused 12 | 1. Productionize the app 13 | 14 | 15 | ### Miyagi codebase 16 | 17 | Showcase how GitHub Copilot X can be used to build AI-infused apps. 18 | 19 | 1. Start with Miyagi codebase in VS Code or GitHub Codespaces 20 | 1. Use GitHub Copilot X to add persistence and messaging to the app 21 | 1. Add SK primitives to the app to make it AI-infused 22 | 1. Deploy the app to Azure using GitHub Actions 23 | 1. Monitor the app using Azure Monitor 24 | 25 | Coming Soon 26 | 27 | [Sign up for updates](https://forms.office.com/r/rLds2s8RH1){ :target="_blank" .md-button .md-button--primary } -------------------------------------------------------------------------------- /docs/wksp/04-Semantic-Kernel-Basics/index.md: -------------------------------------------------------------------------------- 1 | # Introduction to Semantic Kernel (SK) 2 | 3 | We will start with a comprehensive presentation to familiarize participants with the fundamentals of SK and goals-first AI. 4 | 5 | ## Hands-on notebooks and examples 6 | 7 | We will explore the following notebooks and examples to get familiar with SK and its capabilities: 8 | 9 | [.NET](https://github.com/microsoft/semantic-kernel/tree/main/dotnet/notebooks){ .md-button } 10 | [Python](https://github.com/microsoft/semantic-kernel/tree/main/python/samples/getting_started){ .md-button } 11 | [Java](https://github.com/microsoft/semantic-kernel-java/tree/main/samples){ .md-button } 12 | 13 | [Sign up for updates](https://forms.office.com/r/rLds2s8RH1){ :target="_blank" .md-button .md-button--primary } 14 | -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/create-deployable-app/azd-infra.md: -------------------------------------------------------------------------------- 1 | # Azure Developer CLI (AZD) and Bicep templates for Infrastructure as Code deployment 2 | 3 | In this section we go over the creation of `azd` [(Azure Developer CLI)]((https://aka.ms/azure-dev/install)) 4 | files and corresponding bicep templates to be able to build, provision infrastructure and 5 | deploy our solution into Azure. 6 | 7 | ## Azure Developer CLI files overview 8 | 9 | The following components are needed to deploy via AZD 10 | 11 | ### `azure.yaml` file 12 | 13 | This file specifies the components to be deployed. Our file specifies two components to be deployed: 14 | 15 | 1. Application backend - .NET deployed as Azure Container App 16 | 1. Web frontend - Typescript deployed as Azure Container App 17 | 18 | For each component we need to provide the path to the corresponding `Dockerfile` which will be used 19 | to build and package the application: 20 | 21 | ```yaml 22 | name: semantic-kernel-workshop-csharp 23 | metadata: 24 | template: semantic-kernel-workshop-csharp@0.0.1-beta 25 | services: 26 | api: 27 | project: ./App/backend/ 28 | host: containerapp 29 | language: dotnet 30 | docker: 31 | path: ../Dockerfile 32 | context: ../../ 33 | web: 34 | project: ../frontend/ 35 | host: containerapp 36 | language: ts 37 | docker: 38 | path: ./Dockerfile 39 | context: ./ 40 | ``` 41 | 42 | ### `infra` directory 43 | 44 | Within the `infra` directory you have the option to provide either `bicep` or `terraform` templates 45 | to deploy the required infrastructure for our application to run. In this example we 46 | use `bicep` templates which are organized as follows: 47 | 48 | * **infra** 49 | * `main.bicep` - contains the bicep parameters and modules to deploy 50 | * `main.paramters.json` - parameter values to be used during deployment 51 | * `abbreviations.json` - optional file to specify suffix abbreviations for each resource type 52 | * app - subdirectory with application related templates 53 | * `api.bicep` - bicep template for backend application infrastructure 54 | * `web.bicep` - bicep templated for web application infrastructure 55 | * core - subdirectory with templates for core infrastructure components 56 | * **ai** - subdirectory for AI related components 57 | * **bing** - subdirectory for Bing Search service 58 | * **host** - subdirectory for container app, environment and registry components 59 | * **monitor** - subdirectory for monitoring components (e.g. application insights) 60 | * **security** - subdirectory for security components (e.g. keyvault) 61 | * **storage** - subdirectory for storage components (e.g. storage account) 62 | 63 | The `azd init` command can be used to generate a starter template, however the quickest way 64 | to generate an existing template is to find a template that uses similar components from 65 | [awesome-azd](https://azure.github.io/awesome-azd/). 66 | 67 | ## Deploying using AZD CLI 68 | 69 | You can build, provision all resources and deploy by following these steps: 70 | 71 | 1. Switch to `workshop/dotnet` directory. 72 | 1. Ensure Docker desktop is running (if not using Github Codespace). 73 | 1. Open Git bash or WSL (Windows Subsystem for Linux) terminal and run the following commands 74 | 1. Run `azd auth login` to login to your Azure account. 75 | 1. Run `azd up` to provision Azure resources and deploy this sample to those resources. 76 | You will be prompted for the following parameters: 77 | * Environment name: sk-test 78 | * Select an Azure subscription to use from list 79 | * Select an Azure location to use: e.g. (US) East US 2 (eastus2) 80 | * Enter a value for the infrastructure parameters: 81 | * **aiFoundryProjectConnectionString** 82 | * **openAIApiKey** 83 | * **openAiChatGptDeployment**: e.g. gpt-4o 84 | * **openAiEndpoint** 85 | * **groundingWithBingConnectionId** 86 | * **stockServiceApiKey** 87 | 1. After the application has been successfully deployed you will see the API and Web Service URLs printed in the console. 88 | Click the Web Service URL to interact with the application in your browser. 89 | 90 | **NOTE:** It may take a few minutes for the application to be fully deployed. 91 | 92 | ## Deployment removal 93 | 94 | In order to remove all resources deployed, use this command: 95 | 96 | ```bash 97 | azd down --purge 98 | ``` 99 | -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/create-deployable-app/index.md: -------------------------------------------------------------------------------- 1 | # Turning the console application into a Deployable application 2 | 3 | In this lesson we go over the steps on how to create a deployable version of the 4 | semantic kernel console application by creating 3 main components: 5 | 6 | 1. [Backend API (C#) using ASP .NET Core libraries](backend-api.md) 7 | 1. [React JS Web application (with Node Proxy)](web-app.md) 8 | 1. [AZD + Bicep templates for Infrastructure as Code deployment](azd-infra.md) 9 | 10 | ![Chatbot Application Diagram](../images/architecture.png) 11 | -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/create-deployable-app/web-app.md: -------------------------------------------------------------------------------- 1 | # Creating simple Web UI 2 | 3 | The UI was created using React JS and a Node JS proxy to the API. Here is a highlight of key files: 4 | 5 | * `workshop/frontend` 6 | * `Dockerfile` - Dockerfile for building and deploying web app 7 | * `.env` - local file used to provide configuration values (e.g. url) 8 | * `package.json` - required package dependencies 9 | * `server.js` - NodeJS application code 10 | * `src` - React JS application source code directory 11 | * `App.tsx` - main application code 12 | * `index.tsx` - application entry point 13 | 14 | ## Running Web UI locally 15 | 16 | ### Build Web UI 17 | 18 | 1. Go to the frontend directory 19 | 20 | ```bash 21 | cd workshop/frontend 22 | ``` 23 | 24 | 1. Run `npm install` to get required dependencies 25 | 26 | 1. Run `npm run build` to build the React application 27 | 28 | ### Run Web UI 29 | 30 | 1. Create `.env` file in `frontend` directory and provide the following required values: 31 | 1. `PORT` - port where React app is running 32 | 1. `REACT_APP_PROXY_URL` - url to the Node JS proxy 33 | 34 | ```shell 35 | export PORT=3001 36 | export REACT_APP_PROXY_URL=/api/chat 37 | ``` 38 | 39 | 1. On a separate terminal export the following required variables for NodeJS proxy application 40 | (note `API_URL` will be different if using Github Codespace, e.g. `https://awesome-journey-65pj9v9pw52rrrx-5020.app.github.dev/chat`): 41 | 42 | ```bash 43 | export PORT=3001 44 | export API_URL=http://localhost:5000/chat 45 | ``` 46 | 47 | 1. From `workshop/frontend` directory start the NodeJS proxy application using `node server.js` 48 | 49 | 1. On a separate terminal start backend API using: 50 | 51 | ```bash 52 | cd workshop/dotnet/App/backend/ 53 | dotnet run 54 | ``` 55 | 56 | 1. If testing from GitHub Codespace, the port forwarded for .NET application must have a port visibility of Public: 57 | 1. To change this, click on the **PORTS** tab in Visual Studio Code and then right click running .NET application row and hover over **Port Visibility** and click **Public** 58 | and click on **Public** 59 | ![change-port-visibility](./../images/public-port.jpg) 60 | 61 | 1. Navigate to browser on or forwarded address (if using Github Codespace) and test the chat application. 62 | -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/wksp/05-semantic-kernel-workshop/images/architecture.png -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/images/bing-grounding-connection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/wksp/05-semantic-kernel-workshop/images/bing-grounding-connection.jpg -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/images/connected-resources.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/wksp/05-semantic-kernel-workshop/images/connected-resources.jpg -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/images/model-deployments.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/wksp/05-semantic-kernel-workshop/images/model-deployments.jpg -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/images/open-ai-connection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/wksp/05-semantic-kernel-workshop/images/open-ai-connection.jpg -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/images/public-port.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/wksp/05-semantic-kernel-workshop/images/public-port.jpg -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/images/upgrade-connection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/intelligent-app-workshop/c3ce7c938dabfe162a53bb0e27c5814bcf00a096/docs/wksp/05-semantic-kernel-workshop/images/upgrade-connection.jpg -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/index.md: -------------------------------------------------------------------------------- 1 | # Hands-on AI Orchestration using Semantic Kernel Workshop 2 | 3 | This hands-on workshop goes through the following lessons for creating a simple Semantic Kernel 4 | chatbot as a console application: 5 | 6 | 1. [Prerequisites](pre-reqs.md) 7 | 1. [Lesson 1: Semantic Kernel chatbot](lesson1.md) 8 | 1. [Lesson 2: Semantic Kernel chatbot with history](lesson2.md) 9 | 1. [Lesson 3: Semantic Kernel chatbot with plugins](lesson3.md) 10 | 1. [Lesson 4: Describe all plugins in Semantic Kernel chatbot](lesson4.md) 11 | 1. [Lesson 5: Semantic Kernel chatbot with Chat Completion Agent](lesson5.md) 12 | 1. [Lesson 6: Create Grounded Agent with Azure AI Agent service](lesson6.md) 13 | 14 | Subsequently, the following lessons guide you through converting that chatbot application 15 | into a deployable application with a backend API and Web UI frontend and deploying into Azure: 16 | 17 | 1. [Create Backend API](create-deployable-app/backend-api.md) 18 | 1. [Create Web application](create-deployable-app/web-app.md) 19 | 1. [Deploy application into Azure](create-deployable-app/azd-infra.md) 20 | 21 | ![Chatbot Application Diagram](./images/architecture.png) 22 | -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/lesson1.md: -------------------------------------------------------------------------------- 1 | # Lesson 1: Semantic Kernel chatbot 2 | 3 | In this lesson we will create a semantic kernel chatbot with a system prompt and keeping track of chat history. 4 | 5 | 1. Ensure all [pre-requisites](pre-reqs.md) are met and installed. 6 | 7 | 1. Switch to Lesson 1 directory: 8 | 9 | ```bash 10 | cd workshop/dotnet/Lessons/Lesson1 11 | ``` 12 | 13 | 1. Open the project in your favorite IDE or text editor. 14 | 15 | 1. Open `Program.cs` and locate the **TODO** for each step and apply the following changes for each: 16 | 17 | 1. **TODO: Step 1**: add code to initialize kernel with chat completion: 18 | 19 | ```csharp 20 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 21 | Kernel kernel = builder.Build(); 22 | ``` 23 | 24 | 1. **TODO: Step 2**: add the following system prompt: 25 | 26 | ```csharp 27 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 28 | { 29 | ChatSystemPrompt = @"You are a friendly financial advisor that only emits financial advice in a creative and funny tone" 30 | }; 31 | ``` 32 | 33 | 1. **TODO: Step 3**: initialize kernel arguments 34 | 35 | ```csharp 36 | KernelArguments kernelArgs = new(promptExecutionSettings); 37 | ``` 38 | 39 | 1. **TODO: Step 4**: add a loop to invoke prompt asynchronously providing user input and kernel arguments: 40 | 41 | ```csharp 42 | await foreach (var response in kernel.InvokePromptStreamingAsync(userInput, kernelArgs)) 43 | { 44 | Console.Write(response); 45 | } 46 | ``` 47 | 48 | 1. Run the program with this command: 49 | 50 | ```bash 51 | dotnet run 52 | ``` 53 | 54 | 1. When prompted ask for financial advice: 55 | 56 | ```txt 57 | Which stocks do you recommend buying for moderate growth? 58 | ``` 59 | 60 | You will receive a similar response: 61 | 62 | ```txt 63 | Assistant > Ah, the magical world of stock picking! Imagine walking into a buffet, and instead of loading your plate with mystery meat, you're strategically choosing the tastiest, most promising dishes. Here are a few general menus to consider, with a sprinkle of fun: 64 | 65 | 1. **Tech Tango** - Think companies that dance to the tune of innovation! Look for firms diving into AI or cloud computing. They're like the cool kids at the financial disco. 66 | 67 | 2. **Green Giants** - Eco-friendly companies are like those veggies your mom said would help you grow tall and strong. Renewable energy stocks might just add some height to your portfolio. 68 | 69 | 3. **Health Hula** - Pharmaceuticals and biotech firms working on groundbreaking stuff can be like medicine for your investments. Just remember, there's always a bit of a twirl and spin with these. 70 | 71 | 4. **Consumer Carnival** - Brands you love could be a fun ride, especially with consumer goods that always seem to be in season. 72 | 73 | 5. **Financial Fiesta** - Banks or fintech companies can be like salsa on your stock tacos—adding a bit of spice and zing! 74 | 75 | Remember, always research like you're planning the perfect vacation and balance your choices like you balance a pizza with just the right amount of toppings. And of course, consult a real-world financial oracle before making any big moves. Bon appétit in the stock market buffet! 76 | ``` 77 | -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/lesson4.md: -------------------------------------------------------------------------------- 1 | # Lesson 4: Describe all plugins in Semantic Kernel chatbot 2 | 3 | In this lesson we will add functionality to list all plugins and plugin parameters that are loaded in the application's Semantic Kernel instance. 4 | 5 | 1. Ensure all [pre-requisites](pre-reqs.md) are met and installed. 6 | 7 | 1. Switch to Lesson 5 directory: 8 | 9 | ```bash 10 | cd ../Lesson4 11 | ``` 12 | 13 | 1. Start by copying `appsettings.json` from Lesson 1: 14 | 15 | ```bash 16 | cp ../Lesson1/appsettings.json . 17 | ``` 18 | 19 | 1. Run program to validate the code is functional: 20 | 21 | ```bash 22 | dotnet run 23 | ``` 24 | 25 | 1. Locate **TODO: Step 1 - Add import for ModelExtensionMethods** in `Program.cs` and add the following import: 26 | 27 | ```csharp 28 | using Core.Utilities.Extensions; 29 | ``` 30 | 31 | 1. Next locate **TODO: Step 2 - add call to print all plugins and functions** in `Program.cs` and add the following lines to print out kernel plugins info: 32 | 33 | ```csharp 34 | var functions = kernel.Plugins.GetFunctionsMetadata(); 35 | Console.WriteLine(functions.ToPrintableString()); 36 | ``` 37 | 38 | 1. Next locate **TODO: Step 3 - Comment out all code after "Execute program" comment** and comment all lines of code after the `//Execute program` line. 39 | 40 | ```csharp 41 | // TODO: Step 3 - Comment out all code after "Execute program" comment 42 | // Execute program. 43 | /* 44 | const string terminationPhrase = "quit"; 45 | ... 46 | while (userInput != terminationPhrase); 47 | */ 48 | ``` 49 | 50 | 1. Re-run the program and you should see an output similar to this: 51 | 52 | ```bash 53 | ********************************************** 54 | ****** Registered plugins and functions ****** 55 | ********************************************** 56 | 57 | Plugin: GetCurrentUtcTime 58 | GetCurrentUtcTime: Retrieves the current time in UTC. 59 | 60 | Plugin: GetStockPrice 61 | GetStockPrice: Gets stock price 62 | Params: 63 | - symbol: 64 | default: '' 65 | 66 | Plugin: GetStockPriceForDate 67 | GetStockPriceForDate: Gets stock price for a given date 68 | Params: 69 | - symbol: 70 | default: '' 71 | - date: 72 | default: '' 73 | ``` 74 | 75 | 1. Review the `Core.Utilities.Extensions.ModelExtensionMethods` class in the `CoreUtilities` project to understand how the plugins are traversed to print out plugins and corresponding plugin parameters information. 76 | -------------------------------------------------------------------------------- /docs/wksp/05-semantic-kernel-workshop/lesson6.md: -------------------------------------------------------------------------------- 1 | # Lesson 6: Create Grounded Agent with Azure AI Agent service 2 | 3 | In this lesson, we will add a Semantic Kernel Azure AI agent to our chatbot program. This agent will be a Stock Sentiment agent to provide a recommendation to buy, hold, or sell a stock based on a stock sentiment rating. 4 | 5 | 1. Ensure all [pre-requisites](pre-reqs.md) are met and installed. 6 | 7 | 1. Switch to Lesson 6 directory: 8 | 9 | ```bash 10 | cd ../Lesson6 11 | ``` 12 | 13 | 1. Start by copying `appsettings.json` from Lesson 1: 14 | 15 | ```bash 16 | cp ../Lesson1/appsettings.json . 17 | ``` 18 | 19 | 1. Run the program to validate the code is functional: 20 | 21 | ```bash 22 | dotnet run 23 | ``` 24 | 25 | 1. Next, locate **TODO: Step 1 -- Add imports for Agents and Azure.Identity** in `Program.cs` and add the following imports: 26 | 27 | ```csharp 28 | using Azure.AI.Projects; 29 | using Azure.Identity; 30 | using Microsoft.SemanticKernel.Agents.AzureAI; 31 | ``` 32 | 33 | 1. Next, locate **TODO: Step 2 - Initialize connection to Grounding with Bing Search tool and agent** in `Program.cs` and add the following code. Be sure to copy the connectionString and bingConnectionId from Azure AI Foundry: 34 | 35 | ```csharp 36 | var connectionString = AISettingsProvider.GetSettings().AIFoundryProject.ConnectionString; 37 | var bingConnectionId = AISettingsProvider.GetSettings().AIFoundryProject.GroundingWithBingConnectionId; 38 | 39 | var projectClient = new AIProjectClient(connectionString, new AzureCliCredential()); 40 | 41 | ConnectionResponse bingConnection = await projectClient.GetConnectionsClient().GetConnectionAsync(bingConnectionId); 42 | var connectionId = bingConnection.Id; 43 | 44 | ToolConnectionList connectionList = new ToolConnectionList 45 | { 46 | ConnectionList = { new ToolConnection(connectionId) } 47 | }; 48 | BingGroundingToolDefinition bingGroundingTool = new BingGroundingToolDefinition(connectionList); 49 | 50 | var clientProvider = AzureAIClientProvider.FromConnectionString(connectionString, new AzureCliCredential()); 51 | AgentsClient client = clientProvider.Client.GetAgentsClient(); 52 | var definition = await client.CreateAgentAsync( 53 | "gpt-4o", 54 | instructions: 55 | """ 56 | Your responsibility is to find the stock sentiment for a given Stock. 57 | 58 | RULES: 59 | - Report a stock sentiment scale from 1 to 10 where stock sentiment is 1 for sell and 10 for buy. 60 | - Only use current data reputable sources such as Yahoo Finance, MarketWatch, Fidelity and similar. 61 | - Provide the stock sentiment scale in your response and a recommendation to buy, hold or sell. 62 | - Include the reasoning behind your recommendation. 63 | - Be sure to cite the source of the information. 64 | """, 65 | tools: 66 | [ 67 | bingGroundingTool 68 | ]); 69 | var agent = new AzureAIAgent(definition, clientProvider) 70 | { 71 | Kernel = kernel, 72 | }; 73 | 74 | // Create a thread for the agent conversation. 75 | AgentThread thread = await client.CreateThreadAsync(); 76 | ``` 77 | 78 | 1. Next, locate **TODO: Step 3 - Uncomment out all code after "Execute program" comment** in `Program.cs` and uncomment the previously commented block of code: 79 | 80 | 1. Finally, locate **TODO: Step 4 - Invoke the agent** in `Program.cs` and implement this code: 81 | ```csharp 82 | ChatMessageContent message = new(AuthorRole.User, userInput); 83 | await agent.AddChatMessageAsync(thread.Id, message); 84 | 85 | await foreach (ChatMessageContent response in agent.InvokeAsync(thread.Id)) 86 | { 87 | string contentExpression = string.IsNullOrWhiteSpace(response.Content) ? string.Empty : response.Content; 88 | chatHistory.AddAssistantMessage(contentExpression); 89 | Console.WriteLine($"{contentExpression}"); 90 | } 91 | ``` 92 | 93 | 1. Re-run the program and ask for the stock sentiment on Microsoft, you should see an output similar to this: 94 | 95 | ```txt 96 | User > what is the stock sentiment on Microsoft? 97 | Assistant > Assistant > **Microsoft (MSFT) Stock Sentiment: 9/10** 98 | 99 | **Recommendation: Buy** 100 | 101 | **Reasoning:** 102 | - Microsoft's stock has a consensus rating of "Moderate Buy" based on ratings from 29 Wall Street analysts. Out of these, 26 analysts have given a "Buy" rating, while only 3 have given a "Hold" rating【5†source】. 103 | - The average price target for Microsoft is $510.96, which represents a 25.10% upside from the current price of $408.43【5†source】. 104 | - The strong consensus among analysts and significant potential upside suggest a solid buy opportunity. 105 | 106 | **Source:** 107 | MarketBeat, Microsoft (MSFT) Stock Forecast and Price Target 2025【5†source】. 108 | ``` 109 | -------------------------------------------------------------------------------- /docs/wksp/06-use-cases/generation.md: -------------------------------------------------------------------------------- 1 | # Use case deep dive 2 | 3 | Rest of the intelligent app use cases implemented in [Project Miyagi](https://github.com/Azure-Samples/miyagi) and the [Reddog](https://github.com/Azure/reddog-solutions) codebase are coming soon. 4 | 5 | Meanwhile, checkout [Synthesis use case](./synthesis.md) to learn how information is synthesized in Miyagi to generate insights. And, Reddog's [Generative Text (for product tags)](https://reddog-solutions.com/) and [Images (for product images)](https://huggingface.co/thegovind/reddogpillmodel512) implementation. 6 | 7 | Stay tuned! 8 | 9 | [Sign up for updates](https://forms.office.com/r/rLds2s8RH1){ :target="_blank" .md-button .md-button--primary } -------------------------------------------------------------------------------- /docs/wksp/06-use-cases/index.md: -------------------------------------------------------------------------------- 1 | # Deep-Dive into AI Use-Cases 2 | 3 | In this module, we will undertake a comprehensive exploration of [Project Miyagi](https://github.com/Azure-Samples/miyagi) and the [Reddog](https://github.com/Azure/reddog-solutions) codebase. This deep dive will highlight a range of use-cases that can be adopted into your own applications, thereby enabling you to infuse AI to address the diverse needs of your end users. 4 | 5 | ![use-cases-slide](../../assets/images/use-cases-slide.png) 6 | 7 | !!! note "" 8 | For detailed implementation of the use-cases, see [miyagi/services](https://github.com/Azure-Samples/miyagi/tree/main/services) 9 | 10 | ## Use Cases 11 | 12 | 1. [Synthesis](./synthesis.md): Learn how information is synthesized in Miyagi to generate insights, orchestrated by Semantic Kernel. 13 | 1. [Multi-modal Generation](./generation.md): Discover how Generative AI is used in Miyagi and Reddog to generate text, images, and videos. 14 | 1. [Conversation](./generation.md): Deep-dive into how Miyagi Chatbot is built using Semantic Kernel's Copilot Chat, which you can leverage to build your own Copilot. 15 | 1. [Summarization](./generation.md): Understand how to create TL/DRs in your apps using Miyagi's example. 16 | 1. [Translation](./generation.md): Language translation. 17 | 1. [Code generation](./generation.md): Code generation with SK planner and CoT. 18 | 1. [Classification](./generation.md): Explore how Miyagi uses SK to classify expense categories. 19 | 1. [Speech-to-Text](./generation.md): Leverage Whisper to perform SoTA speech-to-text, which is used in Miyagi chatbot. 20 | 1. [Semantic/Neural Search](./generation.md): Learn how to improve search results with AI's understanding of context. 21 | 1. [Anomaly Detection](./generation.md): Discover how AI can identify unusual patterns that could indicate potential issues. 22 | 1. [Plugins](./generation.md): Understand how to extend and enhance your applications with ChatGPT and BingChat plugins. 23 | 1. [Agency and Planning](./generation.md): Learn how Miyagi uses SK's planner and Jarvis for agentic planning to rebalace portfolio based on user's preferences. 24 | -------------------------------------------------------------------------------- /docs/wksp/07-custom-copilot/extend-copilot-ai-doc-intel.md: -------------------------------------------------------------------------------- 1 | # Extend custom copilot with AI Document Intelligence, AI Vision, and multi-modal Foundation model -------------------------------------------------------------------------------- /docs/wksp/07-custom-copilot/index.md: -------------------------------------------------------------------------------- 1 | # Build Custom Copilots using Azure AI Foundry 2 | 3 | We will start with by building copilots using Azure AI Foundry 4 | 5 | ## Step-by Step guide for building a custom copilot using the chat playground in Azure AI Foundry 6 | 7 | Follow this tutorial to build a custom copilot using AI Studio 8 | 9 | [Use the chat playground in Azure AI Foundry portal](https://learn.microsoft.com/en-us/azure/ai-studio/quickstarts/get-started-playground){ .md-button } 10 | 11 | ## Step-by Step guide for building a custom copilot using the prompt flow SDK in Azure AI Foundry 12 | 13 | [Build a basic chat app in Python using Azure AI Foundry SDK](https://learn.microsoft.com/en-us/azure/ai-studio/quickstarts/get-started-code){ .md-button } 14 | -------------------------------------------------------------------------------- /docs/wksp/appendix/design-patterns.md: -------------------------------------------------------------------------------- 1 | # Design patterns 2 | 3 | {{ read_csv('./patterns.csv') }} -------------------------------------------------------------------------------- /docs/wksp/appendix/patterns.csv: -------------------------------------------------------------------------------- 1 | Repo,Description 2 | microsoft/azure-openai-design-patterns,A set of design patterns using the Azure OpenAI service -------------------------------------------------------------------------------- /docs/wksp/appendix/samples.md: -------------------------------------------------------------------------------- 1 | # Intelligent App samples, showcasing Azure OpenAI capabilities 2 | 3 | {{ read_csv('./samples.csv') }} -------------------------------------------------------------------------------- /docs/wksp/appendix/security.csv: -------------------------------------------------------------------------------- 1 | Link,Description 2 | OWASP Top 10 for LLMs,Top 10 list of most critical security risks to Large Language Model (LLM) applications 3 | -------------------------------------------------------------------------------- /docs/wksp/appendix/security.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | {{ read_csv('./security.csv') }} -------------------------------------------------------------------------------- /docs/wksp/other/feedback.md: -------------------------------------------------------------------------------- 1 | # Feedback 2 | 3 | [Workshop feedback](https://forms.office.com/r/v4rCwHkjjB){:target="_blank" .md-button .md-button--primary } 4 | 5 | ![feedback](../../assets/images/00-intro/feedback-qr.png) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs-material 2 | mkdocs-render-swagger-plugin 3 | mkdocs-git-committers-plugin-2 4 | mkdocs-git-revision-date-localized-plugin 5 | mkdocs-git-revision-date-plugin 6 | mkdocs-macros-plugin 7 | mkdocs-with-pdf 8 | mkdocs-glightbox 9 | mkdocs-open-in-new-tab 10 | mkdocs-video 11 | mkdocs-table-reader-plugin -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open("README.md", "r", encoding="utf-8") as fh: 4 | long_description = fh.read() 5 | 6 | with open("requirements.txt", "r", encoding="utf-8") as fh: 7 | requirements = fh.read().splitlines() 8 | 9 | setup( 10 | name="miyagi_mkdocs_material_package", 11 | version="0.1.0", 12 | author="Govind Kamtamneni", 13 | author_email="gok@microsoft.com", 14 | description="A package that uses mkdocs-material and related plugins", 15 | long_description=long_description, 16 | long_description_content_type="text/markdown", 17 | url="https://github.com/Azure/intelligent-app-workshop", 18 | packages=find_packages(), 19 | classifiers=[ 20 | "Development Status :: 3 - Alpha", 21 | "Intended Audience :: Developers", 22 | "License :: OSI Approved :: MIT License", 23 | "Operating System :: OS Independent", 24 | "Programming Language :: Python :: 3", 25 | "Programming Language :: Python :: 3.6", 26 | "Programming Language :: Python :: 3.7", 27 | "Programming Language :: Python :: 3.8", 28 | "Programming Language :: Python :: 3.9", 29 | ], 30 | python_requires=">=3.6", 31 | install_requires=requirements, 32 | ) 33 | -------------------------------------------------------------------------------- /workshop/dotnet/App/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Always 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /workshop/dotnet/App/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base 2 | WORKDIR /app 3 | EXPOSE 8080 4 | EXPOSE 443 5 | 6 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0 AS build 7 | WORKDIR /src 8 | COPY ["../Directory.Build.props", "."] 9 | COPY ["../Directory.Packages.props", "."] 10 | COPY ["App/Directory.Build.props", "App/"] 11 | COPY ["App/backend/", "App/backend/"] 12 | COPY ["../../Core.Utilities/", "Core.Utilities/"] 13 | RUN dotnet restore "App/backend/backend.csproj" 14 | 15 | WORKDIR "/src/App/backend" 16 | FROM build AS publish 17 | RUN dotnet publish "backend.csproj" -o /app 18 | 19 | FROM base AS final 20 | WORKDIR /app 21 | COPY --from=publish /app . 22 | ENTRYPOINT ["dotnet", "backend.dll"] -------------------------------------------------------------------------------- /workshop/dotnet/App/backend/Controllers/PluginInfoController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.SemanticKernel; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Core.Utilities.Models; 6 | using Core.Utilities.Extensions; 7 | 8 | namespace Controllers; 9 | 10 | [ApiController] 11 | [Route("sk")] 12 | public class PluginInfoController : ControllerBase { 13 | 14 | private readonly Kernel _kernel; 15 | 16 | public PluginInfoController(Kernel kernel) 17 | { 18 | _kernel = kernel; 19 | } 20 | 21 | /// 22 | /// Get the metadata for all the plugins and functions. 23 | /// 24 | /// 25 | [HttpGet("/pluginInfo/metadata")] 26 | public async Task> GetPluginInfoMetadata() 27 | { 28 | var functions = _kernel.Plugins.GetFunctionsMetadata().ToPluginFunctionMetadataList(); 29 | return functions; 30 | } 31 | } -------------------------------------------------------------------------------- /workshop/dotnet/App/backend/Extensions/ServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | using Core.Utilities.Models; 3 | // Add import for Plugins 4 | using Core.Utilities.Plugins; 5 | // Add import required for StockService 6 | using Core.Utilities.Services; 7 | using Microsoft.SemanticKernel; 8 | namespace Extensions; 9 | 10 | public static class ServiceExtensions 11 | { 12 | public static void AddSkServices(this IServiceCollection services) 13 | { 14 | services.AddSingleton(_ => 15 | { 16 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 17 | // Enable tracing 18 | builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 19 | Kernel kernel = builder.Build(); 20 | 21 | // Step 2 - Initialize Time plugin and registration in the kernel 22 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 23 | 24 | // Step 6 - Initialize Stock Data Plugin and register it in the kernel 25 | HttpClient httpClient = new(); 26 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 27 | kernel.Plugins.AddFromObject(stockDataPlugin); 28 | 29 | return kernel; 30 | }); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /workshop/dotnet/App/backend/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Antiforgery; 2 | using Extensions; 3 | using System.Text.Json.Serialization; 4 | 5 | var builder = WebApplication.CreateBuilder(args); 6 | 7 | builder.Services.AddControllers(); 8 | builder.Services.AddEndpointsApiExplorer(); 9 | builder.Services.AddSwaggerGen(); 10 | // See: https://aka.ms/aspnetcore/swashbuckle 11 | builder.Services.AddEndpointsApiExplorer(); 12 | builder.Services.AddSwaggerGen(); 13 | // Required to generate enumeration values in Swagger doc 14 | builder.Services.AddControllersWithViews().AddJsonOptions(options => 15 | options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())); 16 | builder.Services.AddOutputCache(); 17 | builder.Services.AddAntiforgery(options => { 18 | options.HeaderName = "X-CSRF-TOKEN-HEADER"; 19 | options.FormFieldName = "X-CSRF-TOKEN-FORM"; }); 20 | builder.Services.AddHttpClient(); 21 | builder.Services.AddDistributedMemoryCache(); 22 | // Add Semantic Kernel services 23 | builder.Services.AddSkServices(); 24 | 25 | // Load user secrets 26 | builder.Configuration.AddUserSecrets(); 27 | 28 | var app = builder.Build(); 29 | app.UseSwagger(); 30 | app.UseSwaggerUI(); 31 | app.UseOutputCache(); 32 | app.UseRouting(); 33 | app.UseCors(); 34 | app.UseAntiforgery(); 35 | app.MapControllers(); 36 | 37 | app.Use(next => context => 38 | { 39 | var antiforgery = app.Services.GetRequiredService(); 40 | var tokens = antiforgery.GetAndStoreTokens(context); 41 | context.Response.Cookies.Append("XSRF-TOKEN", tokens?.RequestToken ?? string.Empty, new CookieOptions() { HttpOnly = false }); 42 | return next(context); 43 | }); 44 | 45 | app.Map("/", () => Results.Redirect("/swagger")); 46 | 47 | app.MapControllerRoute( 48 | "default", 49 | "{controller=ChatController}"); 50 | 51 | app.Run(); -------------------------------------------------------------------------------- /workshop/dotnet/App/backend/backend.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities.Tests/Core.Utilities.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | SKEXP0110;SKEXP0001;SKEXP0101 4 | 5 | 6 | 7 | Always 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities.Tests/Core.Utilities.Tests.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Utilities.Tests", "Core.Utilities.Tests.csproj", "{51B8B6A8-715E-4C2E-B325-80FC8B932942}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {51B8B6A8-715E-4C2E-B325-80FC8B932942}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {51B8B6A8-715E-4C2E-B325-80FC8B932942}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {51B8B6A8-715E-4C2E-B325-80FC8B932942}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {51B8B6A8-715E-4C2E-B325-80FC8B932942}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {F51AE0FC-B37B-4D43-98B2-2B6E098F9D01} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Config/AISettingsProvider.cs: -------------------------------------------------------------------------------- 1 | using Ardalis.GuardClauses; 2 | using Core.Utilities.Models; 3 | using Microsoft.Extensions.Configuration; 4 | using System.Reflection; 5 | 6 | namespace Core.Utilities.Config; 7 | 8 | public static class AISettingsProvider 9 | { 10 | public static AppSettings GetSettings() 11 | { 12 | IConfigurationRoot config = new ConfigurationBuilder() 13 | .AddJsonFile("appsettings.json", optional: true) 14 | .AddEnvironmentVariables() 15 | .AddUserSecrets(Assembly.GetExecutingAssembly()) 16 | .Build(); 17 | 18 | var aiSettings = config 19 | .Get(); 20 | Guard.Against.Null(aiSettings); 21 | Guard.Against.Null(aiSettings.AIFoundryProject); 22 | Guard.Against.NullOrEmpty(aiSettings.AIFoundryProject.DeploymentName); 23 | Guard.Against.NullOrEmpty(aiSettings.AIFoundryProject.GroundingWithBingConnectionId); 24 | Guard.Against.NullOrEmpty(aiSettings.AIFoundryProject.ApiKey); 25 | Guard.Against.NullOrEmpty(aiSettings.AIFoundryProject.Endpoint); 26 | Guard.Against.NullOrEmpty(aiSettings.AIFoundryProject.ConnectionString); 27 | 28 | return aiSettings; 29 | } 30 | } -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Config/KernelBuilderProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | 3 | namespace Core.Utilities.Config; 4 | 5 | public static class KernelBuilderProvider 6 | { 7 | public static IKernelBuilder CreateKernelWithChatCompletion() 8 | { 9 | var applicationSettings = AISettingsProvider.GetSettings(); 10 | return Kernel 11 | .CreateBuilder() 12 | .AddAzureOpenAIChatCompletion( 13 | applicationSettings.AIFoundryProject.DeploymentName, 14 | applicationSettings.AIFoundryProject.Endpoint, 15 | applicationSettings.AIFoundryProject.ApiKey); 16 | } 17 | } -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Core.Utilities.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | SKEXP0110;SKEXP0001;SKEXP0101 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Extensions/ModelExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Models; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.ChatCompletion; 4 | using System.Text; 5 | 6 | namespace Core.Utilities.Extensions 7 | { 8 | public static class ModelExtensionMethods 9 | { 10 | public static string FormatStockData(this Stock stockData) 11 | { 12 | StringBuilder stringBuilder = new(); 13 | 14 | stringBuilder.AppendLine("| Symbol | Price | Open | Low | High | Date "); 15 | stringBuilder.AppendLine("| ----- | ----- | ----- | ----- |"); 16 | stringBuilder.AppendLine($"| {stockData.Symbol} | {stockData.Close} | {stockData.Open} | {stockData.Low} | {stockData.High} | {stockData.From} "); 17 | 18 | return stringBuilder.ToString(); 19 | } 20 | 21 | public static ChatHistory ToChatHistory(this ChatRequest chatRequest) 22 | { 23 | var chatHistory = new ChatHistory(); 24 | chatRequest.MessageHistory.ForEach(chatMessage => { 25 | string role = chatMessage.Role.ToString(); 26 | if ("Tool".Equals(role, StringComparison.OrdinalIgnoreCase)) { 27 | role = AuthorRole.Assistant.Label; 28 | role = "assistant"; 29 | } 30 | chatHistory.Add(new ChatMessageContent(new AuthorRole(role), chatMessage.Message)); 31 | }); 32 | return chatHistory; 33 | } 34 | 35 | public static List FromChatHistory(this ChatHistory chatHistory) { 36 | var messageHistory = new List(); 37 | messageHistory.AddRange(chatHistory 38 | .Where(m => m.Content != null) 39 | .Select(m => new ChatMessage(m.Content!, Enum.TryParse(m.Role.Label, out var role) ? role : Role.User))); 40 | 41 | return messageHistory; 42 | } 43 | 44 | public static IList ToPluginFunctionMetadataList(this IList plugins) 45 | { 46 | return plugins.Select(p => p.ToPluginFunctionMetadata()).ToList(); 47 | } 48 | 49 | public static PluginFunctionMetadata ToPluginFunctionMetadata(this KernelFunctionMetadata kernelFunctionMetadata) 50 | { 51 | return new PluginFunctionMetadata(kernelFunctionMetadata.Name, 52 | kernelFunctionMetadata.Description, 53 | kernelFunctionMetadata.Parameters.Select(p => p.ToPluginParameterMetadata()).ToList()); 54 | } 55 | 56 | public static PluginParameterMetadata ToPluginParameterMetadata(this KernelParameterMetadata pluginParameterMetadata) 57 | { 58 | return new PluginParameterMetadata(pluginParameterMetadata.Name, pluginParameterMetadata.ParameterType?.Name ?? string.Empty, pluginParameterMetadata.Description, pluginParameterMetadata.DefaultValue); 59 | } 60 | 61 | public static String ToPrintableString(this IList plugins) { 62 | var pluginFunctionMetadataList = plugins.ToPluginFunctionMetadataList(); 63 | return pluginFunctionMetadataList?.ToPrintableString() ?? string.Empty; 64 | } 65 | 66 | private static String ToPrintableString(this IList functions) 67 | { 68 | var sb = new StringBuilder(); 69 | sb.AppendLine("**********************************************"); 70 | sb.AppendLine("****** Registered plugins and functions ******"); 71 | sb.AppendLine("**********************************************"); 72 | sb.AppendLine(); 73 | foreach (PluginFunctionMetadata func in functions) 74 | { 75 | sb.AppendLine(ToString(func)); 76 | } 77 | return sb.ToString(); 78 | } 79 | 80 | /// 81 | /// Returns the function information as string 82 | /// 83 | /// 84 | private static String ToString(this PluginFunctionMetadata func) 85 | { 86 | var sb = new StringBuilder(); 87 | sb.AppendLine($"Plugin: {func.Name}"); 88 | sb.AppendLine($" {func.Name}: {func.Description}"); 89 | 90 | if (func.Parameters.Count > 0) 91 | { 92 | sb.AppendLine(" Params:"); 93 | foreach (var p in func.Parameters) 94 | { 95 | sb.AppendLine($" - {p.Name}: {p.Description}"); 96 | sb.AppendLine($" default: '{p.DefaultValue}'"); 97 | } 98 | } 99 | return sb.ToString(); 100 | } 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Models/AggregateStockResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Core.Utilities.Models; 4 | 5 | public record AggregateStockResponse( 6 | int ResultsCount, 7 | string Status, 8 | [property: JsonPropertyName("results")] 9 | List StockResults 10 | ); 11 | 12 | public record StockResult( 13 | [property: JsonPropertyName("o")] 14 | double Open, 15 | [property: JsonPropertyName("c")] 16 | double Close, 17 | [property: JsonPropertyName("h")] 18 | double High, 19 | [property: JsonPropertyName("l")] 20 | double Low 21 | ); -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Models/AppSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Core.Utilities.Models; 4 | 5 | public record AppSettings ( 6 | StockService StockService, 7 | AIFoundryProject AIFoundryProject, 8 | ManagedIdentity? ManagedIdentity = null // Not needed when running locally 9 | ); 10 | 11 | public record StockService ( 12 | string ApiKey 13 | ); 14 | 15 | public record ManagedIdentity ( 16 | string ClientId = "" // Not needed when running locally 17 | ); 18 | 19 | public record AIFoundryProject ( 20 | string ConnectionString, 21 | string GroundingWithBingConnectionId, 22 | string Endpoint, 23 | string DeploymentName, 24 | string ApiKey 25 | ); -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Utilities.Models; 2 | 3 | public record ChatMessage ( 4 | string Message, 5 | Role Role 6 | ); 7 | 8 | public enum Role { 9 | User, 10 | Assistant, 11 | Tool, 12 | System 13 | } 14 | 15 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Models/ChatRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Utilities.Models; 2 | 3 | public record ChatRequest( 4 | string InputMessage, 5 | List MessageHistory 6 | ); 7 | 8 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Models/ChatResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Utilities.Models; 2 | 3 | public record ChatResponse( 4 | string Response, 5 | List MessageHistory 6 | ); 7 | 8 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Models/PluginFunctionMetadata.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Utilities.Models; 2 | 3 | public record PluginFunctionMetadata( 4 | string Name, 5 | string Description, 6 | List Parameters 7 | ); 8 | 9 | public record PluginParameterMetadata( 10 | string Name, 11 | string Type, 12 | string Description, 13 | object? DefaultValue 14 | ); 15 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Models/Stocks.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Utilities.Models; 2 | 3 | public record Stocks(List Stock); 4 | 5 | public record Stock( 6 | string Symbol, 7 | double Open, 8 | double Close, 9 | double High, 10 | double Low, 11 | string From, 12 | string Status = "OK" 13 | ); 14 | 15 | -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Plugins/StockDataPlugin.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Services; 2 | using Core.Utilities.Extensions; 3 | 4 | using Microsoft.SemanticKernel; 5 | using System.ComponentModel; 6 | 7 | namespace Core.Utilities.Plugins; 8 | 9 | public class StockDataPlugin(StocksService stockService) 10 | { 11 | private readonly StocksService _stockService = stockService; 12 | 13 | [KernelFunction, Description("Gets stock price")] 14 | public async Task GetStockPrice(string symbol) 15 | { 16 | string tabularData = (await _stockService.GetStockAggregate(symbol)).FormatStockData(); 17 | return tabularData; 18 | } 19 | 20 | [KernelFunction, Description("Gets stock price for a given date")] 21 | public async Task GetStockPriceForDate(string symbol, string date) 22 | { 23 | var dateTime = DateTime.Parse(date); 24 | string tabularData = (await _stockService.GetStockAggregate(symbol, dateTime)).FormatStockData(); 25 | return tabularData; 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Plugins/TimeInformationPlugin.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Microsoft.SemanticKernel; 3 | 4 | namespace Core.Utilities.Plugins; 5 | 6 | public class TimeInformationPlugin 7 | { 8 | [KernelFunction]  9 | [Description("Retrieves the current time in UTC.")] 10 | public string GetCurrentUtcTime() => DateTime.UtcNow.ToString("R"); 11 | } -------------------------------------------------------------------------------- /workshop/dotnet/Core.Utilities/Services/StocksService.cs: -------------------------------------------------------------------------------- 1 | using Ardalis.GuardClauses; 2 | using Core.Utilities.Config; 3 | using Core.Utilities.Models; 4 | using Microsoft.Extensions.Logging; 5 | using System.Net.Http.Json; 6 | 7 | namespace Core.Utilities.Services 8 | { 9 | /// 10 | /// Service for retrieving stock information from the Polygon API. 11 | /// 12 | public class StocksService 13 | { 14 | private readonly HttpClient _httpClient; 15 | 16 | private string _apiKey; 17 | 18 | private static ILogger logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger(); 19 | 20 | public StocksService(HttpClient httpClient) 21 | { 22 | httpClient.BaseAddress = new Uri("https://api.polygon.io/v1/"); 23 | _httpClient = httpClient; 24 | _apiKey = AISettingsProvider.GetSettings().StockService.ApiKey; 25 | } 26 | 27 | /// 28 | /// Retrieves the daily open and close prices for a stock. 29 | /// NOTE: this requires a premium subscription to get data for the current month 30 | /// 31 | public async Task GetStockDailyOpenClose(string symbol, DateTime? date = null) 32 | { 33 | //Default to yesterday's date if no date is provided as current day pricing requires premium subscription 34 | string dateFormatted = date?.ToString("yyyy-MM-dd") ?? DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd"); 35 | var requestUri = $"open-close/{symbol}/{dateFormatted}?adjusted=true&apiKey={_apiKey}"; 36 | Stock stock = await GetHttpResponse(requestUri); 37 | return stock; 38 | } 39 | 40 | 41 | /// 42 | /// Retrieves the aggregate stock information for a given symbol and date. 43 | /// NOTE: using this to get stock last price as it is free to usecd 44 | /// 45 | public async Task GetStockAggregate(string symbol, DateTime? date = null) 46 | { 47 | logger.LogDebug("> Getting stock aggregate"); 48 | //Default to yesterday's date if no date is provided as current day pricing requires premium subscription 49 | DateTime toDate = date ?? DateTime.Now.AddDays(-1); 50 | string toDateFormatted = toDate.ToString("yyyy-MM-dd"); 51 | //Default fromDate to 4 days ago to account for weekends and Monday holidays 52 | string fromDateFormatted = toDate.AddDays(-4).ToString("yyyy-MM-dd"); 53 | var requestUri = $"/v2/aggs/ticker/{symbol}/range/1/day/{fromDateFormatted}/{toDateFormatted}?adjusted=true&sort=desc&apiKey="; 54 | // Log the requestUri without the apiKey 55 | logger.LogDebug($"Request URI: {requestUri}"); 56 | requestUri += $"{_apiKey}"; 57 | 58 | AggregateStockResponse response = await GetHttpResponse(requestUri); 59 | Stock stock = null; 60 | if (response.StockResults.Count > 0) { 61 | StockResult stockResult = response.StockResults[0]; 62 | stock = new Stock( 63 | Symbol: symbol, 64 | Open: stockResult.Open, 65 | High: stockResult.High, 66 | Low: stockResult.Low, 67 | Close: stockResult.Close, 68 | From: toDateFormatted, 69 | Status: response.Status 70 | ); 71 | 72 | } 73 | logger.LogDebug("< Getting stock aggregate count: " + response.ResultsCount); 74 | return stock; 75 | } 76 | 77 | 78 | private async Task GetHttpResponse(string requestUri) 79 | { 80 | HttpResponseMessage response = await _httpClient.GetAsync(requestUri); 81 | 82 | if (!response.IsSuccessStatusCode) 83 | { 84 | string errorMessage = await response.Content.ReadAsStringAsync(); 85 | throw new HttpRequestException($"Request failed with status code: {response.StatusCode}, message: {errorMessage}"); 86 | } 87 | 88 | T? data = await response.Content.ReadFromJsonAsync(); 89 | Guard.Against.Null(data); 90 | 91 | return data; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /workshop/dotnet/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | SKEXP0110;SKEXP0001;SKEXP0101;SKEXP0050 8 | true 9 | 10 | 11 | -------------------------------------------------------------------------------- /workshop/dotnet/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Exe 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Always 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson1/Lesson1.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Always 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson1/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.Connectors.OpenAI; 4 | 5 | 6 | // TODO: Step 1 - Initialize the kernel with chat completion 7 | 8 | 9 | // TODO: Step 2 - Add system prompt 10 | 11 | 12 | // TODO: Step 3 - Initialize kernel arguments 13 | 14 | // Execute program. 15 | const string terminationPhrase = "quit"; 16 | string? userInput; 17 | do 18 | { 19 | Console.Write("User > "); 20 | userInput = Console.ReadLine(); 21 | 22 | if (userInput is not null and not terminationPhrase) 23 | { 24 | Console.Write("Assistant > "); 25 | // TODO: Step 4 - add a loop to invoke prompt asynchronously providing user input and kernel arguments 26 | 27 | Console.WriteLine(); 28 | } 29 | } 30 | while (userInput != terminationPhrase); 31 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson2/Lesson2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Always 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson2/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.Connectors.OpenAI; 4 | 5 | // TODO: Step 1 - add ChatCompletion import 6 | 7 | // Initialize the kernel with chat completion 8 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 9 | Kernel kernel = builder.Build(); 10 | 11 | // TODO: Step 2a - Get chatCompletionService and initialize chatHistory with system prompt 12 | 13 | // TODO: Step 2b - Remove the promptExecutionSettings and kernelArgs initialization code 14 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 15 | { 16 | // Add Auto invoke kernel functions as the tool call behavior 17 | ChatSystemPrompt = @"You are a friendly financial advisor that only emits financial advice in a creative and funny tone" 18 | }; 19 | 20 | // Initialize kernel arguments 21 | KernelArguments kernelArgs = new(promptExecutionSettings); 22 | 23 | // Execute program. 24 | const string terminationPhrase = "quit"; 25 | string? userInput; 26 | do 27 | { 28 | Console.Write("User > "); 29 | userInput = Console.ReadLine(); 30 | 31 | if (userInput is not null and not terminationPhrase) 32 | { 33 | Console.Write("Assistant > "); 34 | // TODO: Step 3 - Initialize fullMessage variable and add user input to chat history 35 | 36 | 37 | // TODO: Step 4 - Remove the foreach loop and replace it with `chatCompletionService` code 38 | // including adding assistant message to chat history 39 | await foreach (var response in kernel.InvokePromptStreamingAsync(userInput, kernelArgs)) 40 | { 41 | Console.Write(response); 42 | } 43 | 44 | Console.WriteLine(); 45 | } 46 | } 47 | while (userInput != terminationPhrase); 48 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson3/Lesson3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Always 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson3/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // TODO: Step 1 - Add import for Plugins 3 | 4 | // TODO: Step 5 - Add import required for StockService 5 | 6 | using Microsoft.SemanticKernel; 7 | using Microsoft.SemanticKernel.Connectors.OpenAI; 8 | // Add ChatCompletion import 9 | using Microsoft.SemanticKernel.ChatCompletion; 10 | 11 | 12 | // Initialize the kernel with chat completion 13 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 14 | Kernel kernel = builder.Build(); 15 | 16 | // TODO: Step 2 - Initialize Time plugin and registration in the kernel 17 | 18 | 19 | // TODO: Step 6 - Initialize Stock Data Plugin and register it in the kernel 20 | 21 | 22 | // Get chatCompletionService and initialize chatHistory with system prompt 23 | var chatCompletionService = kernel.GetRequiredService(); 24 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 25 | // Remove the promptExecutionSettings and kernelArgs initialization code 26 | // Add system prompt 27 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 28 | { 29 | // Step 3 - Add Auto invoke kernel functions as the tool call behavior 30 | 31 | }; 32 | 33 | // Initialize kernel arguments 34 | KernelArguments kernelArgs = new(promptExecutionSettings); 35 | 36 | // Execute program. 37 | const string terminationPhrase = "quit"; 38 | string? userInput; 39 | do 40 | { 41 | Console.Write("User > "); 42 | userInput = Console.ReadLine(); 43 | 44 | if (userInput is not null and not terminationPhrase) 45 | { 46 | Console.Write("Assistant > "); 47 | // Initialize fullMessage variable and add user input to chat history 48 | string fullMessage = ""; 49 | chatHistory.AddUserMessage(userInput); 50 | 51 | // TODO: Step 4 - Provide promptExecutionSettings and kernel arguments 52 | await foreach (var chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory)) 53 | { 54 | Console.Write(chatUpdate.Content); 55 | fullMessage += chatUpdate.Content ?? ""; 56 | } 57 | chatHistory.AddAssistantMessage(fullMessage); 58 | 59 | Console.WriteLine(); 60 | } 61 | } 62 | while (userInput != terminationPhrase); 63 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson4/Lesson4.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Always 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson4/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // Add import for Plugins 3 | using Core.Utilities.Plugins; 4 | // Add import required for StockService 5 | using Core.Utilities.Services; 6 | // TODO: Step 1 - Add import for ModelExtensionMethods 7 | 8 | using Microsoft.SemanticKernel; 9 | using Microsoft.SemanticKernel.Connectors.OpenAI; 10 | // Add ChatCompletion import 11 | using Microsoft.SemanticKernel.ChatCompletion; 12 | // Temporarily added to enable Semantic Kernel tracing 13 | using Microsoft.Extensions.DependencyInjection; 14 | using Microsoft.Extensions.Logging; 15 | 16 | 17 | // Initialize the kernel with chat completion 18 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 19 | // Enable tracing 20 | //builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 21 | Kernel kernel = builder.Build(); 22 | 23 | // Initialize Time plugin and registration in the kernel 24 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 25 | 26 | // Initialize Stock Data Plugin and register it in the kernel 27 | HttpClient httpClient = new(); 28 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 29 | kernel.Plugins.AddFromObject(stockDataPlugin); 30 | 31 | // Get chatCompletionService and initialize chatHistory with system prompt 32 | var chatCompletionService = kernel.GetRequiredService(); 33 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 34 | // Remove the promptExecutionSettings and kernelArgs initialization code 35 | // Add system prompt 36 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 37 | { 38 | // Add Auto invoke kernel functions as the tool call behavior 39 | ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions 40 | }; 41 | 42 | // Initialize kernel arguments 43 | KernelArguments kernelArgs = new(promptExecutionSettings); 44 | 45 | // TODO: Step 2 - add call to print all plugins and functions 46 | 47 | // TODO: Step 3 - Comment out all code after "Execute program" comment 48 | // Execute program. 49 | const string terminationPhrase = "quit"; 50 | string? userInput; 51 | do 52 | { 53 | Console.Write("User > "); 54 | userInput = Console.ReadLine(); 55 | 56 | if (userInput is not null and not terminationPhrase) 57 | { 58 | Console.Write("Assistant > "); 59 | // Initialize fullMessage variable and add user input to chat history 60 | string fullMessage = ""; 61 | chatHistory.AddUserMessage(userInput); 62 | 63 | // Provide promptExecutionSettings and kernel arguments 64 | await foreach (var chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory, promptExecutionSettings, kernel)) 65 | { 66 | Console.Write(chatUpdate.Content); 67 | fullMessage += chatUpdate.Content ?? ""; 68 | } 69 | chatHistory.AddAssistantMessage(fullMessage); 70 | 71 | Console.WriteLine(); 72 | } 73 | } 74 | while (userInput != terminationPhrase); 75 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson5/Lesson5.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Always 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson5/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // Add import for Plugins 3 | using Core.Utilities.Plugins; 4 | // Add import required for StockService 5 | using Core.Utilities.Services; 6 | // Add import for ModelExtensionMethods 7 | using Core.Utilities.Extensions; 8 | using Microsoft.SemanticKernel; 9 | using Microsoft.SemanticKernel.Connectors.OpenAI; 10 | // TODO: Step 1 - Add import for Agents 11 | 12 | // Add ChatCompletion import 13 | using Microsoft.SemanticKernel.ChatCompletion; 14 | // Temporarily added to enable Semantic Kernel tracing 15 | using Microsoft.Extensions.DependencyInjection; 16 | using Microsoft.Extensions.Logging; 17 | 18 | 19 | // Initialize the kernel with chat completion 20 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 21 | // Enable tracing 22 | //builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 23 | Kernel kernel = builder.Build(); 24 | 25 | // Initialize Time plugin and registration in the kernel 26 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 27 | 28 | // Initialize Stock Data Plugin and register it in the kernel 29 | HttpClient httpClient = new(); 30 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 31 | kernel.Plugins.AddFromObject(stockDataPlugin); 32 | 33 | // TODO: Step 2 - Add code to create Stock Sentiment Agent 34 | 35 | // Get chatCompletionService and initialize chatHistory with system prompt 36 | var chatCompletionService = kernel.GetRequiredService(); 37 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 38 | // Remove the promptExecutionSettings and kernelArgs initialization code 39 | // Add system prompt 40 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 41 | { 42 | // Add Auto invoke kernel functions as the tool call behavior 43 | ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions 44 | }; 45 | 46 | // Initialize kernel arguments 47 | KernelArguments kernelArgs = new(promptExecutionSettings); 48 | 49 | // Add call to print all plugins and functions 50 | var functions = kernel.Plugins.GetFunctionsMetadata(); 51 | // TODO: Step 0a - Comment line to print all plugins and functions 52 | Console.WriteLine(functions.ToPrintableString()); 53 | 54 | // TODO: Step 0b - Uncomment out all code after "Execute program" comment 55 | // Execute program. 56 | /* 57 | const string terminationPhrase = "quit"; 58 | string? userInput; 59 | do 60 | { 61 | Console.Write("User > "); 62 | userInput = Console.ReadLine(); 63 | 64 | if (userInput is not null and not terminationPhrase) 65 | { 66 | Console.Write("Assistant > "); 67 | // Initialize fullMessage variable and add user input to chat history 68 | string fullMessage = ""; 69 | chatHistory.AddUserMessage(userInput); 70 | 71 | // TODO: Step 3 - Replace chatCompletionService with stockSentimentAgent 72 | await foreach (var chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory, promptExecutionSettings, kernel)) 73 | { 74 | Console.Write(chatUpdate.Content); 75 | fullMessage += chatUpdate.Content ?? ""; 76 | } 77 | chatHistory.AddAssistantMessage(fullMessage); 78 | 79 | Console.WriteLine(); 80 | } 81 | } 82 | while (userInput != terminationPhrase); 83 | */ 84 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson6/Lesson6.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Always 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/Lesson6/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // Add import for Plugins 3 | using Core.Utilities.Plugins; 4 | // Add import required for StockService 5 | using Core.Utilities.Services; 6 | using Microsoft.SemanticKernel; 7 | using Microsoft.SemanticKernel.Connectors.OpenAI; 8 | // Add ChatCompletion import 9 | using Microsoft.SemanticKernel.ChatCompletion; 10 | // Temporarily added to enable Semantic Kernel tracing 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Logging; 13 | 14 | // TODO: Step 1 -- Add imports for Agents and Azure.Identity 15 | 16 | 17 | // Initialize the kernel with chat completion 18 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 19 | // Enable tracing 20 | builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 21 | Kernel kernel = builder.Build(); 22 | 23 | // Initialize Time plugin and registration in the kernel 24 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 25 | 26 | // TODO: Step 2 - Initialize connection to Grounding with Bing Search tool and agent 27 | 28 | // Initialize Stock Data Plugin and register it in the kernel 29 | HttpClient httpClient = new(); 30 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 31 | kernel.Plugins.AddFromObject(stockDataPlugin); 32 | 33 | // Get chatCompletionService and initialize chatHistory with system prompt 34 | var chatCompletionService = kernel.GetRequiredService(); 35 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 36 | // Remove the promptExecutionSettings and kernelArgs initialization code 37 | // Add system prompt 38 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 39 | { 40 | // Add Auto invoke kernel functions as the tool call behavior 41 | ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions 42 | }; 43 | 44 | // Initialize kernel arguments 45 | KernelArguments kernelArgs = new(promptExecutionSettings); 46 | 47 | // TODO: Step 3 - Uncomment out all code after "Execute program" comment 48 | // Execute program. 49 | /* 50 | const string terminationPhrase = "quit"; 51 | string? userInput; 52 | do 53 | { 54 | Console.Write("User > "); 55 | userInput = Console.ReadLine(); 56 | 57 | if (userInput is not null and not terminationPhrase) 58 | { 59 | Console.Write("Assistant > "); 60 | // Initialize fullMessage variable and add user input to chat history 61 | string fullMessage = ""; 62 | chatHistory.AddUserMessage(userInput); 63 | 64 | // TODO: Step 4 - Invoke the agent 65 | 66 | Console.WriteLine(); 67 | } 68 | } 69 | while (userInput != terminationPhrase); 70 | */ 71 | -------------------------------------------------------------------------------- /workshop/dotnet/Lessons/appsettings.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "StockService": { 3 | "apiKey": "" 4 | }, 5 | "AIFoundryProject": { 6 | "connectionString": "", 7 | "groundingWithBingConnectionId": "", 8 | "endpoint": "", 9 | "apiKey": "", 10 | "deploymentName": "" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Exe 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Always 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson1/Lesson1.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Always 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson1/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.Connectors.OpenAI; 4 | 5 | 6 | // TODO: Step 1 - Initialize the kernel with chat completion 7 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 8 | Kernel kernel = builder.Build(); 9 | 10 | // TODO: Step 2 - Add system prompt 11 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 12 | { 13 | ChatSystemPrompt = @"You are a friendly financial advisor that only emits financial advice in a creative and funny tone" 14 | }; 15 | 16 | // TODO: Step 3 - Initialize kernel arguments 17 | KernelArguments kernelArgs = new(promptExecutionSettings); 18 | 19 | // Execute program. 20 | const string terminationPhrase = "quit"; 21 | string? userInput; 22 | do 23 | { 24 | Console.Write("User > "); 25 | userInput = Console.ReadLine(); 26 | 27 | if (userInput is not null and not terminationPhrase) 28 | { 29 | Console.Write("Assistant > "); 30 | // TODO: Step 4 - add a loop to invoke prompt asynchronously providing user input and kernel arguments 31 | await foreach (var response in kernel.InvokePromptStreamingAsync(userInput, kernelArgs)) 32 | { 33 | Console.Write(response); 34 | } 35 | Console.WriteLine(); 36 | } 37 | } 38 | while (userInput != terminationPhrase); 39 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson2/Lesson2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Always 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson2/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.Connectors.OpenAI; 4 | // Step 1 - Add ChatCompletion import 5 | using Microsoft.SemanticKernel.ChatCompletion; 6 | 7 | 8 | // Initialize the kernel with chat completion 9 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 10 | Kernel kernel = builder.Build(); 11 | 12 | // Step 2a - Get chatCompletionService and initialize chatHistory with system prompt 13 | var chatCompletionService = kernel.GetRequiredService(); 14 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 15 | // Step 2b - Remove the promptExecutionSettings and kernelArgs initialization code - REMOVED 16 | 17 | // Execute program. 18 | const string terminationPhrase = "quit"; 19 | string? userInput; 20 | do 21 | { 22 | Console.Write("User > "); 23 | userInput = Console.ReadLine(); 24 | 25 | if (userInput is not null and not terminationPhrase) 26 | { 27 | Console.Write("Assistant > "); 28 | // Step 3 - Initialize fullMessage variable and add user input to chat history 29 | string fullMessage = ""; 30 | chatHistory.AddUserMessage(userInput); 31 | 32 | // Step 4 - Replace the foreach loop and replace it with this code including adding assistant message to chat history 33 | await foreach (var chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory)) 34 | { 35 | Console.Write(chatUpdate.Content); 36 | fullMessage += chatUpdate.Content ?? ""; 37 | } 38 | chatHistory.AddAssistantMessage(fullMessage); 39 | 40 | Console.WriteLine(); 41 | } 42 | } 43 | while (userInput != terminationPhrase); 44 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson3/Lesson3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Always 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson3/Lesson3.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lesson3", "Lesson3.csproj", "{BF89ED0F-8671-429B-91A4-CEFB432DAD21}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {BF89ED0F-8671-429B-91A4-CEFB432DAD21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {BF89ED0F-8671-429B-91A4-CEFB432DAD21}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {BF89ED0F-8671-429B-91A4-CEFB432DAD21}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {BF89ED0F-8671-429B-91A4-CEFB432DAD21}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C064C523-9186-413D-8213-7EDE44A472F8} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson3/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // Step 1 - Add import for Plugins 3 | using Core.Utilities.Plugins; 4 | // Step 5 - Add import required for StockService 5 | using Core.Utilities.Services; 6 | using Microsoft.SemanticKernel; 7 | using Microsoft.SemanticKernel.Connectors.OpenAI; 8 | // Add ChatCompletion import 9 | using Microsoft.SemanticKernel.ChatCompletion; 10 | // Temporarily added to enable Semantic Kernel tracing 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Logging; 13 | 14 | 15 | // Initialize the kernel with chat completion 16 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 17 | // Enable tracing 18 | //builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 19 | Kernel kernel = builder.Build(); 20 | 21 | // Step 2 - Initialize Time plugin and registration in the kernel 22 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 23 | 24 | // Step 6 - Initialize Stock Data Plugin and register it in the kernel 25 | HttpClient httpClient = new(); 26 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 27 | kernel.Plugins.AddFromObject(stockDataPlugin); 28 | 29 | // Get chatCompletionService and initialize chatHistory with system prompt 30 | var chatCompletionService = kernel.GetRequiredService(); 31 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 32 | // Remove the promptExecutionSettings and kernelArgs initialization code 33 | // Add system prompt 34 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 35 | { 36 | // Step 3 - Add Auto invoke kernel functions as the tool call behavior 37 | ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions 38 | }; 39 | 40 | // Initialize kernel arguments 41 | KernelArguments kernelArgs = new(promptExecutionSettings); 42 | 43 | // Execute program. 44 | const string terminationPhrase = "quit"; 45 | string? userInput; 46 | do 47 | { 48 | Console.Write("User > "); 49 | userInput = Console.ReadLine(); 50 | 51 | if (userInput is not null and not terminationPhrase) 52 | { 53 | Console.Write("Assistant > "); 54 | // Initialize fullMessage variable and add user input to chat history 55 | string fullMessage = ""; 56 | chatHistory.AddUserMessage(userInput); 57 | 58 | // Step 4 - Provide promptExecutionSettings and kernel arguments 59 | await foreach (var chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory, promptExecutionSettings, kernel)) 60 | { 61 | Console.Write(chatUpdate.Content); 62 | fullMessage += chatUpdate.Content ?? ""; 63 | } 64 | chatHistory.AddAssistantMessage(fullMessage); 65 | 66 | Console.WriteLine(); 67 | } 68 | } 69 | while (userInput != terminationPhrase); 70 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson4/Lesson4.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Always 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson4/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // Add import for Plugins 3 | using Core.Utilities.Plugins; 4 | // Add import required for StockService 5 | using Core.Utilities.Services; 6 | // Step 1 - Add import for ModelExtensionMethods 7 | using Core.Utilities.Extensions; 8 | using Microsoft.SemanticKernel; 9 | using Microsoft.SemanticKernel.Connectors.OpenAI; 10 | // Add ChatCompletion import 11 | using Microsoft.SemanticKernel.ChatCompletion; 12 | // Temporarily added to enable Semantic Kernel tracing 13 | using Microsoft.Extensions.DependencyInjection; 14 | using Microsoft.Extensions.Logging; 15 | 16 | 17 | // Initialize the kernel with chat completion 18 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 19 | // Enable tracing 20 | //builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 21 | Kernel kernel = builder.Build(); 22 | 23 | // Initialize Time plugin and registration in the kernel 24 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 25 | 26 | // Initialize Stock Data Plugin and register it in the kernel 27 | HttpClient httpClient = new(); 28 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 29 | kernel.Plugins.AddFromObject(stockDataPlugin); 30 | 31 | // Get chatCompletionService and initialize chatHistory with system prompt 32 | var chatCompletionService = kernel.GetRequiredService(); 33 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 34 | // Remove the promptExecutionSettings and kernelArgs initialization code 35 | // Add system prompt 36 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 37 | { 38 | // Add Auto invoke kernel functions as the tool call behavior 39 | ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions 40 | }; 41 | 42 | // Initialize kernel arguments 43 | KernelArguments kernelArgs = new(promptExecutionSettings); 44 | 45 | // Step 2 - Add call to print all plugins and functions 46 | var functions = kernel.Plugins.GetFunctionsMetadata(); 47 | Console.WriteLine(functions.ToPrintableString()); 48 | // Step 3 - Comment out all code after "Execute program" comment 49 | // Execute program. 50 | /* 51 | const string terminationPhrase = "quit"; 52 | string? userInput; 53 | do 54 | { 55 | Console.Write("User > "); 56 | userInput = Console.ReadLine(); 57 | 58 | if (userInput is not null and not terminationPhrase) 59 | { 60 | Console.Write("Assistant > "); 61 | // Initialize fullMessage variable and add user input to chat history 62 | string fullMessage = ""; 63 | chatHistory.AddUserMessage(userInput); 64 | 65 | // Provide promptExecutionSettings and kernel arguments 66 | await foreach (var chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory, promptExecutionSettings, kernel)) 67 | { 68 | Console.Write(chatUpdate.Content); 69 | fullMessage += chatUpdate.Content ?? ""; 70 | } 71 | chatHistory.AddAssistantMessage(fullMessage); 72 | 73 | Console.WriteLine(); 74 | } 75 | } 76 | while (userInput != terminationPhrase); 77 | */ 78 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson5/Lesson5.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Always 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson5/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // Add import for Plugins 3 | using Core.Utilities.Plugins; 4 | // Add import required for StockService 5 | using Core.Utilities.Services; 6 | // Add import for ModelExtensionMethods 7 | using Core.Utilities.Extensions; 8 | using Microsoft.SemanticKernel; 9 | using Microsoft.SemanticKernel.Connectors.OpenAI; 10 | // Step 1 - Add import for Agents 11 | using Microsoft.SemanticKernel.Agents; 12 | // Add ChatCompletion import 13 | using Microsoft.SemanticKernel.ChatCompletion; 14 | // Temporarily added to enable Semantic Kernel tracing 15 | using Microsoft.Extensions.DependencyInjection; 16 | using Microsoft.Extensions.Logging; 17 | 18 | 19 | // Initialize the kernel with chat completion 20 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 21 | // Enable tracing 22 | //builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 23 | Kernel kernel = builder.Build(); 24 | 25 | // Initialize Time plugin and registration in the kernel 26 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 27 | 28 | // Initialize Stock Data Plugin and register it in the kernel 29 | HttpClient httpClient = new(); 30 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 31 | kernel.Plugins.AddFromObject(stockDataPlugin); 32 | 33 | // Step 2 - Add code to create Stock Sentiment Agent 34 | ChatCompletionAgent stockSentimentAgent = 35 | new() 36 | { 37 | Name = "StockSentimentAgent", 38 | Instructions = 39 | """ 40 | Your responsibility is to find the stock sentiment for a given Stock. 41 | 42 | RULES: 43 | - Use stock sentiment scale from 1 to 10 where stock sentiment is 1 for sell and 10 for buy. 44 | - Provide the rating in your response and a recommendation to buy, hold or sell. 45 | - Include the reasoning behind your recommendation. 46 | - Include the source of the sentiment in your response. 47 | """, 48 | Kernel = kernel, 49 | Arguments = new KernelArguments(new OpenAIPromptExecutionSettings() { 50 | FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()}) 51 | }; 52 | 53 | // Get chatCompletionService and initialize chatHistory with system prompt 54 | var chatCompletionService = kernel.GetRequiredService(); 55 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 56 | // Remove the promptExecutionSettings and kernelArgs initialization code 57 | // Add system prompt 58 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 59 | { 60 | // Add Auto invoke kernel functions as the tool call behavior 61 | ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions 62 | }; 63 | 64 | // Initialize kernel arguments 65 | KernelArguments kernelArgs = new(promptExecutionSettings); 66 | 67 | // Add call to print all plugins and functions 68 | var functions = kernel.Plugins.GetFunctionsMetadata(); 69 | // Step 0a - Comment line to print all plugins and functions 70 | //Console.WriteLine(functions.ToPrintableString()); 71 | 72 | // Step 0b - Uncomment out all code after "Execute program" comment 73 | // Execute program. 74 | const string terminationPhrase = "quit"; 75 | string? userInput; 76 | do 77 | { 78 | Console.Write("User > "); 79 | userInput = Console.ReadLine(); 80 | 81 | if (userInput is not null and not terminationPhrase) 82 | { 83 | Console.Write("Assistant > "); 84 | // Initialize fullMessage variable and add user input to chat history 85 | string fullMessage = ""; 86 | chatHistory.AddUserMessage(userInput); 87 | 88 | // Step 3 - Replace chatCompletionService with stockSentimentAgent 89 | await foreach (var chatUpdate in stockSentimentAgent.InvokeAsync(chatHistory, kernelArgs)) 90 | { 91 | Console.Write(chatUpdate.Content); 92 | fullMessage += chatUpdate.Content ?? ""; 93 | } 94 | chatHistory.AddAssistantMessage(fullMessage); 95 | 96 | Console.WriteLine(); 97 | } 98 | } 99 | while (userInput != terminationPhrase); 100 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson6/Lesson6.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Always 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Lesson6/Program.cs: -------------------------------------------------------------------------------- 1 | using Core.Utilities.Config; 2 | // Add import for Plugins 3 | using Core.Utilities.Plugins; 4 | // Add import required for StockService 5 | using Core.Utilities.Services; 6 | using Microsoft.SemanticKernel; 7 | using Microsoft.SemanticKernel.Connectors.OpenAI; 8 | // Add ChatCompletion import 9 | using Microsoft.SemanticKernel.ChatCompletion; 10 | // Temporarily added to enable Semantic Kernel tracing 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Logging; 13 | 14 | // TODO: Step 1 -- Add imports for Agents and Azure.Identity 15 | using Azure.AI.Projects; 16 | using Azure.Identity; 17 | using Microsoft.SemanticKernel.Agents.AzureAI; 18 | 19 | 20 | // Initialize the kernel with chat completion 21 | IKernelBuilder builder = KernelBuilderProvider.CreateKernelWithChatCompletion(); 22 | // Enable tracing 23 | // builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Trace)); 24 | Kernel kernel = builder.Build(); 25 | 26 | // Initialize Time plugin and registration in the kernel 27 | kernel.Plugins.AddFromObject(new TimeInformationPlugin()); 28 | 29 | // TODO: Step 2 - Initialize connection to Grounding with Bing Search tool and agent 30 | var connectionString = AISettingsProvider.GetSettings().AIFoundryProject.ConnectionString; 31 | var groundingWithBingConnectionId = AISettingsProvider.GetSettings().AIFoundryProject.GroundingWithBingConnectionId; 32 | 33 | var projectClient = new AIProjectClient(connectionString, new AzureCliCredential()); 34 | 35 | ConnectionResponse bingConnection = await projectClient.GetConnectionsClient().GetConnectionAsync(groundingWithBingConnectionId); 36 | var connectionId = bingConnection.Id; 37 | 38 | ToolConnectionList connectionList = new ToolConnectionList 39 | { 40 | ConnectionList = { new ToolConnection(connectionId) } 41 | }; 42 | BingGroundingToolDefinition bingGroundingTool = new BingGroundingToolDefinition(connectionList); 43 | 44 | var clientProvider = AzureAIClientProvider.FromConnectionString(connectionString, new AzureCliCredential()); 45 | AgentsClient client = clientProvider.Client.GetAgentsClient(); 46 | var definition = await client.CreateAgentAsync( 47 | "gpt-4o", 48 | instructions: 49 | """ 50 | Your responsibility is to find the stock sentiment for a given Stock. 51 | 52 | RULES: 53 | - Report a stock sentiment scale from 1 to 10 where stock sentiment is 1 for sell and 10 for buy. 54 | - Only use current data reputable sources such as Yahoo Finance, MarketWatch, Fidelity and similar. 55 | - Provide the stock sentiment scale in your response and a recommendation to buy, hold or sell. 56 | - Include the reasoning behind your recommendation. 57 | - Be sure to cite the source of the information. 58 | """, 59 | tools: 60 | [ 61 | bingGroundingTool 62 | ]); 63 | var agent = new AzureAIAgent(definition, clientProvider) 64 | { 65 | Kernel = kernel, 66 | }; 67 | 68 | // Create a thread for the agent conversation. 69 | AgentThread thread = await client.CreateThreadAsync(); 70 | 71 | // Initialize Stock Data Plugin and register it in the kernel 72 | HttpClient httpClient = new(); 73 | StockDataPlugin stockDataPlugin = new(new StocksService(httpClient)); 74 | kernel.Plugins.AddFromObject(stockDataPlugin); 75 | 76 | // Get chatCompletionService and initialize chatHistory with system prompt 77 | var chatCompletionService = kernel.GetRequiredService(); 78 | ChatHistory chatHistory = new("You are a friendly financial advisor that only emits financial advice in a creative and funny tone"); 79 | // Remove the promptExecutionSettings and kernelArgs initialization code 80 | // Add system prompt 81 | OpenAIPromptExecutionSettings promptExecutionSettings = new() 82 | { 83 | // Add Auto invoke kernel functions as the tool call behavior 84 | ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions 85 | }; 86 | 87 | // Initialize kernel arguments 88 | KernelArguments kernelArgs = new(promptExecutionSettings); 89 | 90 | // TODO: Step 3 - Uncomment out all code after "Execute program" comment 91 | // Execute program. 92 | 93 | const string terminationPhrase = "quit"; 94 | string? userInput; 95 | do 96 | { 97 | Console.Write("User > "); 98 | userInput = Console.ReadLine(); 99 | 100 | if (userInput is not null and not terminationPhrase) 101 | { 102 | chatHistory.AddUserMessage(userInput); 103 | Console.Write("Assistant > "); 104 | 105 | // TODO: Step 4 - Invoke the agent 106 | ChatMessageContent message = new(AuthorRole.User, userInput); 107 | await agent.AddChatMessageAsync(thread.Id, message); 108 | 109 | await foreach (ChatMessageContent response in agent.InvokeAsync(thread.Id)) 110 | { 111 | string contentExpression = string.IsNullOrWhiteSpace(response.Content) ? string.Empty : response.Content; 112 | chatHistory.AddAssistantMessage(contentExpression); 113 | Console.WriteLine($"{contentExpression}"); 114 | } 115 | } 116 | } 117 | while (userInput != terminationPhrase); 118 | -------------------------------------------------------------------------------- /workshop/dotnet/Solutions/Solutions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lesson1", "Lesson1\Lesson1.csproj", "{B230A526-2B91-4CC7-BF4E-B29568AB9670}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lesson2", "Lesson2\Lesson2.csproj", "{A5E9D722-3085-4780-954C-A132A67EB63B}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {B230A526-2B91-4CC7-BF4E-B29568AB9670}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {B230A526-2B91-4CC7-BF4E-B29568AB9670}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {B230A526-2B91-4CC7-BF4E-B29568AB9670}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {B230A526-2B91-4CC7-BF4E-B29568AB9670}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {A5E9D722-3085-4780-954C-A132A67EB63B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {A5E9D722-3085-4780-954C-A132A67EB63B}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {A5E9D722-3085-4780-954C-A132A67EB63B}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {A5E9D722-3085-4780-954C-A132A67EB63B}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A0BEA744-7023-4A7A-9475-8E2A2FF9E13A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /workshop/dotnet/azure.yaml: -------------------------------------------------------------------------------- 1 | name: semantic-kernel-workshop-csharp 2 | metadata: 3 | template: semantic-kernel-workshop-csharp@0.0.1-beta 4 | services: 5 | api: 6 | project: ./App/backend/ 7 | host: containerapp 8 | language: dotnet 9 | docker: 10 | path: ../Dockerfile 11 | context: ../../ 12 | web: 13 | project: ../frontend/ 14 | host: containerapp 15 | language: ts 16 | docker: 17 | path: ./Dockerfile 18 | context: ./ -------------------------------------------------------------------------------- /workshop/dotnet/infra/app/api.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | @description('The name of the identity') 6 | param identityName string 7 | 8 | @description('The name of the Application Insights') 9 | param applicationInsightsName string 10 | 11 | @description('The name of the container apps environment') 12 | param containerAppsEnvironmentName string 13 | 14 | @description('The name of the container registry') 15 | param containerRegistryName string 16 | 17 | @description('The name of the service') 18 | param serviceName string = 'api' 19 | 20 | @description('The name of the image') 21 | param imageName string = '' 22 | 23 | @description('Specifies if the resource exists') 24 | param exists bool 25 | 26 | @description('The OpenAI endpoint') 27 | param openAiEndpoint string 28 | 29 | @description('The OpenAI ChatGPT deployment name') 30 | param openAiChatGptDeployment string 31 | 32 | @description('The OpenAI API key') 33 | param openAiApiKey string 34 | 35 | @description('The Stock Service API key') 36 | param stockServiceApiKey string 37 | 38 | @description('The user-assigned role client id') 39 | param userAssignedRoleClientId string 40 | 41 | @description('AI Foundry Project connection string') 42 | param aiFoundryProjectConnectionString string 43 | 44 | @description('Grounding with Bing connection id') 45 | param groundingWithBingConnectionId string 46 | 47 | @description('An array of service binds') 48 | param serviceBinds array 49 | 50 | type managedIdentity = { 51 | resourceId: string 52 | clientId: string 53 | } 54 | 55 | @description('Unique identifier for user-assigned managed identity.') 56 | param userAssignedManagedIdentity managedIdentity 57 | 58 | module app '../core/host/container-app-upsert.bicep' = { 59 | name: '${serviceName}-container-app' 60 | params: { 61 | name: name 62 | location: location 63 | tags: union(tags, { 'azd-service-name': serviceName }) 64 | identityName: identityName 65 | imageName: imageName 66 | exists: exists 67 | serviceBinds: serviceBinds 68 | containerAppsEnvironmentName: containerAppsEnvironmentName 69 | containerRegistryName: containerRegistryName 70 | secrets: { 71 | 'open-ai-api-key': openAiApiKey 72 | 'stock-service-api-key': stockServiceApiKey 73 | 'azure-managed-identity-client-id': userAssignedManagedIdentity.clientId 74 | 'user-assigned-role-client-id': userAssignedRoleClientId 75 | 'ai-foundry-project-connection-string': aiFoundryProjectConnectionString 76 | 'grounding-with-bing-connection-id': groundingWithBingConnectionId 77 | } 78 | env: [ 79 | { 80 | name: 'AZURE_MANAGED_IDENTITY_CLIENT_ID' 81 | value: 'azure-managed-identity-client-id' 82 | } 83 | { 84 | name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' 85 | value: !empty(applicationInsightsName) ? applicationInsights.properties.ConnectionString : '' 86 | } 87 | { 88 | name: 'ManagedIdentity__ClientId' 89 | secretREf: 'azure-managed-identity-client-id' 90 | } 91 | { 92 | name: 'AIFoundryProject__Endpoint' 93 | value: openAiEndpoint 94 | } 95 | { 96 | name: 'AIFoundryProject__DeploymentName' 97 | value: openAiChatGptDeployment 98 | } 99 | { 100 | name: 'AIFoundryProject__ApiKey' 101 | secretRef: 'open-ai-api-key' 102 | } 103 | { 104 | name: 'AIFoundryProject__ConnectionString' 105 | secretRef: 'ai-foundry-project-connection-string' 106 | } 107 | { 108 | name: 'AIFoundryProject__GroundingWithBingConnectionId' 109 | secretRef: 'grounding-with-bing-connection-id' 110 | } 111 | { 112 | name: 'AIFoundryProject__UserAssignedRoleClientId' 113 | secretRef: 'user-assigned-role-client-id' 114 | } 115 | { 116 | name: 'StockService__ApiKey' 117 | secretRef: 'stock-service-api-key' 118 | } 119 | ] 120 | targetPort: 8080 121 | } 122 | } 123 | 124 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) { 125 | name: applicationInsightsName 126 | } 127 | 128 | output SERVICE_API_IDENTITY_NAME string = identityName 129 | output SERVICE_API_IMAGE_NAME string = app.outputs.imageName 130 | output SERVICE_API_NAME string = app.outputs.name 131 | output SERVICE_API_URI string = app.outputs.uri 132 | output SERVICE_API_PRINCIPAL_ID string = app.outputs.principalId 133 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/app/user-assigned-identity.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates a Microsoft Entra user-assigned identity.' 2 | 3 | param name string 4 | param location string = resourceGroup().location 5 | param tags object = {} 6 | 7 | resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { 8 | name: name 9 | location: location 10 | tags: tags 11 | } 12 | 13 | output name string = identity.name 14 | output resourceId string = identity.id 15 | output principalId string = identity.properties.principalId 16 | output clientId string = identity.properties.clientId 17 | output tenantId string = identity.properties.tenantId 18 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/app/web.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | @description('The name of the identity') 6 | param identityName string 7 | 8 | @description('The name of the Application Insights') 9 | param applicationInsightsName string 10 | 11 | @description('Port for Web UI') 12 | param webPort string = '80' 13 | 14 | @description('The name of the container apps environment') 15 | param containerAppsEnvironmentName string 16 | 17 | @description('The name of the container registry') 18 | param containerRegistryName string 19 | 20 | @description('The name of the service') 21 | param serviceName string = 'web' 22 | 23 | @description('The name of the image') 24 | param imageName string = '' 25 | 26 | @description('Specifies if the resource exists') 27 | param exists bool 28 | 29 | @description('The URI for the backend API') 30 | param apiEndpoint string 31 | 32 | @description('An array of service binds') 33 | param serviceBinds array 34 | 35 | type managedIdentity = { 36 | resourceId: string 37 | clientId: string 38 | } 39 | 40 | @description('Unique identifier for user-assigned managed identity.') 41 | param userAssignedManagedIdentity managedIdentity 42 | 43 | module app '../core/host/container-app-upsert.bicep' = { 44 | name: '${serviceName}-container-app' 45 | params: { 46 | name: name 47 | location: location 48 | tags: union(tags, { 'azd-service-name': serviceName }) 49 | identityName: identityName 50 | imageName: imageName 51 | exists: exists 52 | serviceBinds: serviceBinds 53 | containerAppsEnvironmentName: containerAppsEnvironmentName 54 | containerRegistryName: containerRegistryName 55 | secrets: { 56 | 'azure-managed-identity-client-id': userAssignedManagedIdentity.clientId 57 | } 58 | env: [ 59 | { 60 | name: 'AZURE_MANAGED_IDENTITY_CLIENT_ID' 61 | value: 'azure-managed-identity-client-id' 62 | } 63 | { 64 | name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' 65 | value: !empty(applicationInsightsName) ? applicationInsights.properties.ConnectionString : '' 66 | } 67 | { 68 | name: 'API_URL' 69 | value: apiEndpoint 70 | } 71 | { 72 | name: 'PORT' 73 | value: webPort 74 | } 75 | { 76 | name: 'REACT_APP_PROXY_URL' 77 | value: '/api/chat' 78 | } 79 | ] 80 | targetPort: 80 81 | } 82 | } 83 | 84 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) { 85 | name: applicationInsightsName 86 | } 87 | 88 | output SERVICE_WEB_IDENTITY_NAME string = identityName 89 | output SERVICE_WEB_IMAGE_NAME string = app.outputs.imageName 90 | output SERVICE_WEB_NAME string = app.outputs.name 91 | output SERVICE_WEB_URI string = app.outputs.uri 92 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/ai/cognitiveservices.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Cognitive Services instance.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | @description('The custom subdomain name used to access the API. Defaults to the value of the name parameter.') 6 | param customSubDomainName string = name 7 | param deployments array = [] 8 | param kind string = 'OpenAI' 9 | 10 | @allowed([ 'Enabled', 'Disabled' ]) 11 | param publicNetworkAccess string = 'Enabled' 12 | param sku object = { 13 | name: 'S0' 14 | } 15 | 16 | param allowedIpRules array = [] 17 | param networkAcls object = empty(allowedIpRules) ? { 18 | defaultAction: 'Allow' 19 | } : { 20 | ipRules: allowedIpRules 21 | defaultAction: 'Deny' 22 | } 23 | 24 | resource account 'Microsoft.CognitiveServices/accounts@2023-05-01' = { 25 | name: name 26 | location: location 27 | tags: tags 28 | kind: kind 29 | identity: { 30 | type: 'SystemAssigned' 31 | } 32 | properties: { 33 | customSubDomainName: customSubDomainName 34 | publicNetworkAccess: publicNetworkAccess 35 | networkAcls: networkAcls 36 | disableLocalAuth: true 37 | } 38 | sku: sku 39 | } 40 | 41 | @batchSize(1) 42 | resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = [for deployment in deployments: { 43 | parent: account 44 | name: deployment.name 45 | properties: { 46 | model: deployment.model 47 | raiPolicyName: contains(deployment, 'raiPolicyName') ? deployment.raiPolicyName : null 48 | } 49 | sku: contains(deployment, 'sku') ? deployment.sku : { 50 | name: 'Standard' 51 | capacity: 20 52 | } 53 | }] 54 | 55 | output endpoint string = account.properties.endpoint 56 | output endpoints object = account.properties.endpoints 57 | output id string = account.id 58 | output name string = account.name 59 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/bing/bing-search.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates Bing Search Service v7' 2 | param name string 3 | param location string = 'global' 4 | param tags object = {} 5 | param sku string = 'F1' 6 | 7 | resource bingSearchService 'Microsoft.Bing/accounts@2020-06-10' = { 8 | name: name 9 | location: location 10 | tags: tags 11 | sku: { 12 | name: sku 13 | } 14 | kind: 'Bing.Search.v7' 15 | } 16 | 17 | output serviceId string = bingSearchService.id 18 | output apiKey string = bingSearchService.listKeys().key1 19 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/host/container-app-upsert.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates or updates an existing Azure Container App.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | @description('The environment name for the container apps') 7 | param containerAppsEnvironmentName string 8 | 9 | @description('The number of CPU cores allocated to a single container instance, e.g., 0.5') 10 | param containerCpuCoreCount string = '0.5' 11 | 12 | @description('The maximum number of replicas to run. Must be at least 1.') 13 | @minValue(1) 14 | param containerMaxReplicas int = 10 15 | 16 | @description('The amount of memory allocated to a single container instance, e.g., 1Gi') 17 | param containerMemory string = '1.0Gi' 18 | 19 | @description('The minimum number of replicas to run. Must be at least 1.') 20 | @minValue(1) 21 | param containerMinReplicas int = 1 22 | 23 | @description('The name of the container') 24 | param containerName string = 'main' 25 | 26 | @description('The name of the container registry') 27 | param containerRegistryName string = '' 28 | 29 | @description('Hostname suffix for container registry. Set when deploying to sovereign clouds') 30 | param containerRegistryHostSuffix string = 'azurecr.io' 31 | 32 | @allowed([ 'http', 'grpc' ]) 33 | @description('The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC') 34 | param daprAppProtocol string = 'http' 35 | 36 | @description('Enable or disable Dapr for the container app') 37 | param daprEnabled bool = false 38 | 39 | @description('The Dapr app ID') 40 | param daprAppId string = containerName 41 | 42 | @description('Specifies if the resource already exists') 43 | param exists bool = false 44 | 45 | @description('Specifies if Ingress is enabled for the container app') 46 | param ingressEnabled bool = true 47 | 48 | @description('The type of identity for the resource') 49 | @allowed([ 'None', 'SystemAssigned', 'UserAssigned' ]) 50 | param identityType string = 'None' 51 | 52 | @description('The name of the user-assigned identity') 53 | param identityName string = '' 54 | 55 | @description('The name of the container image') 56 | param imageName string = '' 57 | 58 | @description('The secrets required for the container') 59 | @secure() 60 | param secrets object = {} 61 | 62 | @description('The environment variables for the container') 63 | param env array = [] 64 | 65 | @description('Specifies if the resource ingress is exposed externally') 66 | param external bool = true 67 | 68 | @description('The service binds associated with the container') 69 | param serviceBinds array = [] 70 | 71 | @description('The target port for the container') 72 | param targetPort int = 80 73 | 74 | resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { 75 | name: name 76 | } 77 | 78 | module app 'container-app.bicep' = { 79 | name: '${deployment().name}-update' 80 | params: { 81 | name: name 82 | location: location 83 | tags: tags 84 | identityType: identityType 85 | identityName: identityName 86 | ingressEnabled: ingressEnabled 87 | containerName: containerName 88 | containerAppsEnvironmentName: containerAppsEnvironmentName 89 | containerRegistryName: containerRegistryName 90 | containerRegistryHostSuffix: containerRegistryHostSuffix 91 | containerCpuCoreCount: containerCpuCoreCount 92 | containerMemory: containerMemory 93 | containerMinReplicas: containerMinReplicas 94 | containerMaxReplicas: containerMaxReplicas 95 | daprEnabled: daprEnabled 96 | daprAppId: daprAppId 97 | daprAppProtocol: daprAppProtocol 98 | secrets: secrets 99 | external: external 100 | env: env 101 | imageName: !empty(imageName) ? imageName : exists ? existingApp.properties.template.containers[0].image : '' 102 | targetPort: targetPort 103 | serviceBinds: serviceBinds 104 | } 105 | } 106 | 107 | output defaultDomain string = app.outputs.defaultDomain 108 | output imageName string = app.outputs.imageName 109 | output name string = app.outputs.name 110 | output uri string = app.outputs.uri 111 | output principalId string = app.outputs.identityPrincipalId 112 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/host/container-apps-environment.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Container Apps environment.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | @description('Name of the Application Insights resource') 7 | param applicationInsightsName string = '' 8 | 9 | @description('Specifies if Dapr is enabled') 10 | param daprEnabled bool = false 11 | 12 | @description('Name of the Log Analytics workspace') 13 | param logAnalyticsWorkspaceName string 14 | 15 | resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { 16 | name: name 17 | location: location 18 | tags: tags 19 | properties: { 20 | appLogsConfiguration: { 21 | destination: 'log-analytics' 22 | logAnalyticsConfiguration: { 23 | customerId: logAnalyticsWorkspace.properties.customerId 24 | sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey 25 | } 26 | } 27 | daprAIInstrumentationKey: daprEnabled && !empty(applicationInsightsName) ? applicationInsights.properties.InstrumentationKey : '' 28 | } 29 | } 30 | 31 | resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { 32 | name: logAnalyticsWorkspaceName 33 | } 34 | 35 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (daprEnabled && !empty(applicationInsightsName)) { 36 | name: applicationInsightsName 37 | } 38 | 39 | output defaultDomain string = containerAppsEnvironment.properties.defaultDomain 40 | output id string = containerAppsEnvironment.id 41 | output name string = containerAppsEnvironment.name 42 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/host/container-apps.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Container Registry and an Azure Container Apps environment.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param containerAppsEnvironmentName string 7 | param containerRegistryName string 8 | param containerRegistryResourceGroupName string = '' 9 | param containerRegistryAdminUserEnabled bool = false 10 | param logAnalyticsWorkspaceName string = '' 11 | param applicationInsightsName string = '' 12 | param daprEnabled bool = false 13 | 14 | module containerAppsEnvironment 'container-apps-environment.bicep' = { 15 | name: '${name}-container-apps-environment' 16 | params: { 17 | name: containerAppsEnvironmentName 18 | location: location 19 | tags: tags 20 | logAnalyticsWorkspaceName: logAnalyticsWorkspaceName 21 | applicationInsightsName: applicationInsightsName 22 | daprEnabled: daprEnabled 23 | } 24 | } 25 | 26 | module containerRegistry 'container-registry.bicep' = { 27 | name: '${name}-container-registry' 28 | scope: !empty(containerRegistryResourceGroupName) ? resourceGroup(containerRegistryResourceGroupName) : resourceGroup() 29 | params: { 30 | name: containerRegistryName 31 | location: location 32 | adminUserEnabled: containerRegistryAdminUserEnabled 33 | tags: tags 34 | sku: { 35 | name: 'Standard' 36 | } 37 | anonymousPullEnabled: false 38 | } 39 | } 40 | 41 | output defaultDomain string = containerAppsEnvironment.outputs.defaultDomain 42 | output environmentName string = containerAppsEnvironment.outputs.name 43 | output environmentId string = containerAppsEnvironment.outputs.id 44 | 45 | output registryLoginServer string = containerRegistry.outputs.loginServer 46 | output registryName string = containerRegistry.outputs.name 47 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/host/container-registry.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Container Registry.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | @description('Indicates whether admin user is enabled') 7 | param adminUserEnabled bool = false 8 | 9 | @description('Indicates whether anonymous pull is enabled') 10 | param anonymousPullEnabled bool = false 11 | 12 | @description('Azure ad authentication as arm policy settings') 13 | param azureADAuthenticationAsArmPolicy object = { 14 | status: 'enabled' 15 | } 16 | 17 | @description('Indicates whether data endpoint is enabled') 18 | param dataEndpointEnabled bool = false 19 | 20 | @description('Encryption settings') 21 | param encryption object = { 22 | status: 'disabled' 23 | } 24 | 25 | @description('Export policy settings') 26 | param exportPolicy object = { 27 | status: 'enabled' 28 | } 29 | 30 | @description('Metadata search settings') 31 | param metadataSearch string = 'Disabled' 32 | 33 | @description('Options for bypassing network rules') 34 | param networkRuleBypassOptions string = 'AzureServices' 35 | 36 | @description('Public network access setting') 37 | param publicNetworkAccess string = 'Enabled' 38 | 39 | @description('Quarantine policy settings') 40 | param quarantinePolicy object = { 41 | status: 'disabled' 42 | } 43 | 44 | @description('Retention policy settings') 45 | param retentionPolicy object = { 46 | days: 7 47 | status: 'disabled' 48 | } 49 | 50 | @description('Scope maps setting') 51 | param scopeMaps array = [] 52 | 53 | @description('SKU settings') 54 | param sku object = { 55 | name: 'Basic' 56 | } 57 | 58 | @description('Soft delete policy settings') 59 | param softDeletePolicy object = { 60 | retentionDays: 7 61 | status: 'disabled' 62 | } 63 | 64 | @description('Trust policy settings') 65 | param trustPolicy object = { 66 | type: 'Notary' 67 | status: 'disabled' 68 | } 69 | 70 | @description('Zone redundancy setting') 71 | param zoneRedundancy string = 'Disabled' 72 | 73 | @description('The log analytics workspace ID used for logging and monitoring') 74 | param workspaceId string = '' 75 | 76 | // 2023-11-01-preview needed for metadataSearch 77 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-11-01-preview' = { 78 | name: name 79 | location: location 80 | tags: tags 81 | sku: sku 82 | properties: { 83 | adminUserEnabled: adminUserEnabled 84 | anonymousPullEnabled: anonymousPullEnabled 85 | dataEndpointEnabled: dataEndpointEnabled 86 | encryption: encryption 87 | metadataSearch: metadataSearch 88 | networkRuleBypassOptions: networkRuleBypassOptions 89 | policies:{ 90 | quarantinePolicy: quarantinePolicy 91 | trustPolicy: trustPolicy 92 | retentionPolicy: retentionPolicy 93 | exportPolicy: exportPolicy 94 | azureADAuthenticationAsArmPolicy: azureADAuthenticationAsArmPolicy 95 | softDeletePolicy: softDeletePolicy 96 | } 97 | publicNetworkAccess: publicNetworkAccess 98 | zoneRedundancy: zoneRedundancy 99 | } 100 | 101 | resource scopeMap 'scopeMaps' = [for scopeMap in scopeMaps: { 102 | name: scopeMap.name 103 | properties: scopeMap.properties 104 | }] 105 | } 106 | 107 | // TODO: Update diagnostics to be its own module 108 | // Blocking issue: https://github.com/Azure/bicep/issues/622 109 | // Unable to pass in a `resource` scope or unable to use string interpolation in resource types 110 | resource diagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(workspaceId)) { 111 | name: 'registry-diagnostics' 112 | scope: containerRegistry 113 | properties: { 114 | workspaceId: workspaceId 115 | logs: [ 116 | { 117 | category: 'ContainerRegistryRepositoryEvents' 118 | enabled: true 119 | } 120 | { 121 | category: 'ContainerRegistryLoginEvents' 122 | enabled: true 123 | } 124 | ] 125 | metrics: [ 126 | { 127 | category: 'AllMetrics' 128 | enabled: true 129 | timeGrain: 'PT1M' 130 | } 131 | ] 132 | } 133 | } 134 | 135 | output id string = containerRegistry.id 136 | output loginServer string = containerRegistry.properties.loginServer 137 | output name string = containerRegistry.name 138 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/monitor/applicationinsights.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Application Insights instance based on an existing Log Analytics workspace.' 2 | param name string 3 | param dashboardName string = '' 4 | param location string = resourceGroup().location 5 | param tags object = {} 6 | param logAnalyticsWorkspaceId string 7 | 8 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { 9 | name: name 10 | location: location 11 | tags: tags 12 | kind: 'web' 13 | properties: { 14 | Application_Type: 'web' 15 | WorkspaceResourceId: logAnalyticsWorkspaceId 16 | } 17 | } 18 | 19 | module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = if (!empty(dashboardName)) { 20 | name: 'application-insights-dashboard' 21 | params: { 22 | name: dashboardName 23 | location: location 24 | applicationInsightsName: applicationInsights.name 25 | } 26 | } 27 | 28 | output connectionString string = applicationInsights.properties.ConnectionString 29 | output id string = applicationInsights.id 30 | output instrumentationKey string = applicationInsights.properties.InstrumentationKey 31 | output name string = applicationInsights.name 32 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/monitor/loganalytics.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates a Log Analytics workspace.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { 7 | name: name 8 | location: location 9 | tags: tags 10 | properties: any({ 11 | retentionInDays: 30 12 | features: { 13 | searchVersion: 1 14 | } 15 | sku: { 16 | name: 'PerGB2018' 17 | } 18 | }) 19 | } 20 | 21 | output id string = logAnalytics.id 22 | output name string = logAnalytics.name 23 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/monitor/monitoring.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Application Insights instance and a Log Analytics workspace.' 2 | param logAnalyticsName string 3 | param includeApplicationInsights bool = false 4 | param applicationInsightsName string 5 | param applicationInsightsDashboardName string = '' 6 | param location string = resourceGroup().location 7 | param tags object = {} 8 | 9 | 10 | module logAnalytics 'loganalytics.bicep' = { 11 | name: 'loganalytics' 12 | params: { 13 | name: logAnalyticsName 14 | location: location 15 | tags: tags 16 | } 17 | } 18 | 19 | module applicationInsights 'applicationinsights.bicep' = if(includeApplicationInsights) { 20 | name: 'applicationinsights' 21 | params: { 22 | name: applicationInsightsName 23 | location: location 24 | tags: tags 25 | dashboardName: applicationInsightsDashboardName 26 | logAnalyticsWorkspaceId: logAnalytics.outputs.id 27 | } 28 | } 29 | 30 | output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString 31 | output applicationInsightsId string = applicationInsights.outputs.id 32 | output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey 33 | output applicationInsightsName string = applicationInsights.outputs.name 34 | output logAnalyticsWorkspaceId string = logAnalytics.outputs.id 35 | output logAnalyticsWorkspaceName string = logAnalytics.outputs.name 36 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/security/keyvault-access.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Assigns an Azure Key Vault access policy.' 2 | param name string = 'add' 3 | 4 | param keyVaultName string 5 | param permissions object = { secrets: [ 'get', 'list' ] } 6 | param principalId string 7 | 8 | resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { 9 | parent: keyVault 10 | name: name 11 | properties: { 12 | accessPolicies: [ { 13 | objectId: principalId 14 | tenantId: subscription().tenantId 15 | permissions: permissions 16 | } ] 17 | } 18 | } 19 | 20 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 21 | name: keyVaultName 22 | } 23 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/security/keyvault-secret.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates or updates a secret in an Azure Key Vault.' 2 | param name string 3 | param tags object = {} 4 | param keyVaultName string 5 | param contentType string = 'string' 6 | @description('The value of the secret. Provide only derived values like blob storage access, but do not hard code any secrets in your templates') 7 | @secure() 8 | param secretValue string 9 | 10 | param enabled bool = true 11 | param exp int = 0 12 | param nbf int = 0 13 | 14 | resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { 15 | name: name 16 | tags: tags 17 | parent: keyVault 18 | properties: { 19 | attributes: { 20 | enabled: enabled 21 | exp: exp 22 | nbf: nbf 23 | } 24 | contentType: contentType 25 | value: secretValue 26 | } 27 | } 28 | 29 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 30 | name: keyVaultName 31 | } 32 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/security/keyvault-secrets.bicep: -------------------------------------------------------------------------------- 1 | param tags object = {} 2 | param keyVaultName string 3 | param secrets array = [] 4 | 5 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 6 | name: keyVaultName 7 | } 8 | 9 | @batchSize(1) 10 | resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = [for secret in secrets: { 11 | parent: keyVault 12 | name: secret.name 13 | tags: tags 14 | properties: { 15 | attributes: { 16 | enabled: contains(secret, 'enabled') ? secret.enabled : true 17 | exp: contains(secret, 'exp') ? secret.exp : 0 18 | nbf: contains(secret, 'nbf') ? secret.nbf : 0 19 | } 20 | contentType: contains(secret, 'contentType') ? secret.contentType : 'string' 21 | value: secret.value 22 | } 23 | }] 24 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/security/keyvault.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Key Vault.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param principalId string = '' 7 | 8 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { 9 | name: name 10 | location: location 11 | tags: tags 12 | properties: { 13 | tenantId: subscription().tenantId 14 | sku: { family: 'A', name: 'standard' } 15 | accessPolicies: !empty(principalId) ? [ 16 | { 17 | objectId: principalId 18 | permissions: { secrets: [ 'get', 'list' ] } 19 | tenantId: subscription().tenantId 20 | } 21 | ] : [] 22 | } 23 | } 24 | 25 | output endpoint string = keyVault.properties.vaultUri 26 | output id string = keyVault.id 27 | output name string = keyVault.name 28 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/security/registry-access.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Assigns ACR Pull permissions to access an Azure Container Registry.' 2 | param containerRegistryName string 3 | param principalId string 4 | 5 | var acrPullRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') 6 | 7 | resource aksAcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 8 | scope: containerRegistry // Use when specifying a scope that is different than the deployment scope 9 | name: guid(subscription().id, resourceGroup().id, principalId, acrPullRole) 10 | properties: { 11 | roleDefinitionId: acrPullRole 12 | principalType: 'ServicePrincipal' 13 | principalId: principalId 14 | } 15 | } 16 | 17 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' existing = { 18 | name: containerRegistryName 19 | } 20 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/security/role.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates a role assignment for a service principal.' 2 | param principalId string 3 | 4 | @allowed([ 5 | 'Device' 6 | 'ForeignGroup' 7 | 'Group' 8 | 'ServicePrincipal' 9 | 'User' 10 | ]) 11 | param principalType string = 'ServicePrincipal' 12 | param roleDefinitionId string 13 | 14 | resource role 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 15 | name: guid(subscription().id, resourceGroup().id, principalId, roleDefinitionId) 16 | properties: { 17 | principalId: principalId 18 | principalType: principalType 19 | roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/security/subscription-role.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | metadata description = 'Creates a role assignment for a service principal.' 3 | param principalId string 4 | 5 | @allowed([ 6 | 'Device' 7 | 'ForeignGroup' 8 | 'Group' 9 | 'ServicePrincipal' 10 | 'User' 11 | ]) 12 | param principalType string = 'ServicePrincipal' 13 | param roleDefinitionId string 14 | 15 | resource role 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 16 | name: guid(subscription().id, principalId, roleDefinitionId) 17 | properties: { 18 | principalId: principalId 19 | principalType: principalType 20 | roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/core/storage/storage-account.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure storage account.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | @allowed([ 7 | 'Cool' 8 | 'Hot' 9 | 'Premium' ]) 10 | param accessTier string = 'Hot' 11 | param allowBlobPublicAccess bool = false 12 | param allowCrossTenantReplication bool = true 13 | param allowSharedKeyAccess bool = true 14 | param containers array = [] 15 | param corsRules array = [] 16 | param defaultToOAuthAuthentication bool = false 17 | param deleteRetentionPolicy object = {} 18 | @allowed([ 'AzureDnsZone', 'Standard' ]) 19 | param dnsEndpointType string = 'Standard' 20 | param files array = [] 21 | param kind string = 'StorageV2' 22 | param minimumTlsVersion string = 'TLS1_2' 23 | param queues array = [] 24 | param shareDeleteRetentionPolicy object = {} 25 | param supportsHttpsTrafficOnly bool = true 26 | param tables array = [] 27 | param networkAcls object = { 28 | bypass: 'AzureServices' 29 | defaultAction: 'Allow' 30 | } 31 | @allowed([ 'Enabled', 'Disabled' ]) 32 | param publicNetworkAccess string = 'Enabled' 33 | param sku object = { name: 'Standard_LRS' } 34 | 35 | resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = { 36 | name: name 37 | location: location 38 | tags: tags 39 | kind: kind 40 | sku: sku 41 | properties: { 42 | accessTier: accessTier 43 | allowBlobPublicAccess: allowBlobPublicAccess 44 | allowCrossTenantReplication: allowCrossTenantReplication 45 | allowSharedKeyAccess: allowSharedKeyAccess 46 | defaultToOAuthAuthentication: defaultToOAuthAuthentication 47 | dnsEndpointType: dnsEndpointType 48 | minimumTlsVersion: minimumTlsVersion 49 | networkAcls: networkAcls 50 | publicNetworkAccess: publicNetworkAccess 51 | supportsHttpsTrafficOnly: supportsHttpsTrafficOnly 52 | } 53 | 54 | resource blobServices 'blobServices' = if (!empty(containers)) { 55 | name: 'default' 56 | properties: { 57 | cors: { 58 | corsRules: corsRules 59 | } 60 | deleteRetentionPolicy: deleteRetentionPolicy 61 | } 62 | resource container 'containers' = [for container in containers: { 63 | name: container.name 64 | properties: { 65 | publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None' 66 | } 67 | }] 68 | } 69 | 70 | resource fileServices 'fileServices' = if (!empty(files)) { 71 | name: 'default' 72 | properties: { 73 | cors: { 74 | corsRules: corsRules 75 | } 76 | shareDeleteRetentionPolicy: shareDeleteRetentionPolicy 77 | } 78 | } 79 | 80 | resource queueServices 'queueServices' = if (!empty(queues)) { 81 | name: 'default' 82 | properties: { 83 | 84 | } 85 | resource queue 'queues' = [for queue in queues: { 86 | name: queue.name 87 | properties: { 88 | metadata: {} 89 | } 90 | }] 91 | } 92 | 93 | resource tableServices 'tableServices' = if (!empty(tables)) { 94 | name: 'default' 95 | properties: {} 96 | } 97 | } 98 | 99 | output id string = storage.id 100 | output name string = storage.name 101 | output primaryEndpoints object = storage.properties.primaryEndpoints 102 | -------------------------------------------------------------------------------- /workshop/dotnet/infra/main.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "environmentName": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | }, 11 | "tags": { 12 | "value": "${AZURE_TAGS}" 13 | }, 14 | "keyVaultName": { 15 | "value": "${AZURE_KEY_VAULT_NAME}" 16 | }, 17 | "keyVaultResourceGroupName": { 18 | "value": "${AZURE_KEY_VAULT_RESOURCE_GROUP}" 19 | }, 20 | "openAiResourceGroupName": { 21 | "value": "${AZURE_OPENAI_RESOURCE_GROUP}" 22 | }, 23 | "openAiResourceGroupLocation": { 24 | "value": "${AZURE_OPENAI_RESOURCE_LOCATION=${AZURE_LOCATION}}" 25 | }, 26 | "chatGptDeploymentName": { 27 | "value": "${AZURE_OPENAI_CHATGPT_DEPLOYMENT=chat}" 28 | }, 29 | "openAiServiceName": { 30 | "value": "${AZURE_OPENAI_SERVICE}" 31 | }, 32 | "openAiSkuName": { 33 | "value": "S0" 34 | }, 35 | "principalId": { 36 | "value": "${AZURE_PRINCIPAL_ID}" 37 | }, 38 | "principalType": { 39 | "value": "${AZURE_PRINCIPAL_TYPE=User}" 40 | }, 41 | "resourceGroupName": { 42 | "value": "${AZURE_RESOURCE_GROUP}" 43 | }, 44 | "storageAccountName": { 45 | "value": "${AZURE_STORAGE_ACCOUNT}" 46 | }, 47 | "storageResourceGroupName": { 48 | "value": "${AZURE_STORAGE_RESOURCE_GROUP}" 49 | }, 50 | "webAppExists": { 51 | "value": "${SERVICE_WEB_RESOURCE_EXISTS=false}" 52 | }, 53 | "webIdentityName": { 54 | "value": "${SERVICE_WEB_IDENTITY_NAME}" 55 | }, 56 | "apiAppExists": { 57 | "value": "${SERVICE_API_RESOURCE_EXISTS=false}" 58 | }, 59 | "useApplicationInsights": { 60 | "value": "${AZURE_USE_APPLICATION_INSIGHTS=true}" 61 | }, 62 | "publicNetworkAccess": { 63 | "value": "${AZURE_PUBLIC_NETWORK_ACCESS=Enabled}" 64 | }, 65 | "openAIApiKey": { 66 | "value": "${OPENAI_API_KEY}" 67 | }, 68 | "useAOAI": { 69 | "value": "${USE_AOAI=false}" 70 | }, 71 | "openAiChatGptDeployment": { 72 | "value": "${OPENAI_CHATGPT_DEPLOYMENT}" 73 | }, 74 | "openAiEndpoint": { 75 | "value": "${OPENAI_ENDPOINT}" 76 | }, 77 | "azureOpenAIChatGptModelVersion": { 78 | "value": "${AZURE_OPENAI_CHATGPT_MODEL_VERSION=2024-07-18}" 79 | }, 80 | "azureOpenAIChatGptModelName": { 81 | "value": "${AZURE_OPENAI_CHATGPT_MODEL_NAME=gpt-4o-mini}" 82 | }, 83 | "azureOpenAIChatGptDeploymentCapacity": { 84 | "value": "${AZURE_OPENAI_CHATGPT_DEPLOYMENT_CAPACITY=30}" 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /workshop/frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | # Exclude node_modules and logs 2 | node_modules 3 | npm-debug.log 4 | 5 | # Exclude Git-related files 6 | .git 7 | .gitignore 8 | -------------------------------------------------------------------------------- /workshop/frontend/.github/workflows/azure-container-apps-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Azure Container Apps 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | workflow_dispatch: 7 | 8 | env: 9 | AZURE_CONTAINER_REGISTRY: gksamples24 10 | CONTAINER_APP_NAME: sample-frontend 11 | RESOURCE_GROUP: copilotwksp 12 | 13 | jobs: 14 | build-and-deploy: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Set up Docker Buildx 20 | uses: docker/setup-buildx-action@v2 21 | 22 | - name: Log in to Azure 23 | uses: azure/login@v1 24 | with: 25 | creds: ${{ secrets.AZURE_CREDENTIALS }} 26 | 27 | - name: Log in to Azure Container Registry 28 | uses: azure/docker-login@v1 29 | with: 30 | login-server: ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io 31 | username: ${{ secrets.AZURE_CLIENT_ID }} 32 | password: ${{ secrets.AZURE_CLIENT_SECRET }} 33 | 34 | - name: Build and push image to ACR 35 | uses: docker/build-push-action@v4 36 | with: 37 | push: true 38 | tags: ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_APP_NAME }}:${{ github.sha }} 39 | file: ./Dockerfile 40 | 41 | - name: Deploy to Azure Container Apps 42 | uses: azure/container-apps-deploy-action@v1 43 | with: 44 | appName: ${{ env.CONTAINER_APP_NAME }} 45 | resourceGroup: ${{ env.RESOURCE_GROUP }} 46 | imageToDeploy: ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_APP_NAME }}:${{ github.sha }} 47 | registryUrl: ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io 48 | registryUsername: ${{ secrets.AZURE_CLIENT_ID }} 49 | registryPassword: ${{ secrets.AZURE_CLIENT_SECRET }} 50 | -------------------------------------------------------------------------------- /workshop/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage 2 | FROM node:16 AS build 3 | 4 | WORKDIR /app 5 | 6 | COPY package*.json ./ 7 | RUN npm install 8 | RUN npm ci 9 | 10 | COPY . . 11 | RUN npm run build 12 | 13 | # Production stage 14 | FROM node:16-alpine 15 | 16 | WORKDIR /app 17 | 18 | COPY --from=build /app/build ./build 19 | COPY --from=build /app/package*.json ./ 20 | COPY --from=build /app/server.js ./ 21 | 22 | # Install production dependencies 23 | RUN npm ci --only=production 24 | 25 | # Set environment variables 26 | ENV NODE_ENV=production 27 | ENV PORT=80 28 | 29 | # Expose the correct port 30 | EXPOSE 80 31 | 32 | # Create a shell script to run the server 33 | RUN echo 'node server.js' > /app/run.sh 34 | RUN chmod +x /app/run.sh 35 | 36 | CMD ["/app/run.sh"] 37 | -------------------------------------------------------------------------------- /workshop/frontend/README.md: -------------------------------------------------------------------------------- 1 | # Simple Copilot Chat Frontend 2 | 3 | A React-based chat application for interacting with an AI assistant (backend), designed for deployment on Azure Container Apps. 4 | 5 | ## Getting Started 6 | 7 | ### Prerequisites 8 | 9 | - **Node.js** (v16 or higher) 10 | - **npm** (v7 or higher) 11 | - **Git** 12 | 13 | ### Installation 14 | 15 | 1. **Install Dependencies:** 16 | 17 | ```bash 18 | npm install 19 | ``` 20 | 21 | 1. **Set Environment Variables:** 22 | 23 | Create a `.env` file in the root directory of frontend and add the following environment variables: 24 | 25 | ```bash 26 | API_URL=https://your-backend-api-url/chat 27 | REACT_APP_PROXY_URL=http://localhost/api/chat 28 | PORT=80 29 | ``` 30 | 31 | 1. **Run the Application:** 32 | 33 | ```bash 34 | npm start 35 | ``` 36 | 37 | The application will be available at `http://localhost:80`. 38 | 39 | ### Docker Usage (Optional) 40 | 41 | 1. **Build the Docker Image:** 42 | 43 | ```bash 44 | docker build -t simple-copilot-frontend . 45 | ``` 46 | 47 | 1. **Run the Docker Container:** 48 | 49 | ```bash 50 | docker run -p 80:80 -d simple-copilot-frontend 51 | ``` -------------------------------------------------------------------------------- /workshop/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@chakra-ui/icons": "^2.2.4", 7 | "@chakra-ui/react": "^2.10.2", 8 | "@emotion/react": "^11.13.3", 9 | "@emotion/styled": "^11.13.0", 10 | "@testing-library/jest-dom": "^5.17.0", 11 | "@testing-library/react": "^13.4.0", 12 | "@testing-library/user-event": "^13.5.0", 13 | "@types/jest": "^27.5.2", 14 | "@types/node": "^16.18.113", 15 | "@types/react": "^18.3.11", 16 | "@types/react-dom": "^18.3.1", 17 | "axios": "^1.7.7", 18 | "cors": "^2.8.5", 19 | "express": "^4.21.1", 20 | "framer-motion": "^11.11.9", 21 | "frontend": "file:", 22 | "react": "^18.3.1", 23 | "react-dom": "^18.3.1", 24 | "react-scripts": "5.0.1", 25 | "typescript": "^4.9.5", 26 | "web-vitals": "^2.1.4" 27 | }, 28 | "scripts": { 29 | "start": "react-scripts start", 30 | "build": "react-scripts build", 31 | "test": "react-scripts test", 32 | "eject": "react-scripts eject" 33 | }, 34 | "eslintConfig": { 35 | "extends": [ 36 | "react-app", 37 | "react-app/jest" 38 | ] 39 | }, 40 | "browserslist": { 41 | "production": [ 42 | ">0.2%", 43 | "not dead", 44 | "not op_mini all" 45 | ], 46 | "development": [ 47 | "last 1 chrome version", 48 | "last 1 firefox version", 49 | "last 1 safari version" 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /workshop/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | Simple Copilot Chat Frontend 13 | 14 | 15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /workshop/frontend/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const cors = require('cors'); 3 | const axios = require('axios'); 4 | const path = require('path'); 5 | 6 | const app = express(); 7 | const PORT = process.env.PORT; 8 | 9 | app.use(cors()); 10 | app.use(express.json()); 11 | 12 | // Serve static files from the React app 13 | app.use(express.static(path.join(__dirname, 'build'))); 14 | 15 | const API_URL = process.env.API_URL; 16 | 17 | app.post('/api/chat', async (req, res) => { 18 | try { 19 | const response = await axios.post(API_URL, req.body, { 20 | headers: { 21 | 'Content-Type': 'application/json', 22 | 'accept': 'text/plain' 23 | } 24 | }); 25 | res.json(response.data); 26 | } catch (error) { 27 | console.error('Error:', error.message); 28 | res.status(500).json({ error: 'An error occurred while processing your request' }); 29 | } 30 | }); 31 | 32 | // The "catchall" handler: for any request that doesn't 33 | // match one above, send back React's index.html file. 34 | app.get('*', (req, res) => { 35 | res.sendFile(path.join(__dirname, 'build', 'index.html')); 36 | }); 37 | 38 | app.listen(PORT, () => { 39 | console.log(`Server running on port ${PORT}`); 40 | console.log(`API URL: ${API_URL}`); 41 | }); 42 | -------------------------------------------------------------------------------- /workshop/frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | ReactDOM.render( 6 | 7 | 8 | , 9 | document.getElementById('root') 10 | ); 11 | -------------------------------------------------------------------------------- /workshop/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /workshop/pre-reqs/azure.yaml: -------------------------------------------------------------------------------- 1 | name: semantic-kernel-workshop-csharp-pre-reqs -------------------------------------------------------------------------------- /workshop/pre-reqs/infra/main.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | 3 | @description('Name of the environment used to generate a short unique hash for resources.') 4 | @minLength(1) 5 | @maxLength(60) 6 | param environmentName string 7 | 8 | @description('Primary location for all resources') 9 | // Locations that support gpt-4o 10 | @allowed([ 'australiaeast', 'brazilsouth', 'canadaeast', 'eastus', 'eastus2', 'francecentral', 'germanywestcentral', 'japaneast', 'koreacentral', 'northcentralus', 'norwayeast', 'polandcentral', 'switzerlandnorth', 'southafricanorth','southcentralus', 'southindia', 'spaincentral', 'swedencentral', 'switzerlandnorth', 'uaenorth', 'uksouth', 'westeurope', 'westus', 'westus3' ]) 11 | param location string 12 | 13 | @description('Tags to apply to the resources') 14 | param tags string = '' 15 | 16 | @description('Name of the resource group') 17 | param resourceGroupName string = '' 18 | 19 | var abbrs = loadJsonContent('./abbreviations.json') 20 | var baseTags = { 'azd-env-name': environmentName } 21 | var updatedTags = union(empty(tags) ? {} : base64ToJson(tags), baseTags) 22 | param name string = 'cognitive-services-account' 23 | 24 | // Organize resources in a resource group 25 | resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { 26 | name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}' 27 | location: location 28 | tags: updatedTags 29 | } 30 | 31 | module cognitiveServicesAccount 'modules/cognitive-services.bicep' = { 32 | name: '${abbrs.cognitiveServicesAccounts}${environmentName}' 33 | scope: resourceGroup 34 | params: { 35 | location: location 36 | tags: updatedTags 37 | name: name 38 | aiHubName: '${abbrs.cognitiveServicesAccounts}${environmentName}-hub' 39 | aiProjectName: '${abbrs.cognitiveServicesAccounts}${environmentName}-pro' 40 | } 41 | } 42 | 43 | output endpoint string = cognitiveServicesAccount.outputs.endpoint 44 | -------------------------------------------------------------------------------- /workshop/pre-reqs/infra/main.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "environmentName": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | }, 11 | "resourceGroupName": { 12 | "value": "${AZURE_RESOURCE_GROUP}" 13 | }, 14 | "tags": { 15 | "value": "${AZURE_TAGS}" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /workshop/pre-reqs/infra/modules/cognitive-services.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Cognitive Services instance.' 2 | 3 | @description('The Azure region where all resources will be deployed') 4 | param location string = resourceGroup().location 5 | @description('Tags to apply to all resources') 6 | param tags object = {} 7 | @description('SKU for the Cognitive Services account') 8 | param sku string = 'S0' 9 | @description('Name of the Cognitive Services account') 10 | param name string = 'cognitive-services-account' 11 | @description('API version for Azure OpenAI API') 12 | param ApiVersion string = '2024-11-20' 13 | @description('Name of the GPT model deployment') 14 | param gptModelDeploymentName string = 'gpt-4o' 15 | @description('Capacity of the GPT model deployment') 16 | param gptModelCapacity int = 1 17 | @description('SKU name for the GPT model deployment') 18 | param gptModelSkuName string = 'Standard' 19 | @description('Format of the GPT model') 20 | param gptModelFormat string = 'OpenAI' 21 | @description('Version of the GPT model') 22 | param gptModelVersion string = '2024-08-06' 23 | @description('Name of the AI Foundry Hub') 24 | param aiHubName string 25 | @description('Display name of the AI Foundry Hub') 26 | param aiHubFriendlyName string = 'AI Foundry Hub' 27 | @description('Description of the AI Foundry Hub') 28 | param aiHubDescription string = 'Azure AI Foundry Hub' 29 | @description('Public network access setting for AI resources') 30 | param publicNetworkAccess string = 'Enabled' 31 | @description('Name of the AI Foundry Project') 32 | param aiProjectName string 33 | @description('Display name of the AI Foundry Project') 34 | param aiProjectFriendlyName string = 'AI Foundry Project for Workshop Pre-Reqs' 35 | @description('Description of the AI Foundry Project') 36 | param aiProjectDescription string = 'AI Foundry Project for Workshop Pre-Reqs' 37 | @description('Name of the OpenAI connection') 38 | param openAiConnectionName string = 'openai-connection' 39 | 40 | resource gpt4oModelDeployment 'Microsoft.CognitiveServices/accounts/deployments@2025-04-01-preview' = { 41 | parent: cognitiveServicesAccount 42 | name: gptModelDeploymentName 43 | sku: { 44 | capacity: gptModelCapacity 45 | name: gptModelSkuName 46 | } 47 | properties: { 48 | model: { 49 | format: gptModelFormat 50 | name: gptModelDeploymentName 51 | version: gptModelVersion 52 | } 53 | } 54 | } 55 | 56 | resource aiHub 'Microsoft.MachineLearningServices/workspaces@2024-07-01-preview' = { 57 | name: aiHubName 58 | location: location 59 | kind: 'hub' 60 | identity: { 61 | type: 'SystemAssigned' 62 | } 63 | properties: { 64 | description: aiHubDescription 65 | friendlyName: aiHubFriendlyName 66 | publicNetworkAccess: publicNetworkAccess 67 | } 68 | tags: tags 69 | } 70 | 71 | // Create the AI Foundry Project 72 | resource aiProject 'Microsoft.MachineLearningServices/workspaces@2024-07-01-preview' = { 73 | name: aiProjectName 74 | location: location 75 | kind: 'project' 76 | identity: { 77 | type: 'SystemAssigned' 78 | } 79 | properties: { 80 | description: aiProjectDescription 81 | friendlyName: aiProjectFriendlyName 82 | hubResourceId: aiHub.id 83 | publicNetworkAccess: publicNetworkAccess 84 | } 85 | tags: tags 86 | } 87 | 88 | // Add Cognitive Services account of kind AIServices 89 | resource cognitiveServicesAccount 'Microsoft.CognitiveServices/accounts@2023-05-01' = { 90 | name: name 91 | location: location 92 | tags: tags 93 | kind: 'OpenAI' 94 | sku: { 95 | name: sku 96 | } 97 | properties: { 98 | networkAcls: { 99 | defaultAction: 'Allow' 100 | } 101 | publicNetworkAccess: 'Enabled' 102 | apiProperties: { 103 | apiType: 'OpenAI' 104 | apiVersion: ApiVersion 105 | } 106 | } 107 | } 108 | 109 | // Connect the Azure OpenAI endpoint to the AI Foundry Project 110 | resource aiServiceConnection 'Microsoft.MachineLearningServices/workspaces/connections@2023-08-01-preview' = { 111 | parent: aiProject 112 | name: openAiConnectionName 113 | properties: { 114 | category: 'AzureOpenAI' 115 | target: cognitiveServicesAccount.properties.endpoint 116 | authType: 'ApiKey' 117 | isSharedToAll: false 118 | credentials: { 119 | key: cognitiveServicesAccount.listKeys().key1 120 | } 121 | metadata: { 122 | resourceName: cognitiveServicesAccount.name 123 | ApiType: 'ApiKey' 124 | ApiVersion: ApiVersion 125 | Kind: 'OpenAI' 126 | AuthType: 'ApiKey' 127 | } 128 | } 129 | } 130 | 131 | output endpoint string = cognitiveServicesAccount.properties.endpoint 132 | --------------------------------------------------------------------------------