This project is a web application that allows users to chat with Azure Copilot to query their own data. In addition to responses returned by Copilot, the application also provides the user with source references, suggested "Follow up Questions", "Supporting Content" and a "Thought Process" tab which allows the user to understand how the AI arrived at it's answers.
Note
As an added bonus, a varity of AI personas are included which provide varying prompts based on their assigned descriptions. This allows the AI to focus on role specific aspects of the data being searched that would logically be most important to the selected persona. So, while searching the exact same dataset, the information which would be of interest to an IT professional would not be the same as what an attorney might be interested in. A list of all the included personas can be found here.
The solution is fully configurable via a parameters.json file. It includes a simple HTML interface and a PowerShell script for deployment.
The index.html file includes the following screens:
- Visual Studio Code
- Node.js (version 20 or higher recommended)
- npm (package management)
- Azure CLI (for deploying to Azure)
- ms-vscode.azurecli - Azure CLI tools
- ms-vscode.powershell - PowerShell language support
- PowerShell Core (for running the deployment script)
- github.vscode-github-actions - GitHub Actions support
- azps-tools.azps-tools - Azure PowerShell tools
- azurite.azurite - Azure Storage emulator
- ms-azure-devops.azure-pipelines - Azure Pipelines support
- ms-azuretools.azure-dev - Azure development tools
- ms-azuretools.vscode-apimanagement - Azure API Management tools
- ms-azuretools.vscode-azure-functions-web - Azure Functions tools
- ms-azuretools.vscode-azureappservice - Azure App Service tools
- ms-azuretools.vscode-azurefunctions - Azure Functions tools
- ms-azuretools.vscode-azureresourcegroups - Azure Resource Groups tools
- ms-azuretools.vscode-azurestaticwebapps - Azure Static Web Apps tools
- ms-azuretools.vscode-azurestorage - Azure Storage tools
- ms-azuretools.vscode-azurevirtualmachines - Azure Virtual Machines tools
- ms-azuretools.vscode-bicep - Bicep language support
- github.codespaces - GitHub Codespaces support
- github.github-vscode-theme - GitHub theme for VS Code
- github.remotehub - GitHub integration for remote repositories
- github.vscode-pull-request-github - GitHub Pull Requests and Issues
- ms-toolsai.vscode-ai - AI tools for VS Code
- ms-toolsai.vscode-ai-inference - AI Inference tools
- ms-toolsai.vscode-ai-remote - AI Remote tools
- ms-toolsai.vscode-ai-remote-web - AI Remote Web tools
- ms-vscode-remote.remote-containers - Remote Containers support
- ms-vscode-remote.remote-wsl - Remote WSL support
- ms-vscode.remote-explorer - Remote Explorer
- ms-vscode.remote-repositories - Remote Repositories
- ms-vscode.remote-server - Remote Server
- esbenp.prettier-vscode - Code formatter
- ms-vscode.azure-account - Azure Account management
- ms-vscode.azure-repos - Azure Repos support
- ms-vscode.live-server - Live Server for local development
- ms-vscode.vscode-node-azure-pack - Node.js Azure Pack
- ms-vsliveshare.vsliveshare - Live Share for collaboration
- msazurermtools.azurerm-vscode-tools - Azure Resource Manager tools
- redhat.vscode-yaml - YAML language support
All of the steps below must be performed in the terminal within VS Code.
Also, you must have an active Azure subscription and be signed into that account in VS Code.
-
Clone the repository:
git clone https://github.com/your-username/copilot-webapp-demo.git cd copilot-webapp-demo
-
Navigate to the
src/deployment
directory and open theAzure AI Demo Deployment.ps1
file in the main editor window and just click the play button in the debugger. All of the required extensions listed in (extensions.txt) will be installed via this script prior to the deployment process.
Note
You must navigate to the src/deployment
directory within the solution before executing the PowerShell script.
The main PowerShell script Azure AI Demo Deployment.ps1 automates the deployment of all the required Azure resources for this custom Copilot web application. There is a template titled parameters.json which contains configuration settings for every aspect of the deployment. It includes initialization, helper functions, resource creation, update functions, and logging to ensure a smooth and automated deployment process.
Once the deployment script completes the following resources should have been created in the resource group:
- Api Management Service (required if using MSAL for authentication in web app but optional if you only plan on using api keys)
- App Service
- App Service Plan
- Application Insights
- Azure AI Hub
- Azure AI Project
- Azure AI Services
- Azure AI Services Multi-Service Account
- Azure Machine Learning Registry
- Azure OpenAI
- Computer Vision
- Document Intelligence
- Function App
- Key Vault
- Log Analytics Workspace
- Managed Identity
- Search Service
- Smart Detector Alert Rule
- Storage Account
- Virtual Network
The image below shows a diagram of the deployed resources:
-
Build-ResourceList
Description: Generates and displays a table of resource names, types, and statuses using global resource objects (populated from the parameters). -
Check-Azure-Login
Description: Checks if the user is logged in to Azure (by calling “az account show”) and returns true or false. -
ConvertTo-ProperCase
Description: Converts input strings to title case (capitalizing the first letter of each word). -
Show-ExistingResourceProvisioningStatus
Description: Lists all resources in a resource group and displays their current provisioning states. -
Find-AppRoot
Description: Recursively searches upward from a given directory until the “app” folder is found (used to set the app’s root directory). -
Format-ErrorInfo
Description: Splits an error message into separate parts (Error, Code, SKU) for display. -
Format-CustomErrorInfo
Description: Processes CLI JSON output (split by “:” in each line) to build and return a hashtable of error details. -
New-RandomPassword
Description: Generates a random password of a specified length (with a minimum count of non‑alphanumeric characters). -
Get-Parameters-Sorted
Description: Returns a new parameters object with its property names sorted alphabetically. -
Get-RandomInt
Description: Uses a cryptographically secure random number generator to return a random integer modulo a given maximum. -
Set-DirectoryPath
Description: Changes the current working directory to a given target directory (throwing an error if it does not exist). -
Split-Guid
Description: Generates a new GUID, removes dashes, and returns the first five characters.
-
Deploy-AppService
Description: Deploys an individual app service (web app or function app) by checking for its existence, optionally zipping code, and deploying via Azure CLI. -
Deploy-OpenAIModels
Description: Iterates over a list of AI models and deploys each using the Azure CLI to a Cognitive Services (or Azure OpenAI) account.
-
Get-Azure-Tenants
Description: Lists available Azure tenants, prompts the user to select one and then lets the user pick a subscription. -
Get-CognitiveServicesApiKey
Description: Retrieves the primary API key for a given Cognitive Services resource. -
Get-KeyVaultSecret
Description: Checks for the existence of a secret in the specified Key Vault; returns the secret if found. -
Get-LatestApiVersion
Description: Using the “az provider show” command, retrieves and returns the latest API version for a specified resource type. -
Get-LatestDotNetRuntime
Description: For either web apps or function apps, queries available .NET runtime versions (filtering by operating system) and returns the latest version. -
Get-OperatingSystem
Description: Detects the current OS (Windows, Linux, macOS, or Unknown) by inspecting$PSVersionTable
.
-
Get-SearchDataSources
Description: Uses the search service’s REST API (with an admin key) to list data source names. -
Get-SearchIndexes
Description: Retrieves the list of indexes from the specified Azure Search service. -
Get-SearchIndexers
Description: Retrieves the list of indexers from the specified Azure Search service. -
Get-SearchSkillSets
Description: Retrieves the names of search skill sets via the Azure Search REST API. -
Start-SearchIndexer
Description: Triggers a run of an Azure Search indexer via its REST API.
-
Get-UniqueSuffix
Description: Iterates until a unique suffix is found for resources; updates global name variables to prevent conflicts. -
Get-ValidServiceName
Description: Normalizes a service name (lowercase, no invalid characters, no consecutive dashes). -
Increment-FormattedNumber
Description: Increments a numeric string while preserving a fixed width (leading zeros). -
Test-DirectoryExists
Description: Checks whether a specified directory exists and creates it if not. -
Test-ResourceGroupExists
,Test-ResourceExists
, andTest-SubnetExists
Description: Helper functions that use Azure CLI commands to verify the existence of a resource group, a generic resource (by name, group, and type), or a subnet.
-
Install-AzureCLI
Description: Checks if the Azure CLI is installed; if not, installs it using OS‑specific commands. -
Install-Extensions
Description: Installs Visual Studio Code extensions from an “extensions.json” file (and handles legacy Azure ML extensions as needed). -
Initialize-Parameters
Description: Loads the deployment parameters from a JSON file and initializes many global variables (resource names, subscription details, etc.); returns a consolidated parameters object. -
Initialize-Azure-Login
Description: Ensures the user is logged in to Azure (invokes device‑code login if needed). -
Invoke-AzureRestMethod
Description: Sends a REST API call to an Azure endpoint using an access token and returns the result. -
Register-ResourceProviders
Description: Registers required Azure resource providers.
-
New-AIHub
Description: Creates a new AI Hub (ML workspace of type “hub”), using storage and Key Vault IDs; handles restoration if the hub was soft‑deleted. -
New-AIHubConnection
Description: Establishes a connection between an AI hub and a resource by generating/updating a connection file and invoking the Azure ML CLI. -
New-AIProject
Description: Creates a new AI project (ML workspace with “project” kind) using dependent resources (App Insights, managed identity, storage, etc.). -
New-ApiManagementApi
Description: Creates a “KeyVault Proxy” API inside an API Management service and its operations. -
New-ApiManagementService
Description: Creates (or restores) an API Management service and then configures it viaNew-ApiManagementApi
. -
New-AppRegistration
Description: Registers an application in Azure AD, sets API permissions and exposes API scopes, and updates Key Vault access policies. -
New-ApplicationInsights
Description: Creates a new Application Insights component if it doesn’t already exist in the resource group. -
New-AppService
Description: Creates and deploys an app service. For web apps it creates the web app; for functions it creates a function app, then deploys code usingDeploy-AppService
. -
New-AppServiceEnvironment
Description: Creates an App Service Environment (ASE) to host app services in an isolated plan; waits for creation before proceeding. -
New-AppServicePlan
Description: Creates an App Service Plan in the specified resource group and location if not already present. -
New-AppServicePlanInASE
Description: Creates an App Service Plan specifically inside an existing ASE. -
New-CognitiveServiceResources
Description: Iterates over a list of cognitive services (AI, Computer Vision, OpenAI, etc.) and creates each resource (with soft‑delete handling). -
New-ContainerRegistry
Description: Creates a container registry for hosting Docker images; handles errors and soft‑deletion. -
New-KeyVault
Description: Creates (or restores) a Key Vault, then calls helper functions to set access policies and retrieves its API key. -
New-LogAnalyticsWorkspace
Description: Creates a Log Analytics workspace if it does not already exist. -
New-ManagedIdentity
Description: Creates a user‑assigned managed identity, updates the parameters file, and assigns the necessary roles. -
New-MachineLearningWorkspace
Description: Creates a machine learning workspace (an AI project) by combining resources such as storage, container registry, Key Vault, and App Insights. -
New-PrivateEndPoint
Description: Creates a private endpoint (for example, for securing SQL or storage access) using Azure CLI. -
New-ResourceGroup
Description: Creates a new Azure resource group, checking (and appending a suffix) until a unique name is found. -
New-Resources
Description: A master function that sequentially calls many otherNew-*
functions to provision storage, networking, cognitive services, search service, etc. -
New-SearchDataSource
Description: Creates a new search datasource (for SharePoint or blob storage) in an Azure Search service using REST calls. -
New-SearchIndex
Description: Creates a new search index by reading a schema file, updating placeholders, and sending a POST request to the search service. -
New-SearchIndexer
Description: Creates a new search indexer (to populate an index) via a REST API call after updating its JSON schema file. -
New-SearchService
Description: Creates (or updates) an Azure Search service; retrieves its API key, and may configure associated resources like skills and indexers. -
New-SearchSkillSet
Description: Creates a new search skillset by reading a schema file, updating it (including inserting a cognitive services key), and issuing a REST call. -
New-StorageService
Description: Creates a new Azure Storage account and container, retrieves the storage key, and configures CORS rules. -
New-SubNet
Description: Creates a subnet within a virtual network if it doesn’t already exist (using delegations where applicable). -
New-VirtualNetwork
Description: Creates a new virtual network in the specified resource group if not already present.
-
Remove-ResourceGroup
Description: Deletes an Azure resource group if it exists, logging success or failure. -
Remove-MachineLearningWorkspace
Description: Deletes an existing machine learning workspace (AI project) via the Azure CLI. -
Reset-DeploymentPath
Description: Navigates up from the current directory until the “deployment” folder is reached; returns that path. -
Reset-SearchIndexer
Description: Resets a search indexer by sending a POST request to the reset endpoint of the Azure Search service. -
Restore-SoftDeletedResource
Description: Based on the resource type (Key Vault, Storage, API Management, etc.), attempts to recover a soft‑deleted resource.
-
Set-KeyVaultAccessPolicies
Description: Sets Key Vault access policies for the current user (using the user principal name) via Azure CLI. -
Set-KeyVaultRoles
Description: Configures access roles on a Key Vault for a managed identity by assigning roles (RBAC or access policies). -
Set-KeyVaultSecrets
Description: Iterates over defined secrets in a global object and stores each secret in the Key Vault. -
Set-RBACRoles
Description: Assigns RBAC roles (such as “Key Vault Administrator” and related roles) to a managed identity for the target resource group scope.
-
Update-AIConnectionFile
Description: Updates or creates an AI connection YAML file for a resource (for AI services, OpenAI, search, or storage) using a defined schema. -
Update-AIProjectFile
Description: Generates or updates the AI project file (ai.project.yaml
) for an ML workspace using provided resource IDs and identity details. -
Update-ConfigFile
Description: Updates the web frontend configuration (config.json
) with the latest resource names, keys, URLs, SAS tokens, and other settings. -
Update-ContainerRegistryFile
Description: Updates (or creates) a YAML file for the container registry by replacing resource base name placeholders. -
Update-MLWorkspaceFile
Description: Updates (or creates) the ML workspace YAML file with current resource settings (storage, Key Vault, App Insights, identity, etc.). -
Update-ParametersFileAppRegistration
Description: Updates the parameters JSON file with new application registration details (client app ID, URI, etc.). -
Update-ResourceBaseName
Description: Updates the resource base name in the parameters file by incrementing a suffix and replacing all occurrences in the file. -
Update-SearchIndexFiles
Description: (Not currently used) Updates search index schema files by replacing resource base name tokens. -
Update-SearchSkillSetFiles
Description: Iterates over search skill set files and updates them with the current resource base name. -
Write-Log
Description: Writes messages with timestamps to a deployment log file and resets the working directory afterward.
Start-Deployment
Description: The master function that orchestrates the entire deployment process. It initializes paths and globals, installs required CLI tools and extensions (if needed), logs the start time and sequence number, creates or updates resource groups and resources (by calling many of theNew-*
functions above), updates configuration files, and finally logs the total execution time.---
There are several manual steps which need to be performed for a variety of reasons but mainly because neither the Azure CLI or PowerShell have been fully updated to allow certain tasks to be executed fully. Much of the documentation is still incomplete and several of the specs are actually incorrect at the time of this writing.
- Updating the parameters.json File: You will need to update this file with whatever your preffered naming convention you plan to use. Once you've decided you will need to check and see what the name of the previous deployment was as the script needs to update a whole bunch of files related to things like search indexes, indexers, skillsets a whole bunch of yaml files containing connector information for the Azure AI service and a whole slew of other things. Part of this process is that the script will read the parameters.json file so it can know what to name all of your Azure resources. Once it has that info it will need to update all of the aforementioned files using the new resource names you provided.
[!IMPORTANT]
Each time you run the deployment script and use a different naming convention you will need to check and make sure that the value for the previousResourceBaseName property in the parameters.json file is set to the previous deployment's base name so it can find and replace all of the old instances with the new ones. For example: If you use the resource base name ofcopilot-demo-001
then the script will update all of the necessary resources with that new base name. Now, should you need to run the script again to deploy it to a new resource group and your new base name iscopilot-demo-002
. The script needs to know what the old name was so it can find of all the old name instances and replace them with the new one. So all of the files that havecopilot-demo-001
will be updated tocopilot-demo-002
. In this example, all of your new resources would be[resource-prefix]-copilot-demo-002
and the previousResourceBasename would be set tocopilot-demo-001
. Make sense? - Storage Service CORS: Make sure to set the CORS value for the Storage Service to "ALL". 1
- Search Service: There could be any number of reasons why the Search Service doesn't work properly. It seems to be very tempermental. I've come up with a few things to try to get it working but if none of these work you may just need to scrap your existing Resource Group and redeploy from scratch.
- Search Service Index CORS: Setting CORS to whatever your web app URL is for the Vector Search Index. It is not enough just to leave it open to "ALL". That will not work. Trust me. This was a nightmare to figure out and I learned a lot more about CORS than I ever really wanted to. In short, your web browser will enforce the SAME ORIGIN policy regardless of whether you want it to or not. So if your search service is srch-copilot-demo-001.azurewebsites.net and your app service is app-copilot-demo-001.azurewebsites.net then you will get a
Could not complete vectorization action. The vectorization endpoint returned status code '401' (Unauthorized).
error.[!WARNING]
You will NOT get theCould not complete vectorization action
error when using a program like Postman because Postman is not a web browser so there is nothing to interfere with your http request. When the CORS setting is set to "All" then the Search Service basically doesn't send anything so your browser assumes that the two services communicating with one another are required to be of the same orgin (i.e. same FQDN). Now, to be fair, your web browser is kinda/sorta doing this for your own protection but it's still kind of annoying when you're trying to troubleshoot stuff. 2 - Search Service Index Redacted API Key: Remove the apiKey
<redacted>
entry from the vector search index json if it exists. Don't just remove the value<redacted>
. Remove the entire property. 3 - Search Service Managed Identity: You may need to remove and then re-add the search services managed identity user. 4
- Search Service Datasource Managed Identity: Setting managed identity type to "User-Assigned" for the Azure Search Service datasource. On the same screen you also need to set the blob container to "content". Note: At the time of this writing, there is a bug where the UI in the Azure Portal does not show that your settings have been changed. You may need to remove and re-add the managed identity user to the Search service in order to run the indexer too. 5
- Search Skillset: Click "Connect AI Service" from the Search Skillset to connect your AI service. 6
- Multi-Service Account: Setting the multi-service account The Azure Search Service indexer's vectorizer to the Azure AI Service multi-service account (i.e. the resource with the cog- prefix). You have to go to the Index settings for each search index to apply this change. Alternatively you can click "import and vectorize data" link at the top of the search screen in the Azure Portal. Select you storage account, blob name, select the managed identity, select AI Vision Vectorized for the "kind" field, select the multi-service account with the "cog-" prefix. You also need to set the Authentication Type to "API Key". 7
- Search Service Index CORS: Setting CORS to whatever your web app URL is for the Vector Search Index. It is not enough just to leave it open to "ALL". That will not work. Trust me. This was a nightmare to figure out and I learned a lot more about CORS than I ever really wanted to. In short, your web browser will enforce the SAME ORIGIN policy regardless of whether you want it to or not. So if your search service is srch-copilot-demo-001.azurewebsites.net and your app service is app-copilot-demo-001.azurewebsites.net then you will get a
- Setting Managed Identity for Cognitive Services:. Set managed identity user for Cognitive Services resource in the Identity section of the resource with the cog- prefix (i.e. cog-copilot-demo-001).
- API Management Service: In order to leverage the REST APIs for the API Management Service (APIM) you need to obtain the subscription key. This is NOT the same thing as the subscriptionId for your Azure subscription. This key is stored in the API/Subscriptions section of the APIM resource. You will need to manually update the
apiManagementService.SubscriptionKey
value in the parameters.json file which will then update theAZURE_APIM_SUBSCRIPTION_KEY
value in the config.json value and used in the deployed app service. Of the 3 keys that are shown you need to copy the value from the last one titled "Built-in all-access subscription". 8
Note
Use of the API Management Service is only necessary if you plan on using the MSAL for authentication as opposed to just using API tokens.
-
API Management CORS: For each of the two API operations
Get OpenAI Service Api Key
andGet Search Service Api Key
, you need to make sure you add the CORS policy to the Inbound Processing section and add the Url of your app service to the Allowed Origins section. -
Azure AI Project / Machine Learning Workspace:
Despite the official Microsoft Azure Machine Learning Workspace schema documentation showing a whole list of parameters that are available, the az ml workspace create
command will only accept the following parameters:
--name
--description
--display-name
--resource-group
--application-insights
--location
--key-vault
--storage-account
The problem with this is that this solution needs to have an Azure AI project created and associated with the Azure Hub deployed in the resource group. Now, despite the official documentation stating that the parameters kind
and hub-id
do exist (albeit currently in preview mode) you cannot set either of those parameters using the Azure CLI. Here's where things get a little confusing. By not having the ability to specify values for those parameters, the "project" gets created as an Azure Machine Learning Workspace and it will only be available in Azure Machine Learning Studio as opposed to Azure AI Studio (recently renamed to Azure AI Foundry). Hence the reason why I titled this first item as Azure AI Project / Machine Learning Workspace. What this essentially means is that this resource can either be created in Azure AI Foundary or Azure Machine Learning Studio depending on where you ultimately decide to create it. Regardless of where the resource is created, it will display in your Resource Group. However, it will have different "purposes" and "structure" depending on where you provision it. Now, at this point you might be asking why you need to have either one in the first place. Well, the nice part about having a project/workspace is that it allows you to better organize your AI resources (i.e. models, endpoints, connected resources like Azure Blob Storage, OpenAI Services, Azure AI Services, Vision Services etc.) similar to how a resource group allows you to organize your cloud resources. In addition, you can invite people to your project/workspace without having to define explicit permissions for each and every resource.
Even trying to pass in a yaml file instead of specifying the parameters directly in the command won't work if you include any other parameters than the ones listed above. So it's kind of annoying because this entire solution would literllay be "one-click" if not for the handful of aforementioned manual steps.
Anyhow, once the project is created you need to make sure to set the quota to dynamic in order to actually make more than just a handful of REST API calls. This however can get pricey so make sure to check your budget before you go nuts.
Note
Another issue with the whole Azure AI project is that because the script cannot create the correct instance of it due to the issues mentioned above, you will still to create one manually. Now, there is a pretty good chance that the script created one for you but...it was created in Azure ML Studio. So you will need to delete that project from your resource group and then be sure to also delete it from the "Recently Deleted" area too. In it's current state it has not been purged and if you try to create the correct project in Azure AI Studio (which you're about to do) it will fail saying the resource already exists. Anyhow...once you've purged the resource, you then create the "correct" project in Azure AI Studio. Make sure to select the correct Hub that the script created to house your previous Azure ML project that you just purged. If you don't then it won't be associated with your resource group or any of the other AI related resources and the solution will not work. Once you've created the project, create two AI models: gpt-4o and text-embedding-3-large. The names for both of these will be "gpt-4o" and "text-embedding".
The next few screenshots outline the manual steps you need to take in order to configure the AI Project.
- Create new AI project and specify existing hub from your resource group. 9
- Select Models and Assets from the left navigation menu (towards the bottom). 10
- Select asset. 11
- Select existing AI service from your resource group. 12
- Add two new models: GPT 4o (name the assets gpt-4o) and text-embedding-3-large (name the asset text-embedding). 13
For testing you can use the built-in VS Code Live Server (uses port 5500 by default) or use the local Node server (uses port 3000 by default) by navigating to the src/deployment
directory and running the following command:
node server.js
The web application is structured to leverage various Azure services for a seamless and scalable deployment. The architecture includes:
-
Frontend: The frontend is built using HTML, CSS, and JavaScript, located in the frontend directory. It includes configuration files, stylesheets, images, and scripts necessary for the user interface.
-
Backend: None. This solution only leverages the built-in REST APIs for all of the required Azure resources.
This architecture ensures a robust, scalable, and maintainable web application leveraging Azure's cloud capabilities.
- Azure AI Demo Deployment.ps1: Main deployment script.
- CognitiveServices.json: Configuration file for Cognitive Services.
- app/: Directory for application-specific files.
- ai.connection.yaml: AI connection configuration file.
- container.registry.yaml: Container registry configuration file.
- frontend/: Contains frontend application files.
- config.blank.json: Blank configuration file for the frontend.
- config.json: Configuration file for the frontend.
- css/: Directory for CSS files.
- styles.css: Main stylesheet.
- favicon.ico: Favicon for the frontend.
- images/: Directory for image files.
- azure-ai-demo-chat.png: Chat screenshot.
- azure-ai-demo-documents-existing.png: Existing documents screenshot.
- azure-ai-demo-selected-docs.png: Documents selected for upload.
- index.html: Main HTML file for the frontend.
- scripts/: Directory for JavaScript files.
- script.js: Main JavaScript file.
- web.config: Web configuration file.
- functions/: Directory for Azure Functions.
- chat/: Directory for chat-related functions.
- AIChatCompletion.cs: AI chat completion function.
- ChatCompletion.cs: Chat completion function.
- ChatCompletion.csproj: Project file for chat completion.
- ChatCompletion.sln: Solution file for chat completion.
- ChatContext.cs: Chat context class.
- ChatHistory.cs: Chat history class.
- ChatOrchestrator.cs: Chat orchestrator class.
- IChatCompletion.cs: Interface for chat completion.
- Properties/: Directory for project properties.
- launchSettings.json: Launch settings for the project.
- chat/: Directory for chat-related functions.
- ml.workspace.yaml: Machine learning workspace configuration file.
- package-lock.json: NPM package lock file.
- package.json: NPM package file.
- temp/: Temporary files directory.
- deployment/: Directory for deployment-specific files.
- images/: Directory for deployment images.
- azure-ai-demo-ai-studio-project-create.png: AI Studio Project creation screenshot.
- azure-ai-demo-ai-studio-project-model-asset-menu.png: AI Studio Model Assets menu screenshot.
- azure-ai-demo-ai-studio-project-model-select.png: AI Studio Select Assets screenshot.
- azure-ai-demo-ai-studio-project-ai-resource.png: AI Studio Select AI Resource screenshot.
- azure-ai-demo-ai-studio-project-model-management.png: AI Studio Add AI Models screenshot.
- azure-ai-demo-documents-upload.png: Upload documents screenshot.
- azure-ai-demo-selected-docs.png: Selected documents screenshot.
- azure-ai-demo-documents-existing.png: Existing documents screenshot.
- azure-ai-demo-search-datasource-managed-identity-config.png: Search Service Datasource Managed Identity screenshot.
- azure-ai-demo-search-skillset-connect-ai-service.png: Search Service Skillset Connect to AI Service screenshot.
- azure-ai-demo-search-index-vectorizer-multi-service-account-config.png: Search Service Index Vectorizer Multi-Service Account screenshot.
- azure-ai-demo-search-managed-identity-remove.png: Removed and Re-Add Search Service Managed Identity screenshot.
- azure-ai-demo-resource-visualizer.png: Azure AI Demo Resource Visualizer screenshot.
- images/: Directory for deployment images.
- deployment.log: Log file for the deployment process.
- directory_structure.txt: File containing the directory structure.
- launch.json: Launch configuration file.
- parameters backup.json: Backup of parameters file.
- parameters.json: Parameters file for the deployment.
- search-index-schema.json: Search index schema file.
- search-indexer-schema.json: Search indexer schema file.
- server.js: Local http server JavaScript file.
- settings.json: Settings file.
├── Azure AI Demo Deployment.ps1
├── CognitiveServices.json
├── app
│ ├── ai.connection.yaml
│ ├── container.registry.yaml
│ ├── frontend
│ │ ├── config.blank.json
│ │ ├── config.json
│ │ ├── css
│ │ │ ├── styles.css
│ │ ├── favicon.ico
│ │ ├── images
│ │ │ ├── azure-ai-demo-chat.png
│ │ │ ├── azure-ai-demo-documents-existing.png
│ │ │ ├── azure-ai-demo-selected-docs.png
│ │ ├── index.html
│ │ ├── scripts
│ │ │ └── script.js
│ │ └── web.config
│ ├── functions
│ │ └── chat
│ │ ├── AIChatCompletion.cs
│ │ ├── ChatCompletion.cs
│ │ ├── ChatCompletion.csproj
│ │ ├── ChatCompletion.sln
│ │ ├── ChatContext.cs
│ │ ├── ChatHistory.cs
│ │ ├── ChatOrchestrator.cs
│ │ ├── IChatCompletion.cs
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ ├── ml.workspace.yaml
│ ├── package-lock.json
│ ├── package.json
│ └── temp
├── deployment
│ ├── images
│ │ ├── azure-ai-demo-ai-studio-project-create.png
│ │ ├── azure-ai-demo-ai-studio-project-model-asset-menu.png
│ │ ├── azure-ai-demo-ai-studio-project-model-select.png
│ │ ├── azure-ai-demo-ai-studio-project-ai-resource.png
│ │ ├── azure-ai-demo-ai-studio-project-model-management.png
│ │ ├── azure-ai-demo-documents-upload.png
│ │ ├── azure-ai-demo-selected-docs.png
│ │ ├── azure-ai-demo-documents-existing.png
│ │ ├── azure-ai-demo-search-datasource-managed-identity-config.png
│ │ ├── azure-ai-demo-search-skillset-connect-ai-service.png
│ │ ├── azure-ai-demo-search-index-vectorizer-multi-service-account-config.png
│ │ ├── azure-ai-demo-search-managed-identity-remove.png
│ │ ├── azure-ai-demo-resource-visualizer.png
├── deployment.log
├── directory_structure.txt
├── launch.json
├── parameters backup.json
├── parameters.json
├── search-index-schema.json
├── search-indexer-schema.json
├── server.js
├── settings.json
Very careful considerations to this solution were made to ensure a smooth and seamless transition between traditional desktop and mobile devices. The UI is adapative and will render the layout accordingly based on the best user experience regardless of the device. Below are several screenshots of the mobile and touch experience.
![]() |
![]() |
![]() |
![]() |
For a more in-depth understanding of the chat workflow click here
Storage Service CORS
Search Service Index CORS
Search Service Index Vectorizer Api-Key Redacted
Search Service Managed Identity Remove
Search Service Datasource Managed Identity
Search Service Skillset Connect to AI Service
Search Service Index Vectorizer Multi-Service Account
API Management Service Subscription Key
API Management Service CORS
Document Screen - Selected Documents
Documents Screen - Existing Documents
- Attorney
- Business Professional
- CEO
- Data Scientist
- Doctor
- Engineer
- Financial Advisor
- Fitness Enthusiast
- Foodie
- HR Manager
- Journalist
- Marketing Professional
- Network Security Specialist
- New Yorker
- Teacher
- Tech Enthusiast
- Teenage Girl
- Traveler
Search Indexing
Before you can chat you need to actually upload documents to Azure Storage using the form on the Documents screen. When you upload documents the search indexer should automatically run. It might take a few minutes to complete so you may not see info from your newly uploaded documents right away. If you'd like to see the progress of the indexing, go to the search service in the Azure portal and find the indexer with the "vector-srch-indexer-copilot-demo" prefix. Check the time stamp to make sure it executed recently.
REST APIs
It is important to note that the technologies used by this solution are changing by the second. New versions of libraries and APIs are being released constantly and documentation is being updated on a near weekly basis. Since this solution leverages REST APIs, ensuring that you are using the most up-to-date API version for each service's API is absolutely critical. With each new API release, new capabilities are added (and sometimes existing ones removed). All the magic happens in the Azure Open AI On Your Own Data API.
A perfect example is the Azure Search Service API. There is actually documentation for how to migrate to the newest version of the API located here. In the documentation, it actually says "2023-07-01-preview was the first REST API for vector support. Do not use this API version. It's now deprecated and you should migrate to either stable or newer preview REST APIs immediately."
Lucky for you this solution defines all of the API versions in the parameters.json file. When newer versions of a particular API are resleased, you just need to update that file and redeploy the web application. The PowerShell script regenerates the config.json file that is deployed as part of the web application zip package using the new values defined in the parameters.json file.
Azure AI Model Versions
At the time of this writing (2/9/2025) you MUST select gpt-4o model version 2024-08-06
standard/global standard. If you select any version other than 2024-08-06
then the citation title property returned from the chat completion REST API call will be null and the JavaScript code used to add footnotes to the response will fail.
VS Code Collapse/Fold
This has nothing to do with the current solution but it's something I found out to be very useful. Sometimes the VS Code collapse/fold feature gets a little wonky and doesn't detect start and end of functions. To fix this, have the file(s) that are having issues open in the editor. Then open VS Settings, search for "Editor Folding" and uncheck the box. Then switch over the the files you're having issues with and then go back to Settings and check the box again to reset the feature and hopefull fix the issue.
Contributions are welcome! Please open an issue or submit a pull request.
This project is licensed under the MIT License. See the LICENSE file for details.