├── .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 | [](https://github.dev/Azure/intelligent-app-workshop)
4 | [](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 | 
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 | 
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 | 
8 |
9 |
10 | ### Plugin
11 |
12 | 
13 |
14 | ### AzureML Prompt flow example
15 | 
16 |
17 | ### Fine-tuned Model
18 |
19 | 
20 |
21 | 
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 | 
--------------------------------------------------------------------------------
/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 | 
10 |
11 | ## [Skills](https://github.com/microsoft/semantic-kernel/tree/main/samples/skills)
12 |
13 | 
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 | 
--------------------------------------------------------------------------------
/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 | 
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 | 
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 | 
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 | 
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 | 
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------