├── .gitignore ├── 00_Introduction └── README.md ├── 01_Azure_Overview ├── README.md └── media │ ├── 2023-12-31-14-19-28.png │ ├── ISV-Tech-Builders-tools-white.png │ ├── azure-cli-example.png │ ├── azure-management-tool-maturity.png │ ├── azure-marketplace-search-results.png │ ├── azure-portal-services.png │ ├── azure-services.png │ ├── azure-template-json-example.png │ ├── bicep_code.png │ ├── consistent-management-layer.png │ ├── landing-zone-accelerator.png │ ├── scope-levels.png │ └── terraform_code.png ├── 02_Overview_Cosmos_DB ├── .DS_Store └── README.md ├── 03_Overview_Azure_OpenAI ├── README.md └── images │ └── 2024-01-23-17-52-46.png ├── 04_Overview_AI_Concepts └── README.md ├── 05_Explore_OpenAI_models ├── README.md └── media │ └── 2024-01-09-13-53-51.png ├── 06_Provision_Azure_Resources ├── README.md └── media │ └── architecture.jpg ├── 07_Create_First_Cosmos_DB_Project ├── README.md └── media │ ├── azure_connection_string.png │ └── emulator_connection_string.png ├── 08_Load_Data └── README.md ├── 09_Vector_Search_Cosmos_DB ├── README.md └── media │ ├── azure_openai_settings.png │ ├── azure_openai_studio_settings_icon.png │ ├── embedding_pipeline.png │ └── vector_search_flow.png ├── 10_LangChain ├── README.md └── media │ └── langchain_rag.png ├── 11_Backend_API ├── .DS_Store ├── README.md └── media │ ├── 2024-01-06-20-01-38.png │ ├── acr_access_keys.png │ ├── container_app_delete_hello_world.png │ ├── container_app_edit_and_deploy.png │ ├── container_app_failed_revision.png │ ├── container_app_log_stream.png │ ├── container_app_overview.png │ ├── container_app_ready.png │ ├── container_deploy.png │ ├── local_backend_docker_build.png │ ├── local_backend_docker_push.png │ ├── local_backend_docker_run.png │ ├── local_backend_running_console.png │ ├── local_backend_swagger_ui.png │ ├── local_backend_swagger_ui_ai_response.png │ └── local_backend_swagger_ui_root_response.png ├── 12_User_Interface ├── README.md └── images │ ├── 2024-01-17-12-41-48.png │ ├── 2024-01-17-12-42-59.png │ ├── 2024-01-17-12-45-30.png │ └── 2024-01-17-12-53-13.png ├── 13_Conclusion └── README.md ├── Backend ├── .env.EXAMPLE ├── .gitignore ├── DOCKERFILE ├── README.md ├── app.js ├── catch_up.js ├── cosmic_works │ └── cosmic_works_ai_agent.js ├── package-lock.json ├── package.json ├── run.sh └── swagger.js ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Labs ├── .gitignore ├── README.md ├── backend_api │ ├── README.md │ └── media │ │ ├── acr_access_keys.png │ │ ├── container_app_delete_hello_world.png │ │ ├── container_app_edit_and_deploy.png │ │ ├── container_app_failed_revision.png │ │ ├── container_app_log_stream.png │ │ ├── container_app_overview.png │ │ ├── container_app_ready.png │ │ ├── container_deploy.png │ │ ├── local_backend_docker_build.png │ │ ├── local_backend_docker_push.png │ │ ├── local_backend_docker_run.png │ │ ├── local_backend_running_console.png │ │ ├── local_backend_swagger_ui.png │ │ ├── local_backend_swagger_ui_ai_response.png │ │ └── local_backend_swagger_ui_root_response.png ├── deploy │ ├── azuredeploy.bicep │ ├── azuredeploy.parameters.json │ ├── deploy.md │ └── images │ │ └── editor-azuredeploy-parameters-json-password.png ├── explore_and_use_models │ ├── README.md │ └── completed │ │ ├── app.js │ │ └── package.json ├── first_cosmos_db_application │ ├── .env.example │ ├── README.md │ ├── index.js │ ├── media │ │ ├── db_bulk_write_output.png │ │ ├── db_connection_output.png │ │ ├── db_delete_output.png │ │ ├── db_insert_output.png │ │ ├── db_retrieve_all_output.png │ │ ├── db_retrieve_output.png │ │ ├── db_update_output.png │ │ └── delete_database_output.png │ └── package.json ├── langchain │ ├── .env.example │ ├── README.md │ ├── catch_up.js │ ├── index.js │ ├── media │ │ ├── agent_output.png │ │ ├── agent_verbose_output.png │ │ ├── initial_vector_search.png │ │ └── rag_chain_output.png │ └── package.json ├── load_data │ ├── .env.example │ ├── README.md │ ├── index.js │ ├── media │ │ ├── customers_sales_loaded.png │ │ └── products_loaded.png │ └── package.json └── vector_search │ ├── .env.example │ ├── README.md │ ├── catch_up.js │ ├── index.js │ ├── media │ ├── rag_with_vector_search_response.png │ ├── text_embedding_output.png │ ├── vector_search_results.png │ └── vectorize_and_store_embeddings.png │ └── package.json ├── README.md ├── SECURITY.md ├── SUPPORT.md └── assets ├── Graphics.pptx └── architecture.pptx /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | -------------------------------------------------------------------------------- /00_Introduction/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to the Azure Cosmos DB + Azure OpenAI Node.js Developer Guide 2 | 3 | ## Pre-requisites 4 | 5 | - [Azure account and subscription](https://azure.microsoft.com/free/) with Owner permissions 6 | - [Node.js 20.11.0 LTS or newer](https://nodejs.org/) 7 | - [Visual Studio Code](https://code.visualstudio.com/download) 8 | - [Docker Desktop](https://www.docker.com/products/docker-desktop/) with [WSL 2 backend (if on Windows)](https://learn.docker.com/desktop/wsl/) 9 | - [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) 10 | - [Bicep CLI](https://learn.microsoft.com/azure/azure-resource-manager/bicep/install#install-manually) 11 | - [Powershell](https://learn.microsoft.com/powershell/scripting/install/installing-powershell?view=powershell-7.3) 12 | 13 | ## Why use this guide? 14 | 15 | The future of software involves combining AI and data services, also known as intelligent applications. This guide is for MongoDB developers looking to implement intelligent applications quickly while leveraging existing skills. The content will focus on the developer journey implementing an Azure-based AI-enabled GPT-based chat application that is augmented using data stored in vCore for Azure Cosmos DB for MongoDB while leveraging Azure OpenAI services. 16 | 17 | ## Introduction 18 | 19 | This guide will walks through the creating intelligent solutions that combines vCore-based Azure Cosmos DB for MongoDB vector search and document retrieval with Azure OpenAI services to build a chat bot experience. The guide includes labs that build and deploy a sample chat app using these technologies, with a focus on vCore-based Azure Cosmos DB for MongoDB, Vector Search, and Azure OpenAI using the Node.js runtime and the JavaScript programming language. For those new to using Azure OpenAI and Vector Search technologies, the guide includes explanations of the core concepts and techniques used when implementing these technologies. 20 | 21 | > **Note:** This developer guide is targeted towards Node.js developers. If you are a Python developer, then you may be interested in the Python version here: [https://github.com/AzureCosmosDB/Azure-OpenAI-Python-Developer-Guide](https://github.com/AzureCosmosDB/Azure-OpenAI-Python-Developer-Guide) -------------------------------------------------------------------------------- /01_Azure_Overview/README.md: -------------------------------------------------------------------------------- 1 | # Azure Overview 2 | 3 | Millions of customers worldwide trust the Azure platform, and there are over 90,000 Cloud Solution Providers (CSPs) partnered with Microsoft to add extra benefits and services to the Azure platform. By leveraging Azure, organizations can easily modernize their applications, expedite application development, and adapt application requirements to meet the demands of their users. This section provides an overview of Azure, its services, and recommendations on how to get started. 4 | 5 | ## Advantages of choosing Azure 6 | 7 | By offering solutions on Azure, ISVs can access one of the largest B2B markets in the world. Through the [Azure Partner Builder's Program](https://partner.microsoft.com/marketing/azure-isv-technology-partners), Microsoft assists ISVs with the tools and platform to offer their solutions for customers to evaluate, purchase, and deploy with just a few clicks of the mouse. 8 | 9 | Microsoft's development suite includes such tools as the various [Visual Studio](https://visualstudio.microsoft.com/) products, [Azure DevOps](https://dev.azure.com/), [GitHub](https://github.com/), and low-code [Power Apps](https://powerapps.microsoft.com/). All of these contribute to Azure's success and growth through their tight integrations with the Azure platform. Organizations that adopt modern tools are 65% more innovative, according to a [2020 McKinsey & Company report.](https://azure.microsoft.com/mediahandler/files/resourcefiles/developer-velocity-how-software-excellence-fuels-business-performance/Developer-Velocity-How-software-excellence-fuels-business-performance-v4.pdf) 10 | 11 | ![This image demonstrates common development tools on the Microsoft cloud platform to expedite application development.](media/ISV-Tech-Builders-tools-white.png "Microsoft cloud tooling") 12 | 13 | To facilitate developers' adoption of Azure, Microsoft offers a [free subscription](https://azure.microsoft.com/free/search/) with $200 credit, applicable for thirty days; year-long access to free quotas for popular services and access to always free Azure service tiers. 14 | 15 | ## Introduction to Azure resource management 16 | 17 | The [Azure Fundamentals Microsoft Learn Module](https://learn.microsoft.com/learn/modules/intro-to-azure-fundamentals/) demonstrates the different classifications of Azure Services. Moreover, Azure supports a variety of common tools, such as Visual Studio, PowerShell, and the Azure CLI, to manage Azure environments. 18 | 19 | ![IaaS and PaaS Azure service classification and categories](media/azure-services.png "Categories of Azure services") 20 | 21 | ### The Azure resource management hierarchy 22 | 23 | Azure provides a flexible resource hierarchy to simplify cost management and security. This hierarchy consists of four levels: 24 | 25 | - **[Management groups](https://learn.microsoft.com/azure/governance/management-groups/overview)**: Management groups consolidate multiple Azure subscriptions for compliance and security purposes. 26 | - **Subscriptions**: Subscriptions govern cost control and access management. Azure users cannot provision Azure resources without a subscription. 27 | - **[Resource groups](https://learn.microsoft.com/azure/azure-resource-manager/management/manage-resource-groups-portal)**: Resource groups consolidate the individual Azure resources for a given deployment. All provisioned Azure resources belong to one resource group. In this guide, it will be required to provision a *resource group* in an *subscription* to hold the required resources. 28 | - Resource groups are placed in a geographic location that determines where metadata about that resource group is stored. 29 | - **Resources**: An Azure resource is an instance of a service. An Azure resource belongs to one resource group located in one subscription. 30 | - Most Azure resources are provisioned in a particular region. 31 | 32 | ![This image shows Azure resource scopes.](media/scope-levels.png "Azure resource scopes") 33 | 34 | ### Create landing zone 35 | 36 | An [Azure landing zone](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/) is the target environment defined as the final resting place of a cloud migration project. In most projects, the landing zone should be scripted via ARM templates for its initial setup. Finally, it should be customized with PowerShell or the Azure Portal to fit the workload's needs. First-time Azure users will find creating and deploying to DEV and TEST environments easy. 37 | 38 | To help organizations quickly move to Azure, Microsoft provides the Azure landing zone accelerator, which generates a landing zone ARM template according to an organization's core needs, governance requirements, and automation setup. The landing zone accelerator is available in the Azure portal. 39 | 40 | ![This image demonstrates the Azure landing zone accelerator in the Azure portal, and how organizations can optimize Azure for their needs and innovate.](media/landing-zone-accelerator.png "Azure landing zone accelerator screenshot") 41 | 42 | ### Automating and managing Azure services 43 | 44 | When it comes to managing Azure resources, there are many potential options. [Azure Resource Manager](https://learn.microsoft.com/azure/azure-resource-manager/management/overview) is the deployment and management service for Azure. It provides a management layer that enables users to create, update, and delete resources in Azure subscriptions. Use management features, like access control, locks, and tags, to secure and organize resources after deployment. 45 | 46 | All Azure management tools, including the [Azure CLI](https://learn.microsoft.com/cli/azure/what-is-azure-cli), [Azure PowerShell](https://learn.microsoft.com/powershell/azure/what-is-azure-powershell?view=azps-7.1.0) module, [Azure REST API](https://learn.microsoft.com/rest/api/azure/), and browser-based Portal, interact with the Azure Resource Manager layer and [Identity and access management (IAM)](https://learn.microsoft.com/azure/role-based-access-control/overview) security controls. 47 | 48 | ![This image demonstrates how the Azure Resource Manager provides a robust, secure interface to Azure resources.](media/consistent-management-layer.png "Azure Resource Manager explained") 49 | 50 | Access control to all Azure services is offered via the [Azure role-based access control (Azure RBAC)](https://learn.microsoft.com/azure/role-based-access-control/overview) natively built into the management platform. Azure RBAC is a system that provides fine-grained access management of Azure resources. Using Azure RBAC, it is possible to segregate duties within teams and grant only the amount of access to users that they need to perform their jobs. 51 | 52 | ### Azure management tools 53 | 54 | The flexibility and variety of Azure's management tools make it intuitive for any user, irrespective of their skill level with specific technologies. As an individual's skill level and administration needs mature, Azure has the right tools to match those needs. 55 | 56 | ![Azure service management tool maturity progression.](media/azure-management-tool-maturity.png "Azure service management tool") 57 | 58 | #### Azure portal 59 | 60 | As a new Azure user, the first resource a person will be exposed to is the Azure Portal. The **Azure Portal** gives developers and architects a view of the state of their Azure resources. It supports extensive user configuration and simplifies reporting. The **[Azure mobile app](https://azure.microsoft.com/get-started/azure-portal/mobile-app/)** provides similar features for users that are away from their main desktop or laptop. 61 | 62 | ![The picture shows the initial Azure service list.](media/azure-portal-services.png "Azure portal Services") 63 | 64 | Azure runs on a common framework of backend resource services, and every action taken in the Azure portal translates into a call to a set of backend APIs developed by the respective engineering team to read, create, modify, or delete resources. 65 | 66 | ##### Azure Marketplace 67 | 68 | [Azure Marketplace](https://learn.microsoft.com/marketplace/azure-marketplace-overview) is an online store that contains thousands of IT software applications and services built by industry-leading technology companies. In Azure Marketplace, it is possible to find, try, buy, and deploy the software and services needed to build new solutions and manage the cloud infrastructure. The catalog includes solutions for different industries and technical areas, free trials, and consulting services from Microsoft partners. 69 | 70 | ![The picture shows an example of Azure Marketplace search results.](media/azure-marketplace-search-results.png "Azure Marketplace Results") 71 | 72 | ##### Evolving 73 | 74 | Moving workloads to Azure alleviates some administrative burdens, but not all. Even though there is no need to worry about the data center, there is still a responsibility for service configuration and user access. Applications will need resource authorization. 75 | 76 | Using the existing command-line tools and REST APIs, it is possible to build custom tools to automate and report resource configurations that do not meet organizational requirements. 77 | 78 | #### Azure PowerShell and CLI 79 | 80 | **Azure PowerShell** and the **Azure CLI** (for Bash shell users) are useful for automating tasks that cannot be performed in the Azure portal. Both tools follow an *imperative* approach, meaning that users must explicitly script the creation of resources in the correct order. 81 | 82 | ![Shows an example of the Azure CLI.](media/azure-cli-example.png "Azure CLI Example") 83 | 84 | There are subtle differences between how each of these tools operates and the actions that can be accomplished. Use the [Azure command-line tool guide](https://learn.microsoft.com/azure/developer/azure-cli/choose-the-right-azure-command-line-tool) to determine the right tool to meet the target goal. 85 | 86 | #### Azure CLI 87 | 88 | It is possible to run the Azure CLI and Azure PowerShell from the [Azure Cloud Shell](https://shell.azure.com), but it does have some limitations. It is also possible to run these tools locally. 89 | 90 | To use the Azure CLI, [download the CLI tools from Microsoft.](https://learn.microsoft.com/cli/azure/install-azure-cli) 91 | 92 | To use the Azure PowerShell cmdlets, install the `Az` module from the PowerShell Gallery, as described in the [installation document.](https://learn.microsoft.com/powershell/azure/install-az-ps?view=azps-6.6.0) 93 | 94 | ##### Azure Cloud Shell 95 | 96 | The Azure Cloud Shell provides Bash and PowerShell environments for managing Azure resources imperatively. It also includes standard development tools, like Visual Studio Code, and files are persisted in an Azure Files share. 97 | 98 | Launch the Cloud Shell in a browser at [https://shell.azure.com](https://shell.azure.com). 99 | 100 | #### PowerShell Module 101 | 102 | The Azure portal and Windows PowerShell can be used for managing Azure Cosmos DB for Mongo DB API. To get started with Azure PowerShell, install the [Azure PowerShell cmdlets](https://learn.microsoft.com/powershell/module/az.cosmosdb/) for Cosmos DB with the following PowerShell command in an administrator-level PowerShell window: 103 | 104 | ```PowerShell 105 | Install-Module -Name Az.CosmosDB 106 | ``` 107 | 108 | #### Infrastructure as Code 109 | 110 | [Infrastructure as Code (IaC)](https://learn.microsoft.com/devops/deliver/what-is-infrastructure-as-code) provides a way to describe or declare what infrastructure looks like using descriptive code. The infrastructure code is the desired state. The environment will be built when the code runs and completes. One of the main benefits of IaC is that it is human readable. Once the environment code is proven and tested, it can be versioned and saved into source code control. Developers can review the environment changes over time. 111 | 112 | There are a few options of IaC tooling to choose from when provisioning and managing Azure resources. These include Azure-native tools from Microsoft, like ARM templates and Azure Bicep, as well as third-party tools popular within the industry like HashiCorp Terraform. 113 | 114 | ##### ARM templates 115 | 116 | [ARM templates](https://learn.microsoft.com/azure/azure-resource-manager/templates/) can deploy Azure resources in a *declarative* manner. Azure Resource Manager can potentially create the resources in an ARM template in parallel. ARM templates can be used to create multiple identical environments, such as development, staging, and production environments. 117 | 118 | ![The picture shows an example of an ARM template JSON export.](media/azure-template-json-example.png "Azure Template JSON") 119 | 120 | ##### Bicep 121 | 122 | Reading, updating, and managing the ARM template JSON code can be difficult for a reasonably sized environment. What if there was a tool that translates simple declarative statements into ARM templates? Better yet, what if there was a tool that took existing ARM templates and translated them into a simple configuration? [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview) is a domain-specific language (DSL) that uses a declarative syntax to deploy Azure resources. Bicep files define the infrastructure to deploy to Azure and then use that file throughout the development lifecycle to repeatedly deploy infrastructure changes. Resources are deployed consistently. 123 | 124 | By using the Azure CLI it is possible to decompile ARM templates to Bicep using the following: 125 | 126 | ```powershell 127 | az bicep decompile --file template.json 128 | ``` 129 | 130 | Additionally, the [Bicep playground](https://aka.ms/bicepdemo) tool can perform similar decompilation of ARM templates. 131 | 132 | ![Sample Bicep code that deploys Azure Cosmos DB for MongoDB](media/bicep_code.png) 133 | 134 | ##### Terraform 135 | 136 | [Hashicorp Terraform](https://www.terraform.io/) is an open-source tool for provisioning and managing cloud infrastructure resources. [Terraform](https://learn.microsoft.com/azure/developer/terraform/overview) simplifies the deployment of Azure services, including Azure Kubernetes Service, Azure Cosmos DB, and Azure AI, through infrastructure-as-code to automate provisioning and management of Azure services. Terraform is also adept at deploying infrastructure across multiple cloud providers. It enables developers to use consistent tooling to manage each infrastructure definition. 137 | 138 | ![Sample Terraform code that deploys Azure Cosmos DB for MongoDB](media/terraform_code.png) 139 | 140 | #### Other tips 141 | 142 | Azure administrators should consult with cloud architects and financial and security personnel to develop an effective organizational hierarchy of resources. 143 | 144 | Here are some best practices to follow for Azure deployments. 145 | 146 | - **Utilize Management Groups** Create at least three levels of management groups. 147 | 148 | - **Adopt a naming convention:** Azure resource names should include business details, such as the organization department, and operational details for IT personnel, like the workload. Defining an [Azure resource naming convention](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming) will help the organization standardize on a common naming convention that will help better identify resources once created. 149 | 150 | - **Adopt other Azure governance tools:** Azure provides mechanisms such as [resource tags](https://learn.microsoft.com/azure/azure-resource-manager/management/tag-resources?tabs=json) and [resource locks](https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?tabs=json) to facilitate compliance, cost management, and security. 151 | -------------------------------------------------------------------------------- /01_Azure_Overview/media/2023-12-31-14-19-28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/2023-12-31-14-19-28.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/ISV-Tech-Builders-tools-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/ISV-Tech-Builders-tools-white.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/azure-cli-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/azure-cli-example.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/azure-management-tool-maturity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/azure-management-tool-maturity.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/azure-marketplace-search-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/azure-marketplace-search-results.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/azure-portal-services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/azure-portal-services.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/azure-services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/azure-services.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/azure-template-json-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/azure-template-json-example.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/bicep_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/bicep_code.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/consistent-management-layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/consistent-management-layer.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/landing-zone-accelerator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/landing-zone-accelerator.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/scope-levels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/scope-levels.png -------------------------------------------------------------------------------- /01_Azure_Overview/media/terraform_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/01_Azure_Overview/media/terraform_code.png -------------------------------------------------------------------------------- /02_Overview_Cosmos_DB/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/02_Overview_Cosmos_DB/.DS_Store -------------------------------------------------------------------------------- /02_Overview_Cosmos_DB/README.md: -------------------------------------------------------------------------------- 1 | # Overview of Azure Cosmos DB 2 | 3 | [Azure Cosmos DB](https://learn.microsoft.com/azure/cosmos-db/introduction) is a globally distributed, multi-model database service that enables querying and storing data using NoSQL models using one of five APIs: SQL (document database), Cassandra (column-family), MongoDB (document database), Azure Table, and graph database. It provides turnkey global distribution, elastic scaling of throughput and storage worldwide, single-digit millisecond latencies at the 99th percentile, and guaranteed high availability with multi-homing capabilities. Azure Cosmos DB provides comprehensive service level agreements (SLAs) for throughput, latency, availability, and consistency guarantees, something not found in any other database service. 4 | 5 | ## Azure Cosmos DB and AI 6 | 7 | The surge of AI-powered applications has led to the need to integrate data from multiple data stores, introducing another layer of complexity as each data store tends to have its own workflow and operational performance. Azure Cosmos DB simplifies this process by providing a unified platform for all data types, including AI data. Azure Cosmos DB supports relational, document, vector, key-value, graph, and table data models, making it an ideal platform for AI applications. The wide array of data model support combined with guaranteed high availability, high throughput, low latency, and tunable consistency are huge advantages when building these types of applications. 8 | 9 | ## Azure Cosmos DB for Mongo DB 10 | 11 | The focus for this developer guide is [Azure Cosmos DB for MongoDB](https://learn.microsoft.com/azure/cosmos-db/mongodb/introduction). Developers can leverage their current MongoDB expertise and use their preferred MongoDB drivers, SDKs, and tools simply by directing applications to the connection string for on the Azure Cosmos DB for MongoDB account. 12 | 13 | ### Azure Cosmos DB for Mongo DB API Architectures 14 | 15 | The [RU architecture](https://learn.microsoft.com/azure/cosmos-db/mongodb/ru/introduction) for Azure Cosmos DB for MongoDB offers instantaneous scalability with zero warmup period, automatic and transparent sharding, and 99.999% availability. It supports active-active databases across multiple regions, cost-efficient, granular, unlimited scalability, real-time analytics, and serverless deployments paying only per operation. 16 | 17 | [vCore-based Azure Cosmos DB for MongoDB architecture](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/introduction) integrates AI-based applications with private organizational data, with text indexing for easy querying. Simplify the development process with high-capacity vertical scaling and free 35-day backups with a point-in-time restore (PITR). 18 | 19 | The [choice between vCore and Request Units (RU)](https://learn.microsoft.com/azure/cosmos-db/mongodb/choose-model) in Azure Cosmos DB for MongoDB API depends on the workload. A list of [compatibility and feature support between RU and vCore](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/compatibility) is available. 20 | 21 | vCore provides predictable performance and cost and is ideal for running high-performance, mission-critical workloads with low latency and high throughput. With vCore, the number of vCPUs and the memory the database needs is configurable and can be scaled up or down as needed. 22 | 23 | Conversely, RU is a consumption-based model that charges based on the number of operations the database performs, including reads, writes, and queries. RU is ideal for scenarios where the workload has unpredictable traffic patterns or a need to optimize cost for bursty workloads. 24 | 25 | A steady-state workload with predictable traffic patterns is best suited for vCore since it provides more predictable performance and cost. However, RU may be a better choice if the workload has unpredictable traffic patterns or requires bursty performance since it allows for paying only for the resources used. 26 | 27 | >**NOTE**: AI-supporting workloads, such as vector search, must use the vCore architecture, as vector search is not supported with RU accounts. 28 | -------------------------------------------------------------------------------- /03_Overview_Azure_OpenAI/README.md: -------------------------------------------------------------------------------- 1 | # Overview of Azure OpenAI 2 | 3 | Azure OpenAI is a collaboration between Microsoft Azure and OpenAI, a leading research organization in artificial intelligence. It is a cloud-based platform that enables developers and data scientists to build and deploy AI models quickly and easily. With Azure OpenAI, users can access a wide range of AI tools and technologies to create intelligent applications, including natural language processing, computer vision, and deep learning. 4 | 5 | Azure OpenAI is designed to accelerate the development of AI applications, allowing users to focus on creating innovative solutions that deliver value to their organizations and customers. 6 | 7 | Here are ways that Azure OpenAI can help developers: 8 | 9 | - **Simplified integration** - Simple and easy-to-use APIs for tasks such as text generation, summarization, sentiment analysis, language translation, and more. 10 | - **Pre-trained models** - AI models that are already fine-tuned on vast amounts of data making it easier for developers to leverage the power of AI without having to train their own models from scratch. 11 | - **Customization** - Developers can also fine-tune the included pre-trained models with their own data with minimal coding, providing an opportunity to create more personalized and specialized AI applications. 12 | - **Documentation and resources** - Azure OpenAI provides comprehensive documentation and resources to help developers get started quickly. 13 | - **Scalability and reliability** - Hosted on Microsoft Azure, the OpenAI service provides robust scalability and reliability that developers can leverage to deploy their applications. 14 | - **Responsible AI** - Azure OpenAI promotes responsible AI by adhering to ethical principles, providing explainability tools, governance features, diversity and inclusion support, and collaboration opportunities. These measures help ensure that AI models are unbiased, explainable, trustworthy, and used in a responsible and compliance manner. 15 | - **Community support** - With an active developer community developers can seek help via forums and other community support channels. 16 | 17 | ## Comparison of Azure OpenAI and OpenAI 18 | 19 | Azure OpenAI Service gives customers advanced language AI with OpenAI GPT-4, GPT-3, Codex, DALL-E, and Whisper models with the security and enterprise promise of Azure. Azure OpenAI co-develops the APIs with OpenAI, ensuring compatibility and a smooth transition from one to the other. 20 | 21 | With Azure OpenAI, customers get the security capabilities of Microsoft Azure while running the same models as OpenAI. Azure OpenAI offers private networking, regional availability, and responsible AI content filtering. 22 | 23 | ## Azure OpenAI Data Privacy and Security 24 | 25 | Azure OpenAI stores and processes data to provide the service and to monitor for uses that violate the applicable product terms. Azure OpenAI is fully controlled by Microsoft. Microsoft hosts the OpenAI models in Microsoft Azure for the usage of Azure OpenAI, and does not interact with any services operated by OpenAI. 26 | 27 | Here are a few important things to know in regards to the security and privacy of prompts (inputs) and completions (outputs), embeddings, and training data when using Azure OpenAI: 28 | 29 | - are NOT available to other customers. 30 | - are NOT available to OpenAI. 31 | - are NOT used to improve OpenAI models. 32 | - are NOT used to improve any Microsoft or 3rd party products or services. 33 | - are NOT used for automatically improving Azure OpenAI models for use in the deployed resource (The models are stateless, unless explicitly fine-tuning models with explicitly provided training data). 34 | - Fine-tuned Azure OpenAI models are available exclusively for the account in which it was created. 35 | 36 | ## Azure AI Platform 37 | 38 | Developers can use the power of AI, cloud-scale data, and cloud-native app development to create highly differentiated digital experiences and establish leadership among competitors. Build or modernize intelligent applications that take advantage of industry-leading AI technology and leverage real-time data and analytics to deliver adaptive, responsive, and personalized experiences. 39 | 40 | The Azure platform of managed AI, containers, and database services, along with offerings developed by or in partnership with key software vendors, enables developers to build, deploy, and scale applications with speed, flexibility, and enterprise-grade security. This platform has been used by market leaders like The NBA, H&R Block, Real Madrid Football Club, Bosch, and Nuance to develop their own intelligent apps. 41 | 42 | Developers can use Azure AI Services, along with other Azure services, to build and modernize intelligent apps on Azure. Examples of this could be: 43 | 44 | - Build new with Azure Kubernetes Service or Azure Container Apps, Azure Cosmos DB, and Azure AI Services 45 | - Modernize with Azure Kubernetes Service, Azure SQL or Azure Database for PostgresSQL, and Azure AI Services 46 | 47 | ### Azure AI Services 48 | 49 | While this guide focuses on building intelligent apps using Azure OpenAI combined with vCore-based Azure Cosmos DB for MongoDB, the Azure AI Platform consists of many additional AI services. Each AI service is built to fit a specific AI and/or Machine Learning (ML) need. 50 | 51 | Here's a list of the AI services within the [Azure AI platform](https://learn.microsoft.com/azure/ai-services/what-are-ai-services): 52 | 53 | | Service | Description | 54 | | --- | --- | 55 | | Azure AI Search | Bring AI-powered cloud search to mobile and web apps | 56 | | Azure OpenAI | Perform a wide variety of natural language tasks | 57 | | Bot Service | Create bots and connect them across channels | 58 | | Content Safety | An AI service that detects unwanted contents | 59 | | Custom Vision | Customize image recognition to fit the business | 60 | | Document Intelligence | Turn documents into usable data at a fraction of the time and cost | 61 | | Face | Detect and identify people and emotions in images | 62 | | Immersive Reader | Help users read and comprehend text | 63 | | Language | Build apps with industry-leading natural language understanding capabilities | 64 | | Machine Learning | ML professionals, data scientists, and engineers can use Azure Machine Learning in their day-to-day workflows to train and deploy models, such as those built from an open-source platform, such as PyTorch, TensorFlow, or scikit-learn | 65 | | Speech | Speech to text, text to speech, translation and speaker recognition | 66 | | Translator | Translate more than 100 languages and dialects | 67 | | Video Indexer | Extract actionable insights from videos | 68 | | Vision | Analyze content in images and videos | 69 | 70 | > **Note:** Follow this link for additional tips to help in determining the which Azure AI service is most appropriate for a specific project requirement: 71 | 72 | The tools that used to customize and configure models are different from those used to call the Azure AI services. Out of the box, most Azure AI services allow for sending data and receive insights without any customization. 73 | 74 | For example: 75 | 76 | - Sending an image to the Azure AI Vision service to detect words and phrases or count the number of people in the frame 77 | - Sending an audio file to the Speech service and get transcriptions and translate the speech to text at the same time 78 | 79 | Azure offers a wide range of tools that are designed for different types of users, many of which can be used with Azure AI services. Designer-driven tools are the easiest to use, and are quick to set up and automate, but might have limitations when it comes to customization. The REST APIs and client libraries provide users with more control and flexibility, but require more effort, time, and expertise to build a solution. When using REST APIs and client libraries, there is an expectation that the developer is comfortable working with modern programming languages like C#, Java, Python, JavaScript, or another popular programming language. 80 | 81 | ### Azure Machine Learning 82 | 83 | [Azure Machine Learning](https://learn.microsoft.com/azure/machine-learning/overview-what-is-azure-machine-learning?view=azureml-api-2) is a cloud service for accelerating and managing the machine learning (ML) project lifecycle. ML professionals, data scientists, and engineers can use it in their day-to-day workflows to train and deploy models and manage machine learning operations (MLOps). 84 | 85 | Azure Machine Learning can be used to create a model or use a model built from an open-source platform, such as PyTorch, TensorFlow, or scikit-learn. Additionally, MLOps tools help monitor, retrain, and redeploy models. 86 | 87 | ML projects often require a team with a varied skill set to build and maintain. Azure Machine Learning has tools that help enable: 88 | 89 | - Collaboration within a team via shared notebooks, compute resources, serverless compute, data, and environments 90 | 91 | - Developing models for fairness and explainability, tracking and auditability to fulfill lineage and audit compliance requirements 92 | 93 | - Deploying ML models quickly and easily at scale, and manage and govern them efficiently with MLOps 94 | 95 | - Running machine learning workloads anywhere with built-in governance, security, and compliance 96 | 97 | Enterprises working in the Microsoft Azure cloud can use familiar security and role-based access control for infrastructure. A project can be set up to deny access to protected data and select operations. 98 | 99 | #### Azure Machine Learning vs Azure Open AI 100 | 101 | Many of the Azure AI services are suited to a very specific AI / ML need. The Azure Machine Learning and Azure OpenAI services offer more flexible usage based on the solution requirements. 102 | 103 | Here are a couple differentiators to help determine which of these to services to use when comparing the two: 104 | 105 | - Azure Machine Learning service is appropriate for solutions where a custom model needs to be trained specifically on private data. 106 | 107 | - Azure OpenAI service is appropriate for solutions that require pre-trained models that provide natural language processing or vision services, such as the GPT-4 or DALL-E models from OpenAI. 108 | 109 | If the solution requires other more task specific AI features, then one of the other Azure AI services should be considered. 110 | 111 | ### Azure AI Studio 112 | 113 | Azure AI Studio is a web portal that brings together multiple Azure AI-related services into a single, unified development environment. 114 | 115 | Specifically, Azure AI Studio combines: 116 | 117 | - The model catalog and prompt flow development capabilities of Azure Machine Learning service. 118 | 119 | - The generative AI model deployment, testing, and custom data integration capabilities of Azure OpenAI service. 120 | 121 | - Integration with Azure AI Services for speech, vision, language, document intelligence, and content safety. 122 | 123 | Azure AI Studio enables teams to collaborate efficiently and effectively on AI projects, such as developing custom copilot applications that use large language models (LLMs). 124 | 125 | ![Azure AI Studio screenshot](images/2024-01-23-17-52-46.png) 126 | 127 | Tasks accomplished using Azure AI Studio include: 128 | 129 | - Deploying models from the model catalog to real-time inferencing endpoints for client applications to consume. 130 | - Deploying and testing generative AI models in an Azure OpenAI service. 131 | - Integrating data from custom data sources to support a retrieval augmented generation (RAG) approach to prompt engineering for generative AI models. 132 | - Using prompt flow to define workflows that integrate models, prompts, and custom processing. 133 | - Integrating content safety filters into a generative AI solution to mitigate potential harms. 134 | - Extending a generative AI solution with multiple AI capabilities using Azure AI services. 135 | -------------------------------------------------------------------------------- /03_Overview_Azure_OpenAI/images/2024-01-23-17-52-46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/03_Overview_Azure_OpenAI/images/2024-01-23-17-52-46.png -------------------------------------------------------------------------------- /05_Explore_OpenAI_models/README.md: -------------------------------------------------------------------------------- 1 | # Explore the Azure OpenAI models and endpoints (console app) 2 | 3 | ## Azure OpenAI Models 4 | 5 | Azure OpenAI is powered by a diverse set of models with different capabilities. 6 | 7 | | Model | Description | 8 | | -- | --- | 9 | | GPT-4 | A set of models that improve on GPT-3.5 and can understand and generate natural language and code. | 10 | | GPT-3.5 | A set of models that improve on GPT-3 and can understand and generate natural language and code. | 11 | | Embeddings | A set of models that can convert text into numerical vector form to facilitate text similarity. | 12 | | DALL-E | A series of models that can generate original images from natural language. | 13 | | Whisper | A series of models that can transcribe and translate speech to text. | 14 | 15 | ### GPT-4 and GPT-3.5 Models 16 | 17 | GPT-4 can solve difficult problems with greater accuracy than any of OpenAI's previous models. Like GPT-3.5 Turbo, GPT-4 is optimized for chat and works well for traditional completions tasks. 18 | 19 | The GPT-35-Turbo and GPT-4 models are language models that are optimized for conversational interfaces. The models behave differently than the older GPT-3 models. Previous models were text-in and text-out, meaning they accepted a prompt string and returned a completion to append to the prompt. However, the GPT-35-Turbo and GPT-4 models are conversation-in and message-out. The models expect input formatted in a specific chat-like transcript format, and return a completion that represents a model-written message in the chat. While this format was designed specifically for multi-turn conversations, it can also work well for non-chat scenarios too. 20 | 21 | ### Embeddings 22 | 23 | Embeddings, such as the `text-embedding-ada-002` model, measure the relatedness of text strings. 24 | 25 | Embeddings are commonly used for the following: 26 | 27 | - **Search** - results are ranked by relevance to a query string 28 | - **Clustering** - text strings are grouped by similarity 29 | - **Recommendations** - items with related text strings are recommended 30 | - **Anomaly detection** - outliers with little relatedness are identified 31 | - **Diversity measurement** - similarity distributions are analyzed 32 | - **Classification** - text strings are classified by their most similar label 33 | 34 | ### DALL-E 35 | 36 | DALL-E is a model that can generate an original images from a natural language text description given as input. 37 | 38 | ### Whisper 39 | 40 | Whisper is a speech recognition model, designed for general-purpose applications. Trained on an extensive dataset encompassing diverse audio inputs, and operates as a multi-tasking model capable of executing tasks like multilingual speech recognition, speech translation, and language identification. 41 | 42 | ## Selecting an LLM 43 | 44 | Before a Large Language Model (LLM) can be implemented into a solution, an LLM model must be chosen. For this the business use case and other aspects to the overall goal of the AI solution will need to be defined. 45 | 46 | Once the business goals of the solution are known, there are a few key considerations to think about: 47 | 48 | - **Business Use Case** - What are the specific tasks the business needs the AI solution to perform? Each LLM is designed for different goals, such as text generation, language translation, image generation, answering questions, code generation, etc. 49 | - **Pricing** - For cases where there may be multiple LLMs to choose from, the [pricing](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/) of the LLM could be a factor to consider. For example, when choosing between GPT-3.5 or GPT-4, it may be worth to consider that the overall cost of GPT-4 may be higher than GPT-3.5 for the solution since GPT-4 requires more compute power behind the scenes than GPT-3.5 50 | - **Accuracy** - For cases where there may be multiple LLMs to choose from, the comparison of accuracy between them may be a factor to consider. For example, GPT-4 offers improvements over GPT-3.5 and depending on the use case, GPT-4 may provide increased accuracy. 51 | - **Quotas and limits** - The Azure OpenAI service does have [quotas and limits](https://learn.microsoft.com/azure/ai-services/openai/quotas-limits) on using the service. This may affect the performance and pricing of the AI solution. Additionally, some of quotas and limits may vary depending on the Azure Region that is used to host the Azure OpenAI service. The potential impact of these on the pricing and performance of the solution will want to be considered in the design phase of the solution. 52 | 53 | ## Do I use an out-of-the-box model or a fine-tuned model? 54 | 55 | A base model is a model that hasn't been customized or fine-tuned for a specific use case. Fine-tuned models are customized versions of base models where a model's weights are trained on a unique set of prompts. Fine-tuned models achieve better results on a wider number of tasks without needing to provide detailed examples for in-context learning as part of the completion prompt. 56 | 57 | The [fine-tuning guide](https://learn.microsoft.com/azure/ai-services/openai/how-to/fine-tuning) can be referenced for more information. 58 | 59 | ## Explore and use Azure OpenAI models from code 60 | 61 | The `key` and `endpoint` necessary to make API calls to Azure OpenAI can be located on **Azure OpenAI** blade in the Azure Portal on the **Keys and Endpoint** pane. 62 | 63 | ![Azure OpenAI Keys and Endpoint pane in the Azure Portal](media/2024-01-09-13-53-51.png) 64 | 65 | ## Lab: Explore and use Azure OpenAI models from code 66 | 67 | This labs demonstrates using an Azure OpenAI model to obtain a completion response using the Node.js runtime with the JavaScript programming language. 68 | 69 | Visit the lab repository to complete [this lab](https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/blob/main/Labs/explore_and_use_models/README.md). 70 | -------------------------------------------------------------------------------- /05_Explore_OpenAI_models/media/2024-01-09-13-53-51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/05_Explore_OpenAI_models/media/2024-01-09-13-53-51.png -------------------------------------------------------------------------------- /06_Provision_Azure_Resources/README.md: -------------------------------------------------------------------------------- 1 | # Provision Azure resources (Azure Cosmos DB workspace, Azure OpenAI, etc.) 2 | 3 | As the guide walks you through the concepts of integrating vCore-based Azure Cosmos DB for MongoDB and Azure OpenAI, the hands-on labs will also guide you through building a sample solution. The focus of this guide and the labs is limited to vCore-based Azure Cosmos DB for MongoDB, Vector Search, Azure OpenAI, and the Python programming language. With this focus, the labs include an Azure Bicep template that will deploy the following Azure resources the solution will be deployed to: 4 | 5 | - Azure Resource Group 6 | - vCore-based Azure Cosmos DB for MongoDB 7 | - Azure OpenAI 8 | - ChatGPT-3.5 `completions` model 9 | - text-embedding-ada-002 model `embeddings` model 10 | - Azure App Service - for hosting the front-end, static SPA web application written in React 11 | - Azure Container App - for hosting the back-end, Node.js API application written in JavaScript 12 | - Azure Container Registry - to host Docker images of backend, API application 13 | 14 | ## Architecture Diagram 15 | 16 | ![Solution architecture diagram showing how the Azure services deployed are connected](media/architecture.jpg) 17 | 18 | Once the Azure resources are provisioned, this guide will walk you through everything that is necessary to build the Node.js Back-end API application. 19 | 20 | The Front-end Web App is a static SPA application written in React. Since React is outside the scope of this guide, the Front-end Web App is pre-built for you and will be configured automatically on deployment. You do not need any experience with React in order to complete the labs in this guide. 21 | 22 | ## Lab - Provision Azure Resources 23 | 24 | This lab will walk you through deploying the Azure resources necessary for the solution built in this guide. The deployment will be done using an Azure Bicep template that is configured to provision all the necessary resources. 25 | 26 | > **Note**: You will need an Azure Subscription and have the necessary permissions to provision the Azure resources. 27 | 28 | Please visit the lab repository to complete [this lab](https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/blob/main/Labs/deploy/deploy.md). 29 | -------------------------------------------------------------------------------- /06_Provision_Azure_Resources/media/architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/06_Provision_Azure_Resources/media/architecture.jpg -------------------------------------------------------------------------------- /07_Create_First_Cosmos_DB_Project/README.md: -------------------------------------------------------------------------------- 1 | # Create your first Cosmos DB project 2 | 3 | This section will cover how to create your first Cosmos DB project. We'll create a simple application to demonstrate the basic CRUD operations. We'll also cover using the Azure Cosmos DB Emulator to test code locally. 4 | 5 | ## Emulator support 6 | 7 | Azure Cosmos DB has an emulator that can be used to develop code locally. The emulator supports the API for NoSQL and the API for MongoDB. The use of the emulator does not require an Azure subscription, nor does it incur any costs, so it is ideal for local development and testing. The Azure Cosmos DB emulator can also be utilized with unit tests in a [GitHub Actions CI workflow](https://learn.microsoft.com/azure/cosmos-db/how-to-develop-emulator?tabs=windows%2Cpython&pivots=api-mongodb#use-the-emulator-in-a-github-actions-ci-workflow). 8 | 9 | There is not 100% feature parity between the emulator and the cloud service. Visit the [Azure Cosmos DB emulator](https://learn.microsoft.com/azure/cosmos-db/emulator) documentation for more details. 10 | 11 | For Windows machines, the emulator can be installed via an installer. There is a Windows container using Docker available. However, it does not currently support the API for Mongo DB. A Docker image is also available for Linux that does support the API for Mongo DB. 12 | 13 | Learn more about the pre-requisites and installation of the emulator [here](https://learn.microsoft.com/azure/cosmos-db/how-to-develop-emulator?tabs=windows%2Cpython&pivots=api-mongodb). 14 | 15 | >**NOTE**: When using the Azure CosmosDB emulator using the API for MongoDB it must be started with the [MongoDB endpoint options enabled](https://learn.microsoft.com/azure/cosmos-db/how-to-develop-emulator?tabs=windows%2Cpython&pivots=api-mongodb#start-the-emulator) at the command-line. 16 | 17 | **The Azure Cosmos DB emulator does not support vector search. To complete the vector search and AI-related labs, a vCore-based Azure Cosmos DB for MongoDB account in Azure is required.** 18 | 19 | ## Authentication 20 | 21 | Authentication to Azure Cosmos DB API for Mongo DB uses a connection string. The connection string is a URL that contains the authentication information for the Azure Cosmos DB account or local emulator. The username and password used when provisioning the Azure Cosmos DB API for MongoDB service are used in the connection string when authenticating to Azure. 22 | 23 | ### Retrieving the connection string from the Cosmos DB Emulator 24 | 25 | The splash screen or **Quickstart** section of the Cosmos DB Emulator will display the connection string. Access this screen through the following URL: `https://localhost:8081/_explorer/index.html`. 26 | 27 | ![The Azure Cosmos DB emulator screen displays with the local host url, the Quickstart tab, and the Mongo connection string highlighted.](media/emulator_connection_string.png) 28 | 29 | ### Retrieving the connection string from the Azure portal 30 | 31 | Retrieve the connection string from the Azure portal by navigating to the Azure Cosmos DB account and selecting the **Connection String** menu item on the left-hand side of the screen. The connection string contains tokens for the username and password that must be replaced with the username and password used when provisioning the Azure Cosmos DB API for MongoDB service. 32 | 33 | ![The Azure CosmosDb API for MongoDB Connection strings screen displays with the copy button next to the connection string highlighted.](media/azure_connection_string.png) 34 | 35 | ## Lab - Create your first Cosmos DB for MongoDB application 36 | 37 | In this lab, we'll create a Cosmos DB for the MongoDB application using the **mongodb** NPM package that includes the MongoDB Node.js Driver and its dependencies. Both the Azure Cosmos DB Emulator and Azure Cosmos DB account in Azure are supported for completion of this lab. 38 | 39 | Please visit the lab repository to complete [this lab](https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/blob/main/Labs/first_cosmos_db_application/README.md). 40 | 41 | The following concepts are covered in detail in this lab: 42 | 43 | ### Creating a MongoDB database client 44 | 45 | The `mongodb` NPM package is used to create a MongoDB database client. The client enables both DDL (data definition language) and DML (data manipulation language) operations. 46 | 47 | ```javascript 48 | const client = new MongoClient(process.env.MONGODB_URI); 49 | ``` 50 | 51 | ### Creating a database 52 | 53 | When using the `mongodb` client, the creation of a database is automatic when referenced. No specific api calls to create a database are required, if a database already exists, a reference to the database is returned. 54 | 55 | >**Note:**: That the creation of databases and collections are lazy, meaning they will not be created until a document is inserted into a collection. 56 | 57 | ```javascript 58 | const db = client.db('cosmic_works'); 59 | ``` 60 | 61 | ### Creating a collection 62 | 63 | Similar behavior to the creation of a database is experienced when creating a collection. If the collection does not exist, it will be created once a document is inserted into the collection. 64 | 65 | ```javascript 66 | const products = db.collection('products'); 67 | ``` 68 | 69 | ### Creating a document 70 | 71 | The `insertOne` method is used to insert a document into a collection. The document is a product document. 72 | 73 | ```javascript 74 | const result = await products.insertOne(product); 75 | ``` 76 | 77 | ### Reading a document 78 | 79 | The `findOne` method is used to retrieve a single document from a collection. The method returns the product document. 80 | 81 | ```javascript 82 | const product = await products.findOne({ _id: '2BA4A26C-A8DB-4645-BEB9-F7D42F50262E' }); 83 | ``` 84 | 85 | ### Updating a document 86 | 87 | The `findOneAndUpdate` method is used to update a single document in a collection. The method returns the updated document object. 88 | 89 | ```javascript 90 | const options = { returnDocument: 'after' }; 91 | const updated = await products.findOneAndUpdate( 92 | { _id: '2BA4A26C-A8DB-4645-BEB9-F7D42F50262E' }, 93 | { $set: { price: 14242.42 } }, 94 | options); 95 | ``` 96 | 97 | ### Deleting a document 98 | 99 | The `deleteOne` method is used to delete a single document from a collection. 100 | 101 | ```javascript 102 | const result = await products.deleteOne({ _id: '2BA4A26C-A8DB-4645-BEB9-F7D42F50262E' }); 103 | ``` 104 | 105 | ### Querying documents 106 | 107 | The `find` method is used to query documents from a collection. The method returns a cursor object that can be converted to an array using the `toArray` method. 108 | 109 | ```javascript 110 | const allProducts = await products.find({}).toArray(); 111 | ``` 112 | -------------------------------------------------------------------------------- /07_Create_First_Cosmos_DB_Project/media/azure_connection_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/07_Create_First_Cosmos_DB_Project/media/azure_connection_string.png -------------------------------------------------------------------------------- /07_Create_First_Cosmos_DB_Project/media/emulator_connection_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/07_Create_First_Cosmos_DB_Project/media/emulator_connection_string.png -------------------------------------------------------------------------------- /08_Load_Data/README.md: -------------------------------------------------------------------------------- 1 | # Load data into Azure Cosmos DB API for MongoDB 2 | 3 | The previous lab demonstrated how to add data to a collection individually. This lab will demonstrate how to load data using bulk operations into multiple collections. This data will be used in subsequent labs to explain further the capabilities of Azure Cosmos DB API for MongoDB with respect to AI. 4 | 5 | When loading data, bulk operations are preferred over adding each document individually. Bulk operations involve performing multiple database operations as a batch rather than executing them simultaneously. This approach is more efficient and provides several benefits: 6 | 7 | 1. Performance: By issuing load operations in bulk, the lab can significantly reduce the overhead of network round-trips and database operations. This results in faster data loading and improved overall performance. 8 | 9 | 2. Scalability: Bulk operations allow the lab to handle large volumes of data efficiently. They can quickly process and load a substantial amount of customer, product, and sales data, enabling them to scale their operations as needed. 10 | 11 | 3. Atomicity: Bulk operations ensure that all database changes within a batch are treated as a single transaction. The entire batch can be rolled back if any document fails to load, maintaining data integrity and consistency. 12 | 13 | 4. Simplified code logic: By using bulk operations, the lab can simplify its code logic and reduce the number of database queries. This results in cleaner, more manageable code and reduces the likelihood of errors or inconsistencies. 14 | 15 | ## Lab - Load data into Azure Cosmos DB API for MongoDB collections 16 | 17 | This lab will load the Cosmic Works Customer, Product, and Sales data into Azure Cosmos DB API for MongoDB collections using bulk operations. Both the Azure Cosmos DB Emulator and Azure Cosmos DB account in Azure are supported for completion of this lab. 18 | 19 | Please visit the lab repository to complete [this lab](https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/blob/main/08_Load_Data/README.md). 20 | 21 | This lab demonstrates the use of bulk operations to load product, customer, and sales data into Azure Cosmos DB API for MongoDB collections. As an example, the following code snippet inserts product data using the `bulkWrite` method allowing for insert functionality using the `InsertOne` operation. The bulkWrite method is used to perform multiple write operations in a single batch, write operations can include a mixture of insert, update, and delete operations: 22 | 23 | ```javascript 24 | var result = await productCollection.bulkWrite( 25 | productData.map((product) => ({ 26 | insertOne: { 27 | document: product 28 | } 29 | })) 30 | ); 31 | ``` 32 | 33 | The lab continues with bulk loading customer and sales data, this time with the `insertMany` method. The insertMany method is used to insert multiple documents into a collection, it differs from the bulkWrite method in that it only supports insert operations. The following code snippet demonstrates the use of the simplified `insertMany` method to insert customer data: 34 | 35 | ```javascript 36 | var result = await customerCollection.insertMany(customerData); 37 | ``` 38 | -------------------------------------------------------------------------------- /09_Vector_Search_Cosmos_DB/README.md: -------------------------------------------------------------------------------- 1 | # Use vector search on embeddings in vCore-based Azure Cosmos DB for MongoDB 2 | 3 | >**NOTE**: vCore-based Azure Cosmos DB for MongoDB supports vector search on embeddings. This functionality is not supported on RUs-based accounts. 4 | 5 | ## Embeddings and vector search 6 | 7 | Embedding is a way of serializing the semantic meaning of data into a vector representation. Because the generated vector embedding represents the semantic meaning, it means that when it is searched, it can find similar data based on the semantic meaning of the data rather than exact text. Data can come from many sources, including text, images, audio, and video. Because the data is represented as a vector, vector search can, therefore, find similar data across all different types of data. 8 | 9 | Embeddings are created by sending data to an embedding model, where it is transformed into a vector, which then can be stored as a vector field within its source document in vCore-based Azure Cosmos DB for MongoDB. vCore-based Azure Cosmos DB for MongoDB supports the creation of vector search indexes on top of these vector fields. A vector search index is a collection of vectors in [latent space](https://idl.cs.washington.edu/papers/latent-space-cartography/) that enables a semantic similarity search across all data (vectors) contained within. 10 | 11 | ![A typical embedding pipeline that demonstrates how source data is transformed into vectors using an embedding model then stored in a document in an Azure Cosmos DB vCore database and exposed via a vector search index.](media/embedding_pipeline.png) 12 | 13 | ## Why vector search? 14 | 15 | Vector search is an important RAG (Retrieval Augmented Generation) pattern component. Large Language Model (LLM) data is trained on a snapshot of public data at a point in time. This data does not contain recent public information, nor does it collect private, corporate information. LLMs are also very broad in their knowledge, and including information from a RAG process can help it focus accurately on a specific domain. 16 | 17 | A vector index search allows for a prompt pre-processing step where relevant information can be semantically retrieved from an index and then used to generate a factually accurate prompt for the LLM to reason over. This provides the knowledge augmentation and focus (attention) to the LLM. 18 | 19 | In this example, assume textual data is vectorized and stored within an vCore-based Azure Cosmos DB for MongoDB database. The text data and embeddings/vector field are stored in the same document. A vector search index has been created on the vector field. When a message is received from a chat application, this message is also vectorized using the same embedding model (ex., Azure OpenAI text-embedding-ada-002), which is then used as input to the vector search index. The vector search index returns a list of documents whose vector field is semantically similar to the incoming message. The unvectorized text stored within the same document is then used to augment the LLM prompt. The LLM receives the prompt and responds to the requestor based on the information it has been given. 20 | 21 | ![A typical vector search request in a RAG scenario depicts an incoming message getting vectorized and used as input to a vector store index search. Multiple results of the vector search are used to build a prompt fed to the LLM. The LLM returns a response to the requestor.](media/vector_search_flow.png) 22 | 23 | ## Why use vCore-based Azure Cosmos DB for MongoDB as a vector store? 24 | 25 | It is common practice to store vectorized data in a dedicated vector store as vector search indexing is not a common capability of most databases. However, this introduces additional complexity to the solution as the data must be stored in two different locations. vCore-based Azure Cosmos DB for MongoDB supports vector search indexing, which means that the vectorized data can be stored in the same document as the original data. This reduces the complexity of the solution and allows for a single database to be used for both the vector store and the original data. 26 | 27 | ## Lab - Use vector search on embeddings in vCore-based Azure Cosmos DB for MongoDB 28 | 29 | In this lab, we'll demonstrate how to add an embedding field to a document, create a vector search index, and perform a vector search query. The lab ends with a demonstration of utilizing vector search with an LLM in a RAG scenario using Azure OpenAI. 30 | 31 | This lab requires the Azure OpenAI endpoint and access key to be added to the settings (`.env`) file. Access this information by opening [Azure OpenAI Studio](https://oai.azure.com/portal) and selecting the **Gear**/Settings icon located to the right in the top toolbar. 32 | 33 | ![Azure OpenAI Studio displays with the Gear icon highlighted in the top toolbar.](media/azure_openai_studio_settings_icon.png) 34 | 35 | On the **Settings** screen, select the **Resource** tab, then copy and record the **Endpoint** and **Key** values for use in the lab. 36 | 37 | ![The Azure OpenAI resource settings screen displays with the endpoint and key values highlighted.](media/azure_openai_settings.png) 38 | 39 | >**NOTE**: This lab can only be completed using a deployed vCore-based Azure Cosmos DB for MongoDB account due to the use of vector search. The Azure Cosmos DB Emulator does not support vector search. 40 | 41 | This lab also requires the data provided in the previous lab titled [Load data into Azure Cosmos DB API for MongoDB collections](../08_Load_Data/README.md#lab---load-data-into-azure-cosmos-db-api-for-mongodb-collections). Run all cells in this notebook to prepare the data for use in this lab. 42 | 43 | Please visit the lab repository to complete [this lab](https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/blob/main/Labs/vector_search/README.md). 44 | 45 | Some highlights from the lab include: 46 | 47 | ### Instantiating an AzureOpenAI client 48 | 49 | ```javascript 50 | const { OpenAIClient, AzureKeyCredential } = require("@azure/openai"); 51 | 52 | // Instantiate an AzureOpenAI client 53 | const ai_client = new OpenAIClient( 54 | AOAI_ENDPOINT, 55 | new AzureKeyCredential(AOAI_KEY) 56 | ) 57 | ``` 58 | 59 | ### Vectorizing text using Azure OpenAI 60 | 61 | ```javascript 62 | //Generate embedding vectors from a text string 63 | async function generateEmbeddings(text) { 64 | const embeddings = await aoaiClient.getEmbeddings(embeddingsDeploymentName, text); 65 | // Rest period to avoid rate limiting on Azure OpenAI 66 | await new Promise(resolve => setTimeout(resolve, 500)); 67 | return embeddings.data[0].embedding; 68 | } 69 | ``` 70 | 71 | ### Adding an embedding field to a document and creating a vector search index on a collection 72 | 73 | The lab creates an embedding field named `contentVector` in each collection and populates the value with the vectorized text of the JSON representation of the document. 74 | 75 | ```javascript 76 | async function addCollectionContentVectorField(db, collectionName) { 77 | const collection = db.collection(collectionName); 78 | const docs = await collection.find({}).toArray(); 79 | const bulkOperations = []; 80 | console.log(`Generating content vectors for ${docs.length} documents in ${collectionName} collection`); 81 | for (let i=0; i 0) { 102 | console.log(`Persisting the generated content vectors in the ${collectionName} collection using bulkWrite upserts`); 103 | await collection.bulkWrite(bulkOperations); 104 | console.log(`Finished persisting the content vectors to the ${collectionName} collection`); 105 | } 106 | 107 | //check to see if the vector index already exists on the collection 108 | console.log(`Checking if vector index exists in the ${collectionName} collection`) 109 | const vectorIndexExists = await collection.indexExists('VectorSearchIndex'); 110 | if (!vectorIndexExists) { 111 | await db.command({ 112 | "createIndexes": collectionName, 113 | "indexes": [ 114 | { 115 | "name": "VectorSearchIndex", 116 | "key": { 117 | "contentVector": "cosmosSearch" 118 | }, 119 | "cosmosSearchOptions": { 120 | "kind": "vector-ivf", 121 | "numLists": 1, 122 | "similarity": "COS", 123 | "dimensions": 1536 124 | } 125 | } 126 | ] 127 | }); 128 | console.log(`Created vector index on contentVector field on ${collectionName} collection`); 129 | } 130 | else { 131 | console.log(`Vector index already exists on contentVector field in the ${collectionName} collection`); 132 | } 133 | } 134 | ``` 135 | 136 | ### Performing a vector search query 137 | 138 | ```javascript 139 | async function vectorSearch(db, collectionName, query, numResults = 3) { 140 | const collection = db.collection(collectionName); 141 | // generate the embedding for incoming question 142 | const queryEmbedding = await generateEmbeddings(query); 143 | 144 | const pipeline = [ 145 | { 146 | '$search': { 147 | "cosmosSearch": { 148 | "vector": queryEmbedding, 149 | "path": "contentVector", 150 | "k": numResults 151 | }, 152 | "returnStoredSource": true 153 | } 154 | }, 155 | { '$project': { 'similarityScore': { '$meta': 'searchScore' }, 'document': '$$ROOT' } } 156 | ]; 157 | 158 | //perform vector search and return the results as an array 159 | const results = await collection.aggregate(pipeline).toArray(); 160 | return results; 161 | } 162 | ``` 163 | 164 | ### Using vector search results with an LLM in a RAG scenario 165 | 166 | ```javascript 167 | async function ragWithVectorsearch(db, collectionName, question, numResults=3) { 168 | //A system prompt describes the responsibilities, instructions, and persona of the AI. 169 | const systemPrompt = ` 170 | You are a helpful, fun and friendly sales assistant for Cosmic Works, a bicycle and bicycle accessories store. 171 | Your name is Cosmo. 172 | You are designed to answer questions about the products that Cosmic Works sells. 173 | 174 | Only answer questions related to the information provided in the list of products below that are represented 175 | in JSON format. 176 | 177 | If you are asked a question that is not in the list, respond with "I don't know." 178 | 179 | List of products: 180 | `; 181 | const collection = db.collection(collectionName); 182 | //generate vector embeddings for the incoming question 183 | const queryEmbedding = await generateEmbeddings(question); 184 | //perform vector search and return the results 185 | results = await vectorSearch(db, collectionName, question, numResults); 186 | productList = ""; 187 | //remove contentVector from the results, create a string of the results for the prompt 188 | for (const result of results) { 189 | delete result['document']['contentVector']; 190 | productList += JSON.stringify(result['document']) + "\n\n"; 191 | } 192 | 193 | //assemble the prompt for the large language model (LLM) 194 | const formattedPrompt = systemPrompt + productList; 195 | //prepare messages for the LLM call, TODO: if message history is desired, add them to this messages array 196 | const messages = [ 197 | { 198 | "role": "system", 199 | "content": formattedPrompt 200 | }, 201 | { 202 | "role": "user", 203 | "content": question 204 | } 205 | ]; 206 | 207 | //call the Azure OpenAI model to get the completion and return the response 208 | const completion = await aoaiClient.getChatCompletions(completionsDeploymentName, messages); 209 | return completion.choices[0].message.content; 210 | } 211 | ``` 212 | -------------------------------------------------------------------------------- /09_Vector_Search_Cosmos_DB/media/azure_openai_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/09_Vector_Search_Cosmos_DB/media/azure_openai_settings.png -------------------------------------------------------------------------------- /09_Vector_Search_Cosmos_DB/media/azure_openai_studio_settings_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/09_Vector_Search_Cosmos_DB/media/azure_openai_studio_settings_icon.png -------------------------------------------------------------------------------- /09_Vector_Search_Cosmos_DB/media/embedding_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/09_Vector_Search_Cosmos_DB/media/embedding_pipeline.png -------------------------------------------------------------------------------- /09_Vector_Search_Cosmos_DB/media/vector_search_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/09_Vector_Search_Cosmos_DB/media/vector_search_flow.png -------------------------------------------------------------------------------- /10_LangChain/README.md: -------------------------------------------------------------------------------- 1 | # LangChain 2 | 3 | [LangChain](https://www.langchain.com/) is an open-source framework designed to simplify the creation of applications that use large language models (LLMs). LangChain has a vibrant community of developers and contributors and is used by many companies and organizations. LangChain utilizes proven Prompt Engineering patterns and techniques to optimize LLMs, ensuring successful and accurate results through verified and tested best practices. 4 | 5 | Part of the appeal of LangChain syntax is the capability of breaking down large complex interactions with LLMs into smaller, more manageable steps by composing a reusable [chain](https://python.langchain.com/docs/modules/chains/) process. LangChain provides a syntax for chains([LCEL](https://python.langchain.com/docs/modules/chains/#lcel)), the ability to integrate with external systems through [tools](https://python.langchain.com/docs/integrations/tools/), and end-to-end [agents](https://python.langchain.com/docs/modules/agents/) for common applications. 6 | 7 | The concept of an agent is quite similar to that of a chain in LangChain but with one fundamental difference. A chain in LangChain is a hard-coded sequence of steps executed in a specific order. Conversely, an agent leverages the LLM to assess the incoming request with the current context to decide what steps or actions need to be executed and in what order. 8 | 9 | LangChain agents can leverage tools and toolkits. A tool can be an integration into an external system, custom code, or even another chain. A toolkit is a collection of tools that can be used to solve a specific problem. 10 | 11 | ## LangChain RAG pattern 12 | 13 | Earlier in this guide, the RAG (Retrieval Augmented Generation) pattern was introduced. In LangChain, the RAG pattern is implemented as part of a chain that combines a retriever and a Large Language Model (generator). The retriever is responsible for finding the most relevant documents for a given query, in this case, doing a vector search on vCore-based Azure Cosmos DB for MongoDB, and the LLM (generator) is responsible for reasoning over the incoming prompt and context. 14 | 15 | ![LangChain RAG diagram shows the flow of an incoming message through a retriever, augmenting the prompt, parsing the output and returning the final message.](media/langchain_rag.png) 16 | 17 | When an incoming message is received, the retriever will vectorize the message and perform a vector search to find the most relevant documents for the given query. The retriever returns a list of documents that are then used to augment the prompt. The augmented prompt is then passed to the LLM (generator) to reason over the prompt and context. The output from the LLM is then parsed and returned as the final message. 18 | 19 | > **Note**: A vector store retriever is only one type of retriever that can be used in the RAG pattern. Learn more about retrievers in the [LangChain documentation](https://python.langchain.com/docs/modules/data_connection/retrievers/). 20 | 21 | ## Lab - Vector search and RAG using LangChain 22 | 23 | In this lab uses LangChain to re-implement the RAG pattern introduced in the previous lab. Take note of the readability of the code and how easy it is to compose a reusable RAG chain using LangChain that queries the products vector index in vCore-based Azure Cosmos DB for MongoDB. The lab concludes with the creation of an agent with various tools for the LLM to leverage to fulfill the incoming request. 24 | 25 | Please visit the lab repository to complete [this lab](https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/blob/main/Labs/langchain/README.md). 26 | 27 | Some highlights of the lab include: 28 | 29 | ### Instantiating a vector store reference 30 | 31 | ```javascript 32 | // set up the MongoDB client 33 | const dbClient = new MongoClient(process.env.AZURE_COSMOSDB_CONNECTION_STRING); 34 | 35 | // set up the Azure Cosmos DB vector store 36 | const azureCosmosDBConfig = { 37 | client: dbClient, 38 | databaseName: "cosmic_works", 39 | collectionName: "products", 40 | indexName: "VectorSearchIndex", 41 | embeddingKey: "contentVector", 42 | textKey: "_id" 43 | } 44 | const vectorStore = new AzureCosmosDBVectorStore(new OpenAIEmbeddings(), azureCosmosDBConfig); 45 | ``` 46 | 47 | ### Composing a reusable RAG chain 48 | 49 | ```javascript 50 | async function ragLCELChain(question) { 51 | // A system prompt describes the responsibilities, instructions, and persona of the AI. 52 | // Note the addition of the templated variable/placeholder for the list of products and the incoming question. 53 | const systemPrompt = ` 54 | You are a helpful, fun and friendly sales assistant for Cosmic Works, a bicycle and bicycle accessories store. 55 | Your name is Cosmo. 56 | You are designed to answer questions about the products that Cosmic Works sells. 57 | 58 | Only answer questions related to the information provided in the list of products below that are represented 59 | in JSON format. 60 | 61 | If you are asked a question that is not in the list, respond with "I don't know." 62 | 63 | Only answer questions related to Cosmic Works products, customers, and sales orders. 64 | 65 | If a question is not related to Cosmic Works products, customers, or sales orders, 66 | respond with "I only answer questions about Cosmic Works" 67 | 68 | List of products: 69 | {products} 70 | 71 | Question: 72 | {question} 73 | `; 74 | const retriever = vectorStore.asRetriever(); 75 | const prompt = PromptTemplate.fromTemplate(systemPrompt); 76 | 77 | // The RAG chain will populate the variable placeholders of the system prompt 78 | // with the formatted list of products based on the documents retrieved from the vector store. 79 | // The RAG chain will then invoke the LLM with the populated prompt and the question. 80 | // The response from the LLM is then parsed as a string and returned. 81 | const ragChain = RunnableSequence.from([ 82 | { 83 | products: retriever.pipe(formatDocuments), 84 | question: new RunnablePassthrough() 85 | }, 86 | prompt, 87 | chatModel, 88 | new StringOutputParser() 89 | ]); 90 | 91 | return await ragChain.invoke(question); 92 | } 93 | ``` 94 | 95 | ### Creating tools for LangChain agents to use 96 | 97 | Tools are selected by the Large Language model at runtime. In this case, depending on the incoming user request the LLM will decide which collection in the database to query. The following code shows how to create a tool for the LLM to use to query the products collection in the database. 98 | 99 | ```javascript 100 | // A tool that retrieves product information from Cosmic Works based on the user's question. 101 | const productsRetrieverTool = new DynamicTool({ 102 | name: "products_retriever_tool", 103 | description: `Searches Cosmic Works product information for similar products based on the question. 104 | Returns the product information in JSON format.`, 105 | func: async (input) => await retrieverChain.invoke(input), 106 | }); 107 | ``` 108 | 109 | ### Creating tools that call Python functions 110 | 111 | Users may query for information that does not have a semantic meaning, such as an ID GUID value or a SKU number. Providing agents with tools to call Python functions to retrieve documents based on these fields is a common practice. The following is an example of adding tools that call out to Python functions for the products collection. 112 | 113 | ```javascript 114 | // A tool that will lookup a product by its SKU. Note that this is not a vector store lookup. 115 | const productLookupTool = new DynamicTool({ 116 | name: "product_sku_lookup_tool", 117 | description: `Searches Cosmic Works product information for a single product by its SKU. 118 | Returns the product information in JSON format. 119 | If the product is not found, returns null.`, 120 | func: async (input) => { 121 | const db = dbClient.db("cosmic_works"); 122 | const products = db.collection("products"); 123 | const doc = await products.findOne({ "sku": input }); 124 | if (doc) { 125 | //remove the contentVector property to save on tokens 126 | delete doc.contentVector; 127 | } 128 | return doc ? JSON.stringify(doc, null, '\t') : null; 129 | }, 130 | }); 131 | ``` 132 | 133 | ### Creating an agent armed with tools for vector search and Python functions calling 134 | 135 | ```javascript 136 | // Define the agent and executor 137 | // An agent is a type of chain that reasons over the input prompt and has the ability 138 | // to decide which function(s) (tools) to use and parses the output of the functions. 139 | const runnableAgent = RunnableSequence.from([ 140 | { 141 | input: (i) => i.input, 142 | agent_scratchpad: (i) => formatToOpenAIFunctionMessages(i.steps), 143 | }, 144 | prompt, 145 | modelWithFunctions, 146 | new OpenAIFunctionsAgentOutputParser(), 147 | ]); 148 | 149 | // An agent executor can be thought of as a runtime, it orchestrates the actions of the agent 150 | // until completed. This can be the result of a single or multiple actions (one can feed into the next). 151 | // Note: If you wish to see verbose output of the tool usage of the agent, 152 | // set returnIntermediateSteps to true 153 | const executor = AgentExecutor.fromAgentAndTools({ 154 | agent: runnableAgent, 155 | tools, 156 | returnIntermediateSteps: true 157 | }); 158 | ``` 159 | -------------------------------------------------------------------------------- /10_LangChain/media/langchain_rag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/10_LangChain/media/langchain_rag.png -------------------------------------------------------------------------------- /11_Backend_API/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/.DS_Store -------------------------------------------------------------------------------- /11_Backend_API/README.md: -------------------------------------------------------------------------------- 1 | # Lab - Backend API 2 | 3 | In the previous lab, a LangChain agent was created armed with tools to do vector lookups and concrete document id lookups via function calling. In this lab, the agent functionality needs to be extracted into a backend api for the frontend application that will allow users to interact with the agent. 4 | 5 | This lab implements a backend API using FastAPI that exposes the LangChain agent functionality. The provided code leverages Docker containers and includes full step-by-step instructions to run and test the API locally as well as deployed to [Azure Container Apps](https://learn.microsoft.com/azure/container-apps/overview) (leveraging the [Azure Container Registry](https://learn.microsoft.com/azure/container-registry/)). 6 | 7 | This lab also requires the data provided in the previous lab titled [Load data into Azure Cosmos DB API for MongoDB collections](../08_Load_Data/README.md#lab---load-data-into-azure-cosmos-db-api-for-mongodb-collections) as well as the populated vector index created in the lab titled [Vector Search using vCore-based Azure Cosmos DB for MongoDB](../09_Vector_Search_Cosmos_DB/README.md#lab---use-vector-search-on-embeddings-in-vcore-based-azure-cosmos-db-for-mongodb). Run all cells in both notebooks to prepare the data for use in this lab. 8 | 9 | Please visit the lab repository to complete [this lab](https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/blob/main/Labs/backend_api/README.md). 10 | -------------------------------------------------------------------------------- /11_Backend_API/media/2024-01-06-20-01-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/2024-01-06-20-01-38.png -------------------------------------------------------------------------------- /11_Backend_API/media/acr_access_keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/acr_access_keys.png -------------------------------------------------------------------------------- /11_Backend_API/media/container_app_delete_hello_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/container_app_delete_hello_world.png -------------------------------------------------------------------------------- /11_Backend_API/media/container_app_edit_and_deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/container_app_edit_and_deploy.png -------------------------------------------------------------------------------- /11_Backend_API/media/container_app_failed_revision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/container_app_failed_revision.png -------------------------------------------------------------------------------- /11_Backend_API/media/container_app_log_stream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/container_app_log_stream.png -------------------------------------------------------------------------------- /11_Backend_API/media/container_app_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/container_app_overview.png -------------------------------------------------------------------------------- /11_Backend_API/media/container_app_ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/container_app_ready.png -------------------------------------------------------------------------------- /11_Backend_API/media/container_deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/container_deploy.png -------------------------------------------------------------------------------- /11_Backend_API/media/local_backend_docker_build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/local_backend_docker_build.png -------------------------------------------------------------------------------- /11_Backend_API/media/local_backend_docker_push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/local_backend_docker_push.png -------------------------------------------------------------------------------- /11_Backend_API/media/local_backend_docker_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/local_backend_docker_run.png -------------------------------------------------------------------------------- /11_Backend_API/media/local_backend_running_console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/local_backend_running_console.png -------------------------------------------------------------------------------- /11_Backend_API/media/local_backend_swagger_ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/local_backend_swagger_ui.png -------------------------------------------------------------------------------- /11_Backend_API/media/local_backend_swagger_ui_ai_response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/local_backend_swagger_ui_ai_response.png -------------------------------------------------------------------------------- /11_Backend_API/media/local_backend_swagger_ui_root_response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/11_Backend_API/media/local_backend_swagger_ui_root_response.png -------------------------------------------------------------------------------- /12_User_Interface/README.md: -------------------------------------------------------------------------------- 1 | # Connect the chat user interface with the chatbot API 2 | 3 | In the previous lab, the backend API code was configured and deployed. The backend API integrates vCore-based Azure Cosmos DB for MongoDB with Azure OpenAI. When the Azure resource template for this lab was run to deploy the necessary Azure resources, a front-end web application written as a SPA (single page application) in React was deployed. 4 | 5 | The URL to access this front-end application within the Azure Portal on the **Web App** resource with the name that ends with **-web**. 6 | 7 | The following screenshot shows where to find the front-end application URL: 8 | 9 | ![Web App resource for front-end application with Default domain highlighted](images/2024-01-17-12-41-48.png) 10 | 11 | Navigating to this URL in the browser accesses the front-end application. Through this front-end application User Interface, questions can be submitted to the Azure OpenAI model about the CosmicWorks company data, then it will generate responses accordingly. 12 | 13 | ![Front-end Web Application User Interface](images/2024-01-17-12-42-59.png) 14 | 15 | While the code for the SPA web application is outside the scope of this dev guide. It's worth noting that the Web App is configured with the URL for the Backend API using the **Application setting** named `API_ENDPOINT`. When the application was deployed as part of the Azure template deployment, it was automatically configured with this URL to connect the front-end SPA web application to the Backend API. 16 | 17 | ![Web App resource showing the application settings with the API_ENDPOINT setting highlighted](images/2024-01-17-12-45-30.png) 18 | 19 | ## Ask questions about data and observe the responses 20 | 21 | To ask the AI questions about the CosmicWorks company data, type the questions in to the front-end application chat user interface. The web application includes tiles with a couple example questions to get started. To use these, simply click on the question tile and it will generate an answer. 22 | 23 | ![Front-end Web Application User Interface](images/2024-01-17-12-42-59.png) 24 | 25 | These example questions are: 26 | - What was the price of the product with sku `FR-R92B-58`? 27 | - What is the SKU of HL Road Frame - Black? 28 | - What is HL Road Frame? 29 | 30 | > **Note**: It's possible the first time you ask a question within the Front end application there may be an error. Occasionally when the Azure Bicep template deploys the front end application there will be an issue configuring the use of the `API_ENDPOINT` app setting. If this happens, simply navigate to **Deployment** -> **Deployment Center**, then click **Sync** to have the Web App refresh the deployment of the front end app from it's GitHub repository source code. This should fix that error. 31 | 32 | The chat user interface presents as a traditional chat application style interface when asking questions. 33 | 34 | ![Chat user interface screenshot with question and generated answer displayed](images/2024-01-17-12-53-13.png) 35 | 36 | Go ahead, ask the service a few questions about CosmicWorks and observe the responses. 37 | 38 | ## What do I do if the responses are incorrect? 39 | 40 | It's important to remember the model is pre-trained with data, given a system message to guide it, in addition to the company data it has access to via vCore-based Azure Cosmos DB for MongoDB. There are times when the Azure OpenAI model may generate an incorrect response to the prompt given that is either incomplete or even a hallucination (aka includes information that is not correct or accurate). 41 | 42 | There are a few options of how this can be handled when the response is incorrect: 43 | 44 | 1. Provide a new prompt that includes more specific and structured information that can help the model generate a more accurate response. 45 | 2. Include more data in the library of company information the model has access to. The incorrect response may be a result of data or information about the company that is missing currently. 46 | 3. Use Prompt Engineering techniques to enhance the System message and/or Supporting information provided to guide the model. 47 | 48 | While it may be simple to ask the model questions, there are times when Prompt Engineering skills may be necessary to get the most value and reliable responses from the AI model. 49 | 50 | ## What happens when I start exceeding my token limits? 51 | 52 | A Token in Azure OpenAI is a basic unit of input and output that the service processes. Generally, the models understand and process text by breaking it down into tokens. 53 | 54 | For example, the word `hamburger` gets broken up into the tokens `ham`, `bur` and `ger`, while a short and common word like `pear` is a single token. Many tokens start with a whitespace, for example ` hello` and ` bye`. 55 | 56 | The total number of tokens processed in a given request depends on the length of the input, output and request parameters. The quantity of tokens being processed will also affect the response latency and throughput for the models. 57 | 58 | > **Note**: The [pricing of the Azure OpenAI](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/) service is primarily based on token usage. 59 | 60 | ### Exceeding Token Quota Limits 61 | 62 | Azure OpenAI has **tokens per minute** quota limits on the service. This quota limit, is based on the OpenAI model being used and the Azure region it's hosted in. 63 | 64 | > **Note**: The [Azure OpenAI Quotas and limits documentation](https://learn.microsoft.com/azure/ai-services/openai/quotas-limits) contains further information on the specific quotas per OpenAI model and Azure region. 65 | 66 | If an applications usage of an Azure OpenAI model exceeds the token quota limits, then the service will respond with a **Rate Limit Error** (Error code 429). 67 | 68 | When this error is encountered, there are a couple options available for handling it: 69 | 70 | - **Wait a minute** - With the tokens quota limit being a rate limits of the maximum number of tokens allowed per minute, the application will be able to send more prompts to the model again after the quota resets each minute. 71 | - **Request a quota increase** - It may be possible to get Microsoft to increase the token quota to a higher limit, but it's not guaranteed to be approved. This request can be made at [https://aka.ms/oai/quotaincrease](https://aka.ms/oai/quotaincrease) 72 | 73 | ### Tips to Minimize Token Rate Limit Errors 74 | 75 | Here are a few tips that can help to minimize an applications token rate limit errors: 76 | 77 | - **Retry Logic** - Implement retry logic in the application so it will retry the call to the Azure OpenAI model, rather than throwing an exception the first time. This is generally best practices when consuming external APIs from applications so they can gracefully handle any unexpected exceptions. 78 | - **Scale Workload Gradually** - Avoid increasing the workload of the application too quickly. By gradually increasing the scale of the workload. 79 | - **Asynchronous Load Patterns** - While there are time sensitive operations that will require a response immediately, there are also operations that are able to be run more asynchronously. Background processes or other similar operations could be build in a way to perform a combination of rate limiting the applications own usage of the model, or even delaying calls until periods of the day where the application is under less load. 80 | - **Set `max_tokens`** - Setting a lower `max_tokens` when calling the service when a short response is expected will limit the maximum number of tokens allowed for the generated answer. 81 | - **Set `best_of`** - Setting a lower `best_of` when calling the service enables the application to control the number of candidate completions generated and how many to return from the service. 82 | 83 | ### Exceeding Token Limit for System message 84 | 85 | When configuring a System message to guide the generated responses, there is a limit on how long the System message can be. The token limit for the System message is 400 tokens. 86 | 87 | If the System message provided is more than 400 tokens, the rest of the tokens beyond the first 400 will be ignored. 88 | -------------------------------------------------------------------------------- /12_User_Interface/images/2024-01-17-12-41-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/12_User_Interface/images/2024-01-17-12-41-48.png -------------------------------------------------------------------------------- /12_User_Interface/images/2024-01-17-12-42-59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/12_User_Interface/images/2024-01-17-12-42-59.png -------------------------------------------------------------------------------- /12_User_Interface/images/2024-01-17-12-45-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/12_User_Interface/images/2024-01-17-12-45-30.png -------------------------------------------------------------------------------- /12_User_Interface/images/2024-01-17-12-53-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/12_User_Interface/images/2024-01-17-12-53-13.png -------------------------------------------------------------------------------- /13_Conclusion/README.md: -------------------------------------------------------------------------------- 1 | # Conclusion 2 | 3 | This guide was designed to provide an insightful journey for Python/MongoDB developers to get started with vCore-based Azure Cosmos DB for MongoDB as it applies to creating exciting AI-enabled applications using existing skills. We hope you found this guide helpful and informative. 4 | 5 | ## Clean up 6 | 7 | To clean up the resources created in this guide, delete the `mongo-devguide-rg` resource group in the Azure Portal. 8 | 9 | Alternatively, you can use the Azure CLI to delete the resource group. The following command deletes the resource group and all resources within it. The `--no-wait` flag makes the command return immediately, without waiting for the deletion to complete. 10 | 11 | >**Note**: Ensure the Azure CLI session is authenticated using `az login` and the correct subscription is selected using `az account set --subscription `. 12 | 13 | ```powershell 14 | az group delete --name mongo-devguide-rg --yes --no-wait 15 | ``` 16 | -------------------------------------------------------------------------------- /Backend/.env.EXAMPLE: -------------------------------------------------------------------------------- 1 | AZURE_COSMOSDB_CONNECTION_STRING= 2 | AZURE_OPENAI_API_INSTANCE_NAME= 3 | AZURE_OPENAI_API_KEY= 4 | AZURE_OPENAI_API_DEPLOYMENT_NAME=completions 5 | AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME=embeddings 6 | AZURE_OPENAI_API_VERSION=2023-09-01-preview 7 | -------------------------------------------------------------------------------- /Backend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /Backend/DOCKERFILE: -------------------------------------------------------------------------------- 1 | FROM node:21 2 | 3 | WORKDIR /usr/src/app 4 | COPY package*.json ./ 5 | RUN npm install 6 | COPY . . 7 | 8 | EXPOSE 80 9 | 10 | CMD [ "node", "--env-file=.env", "app.js", "port=80" ] -------------------------------------------------------------------------------- /Backend/README.md: -------------------------------------------------------------------------------- 1 | # Cosmos DB Dev Guide Backend App - Node.js 2 | -------------------------------------------------------------------------------- /Backend/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const cors = require('cors') 3 | const swagger = require('./swagger'); 4 | const CosmicWorksAIAgent = require('./cosmic_works/cosmic_works_ai_agent'); 5 | 6 | const app = express(); 7 | app.use(express.json()); 8 | app.use(cors()); // enable all CORS requests 9 | 10 | 11 | // This map is to store agents and their chat history for each session. 12 | // This is for demonstration only and should be hydrated by storing these 13 | // values in a database rather than in-memory. 14 | let agentInstancesMap = new Map(); 15 | 16 | /* Health probe endpoint. */ 17 | /** 18 | * @openapi 19 | * /: 20 | * get: 21 | * description: Health probe endpoint 22 | * responses: 23 | * 200: 24 | * description: Returns status=ready json 25 | */ 26 | app.get('/', (req, res) => { 27 | res.send({ "status": "ready" }); 28 | }); 29 | 30 | 31 | /** 32 | * @openapi 33 | * /ai: 34 | * post: 35 | * description: Run the Cosmic Works AI agent 36 | * requestBody: 37 | * required: true 38 | * content: 39 | * application/json: 40 | * schema: 41 | * type: object 42 | * properties: 43 | * prompt: 44 | * type: string 45 | * default: "" 46 | * session_id: 47 | * type: string 48 | * default: "1234" 49 | * responses: 50 | * 200: 51 | * description: Returns the OpenAI response. 52 | */ 53 | app.post('/ai', async (req, res) => { 54 | let agent = {}; 55 | let prompt = req.body.prompt; 56 | let session_id = req.body.session_id; 57 | 58 | if (agentInstancesMap.has(session_id)) { 59 | agent = agentInstancesMap.get(session_id); 60 | } else { 61 | agent = new CosmicWorksAIAgent(); 62 | agentInstancesMap.set(session_id, agent); 63 | } 64 | 65 | let result = await agent.executeAgent(prompt); 66 | res.send({ message: result }); 67 | }); 68 | 69 | swagger(app) 70 | 71 | 72 | // parse out hosting port from cmd arguments if passed in 73 | // otherwise default to port 4242 74 | var port = (() => { 75 | const { argv } = require('node:process'); 76 | var port = 4242; // default 77 | if (argv){ 78 | argv.forEach((v, i) => { 79 | if (v && (v.toLowerCase().startsWith('port='))) 80 | { 81 | port = v.substring(5); 82 | } 83 | }); 84 | } 85 | return port; 86 | })(); 87 | 88 | app.listen(port, () => { 89 | console.log(`Server started on port ${port}`); 90 | }); 91 | -------------------------------------------------------------------------------- /Backend/catch_up.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { MongoClient } = require('mongodb'); 3 | const { OpenAIClient, AzureKeyCredential} = require("@azure/openai"); 4 | 5 | // set up the MongoDB client 6 | const dbClient = new MongoClient(process.env.AZURE_COSMOSDB_CONNECTION_STRING); 7 | // set up the Azure OpenAI client 8 | const embeddingsDeploymentName = "embeddings"; 9 | const aoaiClient = new OpenAIClient("https://" + process.env.AZURE_OPENAI_API_INSTANCE_NAME + ".openai.azure.com/", 10 | new AzureKeyCredential(process.env.AZURE_OPENAI_API_KEY)); 11 | 12 | async function main() { 13 | try { 14 | await dbClient.connect(); 15 | console.log('Connected to MongoDB'); 16 | const db = dbClient.db('cosmic_works'); 17 | 18 | // Load product data 19 | console.log('Loading product data') 20 | // Initialize the product collection pointer (will automatically be created if it doesn't exist) 21 | const productCollection = db.collection('products'); 22 | // Load the product data from the raw data from Cosmic Works while also removing the system properties 23 | const productRawData = "https://cosmosdbcosmicworks.blob.core.windows.net/cosmic-works-small/product.json"; 24 | const productData = (await (await fetch(productRawData)).json()) 25 | .map(prod => cleanData(prod)); 26 | // Delete all existing products and insert the new data 27 | await productCollection.deleteMany({}); 28 | // Utilize bulkWrite to insert all the products at once 29 | var result = await productCollection.bulkWrite( 30 | productData.map((product) => ({ 31 | insertOne: { 32 | document: product 33 | } 34 | })) 35 | ); 36 | console.log(`${result.insertedCount} products inserted`); 37 | 38 | await addCollectionContentVectorField(db, 'products'); 39 | 40 | } catch (err) { 41 | console.error(err); 42 | } finally { 43 | await dbClient.close(); 44 | console.log('Disconnected from MongoDB'); 45 | } 46 | } 47 | 48 | async function generateEmbeddings(text) { 49 | const embeddings = await aoaiClient.getEmbeddings(embeddingsDeploymentName, text); 50 | // Rest period to avoid rate limiting on Azure OpenAI 51 | await new Promise(resolve => setTimeout(resolve, 500)); 52 | return embeddings.data[0].embedding; 53 | } 54 | 55 | async function addCollectionContentVectorField(db, collectionName) { 56 | const collection = db.collection(collectionName); 57 | const docs = await collection.find({}).toArray(); 58 | const bulkOperations = []; 59 | console.log(`Generating content vectors for ${docs.length} documents in ${collectionName} collection`); 60 | for (let i=0; i 0) { 81 | console.log(`Persisting the generated content vectors in the ${collectionName} collection using bulkWrite upserts`); 82 | await collection.bulkWrite(bulkOperations); 83 | console.log(`Finished persisting the content vectors to the ${collectionName} collection`); 84 | } 85 | 86 | //check to see if the vector index already exists on the collection 87 | console.log(`Checking if vector index exists in the ${collectionName} collection`) 88 | const vectorIndexExists = await collection.indexExists('VectorSearchIndex'); 89 | if (!vectorIndexExists) { 90 | await db.command({ 91 | "createIndexes": collectionName, 92 | "indexes": [ 93 | { 94 | "name": "VectorSearchIndex", 95 | "key": { 96 | "contentVector": "cosmosSearch" 97 | }, 98 | "cosmosSearchOptions": { 99 | "kind": "vector-ivf", 100 | "numLists": 1, 101 | "similarity": "COS", 102 | "dimensions": 1536 103 | } 104 | } 105 | ] 106 | }); 107 | console.log(`Created vector index on contentVector field on ${collectionName} collection`); 108 | } 109 | else { 110 | console.log(`Vector index already exists on contentVector field in the ${collectionName} collection`); 111 | } 112 | } 113 | 114 | main().catch(console.error); -------------------------------------------------------------------------------- /Backend/cosmic_works/cosmic_works_ai_agent.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { MongoClient } = require('mongodb'); 3 | const { AgentExecutor } = require("langchain/agents"); 4 | const { OpenAIFunctionsAgentOutputParser } = require("langchain/agents/openai/output_parser"); 5 | const { formatToOpenAIFunctionMessages } = require("langchain/agents/format_scratchpad"); 6 | const { DynamicTool } = require("@langchain/core/tools"); 7 | const { RunnableSequence } = require("@langchain/core/runnables"); 8 | const { HumanMessage, AIMessage } = require("@langchain/core/messages"); 9 | const { MessagesPlaceholder, ChatPromptTemplate } = require("@langchain/core/prompts"); 10 | const { convertToOpenAIFunction } = require("@langchain/core/utils/function_calling"); 11 | const { ChatOpenAI, OpenAIEmbeddings } = require("@langchain/openai"); 12 | const { AzureCosmosDBVectorStore } = require("@langchain/community/vectorstores/azure_cosmosdb"); 13 | 14 | class CosmicWorksAIAgent { 15 | constructor() { 16 | // set up the MongoDB client 17 | this.dbClient = new MongoClient(process.env.AZURE_COSMOSDB_CONNECTION_STRING); 18 | // set up the Azure Cosmos DB vector store 19 | const azureCosmosDBConfig = { 20 | client: this.dbClient, 21 | databaseName: "cosmic_works", 22 | collectionName: "products", 23 | indexName: "VectorSearchIndex", 24 | embeddingKey: "contentVector", 25 | textKey: "_id" 26 | } 27 | this.vectorStore = new AzureCosmosDBVectorStore(new OpenAIEmbeddings(), azureCosmosDBConfig); 28 | 29 | // set up the OpenAI chat model 30 | // https://js.langchain.com/docs/integrations/chat/azure 31 | this.chatModel = new ChatOpenAI({ 32 | temperature: 0, 33 | azureOpenAIApiKey: process.env.AZURE_OPENAI_API_KEY, 34 | azureOpenAIApiVersion: process.env.AZURE_OPENAI_API_VERSION, 35 | azureOpenAIApiInstanceName: process.env.AZURE_OPENAI_API_INSTANCE_NAME, 36 | azureOpenAIApiDeploymentName: process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME 37 | }); 38 | 39 | // initialize the chat history 40 | this.chatHistory = []; 41 | 42 | // initialize the agent executor 43 | (async () => { 44 | this.agentExecutor = await this.buildAgentExecutor(); 45 | })(); 46 | } 47 | 48 | async formatDocuments(docs) { 49 | // Prepares the product list for the system prompt. 50 | let strDocs = ""; 51 | for (let index = 0; index < docs.length; index++) { 52 | let doc = docs[index]; 53 | let docFormatted = { "_id": doc.pageContent }; 54 | Object.assign(docFormatted, doc.metadata); 55 | 56 | // Build the product document without the contentVector and tags 57 | if ("contentVector" in docFormatted) { 58 | delete docFormatted["contentVector"]; 59 | } 60 | if ("tags" in docFormatted) { 61 | delete docFormatted["tags"]; 62 | } 63 | 64 | // Add the formatted product document to the list 65 | strDocs += JSON.stringify(docFormatted, null, '\t'); 66 | 67 | // Add a comma and newline after each item except the last 68 | if (index < docs.length - 1) { 69 | strDocs += ",\n"; 70 | } 71 | } 72 | // Add two newlines after the last item 73 | strDocs += "\n\n"; 74 | return strDocs; 75 | } 76 | 77 | async buildAgentExecutor() { 78 | // A system prompt describes the responsibilities, instructions, and persona of the AI. 79 | // Note the variable placeholders for the list of products and the incoming question are not included. 80 | // An agent system prompt contains only the persona and instructions for the AI. 81 | const systemMessage = ` 82 | You are a helpful, fun and friendly sales assistant for Cosmic Works, a bicycle and bicycle accessories store. 83 | 84 | Your name is Cosmo. 85 | 86 | You are designed to answer questions about the products that Cosmic Works sells, the customers that buy them, and the sales orders that are placed by customers. 87 | 88 | If you don't know the answer to a question, respond with "I don't know." 89 | 90 | Only answer questions related to Cosmic Works products, customers, and sales orders. 91 | 92 | If a question is not related to Cosmic Works products, customers, or sales orders, 93 | respond with "I only answer questions about Cosmic Works" 94 | `; 95 | // Create vector store retriever chain to retrieve documents and formats them as a string for the prompt. 96 | const retrieverChain = this.vectorStore.asRetriever().pipe(this.formatDocuments); 97 | 98 | // Define tools for the agent can use, the description is important this is what the AI will 99 | // use to decide which tool to use. 100 | 101 | // A tool that retrieves product information from Cosmic Works based on the user's question. 102 | const productsRetrieverTool = new DynamicTool({ 103 | name: "products_retriever_tool", 104 | description: `Searches Cosmic Works product information for similar products based on the question. 105 | Returns the product information in JSON format.`, 106 | func: async (input) => await retrieverChain.invoke(input), 107 | }); 108 | 109 | // A tool that will lookup a product by its SKU. Note that this is not a vector store lookup. 110 | const productLookupTool = new DynamicTool({ 111 | name: "product_sku_lookup_tool", 112 | description: `Searches Cosmic Works product information for a single product by its SKU. 113 | Returns the product information in JSON format. 114 | If the product is not found, returns null.`, 115 | func: async (input) => { 116 | const db = this.dbClient.db("cosmic_works"); 117 | const products = db.collection("products"); 118 | const doc = await products.findOne({ "sku": input }); 119 | if (doc) { 120 | //remove the contentVector property to save on tokens 121 | delete doc.contentVector; 122 | } 123 | return doc ? JSON.stringify(doc, null, '\t') : null; 124 | }, 125 | }); 126 | 127 | // Generate OpenAI function metadata to provide to the LLM 128 | // The LLM will use this metadata to decide which tool to use based on the description. 129 | const tools = [productsRetrieverTool, productLookupTool]; 130 | const modelWithFunctions = this.chatModel.bind({ 131 | functions: tools.map((tool) => convertToOpenAIFunction(tool)), 132 | }); 133 | 134 | // OpenAI function calling is fine-tuned for tool using therefore you don't need to provide instruction. 135 | // All that is required is that there be two variables: `input` and `agent_scratchpad`. 136 | // Input represents the user prompt and agent_scratchpad acts as a log of tool invocations and outputs. 137 | const prompt = ChatPromptTemplate.fromMessages([ 138 | ["system", systemMessage], 139 | new MessagesPlaceholder("chat_history"), 140 | ["human", "{input}"], 141 | new MessagesPlaceholder("agent_scratchpad") 142 | ]); 143 | 144 | // Define the agent and executor 145 | // An agent is a type of chain that reasons over the input prompt and has the ability 146 | // to decide which function(s) (tools) to use and parses the output of the functions. 147 | const runnableAgent = RunnableSequence.from([ 148 | { 149 | input: (i) => i.input, 150 | agent_scratchpad: (i) => formatToOpenAIFunctionMessages(i.steps), 151 | chat_history: (i) => i.chat_history 152 | }, 153 | prompt, 154 | modelWithFunctions, 155 | new OpenAIFunctionsAgentOutputParser(), 156 | ]); 157 | 158 | // An agent executor can be thought of as a runtime, it orchestrates the actions of the agent 159 | // until completed. This can be the result of a single or multiple actions (one can feed into the next). 160 | // Note: If you wish to see verbose output of the tool usage of the agent, 161 | // set returnIntermediateSteps to true 162 | const executor = AgentExecutor.fromAgentAndTools({ 163 | agent: runnableAgent, 164 | tools, 165 | //returnIntermediateSteps: true 166 | }); 167 | 168 | return executor; 169 | } 170 | 171 | // Helper function that executes the agent with user input and returns the string output 172 | async executeAgent(input) { 173 | let returnValue = ""; 174 | try { 175 | await this.dbClient.connect(); 176 | // Invoke the agent with the user input 177 | const result = await this.agentExecutor.invoke({ input: input, chat_history: this.chatHistory }); 178 | 179 | this.chatHistory.push(new HumanMessage(input)); 180 | this.chatHistory.push(new AIMessage(result.output)); 181 | 182 | // Output the intermediate steps of the agent if returnIntermediateSteps is set to true 183 | if (this.agentExecutor.returnIntermediateSteps) { 184 | console.log(JSON.stringify(result.intermediateSteps, null, 2)); 185 | } 186 | // Return the final response from the agent 187 | returnValue = result.output; 188 | } finally { 189 | await this.dbClient.close(); 190 | } 191 | return returnValue; 192 | } 193 | }; 194 | 195 | module.exports = CosmicWorksAIAgent; 196 | -------------------------------------------------------------------------------- /Backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@azure/openai": "1.0.0-beta.11", 13 | "@langchain/community": "0.0.32", 14 | "cors": "^2.8.5", 15 | "dotenv": "16.4.4", 16 | "langchain": "0.1.21", 17 | "mongodb": "6.3.0", 18 | "swagger-jsdoc": "^6.2.8", 19 | "swagger-ui-express": "^5.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Backend/run.sh: -------------------------------------------------------------------------------- 1 | npm install 2 | 3 | node --env-file=.env app.js port=4242 4 | -------------------------------------------------------------------------------- /Backend/swagger.js: -------------------------------------------------------------------------------- 1 | const swaggerJsdoc = require('swagger-jsdoc') 2 | const swaggerUi = require('swagger-ui-express') 3 | 4 | // https://abbaslanbay.medium.com/node-js-rest-api-using-express-and-swagger-39744533dba4 5 | 6 | const options = { 7 | swaggerDefinition: { 8 | openapi: '3.0.1', 9 | info: { 10 | title: 'API', 11 | version: '0.1.0', 12 | description: '', 13 | }/*, 14 | servers: [ 15 | { 16 | url: 'http://localhost:80', 17 | }, 18 | ],*/ 19 | }, 20 | apis: ['*.js'], 21 | } 22 | 23 | const specs = swaggerJsdoc(options) 24 | 25 | module.exports = (app) => { 26 | app.use('/docs', swaggerUi.serve, swaggerUi.setup(specs)) 27 | } 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /Labs/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | .pnpm-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # Snowpack dependency directory (https://snowpack.dev/) 48 | web_modules/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional stylelint cache 60 | .stylelintcache 61 | 62 | # Microbundle cache 63 | .rpt2_cache/ 64 | .rts2_cache_cjs/ 65 | .rts2_cache_es/ 66 | .rts2_cache_umd/ 67 | 68 | # Optional REPL history 69 | .node_repl_history 70 | 71 | # Output of 'npm pack' 72 | *.tgz 73 | 74 | # Yarn Integrity file 75 | .yarn-integrity 76 | 77 | # dotenv environment variable files 78 | .env 79 | .env.development.local 80 | .env.test.local 81 | .env.production.local 82 | .env.local 83 | 84 | # parcel-bundler cache (https://parceljs.org/) 85 | .cache 86 | .parcel-cache 87 | 88 | # Next.js build output 89 | .next 90 | out 91 | 92 | # Nuxt.js build / generate output 93 | .nuxt 94 | dist 95 | 96 | # Gatsby files 97 | .cache/ 98 | # Comment in the public line in if your project uses Gatsby and not Next.js 99 | # https://nextjs.org/blog/next-9-1#public-directory-support 100 | # public 101 | 102 | # vuepress build output 103 | .vuepress/dist 104 | 105 | # vuepress v2.x temp and cache directory 106 | .temp 107 | .cache 108 | 109 | # Docusaurus cache and generated files 110 | .docusaurus 111 | 112 | # Serverless directories 113 | .serverless/ 114 | 115 | # FuseBox cache 116 | .fusebox/ 117 | 118 | # DynamoDB Local files 119 | .dynamodb/ 120 | 121 | # TernJS port file 122 | .tern-port 123 | 124 | # Stores VSCode versions used for testing VSCode extensions 125 | .vscode-test 126 | 127 | # yarn v2 128 | .yarn/cache 129 | .yarn/unplugged 130 | .yarn/build-state.yml 131 | .yarn/install-state.gz 132 | .pnp.* 133 | 134 | package-lock.json -------------------------------------------------------------------------------- /Labs/README.md: -------------------------------------------------------------------------------- 1 | # Azure Cosmos DB + Azure OpenAI Node.js developer guide companion labs 2 | -------------------------------------------------------------------------------- /Labs/backend_api/README.md: -------------------------------------------------------------------------------- 1 | # Lab - Backend API 2 | 3 | In the previous lab, a LangChain agent was created armed with tools to do vector lookups and concrete document id lookups via function calling. In this lab, the agent functionality needs to be extracted into a backend api for the frontend application that will allow users to interact with the agent. 4 | 5 | The information provided in this section assumes that the dependent infrastructure is deployed and have completed the previous labs in this dev guide. 6 | 7 | ## Overview 8 | 9 | The backend api is a Node.js web application, using Express and Swagger, that will expose endpoints for the frontend application to interact with. The backend api is a containerized application that will be deployed to [Azure Container Apps](https://learn.microsoft.com/en-us/azure/container-apps/overview). 10 | 11 | ## Clone the Backend API 12 | 13 | Create a folder to house the repository. Open a terminal and navigate to the folder. Clone the repository, then navigate to the `Backend` folder within the repository. 14 | 15 | ```bash 16 | git clone https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide.git 17 | 18 | cd Azure-OpenAI-Node.js-Developer-Guide 19 | cd Backend 20 | ``` 21 | 22 | ## Run the backend api locally 23 | 24 | When developing a backend api, it is often useful to run the application locally to test and debug. This section outlines how to run the backend api locally while watching the file system for code changes. Any detected changes will automatically restart the backend api. 25 | 26 | 1. Open the backend api folder location in VS Code. 27 | 28 | 2. Open a **Terminal** window in VS Code (CTRL+`). 29 | 30 | 3. Setup the `.env` file. Copy the `.env.example` file to `.env` and update the values. These are the same environment variables used in the previous labs. 31 | 32 | ```bash 33 | cp .env.EXAMPLE .env 34 | ``` 35 | 36 | 3. Add the following settings to the `.env` file, populating the MongoDB connection string and replacing the values from the deployed Azure OpenAI service: 37 | 38 | ```bash 39 | AZURE_COSMOSDB_CONNECTION_STRING= 40 | AZURE_OPENAI_API_INSTANCE_NAME= 41 | AZURE_OPENAI_API_KEY= 42 | AZURE_OPENAI_API_DEPLOYMENT_NAME=completions 43 | AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME=embeddings 44 | AZURE_OPENAI_API_VERSION=2023-09-01-preview 45 | ``` 46 | 47 | Replace `` with the MongoDB connection string. Replace `` with the name of the deployed OpenAI service, and `` with the Azure OpenAI API key. Leave all other values untouched. 48 | 49 | >**Note**: The Azure OpenAI service name is not the full endpoint. Only the service name is required. For example, if the endpoint is `https://myservicename.openai.azure.com/`, then the service name is `myservicename`. 50 | 51 | 5. Run the following command to install any dependencies: 52 | 53 | ```bash 54 | npm install 55 | ``` 56 | 57 | 6. Run the following command to start the backend api. 58 | 59 | ```bash 60 | node --env-file=.env app.js 61 | ``` 62 | 63 | ![The VSCode terminal window displays with the backend API started.](media/local_backend_running_console.png "Local backend api running") 64 | 65 | 7. Open a browser and navigate to `http://localhost:4242/docs` to view the Swagger UI. 66 | 67 | ![The Swagger UI displays for the locally running backend api](media/local_backend_swagger_ui.png "Local backend api Swagger UI") 68 | 69 | 8. Expand the **GET / Root** endpoint and select **Try it out**. Select **Execute** to send the request. The response should display a status of `ready`. 70 | 71 | ![The Swagger UI displays the GET / Root endpoint reponse that has a status of ready.](media/local_backend_swagger_ui_root_response.png "Local backend api Swagger UI Root response") 72 | 73 | 9. Expand the **POST /ai** endpoint and select **Try it out**. In the **Request body** field, enter the following JSON. 74 | 75 | ```json 76 | { 77 | "session_id": "abc123", 78 | "prompt": "What was the price of the product with sku `FR-R92B-58`" 79 | } 80 | ``` 81 | 82 | 10. Select **Execute** to send the request. Observe that the response indicates the price as being `$1431.50`. 83 | 84 | ![The Swagger UI displays the POST /ai endpoint reponse that has a status of ready.](media/local_backend_swagger_ui_ai_response.png "Local backend api Swagger UI AI response") 85 | 86 | 11. In the Terminal window, press CTRL+C to stop the backend api. 87 | 88 | ## Build and run the backend api container locally in Docker Desktop 89 | 90 | When deployed to Azure, the backend api will be running in a container. It is important to test the container locally to ensure it is working as expected. Containers are important because they provide a consistent environment for the application to run in. This consistency allows the application to run the same way in development, test, and production environments - whether they be locally or in the cloud. 91 | 92 | The backend api contains a `Dockerfile` that defines the container image and is used by Docker to build the container image. The Dockerfile contains instructions for Docker to build the container image. The container image is a snapshot of the application and its dependencies. The container image can be thought of an installer for the application to be deployed as needed in any environment. 93 | 94 | The `Dockerfile` for the backend api is shown below. 95 | 96 | ```dockerfile 97 | FROM node:21 98 | 99 | WORKDIR /usr/src/app 100 | COPY package*.json ./ 101 | RUN npm install 102 | COPY . . 103 | 104 | EXPOSE 80 105 | 106 | CMD [ "node", "--env-file=.env", "app.js", "port=80" ] 107 | ``` 108 | 109 | Notice the steps of installing the pip dependencies, and running the **uvicorn** command line similar to what was done in the previous section. 110 | 111 | 1. Ensure Docker Desktop is running. 112 | 113 | 2. Open a **Terminal** window in VS Code (CTRL+`). 114 | 115 | 4. Run the following command to build the container image. Once complete, a message displays the operation has `FINISHED`. 116 | 117 | ```bash 118 | docker build --pull --rm -f "DOCKERFILE" -t devguidenodebackendapi:latest "." 119 | ``` 120 | 121 | ![The VSCode terminal window displays the docker build command and the FINISHED message.](media/local_backend_docker_build.png "Local backend api Docker build") 122 | 123 | 5. Lastly, run the container in Docker Desktop using the following command. 124 | 125 | ```bash 126 | docker run -d -p 4242:80 --name devguide-backend-api devguidenodebackendapi:latest 127 | ``` 128 | 129 | ![The VSCode terminal window displays the docker run command.](media//local_backend_docker_run.png "Local backend api Docker run") 130 | 131 | 6. Open a browser and navigate to `http://localhost:4242/docs` to view the Swagger UI. 132 | 133 | 7. Repeat steps 8-10 from the previous section to test the backend api running in a container on Docker Desktop. 134 | 135 | ## Deploy the backend api to Azure Container Apps 136 | 137 | ### Retrieve the Azure Container Registry login server and admin credentials 138 | 139 | The backend api container image needs to be pushed to an Azure Container Registry (ACR) before it can be deployed to Azure Container Apps. The ACR is a private container registry that will store the container image. Azure Container Apps will pull the container image from the ACR to deploy the backend api. 140 | 141 | 1. In the Azure portal, open the provisioned resource group and locate and open the **Container Registry** resource. 142 | 143 | 2. Select **Access keys** from the left-hand menu. Record the **Login server** value and the **Username** and **Password** values for later use. 144 | 145 | ![The Azure portal displays the Container Registry resource with the Access keys menu item selected. The login server, username and password values are highlighted.](media/acr_access_keys.png "Container Registry Access keys") 146 | 147 | ### Push the backend api container image to the Azure Container Registry 148 | 149 | Earlier, the backend api container image was built locally. Now that the ACR login server and admin credentials are known, the container image can be pushed to the Azure Container Registry. 150 | 151 | 1. Return to the terminal window in VS Code. 152 | 153 | 2. Run the following command to tag the container image with the ACR login server. Replace the `` value. This command will silently complete with no output. 154 | 155 | ```bash 156 | docker tag devguidenodebackendapi:latest /devguidenodebackendapi:v1 157 | ``` 158 | 159 | 3. Run the following command to log into the ACR. Replace the ``, ``, and `` values. The message `Login Succeeded` displays when the login is successful. 160 | 161 | ```bash 162 | docker login -u -p 163 | ``` 164 | 165 | 4. Once authenticated, push the container image to the ACR using the following command. Replace the `` value. 166 | 167 | ```bash 168 | docker push /devguidenodebackendapi:v1 169 | ``` 170 | 171 | ![The VSCode terminal window displays the docker login and docker push commands.](media/local_backend_docker_push.png "Local backend api Docker push") 172 | 173 | ### Deploy the backend api ACR container image to Azure Container Apps 174 | 175 | The last step is to deploy the backend api container image to Azure Container Apps. Azure Container Apps is a fully managed serverless container platform that allows developers to deploy containerized applications without having to manage any infrastructure. 176 | 177 | 1. In the Azure portal, open the provisioned resource group and locate and open the **Container App** resource, the name will end in `-api`. Record the name of this resource. 178 | 179 | 2. Back in the resource group, locate the **Container Apps Environment** resource, the name will end in `-containerappenv`. Record the name of this resource. 180 | 181 | 3. Also record the name of the resource group. 182 | 183 | 4. Return to the terminal window in VS Code. 184 | 185 | 5. Log into the Azure CLI using the following command. 186 | 187 | ```bash 188 | az login 189 | ``` 190 | 191 | 6. Optionally set the current subscription to the correct subscription using the following command. 192 | 193 | ```bash 194 | az account set --subscription 195 | ``` 196 | 197 | 7. Install the Azure Container Apps extension for the CLI using the following command. 198 | 199 | ```bash 200 | az extension add --name containerapp --upgrade 201 | ``` 202 | 203 | 8. Run the following command to deploy the backend api container image to the existing Azure Container Apps resource. Replace the ``, ``, ``, and `` values. 204 | 205 | ```bash 206 | az containerapp up --name --image /devguidenodebackendapi:v1 --resource-group --environment --ingress external 207 | ``` 208 | 209 | ![The console output of the container app up command displays with the endpoint highlighted.](media/container_deploy.png) 210 | 211 | 9. In the Azure Portal, locate and open the **Container App** resource ending in `-api`. 212 | 213 | 10. Notice on the **Overview** screen, there is a failed container revision. This is because the `hello-world` container is running at the same binding address as the backend api container. 214 | 215 | ![The Azure portal displays the Container App resource with a failed container revision listed.](media/container_app_failed_revision.png "Container App Failed Revision") 216 | 217 | 11. View the error from the logs, or optionally select **Log stream** from the left menu, then select the api container log stream. 218 | 219 | ![The Azure portal displays the Container App resource with the Log stream menu item selected and the output of the api container with the error highlighted.](media/container_app_log_stream.png "Container App Log Stream") 220 | 221 | 12. To rectify this, the `hello-world` container needs to be deleted. Select **Containers** from the left menu, then choose the **Edit and Deploy** button from the toolbar. 222 | 223 | ![The Azure portal displays the Container App resource with the Containers menu item selected. The Edit and Deploy button is highlighted.](media/container_app_edit_and_deploy.png "Container App Edit and Deploy") 224 | 225 | 13. On the **Create and deploy new revision** screen, beneath the **Container image** heading, check the box next to the `hello-world` container, then select **Delete**. 226 | 227 | ![The Azure portal displays the Create and deploy new revision screen with the hello-world container selected.](media/container_app_delete_hello_world.png "Container App Delete hello-world") 228 | 229 | 14. Select **Create** to deploy the new revision. In less than a minute, the new revision is deployed. 230 | 231 | 15. Refresh the browser, then from the left menu, select **Overview**. Select the **Application URL** link. 232 | 233 | ![The Azure portal displays the Container App resource Overview screen with the Application URL highlighted.](media/container_app_overview.png "Container App Overview") 234 | 235 | 16. The UI should show the status as `ready`. 236 | 237 | ![The Azure portal displays the Container App resource with the Overview menu item selected. The Application URL is highlighted.](media/container_app_ready.png "Container App Ready") 238 | 239 | 17. In the address bar of the browser, append `/docs` to the URL and press ENTER to view the Swagger UI. 240 | 241 | 18. Repeat steps 8-10 from the [Run the backend api locally section](#run-the-backend-api-locally) to test the backend api running in a container on Azure Container Apps. 242 | 243 | Congratulations on the successful deployment of the backend api to Azure Container Apps where it is ready to service the frontend application. -------------------------------------------------------------------------------- /Labs/backend_api/media/acr_access_keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/acr_access_keys.png -------------------------------------------------------------------------------- /Labs/backend_api/media/container_app_delete_hello_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/container_app_delete_hello_world.png -------------------------------------------------------------------------------- /Labs/backend_api/media/container_app_edit_and_deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/container_app_edit_and_deploy.png -------------------------------------------------------------------------------- /Labs/backend_api/media/container_app_failed_revision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/container_app_failed_revision.png -------------------------------------------------------------------------------- /Labs/backend_api/media/container_app_log_stream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/container_app_log_stream.png -------------------------------------------------------------------------------- /Labs/backend_api/media/container_app_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/container_app_overview.png -------------------------------------------------------------------------------- /Labs/backend_api/media/container_app_ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/container_app_ready.png -------------------------------------------------------------------------------- /Labs/backend_api/media/container_deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/container_deploy.png -------------------------------------------------------------------------------- /Labs/backend_api/media/local_backend_docker_build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/local_backend_docker_build.png -------------------------------------------------------------------------------- /Labs/backend_api/media/local_backend_docker_push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/local_backend_docker_push.png -------------------------------------------------------------------------------- /Labs/backend_api/media/local_backend_docker_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/local_backend_docker_run.png -------------------------------------------------------------------------------- /Labs/backend_api/media/local_backend_running_console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/local_backend_running_console.png -------------------------------------------------------------------------------- /Labs/backend_api/media/local_backend_swagger_ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/local_backend_swagger_ui.png -------------------------------------------------------------------------------- /Labs/backend_api/media/local_backend_swagger_ui_ai_response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/local_backend_swagger_ui_ai_response.png -------------------------------------------------------------------------------- /Labs/backend_api/media/local_backend_swagger_ui_root_response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/backend_api/media/local_backend_swagger_ui_root_response.png -------------------------------------------------------------------------------- /Labs/deploy/azuredeploy.bicep: -------------------------------------------------------------------------------- 1 | /* *************************************************************** 2 | Azure Cosmos DB + Azure OpenAI Node.js developer guide lab 3 | ****************************************************************** 4 | This Azure resource deployment template uses some of the following practices: 5 | - [Abbrevation examples for Azure resources](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations) 6 | */ 7 | 8 | 9 | 10 | /* *************************************************************** */ 11 | /* Parameters */ 12 | /* *************************************************************** */ 13 | 14 | @description('Location where all resources will be deployed. This value defaults to the **East US** region.') 15 | @allowed([ 16 | 'eastus' 17 | 'francecentral' 18 | 'southcentralus' 19 | 'uksouth' 20 | 'westeurope' 21 | ]) 22 | param location string = 'eastus' 23 | 24 | @description(''' 25 | Unique name for the deployed services below. Max length 17 characters, alphanumeric only: 26 | - Azure Cosmos DB for MongoDB vCore 27 | - Azure OpenAI Service 28 | 29 | The name defaults to a unique string generated from the resource group identifier. Prefixed with 30 | **dg** 'developer guide' as the id may start with a number which is an invalid name for 31 | many resources. 32 | ''') 33 | @maxLength(17) 34 | param name string = 'dg${uniqueString(resourceGroup().id)}' 35 | 36 | @description('Specifies the SKU for the Azure App Service plan. Defaults to **B1**') 37 | @allowed([ 38 | 'B1' 39 | 'S1' 40 | 'P0v3' 41 | ]) 42 | param appServiceSku string = 'P0v3' //'B1' 43 | 44 | @description('Specifies the SKU for the Azure OpenAI resource. Defaults to **S0**') 45 | @allowed([ 46 | 'S0' 47 | ]) 48 | param openAiSku string = 'S0' 49 | 50 | @description('MongoDB vCore user Name. No dashes.') 51 | param mongoDbUserName string 52 | 53 | @description('MongoDB vCore password. 8-256 characters, 3 of the following: lower case, upper case, numeric, symbol.') 54 | @minLength(8) 55 | @maxLength(256) 56 | @secure() 57 | param mongoDbPassword string 58 | 59 | @description('Azure Container Registry SKU. Defaults to **Basic**') 60 | param acrSku string = 'Basic' 61 | 62 | /* *************************************************************** */ 63 | /* Variables */ 64 | /* *************************************************************** */ 65 | 66 | var openAiSettings = { 67 | name: '${name}-openai' 68 | sku: openAiSku 69 | maxConversationTokens: '100' 70 | maxCompletionTokens: '500' 71 | completionsModel: { 72 | name: 'gpt-35-turbo' 73 | version: '0613' 74 | deployment: { 75 | name: 'completions' 76 | } 77 | sku: { 78 | name: 'Standard' 79 | capacity: 120 80 | } 81 | } 82 | embeddingsModel: { 83 | name: 'text-embedding-ada-002' 84 | version: '2' 85 | deployment: { 86 | name: 'embeddings' 87 | } 88 | sku: { 89 | name: 'Standard' 90 | capacity: 120 91 | } 92 | } 93 | } 94 | 95 | var mongovCoreSettings = { 96 | mongoClusterName: '${name}-mongo' 97 | mongoClusterLogin: mongoDbUserName 98 | mongoClusterPassword: mongoDbPassword 99 | } 100 | 101 | var appServiceSettings = { 102 | plan: { 103 | name: '${name}-web' 104 | sku: appServiceSku 105 | } 106 | web: { 107 | name: '${name}-web' 108 | git: { 109 | repo: 'https://github.com/AzureCosmosDB/Azure-OpenAI-Developer-Guide-Front-End.git' 110 | branch: 'main' 111 | } 112 | } 113 | } 114 | 115 | /* *************************************************************** */ 116 | /* Azure Cosmos DB for MongoDB vCore */ 117 | /* *************************************************************** */ 118 | 119 | resource mongoCluster 'Microsoft.DocumentDB/mongoClusters@2023-03-01-preview' = { 120 | name: mongovCoreSettings.mongoClusterName 121 | location: location 122 | properties: { 123 | administratorLogin: mongovCoreSettings.mongoClusterLogin 124 | administratorLoginPassword: mongovCoreSettings.mongoClusterPassword 125 | serverVersion: '5.0' 126 | nodeGroupSpecs: [ 127 | { 128 | kind: 'Shard' 129 | sku: 'M30' 130 | diskSizeGB: 128 131 | enableHa: false 132 | nodeCount: 1 133 | } 134 | ] 135 | } 136 | } 137 | 138 | resource mongoFirewallRulesAllowAzure 'Microsoft.DocumentDB/mongoClusters/firewallRules@2023-03-01-preview' = { 139 | parent: mongoCluster 140 | name: 'allowAzure' 141 | properties: { 142 | startIpAddress: '0.0.0.0' 143 | endIpAddress: '0.0.0.0' 144 | } 145 | } 146 | 147 | resource mongoFirewallRulesAllowAll 'Microsoft.DocumentDB/mongoClusters/firewallRules@2023-03-01-preview' = { 148 | parent: mongoCluster 149 | name: 'allowAll' 150 | properties: { 151 | startIpAddress: '0.0.0.0' 152 | endIpAddress: '255.255.255.255' 153 | } 154 | } 155 | 156 | 157 | /* *************************************************************** */ 158 | /* Azure OpenAI */ 159 | /* *************************************************************** */ 160 | 161 | resource openAiAccount 'Microsoft.CognitiveServices/accounts@2023-05-01' = { 162 | name: openAiSettings.name 163 | location: location 164 | sku: { 165 | name: openAiSettings.sku 166 | } 167 | kind: 'OpenAI' 168 | properties: { 169 | customSubDomainName: openAiSettings.name 170 | publicNetworkAccess: 'Enabled' 171 | } 172 | } 173 | 174 | resource openAiEmbeddingsModelDeployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = { 175 | parent: openAiAccount 176 | name: openAiSettings.embeddingsModel.deployment.name 177 | sku: { 178 | name: openAiSettings.embeddingsModel.sku.name 179 | capacity: openAiSettings.embeddingsModel.sku.capacity 180 | } 181 | properties: { 182 | model: { 183 | format: 'OpenAI' 184 | name: openAiSettings.embeddingsModel.name 185 | version: openAiSettings.embeddingsModel.version 186 | } 187 | } 188 | } 189 | 190 | resource openAiCompletionsModelDeployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = { 191 | parent: openAiAccount 192 | name: openAiSettings.completionsModel.deployment.name 193 | dependsOn: [ 194 | openAiEmbeddingsModelDeployment 195 | ] 196 | sku: { 197 | name: openAiSettings.completionsModel.sku.name 198 | capacity: openAiSettings.completionsModel.sku.capacity 199 | } 200 | properties: { 201 | model: { 202 | format: 'OpenAI' 203 | name: openAiSettings.completionsModel.name 204 | version: openAiSettings.completionsModel.version 205 | } 206 | } 207 | } 208 | 209 | /* *************************************************************** */ 210 | /* Logging and instrumentation */ 211 | /* *************************************************************** */ 212 | 213 | resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { 214 | name: '${name}-loganalytics' 215 | location: location 216 | properties: { 217 | sku: { 218 | name: 'PerGB2018' 219 | } 220 | } 221 | } 222 | resource appServiceWebInsights 'Microsoft.Insights/components@2020-02-02' = { 223 | name: '${appServiceSettings.web.name}-appi' 224 | location: location 225 | kind: 'web' 226 | properties: { 227 | Application_Type: 'web' 228 | WorkspaceResourceId: logAnalytics.id 229 | } 230 | } 231 | 232 | /* *************************************************************** */ 233 | /* App Plan Hosting - Azure App Service Plan */ 234 | /* *************************************************************** */ 235 | resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { 236 | name: '${appServiceSettings.plan.name}-asp' 237 | location: location 238 | sku: { 239 | name: appServiceSettings.plan.sku 240 | } 241 | kind: 'linux' 242 | properties: { 243 | reserved: true 244 | } 245 | } 246 | 247 | 248 | /* *************************************************************** */ 249 | /* Front-end Web App Hosting - Azure App Service */ 250 | /* *************************************************************** */ 251 | 252 | resource appServiceWeb 'Microsoft.Web/sites@2022-03-01' = { 253 | name: appServiceSettings.web.name 254 | location: location 255 | properties: { 256 | serverFarmId: appServicePlan.id 257 | httpsOnly: true 258 | siteConfig: { 259 | linuxFxVersion: 'NODE|20-lts' 260 | appCommandLine: 'pm2 serve /home/site/wwwroot/dist --no-daemon --spa' 261 | alwaysOn: true 262 | } 263 | } 264 | } 265 | 266 | resource appServiceWebSettings 'Microsoft.Web/sites/config@2022-03-01' = { 267 | parent: appServiceWeb 268 | name: 'appsettings' 269 | kind: 'string' 270 | properties: { 271 | APPINSIGHTS_INSTRUMENTATIONKEY: appServiceWebInsights.properties.InstrumentationKey 272 | API_ENDPOINT: 'https://${backendApiContainerApp.properties.configuration.ingress.fqdn}' 273 | } 274 | } 275 | 276 | resource appServiceWebDeployment 'Microsoft.Web/sites/sourcecontrols@2021-03-01' = { 277 | parent: appServiceWeb 278 | name: 'web' 279 | properties: { 280 | repoUrl: appServiceSettings.web.git.repo 281 | branch: appServiceSettings.web.git.branch 282 | isManualIntegration: true 283 | } 284 | } 285 | 286 | 287 | /* *************************************************************** */ 288 | /* Registry for Back-end API Image - Azure Container Registry */ 289 | /* *************************************************************** */ 290 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' = { 291 | name: replace('${name}registry','-', '') 292 | location: location 293 | sku: { 294 | name: acrSku 295 | } 296 | properties: { 297 | adminUserEnabled: true 298 | } 299 | } 300 | 301 | /* *************************************************************** */ 302 | /* Container environment - Azure Container App Environment */ 303 | /* *************************************************************** */ 304 | resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { 305 | name: '${name}-containerappenv' 306 | location: location 307 | properties: { 308 | appLogsConfiguration: { 309 | destination: 'log-analytics' 310 | logAnalyticsConfiguration: { 311 | customerId: logAnalytics.properties.customerId 312 | sharedKey: logAnalytics.listKeys().primarySharedKey 313 | } 314 | } 315 | workloadProfiles: [ 316 | { 317 | name: 'Warm' 318 | minimumCount: 1 319 | maximumCount: 10 320 | workloadProfileType: 'E4' 321 | } 322 | ] 323 | infrastructureResourceGroup: 'ME_${resourceGroup().name}' 324 | } 325 | } 326 | 327 | /* *************************************************************** */ 328 | /* Back-end API App Application - Azure Container App */ 329 | /* deploys default hello world */ 330 | /* *************************************************************** */ 331 | resource backendApiContainerApp 'Microsoft.App/containerApps@2023-05-01' = { 332 | name: '${name}-api' 333 | location: location 334 | properties: { 335 | environmentId: containerAppEnvironment.id 336 | configuration: { 337 | ingress: { 338 | external: true 339 | targetPort: 80 340 | allowInsecure: false 341 | traffic: [ 342 | { 343 | latestRevision: true 344 | weight: 100 345 | } 346 | ] 347 | corsPolicy: { 348 | allowCredentials: false 349 | allowedHeaders: [ 350 | '*' 351 | ] 352 | allowedOrigins: [ 353 | '*' 354 | ] 355 | } 356 | } 357 | registries: [ 358 | { 359 | server: containerRegistry.name 360 | username: containerRegistry.properties.loginServer 361 | passwordSecretRef: 'container-registry-password' 362 | } 363 | ] 364 | secrets: [ 365 | { 366 | name: 'container-registry-password' 367 | value: containerRegistry.listCredentials().passwords[0].value 368 | } 369 | ] 370 | } 371 | template: { 372 | containers: [ 373 | { 374 | name: 'hello-world' 375 | image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' 376 | resources: { 377 | cpu: 1 378 | memory: '2Gi' 379 | } 380 | } 381 | ] 382 | scale: { 383 | minReplicas: 1 384 | maxReplicas: 1 385 | } 386 | } 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /Labs/deploy/azuredeploy.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 | "location": { 6 | "value": "eastus" 7 | }, 8 | "openAiSku": { 9 | "value": "S0" 10 | }, 11 | "mongoDbUserName": { 12 | "value": "cosmicworksadmin" 13 | }, 14 | 15 | "mongoDbPassword": { 16 | "value": "" 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Labs/deploy/deploy.md: -------------------------------------------------------------------------------- 1 | # Solution deployment 2 | 3 | ## Prerequisites 4 | 5 | - Owner on Azure subscription 6 | - Account approved for Azure OpenAI service 7 | - Azure CLI installed 8 | - Azure PowerShell installed 9 | 10 | ## Clone the repository 11 | 12 | Create a folder to house the repository. Open a terminal and navigate to the folder. Clone the repository, then navigate to the `Labs/deploy` folder within the repository. 13 | 14 | ```bash 15 | git clone https://github.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide.git 16 | 17 | cd Azure-OpenAI-Node.js-Developer-Guide 18 | cd Labs 19 | cd deploy 20 | ``` 21 | 22 | Open the `azuredeploy.parameters.json` file, then edit the `mongoDbPassword` to a password you wish to use for the MongoDB Admin User: 23 | 24 | ![editing the azuredeploy.parameters.json file with mongoDBPassword parameter highlighted](images/editor-azuredeploy-parameters-json-password.png) 25 | 26 | When the Azure Bicep template is deployed, this parameters file will be used to configure the Mongo DB Password and other parameters when provisioning the Azure resources. 27 | 28 | ## Login to Azure 29 | 30 | Open a terminal window and log in to Azure using the following command: 31 | 32 | ```Powershell 33 | Connect-AzAccount 34 | ``` 35 | 36 | ### Set the desired subscription (Optional) 37 | 38 | If you have more than one subscription associated with your account, set the desired subscription using the following command: 39 | 40 | ```Powershell 41 | Set-AzContext -SubscriptionId 42 | ``` 43 | 44 | ## Create resource group 45 | 46 | ```Powershell 47 | New-AzResourceGroup -Name mongo-devguide-rg -Location 'eastus' 48 | ``` 49 | 50 | ## Deploy using bicep template 51 | 52 | Deploy the solution resources using the following command (this will take a few minutes to run): 53 | 54 | ```Powershell 55 | New-AzResourceGroupDeployment -ResourceGroupName mongo-devguide-rg -TemplateFile .\azuredeploy.bicep -TemplateParameterFile .\azuredeploy.parameters.json -c 56 | ``` 57 | -------------------------------------------------------------------------------- /Labs/deploy/images/editor-azuredeploy-parameters-json-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/deploy/images/editor-azuredeploy-parameters-json-password.png -------------------------------------------------------------------------------- /Labs/explore_and_use_models/README.md: -------------------------------------------------------------------------------- 1 | # Lab - Explore and use Azure OpenAI models from code 2 | 3 | ## OpenAI Client Library 4 | 5 | When integrating Azure OpenAI service in a solution written in Node.js, the OpenAI NPM client library is used. This library is maintained by OpenAI, and is compatible with the Azure OpenAI service. 6 | 7 | Install the latest openai client library using `npm`: 8 | 9 | ```bash 10 | npm install @azure/openai 11 | ``` 12 | 13 | Create a new `app.js` file for the Node.js program, and add the following variable definition using `require` so the app can use the OpenAI library. 14 | 15 | ```javascript 16 | const { OpenAIClient, AzureKeyCredential } = require("@azure/openai"); 17 | ``` 18 | 19 | ## Chat completions 20 | 21 | Create the Azure OpenAI client to call the Azure OpenAI Chat completion API: 22 | 23 | ```javascript 24 | const client = new OpenAIClient( 25 | "") 27 | ); 28 | ``` 29 | 30 | Once the Azure OpenAI client to be used for Chat completion has been created, the next step is to call the `.getCompletions` method on the client to perform a chat completion. 31 | 32 | ```javascript 33 | const chatResponse = client.getChatCompletions( 34 | "completions", // deployment name 35 | [ 36 | {role: "system", content: "You are a helpful, fun and friendly sales assistant for Cosmic Works, a bicycle and bicycle accessories store."}, 37 | {role: "user", content: "Do you sell bicycles?"}, 38 | {role: "assistant", content: "Yes, we do sell bicycles. What kind of bicycle are you looking for?"}, 39 | {role: "user", content: "I'm not sure what I'm looking for. Could you help me decide?"} 40 | ]); 41 | ``` 42 | 43 | The `.getCompletions` method returns a Javascript Promise object for asynchronous programming. In this example the next step is to call the `.then` method on the promise, passing it a function that writes the response from Azure OpenAI to the console. 44 | 45 | ```javascript 46 | chatResponse.then((result) => { 47 | for (const choice of result.choices) { 48 | console.log(choice.message.content); 49 | } 50 | }).catch((err) => console.log(`Error: ${err}`)); 51 | ``` 52 | 53 | The response from the Azure OpenAI service should be similar to the following: 54 | 55 | ```text 56 | Absolutely, I'd be glad to help you find the perfect bicycle. To narrow down the options, let's consider a few questions: 57 | 58 | 1. **Purpose**: What do you want to use the bike for? Are you looking for a bike for commuting, road cycling, mountain biking, recreational riding, or maybe a versatile hybrid? 59 | 60 | 2. **Riding Surface**: Where do you plan to ride? Are you going to be on paved roads, trails, or a mix of both? 61 | 62 | 3. **Experience Level**: Are you a beginner, intermediate, or experienced cyclist? 63 | 64 | 4. **Comfort and Fit**: Do you have any specific comfort needs or preferences? For example, some riders prefer a more upright riding position, while others might want a bike that allows for a more aggressive posture. 65 | 66 | 5. **Budget**: How much are you looking to spend on your new bike? 67 | 68 | 6. **Features**: Are there any specific features you're interested in? For example, some people want a bike with space for luggage racks and fenders, while others might prioritize a lightweight frame and high-performance components. 69 | 70 | 7. **Frequency of Use**: How often do you anticipate riding the bike? 71 | 72 | Once I have a better understanding of what you're looking for, I can recommend some options that would be a good fit for your needs. 73 | ``` 74 | -------------------------------------------------------------------------------- /Labs/explore_and_use_models/completed/app.js: -------------------------------------------------------------------------------- 1 | const { OpenAIClient, AzureKeyCredential } = require("@azure/openai"); 2 | 3 | const client = new OpenAIClient( 4 | "") 6 | ); 7 | 8 | const chatResponse = client.getChatCompletions( 9 | "completions", // deployment name 10 | [ 11 | {role: "system", content: "You are a helpful, fun and friendly sales assistant for Cosmic Works, a bicycle and bicycle accessories store."}, 12 | {role: "user", content: "Do you sell bicycles?"}, 13 | {role: "assistant", content: "Yes, we do sell bicycles. What kind of bicycle are you looking for?"}, 14 | {role: "user", content: "I'm not sure what I'm looking for. Could you help me decide?"} 15 | ]); 16 | 17 | chatResponse.then((result) => { 18 | for (const choice of result.choices) { 19 | console.log(choice.message.content); 20 | } 21 | }).catch((err) => { 22 | console.log(JSON.stringify(err)); 23 | console.log(`Error: ${err}`) 24 | }); 25 | 26 | /* 27 | https://learn.microsoft.com/en-us/azure/ai-services/openai/quickstart?tabs=command-line%2Cpython&pivots=programming-language-javascript 28 | */ -------------------------------------------------------------------------------- /Labs/explore_and_use_models/completed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@azure/openai": "^1.0.0-beta.11" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/.env.example: -------------------------------------------------------------------------------- 1 | MONGODB_URI=mongodb+srv://:@.mongocluster.cosmos.azure.com/?tls=true&authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000 -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/README.md: -------------------------------------------------------------------------------- 1 | # Lab - Create your first Cosmos DB for MongoDB application 2 | 3 | This lab demonstrates the creation of a Cosmos DB for MongoDB application. The lab will cover creating a database client and using that client to create a database, collection, and documents. The lab will also cover querying for documents and updating and deleting documents. 4 | 5 | ## Create a MongoDB client and connect to the Cosmos DB for MongoDB API service 6 | 7 | 1. In the lab folder, create a `.env` file and add the following environment variables, replace `` with your Cosmos DB for MongoDB API service connection string: 8 | 9 | ```text 10 | MONGODB_URI= 11 | ``` 12 | 13 | 2. In Visual Studio Code, open a terminal window and navigate to the lab folder `first_cosmos_db_application`. 14 | 15 | 3. Install the required packages by running the following command in the terminal window: 16 | 17 | ```bash 18 | npm install 19 | ``` 20 | 21 | 4. Open the `index.js` file, at the top of the file, add the following code to import the MongoDB client from the **mongodb** package: 22 | 23 | ```javascript 24 | const { MongoClient } = require('mongodb'); 25 | ``` 26 | 27 | 5. In the `main` function, add the following code to initialize the MongoDB client. 28 | 29 | ```javascript 30 | const client = new MongoClient(process.env.MONGODB_URI); 31 | ``` 32 | 33 | 6. Directly beneath the client initialization, add the following code to connect to the Cosmos DB for MongoDB database service using the client. This code connects to the database service and outputs messages to the console to indicate the connection status. 34 | 35 | ```javascript 36 | try { 37 | await client.connect(); 38 | console.log('Connected to MongoDB'); 39 | } catch (err) { 40 | console.error(err); 41 | } finally { 42 | await client.close(); 43 | console.log('Disconnected from MongoDB'); 44 | } 45 | ``` 46 | 47 | 7. Verify the code listing in the `index.js` file matches the following code: 48 | 49 | ```javascript 50 | require('dotenv').config(); 51 | const { MongoClient } = require('mongodb'); 52 | 53 | async function main() { 54 | const client = new MongoClient(process.env.MONGODB_URI); 55 | try { 56 | await client.connect(); 57 | console.log('Connected to MongoDB'); 58 | } catch (err) { 59 | console.error(err); 60 | } finally { 61 | await client.close(); 62 | console.log('Disconnected from MongoDB'); 63 | } 64 | } 65 | main().catch(console.error); 66 | ``` 67 | 68 | 8. Save the changes to the file, and run the application by running the following command in the terminal window. This command will output the connection success and disconnection messages to the console. 69 | 70 | ```bash 71 | npm start 72 | ``` 73 | 74 | ![Console output showing a successful connection and disconnection from the database.](media/db_connection_output.png "Database connectivity console output") 75 | 76 | ## Create a MongoDB database 77 | 78 | When using the `mongodb` client, the creation of a database is automatic when referenced. No specific api calls to create a database are required, if a database already exists, a reference to the database is returned. 79 | 80 | 1. In the `index.js` file, after the database connection code, add the following code to obtain a reference to a database. Save the file. 81 | 82 | ```javascript 83 | const db = client.db('cosmic_works'); 84 | ``` 85 | 86 | >**Note:**: That the creation of databases and collections are lazy, meaning they will not be created until a document is inserted into a collection. Running the application now will not create the database. 87 | 88 | ## Create a collection 89 | 90 | Creating collections behaves similarly to the database creation. If the collection does not exist, it will be created. It's important to note that databases and collections are lazily created. This means that the database and collection will not be created until the first document is inserted. 91 | 92 | 1. In the `index.js` file, after the database reference code, add the following code to obtain a reference to a collection. Save the file. 93 | 94 | ```javascript 95 | const products = db.collection('products'); 96 | ``` 97 | 98 | >**Note:**: Remember that the creation of databases and collections are lazy, meaning they will not be created until a document is inserted into a collection. Running the application now will not create the database or the collection at this point. 99 | 100 | ## Create a document 101 | 102 | Documents in Cosmos DB API for MongoDB are represented as JSON objects. One method of creating a document is using the `insertOne` method. This method takes a single document and inserts it into the database. This operation returns an [InsertOneResult](https://mongodb.github.io/node-mongodb-native/6.3/interfaces/InsertOneResult.html) object that contains the property **insertedId**. This property contains the unique identifier of the document that was just inserted. 103 | 104 | 1. In the `index.js` file, after the collection reference code, add the following code to insert a document into the collection. Save the file. 105 | 106 | ```javascript 107 | const product = { 108 | _id: '2BA4A26C-A8DB-4645-BEB9-F7D42F50262E', 109 | categoryId: '56400CF3-446D-4C3F-B9B2-68286DA3BB99', 110 | categoryName: 'Bikes, Mountain Bikes', 111 | sku: 'BK-M18S-42', 112 | name: 'Mountain-100 Silver, 42', 113 | description: 'The product called "Mountain-500 Silver, 42"', 114 | price: 742.42 115 | }; 116 | const result = await products.insertOne(product); 117 | console.log(`A product was inserted with the _id: ${result.insertedId}`); 118 | ``` 119 | 120 | 2. Run the application. In addition to the connectivity messages in addition to the document insertion message. 121 | 122 | ```bash 123 | npm start 124 | ``` 125 | 126 | ![Console output showing a successful connection, document insertion, and disconnection messages.](media/db_insert_output.png "Database document insertion console output") 127 | 128 | 3. Return to `index.js` and delete or comment out the code from step 1 of this section. This will ensure that the same record gets re-added each time the application is run. 129 | 130 | ## Read a document 131 | 132 | The insertion of the product in the previous section automatically created the database and collection. The `findOne` method is used to retrieve a single document from the database. The `findOne` method takes a filter as an argument. This filter is used to find the document in the database. In this case, the filter is the unique identifier or **_id** of the document that was just inserted. 133 | 134 | 1. In the `index.js` file, after the collection reference code, add the following code to retrieve a document from the collection. Save the file. 135 | 136 | ```javascript 137 | const product = await products.findOne({ _id: '2BA4A26C-A8DB-4645-BEB9-F7D42F50262E' }); 138 | console.log("Found the product:", product); 139 | ``` 140 | 141 | 2. Run the application. In addition to the connectivity messages, the document retrieval message will be displayed. 142 | 143 | ```bash 144 | npm start 145 | ``` 146 | 147 | ![Console output displays the connectivity messages as well as the retrieval of the document message.](media/db_retrieve_output.png "Document is retrieved.") 148 | 149 | ## Update a document 150 | 151 | The `findOneAndUpdate` method is used to update a single document in the database. This method takes a filter and an update as arguments. The filter is used to find the document to update. The update is a dictionary of the properties to update. In this case, the `findOneAndUpdate` method is used to update the name property of the document. The updated document is the return value for this method. 152 | 153 | 1. In the `index.js` file, after the collection reference code and before the `findOne` code, add the following code to update a document in the collection. Save the file. 154 | 155 | ```javascript 156 | const options = { returnDocument: 'after' }; 157 | const updated = await products.findOneAndUpdate( 158 | { _id: '2BA4A26C-A8DB-4645-BEB9-F7D42F50262E' }, 159 | { $set: { price: 14242.42 } }, 160 | options); 161 | ``` 162 | 163 | 2. Run the application. In addition to the connectivity messages, the document retrieved message will be displayed with the updated price. 164 | 165 | ```bash 166 | npm start 167 | ``` 168 | 169 | ![Console output displays the connectivity messages as well as the retrieval of the document message with the updated price.](media/db_update_output.png "Document is updated.") 170 | 171 | 3. Remove the code that was just added in this section from the `index.js` file and save the file. 172 | 173 | ## Delete a document 174 | 175 | The `deleteOne` method is used to delete a single document from the database. This method takes a filter as an argument. This filter is used to find the document to delete. In this case, the filter is the unique identifier or `_id` of the document that was just inserted and updated. The `deleteOne` method returns a [`DeleteResult`](https://mongodb.github.io/node-mongodb-native/6.3/interfaces/DeleteResult.html) object. 176 | 177 | 1. In the `index.js` file, after the collection reference code and before the `findOne` code, add the following code to delete a document from the collection. Save the file. 178 | 179 | ```javascript 180 | const result = await products.deleteOne({ _id: '2BA4A26C-A8DB-4645-BEB9-F7D42F50262E' }); 181 | console.log(`Number of documents deleted: ${result.deletedCount}`); 182 | ``` 183 | 184 | 2. Run the application. In addition to the connectivity messages, the document deletion message will be displayed. Note the retrieval message displays `null` as the document was deleted. 185 | 186 | ```bash 187 | npm start 188 | ``` 189 | 190 | ![Console output displays the connectivity messages as well as the deletion of the document message.](media/db_delete_output.png "Document is deleted.") 191 | 192 | 3. Remove the code that was just added in this section, as well as the `findOne` code from the `index.js` file and save the file. 193 | 194 | ## Query for multiple documents 195 | 196 | In this section, multiple product documents are written to the database using a `bulkWrite` operation. Bulk operations will be covered in more detail in the next lab. Having multiple documents in the products collection will allow for querying for multiple documents using the `find` method. This method takes a filter as an argument. This filter is used to find the documents to return. In this case, the filter is empty and therefore will return all documents in the collection. The `find` method returns a cursor that can be converted to an array of documents using the `toArray` method. 197 | 198 | 1. In the `index.js` file, add the following code to insert multiple product documents in the database. Place this code directly beneath the collection reference code. 199 | 200 | ```javascript 201 | const productsToInsert = [ 202 | { 203 | _id: "2BA4A26C-A8DB-4645-BEB9-F7D42F50262E", 204 | categoryId: "56400CF3-446D-4C3F-B9B2-68286DA3BB99", 205 | categoryName: "Bikes, Mountain Bikes", 206 | sku:"BK-M18S-42", 207 | name: "Mountain-100 Silver, 42", 208 | description: 'The product called "Mountain-500 Silver, 42"', 209 | price: 742.42 210 | }, 211 | { 212 | _id: "027D0B9A-F9D9-4C96-8213-C8546C4AAE71", 213 | categoryId: "26C74104-40BC-4541-8EF5-9892F7F03D72", 214 | categoryName: "Components, Saddles", 215 | sku: "SE-R581", 216 | name: "LL Road Seat/Saddle", 217 | description: 'The product called "LL Road Seat/Saddle"', 218 | price: 27.12 219 | }, 220 | { 221 | _id: "4E4B38CB-0D82-43E5-89AF-20270CD28A04", 222 | categoryId: "75BF1ACB-168D-469C-9AA3-1FD26BB4EA4C", 223 | categoryName: "Bikes, Touring Bikes", 224 | sku: "BK-T44U-60", 225 | name: "Touring-2000 Blue, 60", 226 | description: 'The product called Touring-2000 Blue, 60"', 227 | price: 1214.85 228 | }, 229 | { 230 | _id: "5B5E90B8-FEA2-4D6C-B728-EC586656FA6D", 231 | categoryId: "75BF1ACB-168D-469C-9AA3-1FD26BB4EA4C", 232 | categoryName: "Bikes, Touring Bikes", 233 | sku: "BK-T79Y-60", 234 | name: "Touring-1000 Yellow, 60", 235 | description: 'The product called Touring-1000 Yellow, 60"', 236 | price: 2384.07 237 | }, 238 | { 239 | _id: "7BAA49C9-21B5-4EEF-9F6B-BCD6DA7C2239", 240 | categoryId: "26C74104-40BC-4541-8EF5-9892F7F03D72", 241 | categoryName: "Components, Saddles", 242 | sku: "SE-R995", 243 | name: "HL Road Seat/Saddle", 244 | description: 'The product called "HL Road Seat/Saddle"', 245 | price: 52.64, 246 | } 247 | ] 248 | const result = await products.bulkWrite( 249 | productsToInsert.map((product) => ({ 250 | insertOne: { 251 | document: product 252 | } 253 | })) 254 | ); 255 | console.log("Bulk write operation result:", result); 256 | ``` 257 | 258 | 2. Immediately following the preceding code, add the following code to query for multiple documents in the collection. Save the file. 259 | 260 | ```javascript 261 | const allProducts = await products.find({}).toArray(); 262 | console.log("Found the following products:", allProducts); 263 | ``` 264 | 265 | 3. Run the application. In addition to the connectivity messages, the bulk write operation result showing the inserted id values and the retrieval of all documents output to the console. 266 | 267 | ```bash 268 | npm start 269 | ``` 270 | 271 | ![The first part of the console output displays the connectivity messages as well as the bulk write operation result.](media/db_bulk_write_output.png "Bulk write operation result") 272 | 273 | ![The second part of the console output displays the retrieval of all documents.](media/db_retrieve_all_output.png "Retrieval of all documents") 274 | 275 | 4. Remove all code added in this section, and save the `index.js` file. 276 | 277 | ## Clean up resources 278 | 279 | Clean up the items created in this lab by deleting the MongoDB database. 280 | 281 | 1. In `index.js`, add the following code after the collection reference code to delete the database. Save the file. 282 | 283 | ```javascript 284 | await db.dropDatabase(); 285 | ``` 286 | 287 | 2. Run the application. In addition to the connectivity messages, the database deletion message will be displayed. 288 | 289 | ```bash 290 | npm start 291 | ``` 292 | 293 | ![The console output displays with the database service connection messages as well as a message that the database has been dropped.](media/delete_database_output.png "Database dropped") 294 | -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | 3 | async function main() { 4 | } 5 | 6 | main().catch(console.error); 7 | -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/db_bulk_write_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/db_bulk_write_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/db_connection_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/db_connection_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/db_delete_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/db_delete_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/db_insert_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/db_insert_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/db_retrieve_all_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/db_retrieve_all_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/db_retrieve_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/db_retrieve_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/db_update_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/db_update_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/media/delete_database_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/first_cosmos_db_application/media/delete_database_output.png -------------------------------------------------------------------------------- /Labs/first_cosmos_db_application/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-nodejs-devguide-first-cosmos-db-application", 3 | "version": "1.0.0", 4 | "description": "A Node.js application that connects to MongoDB", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "dependencies": { 10 | "mongodb": "6.3.0", 11 | "dotenv": "16.4.4" 12 | }, 13 | "author": "Microsoft", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /Labs/langchain/.env.example: -------------------------------------------------------------------------------- 1 | AZURE_COSMOSDB_CONNECTION_STRING= 2 | AZURE_OPENAI_API_INSTANCE_NAME= 3 | AZURE_OPENAI_API_KEY= 4 | AZURE_OPENAI_API_DEPLOYMENT_NAME=completions 5 | AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME=embeddings 6 | AZURE_OPENAI_API_VERSION=2023-09-01-preview -------------------------------------------------------------------------------- /Labs/langchain/catch_up.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { MongoClient } = require('mongodb'); 3 | const { OpenAIClient, AzureKeyCredential} = require("@azure/openai"); 4 | 5 | // set up the MongoDB client 6 | const dbClient = new MongoClient(process.env.AZURE_COSMOSDB_CONNECTION_STRING); 7 | // set up the Azure OpenAI client 8 | const embeddingsDeploymentName = "embeddings"; 9 | const aoaiClient = new OpenAIClient("https://" + process.env.AZURE_OPENAI_API_INSTANCE_NAME + ".openai.azure.com/", 10 | new AzureKeyCredential(process.env.AZURE_OPENAI_API_KEY)); 11 | 12 | async function main() { 13 | try { 14 | await dbClient.connect(); 15 | console.log('Connected to MongoDB'); 16 | const db = dbClient.db('cosmic_works'); 17 | 18 | // Load product data 19 | console.log('Loading product data') 20 | // Initialize the product collection pointer (will automatically be created if it doesn't exist) 21 | const productCollection = db.collection('products'); 22 | // Load the product data from the raw data from Cosmic Works while also removing the system properties 23 | const productRawData = "https://cosmosdbcosmicworks.blob.core.windows.net/cosmic-works-small/product.json"; 24 | const productData = (await (await fetch(productRawData)).json()) 25 | .map(prod => cleanData(prod)); 26 | // Delete all existing products and insert the new data 27 | await productCollection.deleteMany({}); 28 | // Utilize bulkWrite to insert all the products at once 29 | var result = await productCollection.bulkWrite( 30 | productData.map((product) => ({ 31 | insertOne: { 32 | document: product 33 | } 34 | })) 35 | ); 36 | console.log(`${result.insertedCount} products inserted`); 37 | 38 | await addCollectionContentVectorField(db, 'products'); 39 | 40 | } catch (err) { 41 | console.error(err); 42 | } finally { 43 | await dbClient.close(); 44 | console.log('Disconnected from MongoDB'); 45 | } 46 | } 47 | 48 | async function generateEmbeddings(text) { 49 | const embeddings = await aoaiClient.getEmbeddings(embeddingsDeploymentName, text); 50 | // Rest period to avoid rate limiting on Azure OpenAI 51 | await new Promise(resolve => setTimeout(resolve, 500)); 52 | return embeddings.data[0].embedding; 53 | } 54 | 55 | async function addCollectionContentVectorField(db, collectionName) { 56 | const collection = db.collection(collectionName); 57 | const docs = await collection.find({}).toArray(); 58 | const bulkOperations = []; 59 | console.log(`Generating content vectors for ${docs.length} documents in ${collectionName} collection`); 60 | for (let i=0; i 0) { 81 | console.log(`Persisting the generated content vectors in the ${collectionName} collection using bulkWrite upserts`); 82 | await collection.bulkWrite(bulkOperations); 83 | console.log(`Finished persisting the content vectors to the ${collectionName} collection`); 84 | } 85 | 86 | //check to see if the vector index already exists on the collection 87 | console.log(`Checking if vector index exists in the ${collectionName} collection`) 88 | const vectorIndexExists = await collection.indexExists('VectorSearchIndex'); 89 | if (!vectorIndexExists) { 90 | await db.command({ 91 | "createIndexes": collectionName, 92 | "indexes": [ 93 | { 94 | "name": "VectorSearchIndex", 95 | "key": { 96 | "contentVector": "cosmosSearch" 97 | }, 98 | "cosmosSearchOptions": { 99 | "kind": "vector-ivf", 100 | "numLists": 1, 101 | "similarity": "COS", 102 | "dimensions": 1536 103 | } 104 | } 105 | ] 106 | }); 107 | console.log(`Created vector index on contentVector field on ${collectionName} collection`); 108 | } 109 | else { 110 | console.log(`Vector index already exists on contentVector field in the ${collectionName} collection`); 111 | } 112 | } 113 | 114 | function cleanData(obj) { 115 | cleaned = Object.fromEntries( 116 | Object.entries(obj).filter(([key, _]) => !key.startsWith('_')) 117 | ); 118 | //rename id field to _id 119 | cleaned["_id"] = cleaned["id"]; 120 | delete cleaned["id"]; 121 | return cleaned; 122 | } 123 | 124 | 125 | main().catch(console.error); -------------------------------------------------------------------------------- /Labs/langchain/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { MongoClient } = require('mongodb'); 3 | 4 | // set up the MongoDB client 5 | const dbClient = new MongoClient(process.env.AZURE_COSMOSDB_CONNECTION_STRING); 6 | 7 | async function main() { 8 | try { 9 | await dbClient.connect(); 10 | console.log("Connected to MongoDB"); 11 | 12 | } catch (err) { 13 | console.error(err); 14 | } finally { 15 | await dbClient.close(); 16 | console.log('Disconnected from MongoDB'); 17 | } 18 | } 19 | 20 | main().catch(console.error); -------------------------------------------------------------------------------- /Labs/langchain/media/agent_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/langchain/media/agent_output.png -------------------------------------------------------------------------------- /Labs/langchain/media/agent_verbose_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/langchain/media/agent_verbose_output.png -------------------------------------------------------------------------------- /Labs/langchain/media/initial_vector_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/langchain/media/initial_vector_search.png -------------------------------------------------------------------------------- /Labs/langchain/media/rag_chain_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/langchain/media/rag_chain_output.png -------------------------------------------------------------------------------- /Labs/langchain/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-nodejs-devguide-langchain", 3 | "version": "1.0.0", 4 | "description": "A Node.js application that uses LangChain to perform RAG search and function calling.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "dependencies": { 10 | "mongodb": "6.3.0", 11 | "dotenv": "16.4.4", 12 | "@azure/openai": "1.0.0-beta.11", 13 | "langchain": "0.1.21", 14 | "@langchain/community": "0.0.32" 15 | }, 16 | "author": "Microsoft", 17 | "license": "MIT" 18 | } 19 | -------------------------------------------------------------------------------- /Labs/load_data/.env.example: -------------------------------------------------------------------------------- 1 | MONGODB_URI=mongodb+srv://:@.mongocluster.cosmos.azure.com/?tls=true&authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000 -------------------------------------------------------------------------------- /Labs/load_data/README.md: -------------------------------------------------------------------------------- 1 | # Lab - Load data into Cosmos DB using the MongoDB API 2 | 3 | This lab demonstrates bulk loading of data from the Cosmic Works JSON files into Cosmos DB for MongoDB. 4 | 5 | ## Setup the lab environment 6 | 7 | 1. In the lab folder, create a `.env` file and add the following environment variables, replace `` with your Cosmos DB for MongoDB API service connection string: 8 | 9 | ```text 10 | MONGODB_URI= 11 | ``` 12 | 13 | 2. In Visual Studio Code, open a terminal window and navigate to the lab folder `load_data`. 14 | 15 | 3. Install the required packages by running the following command in the terminal window: 16 | 17 | ```bash 18 | npm install 19 | ``` 20 | 21 | ## Bulk load product data 22 | 23 | There is more than one option when performing bulk operations in Cosmos DB for MongoDB. In this section, data will be loaded using the `bulkWrite` method. The `bulkWrite` method is used to perform multiple write operations in a single batch, write operations can include a mixture of insert, update, and delete operations. 24 | 25 | 1. Open the `index.js` file, and directly beneath the `const db = client.db('cosmic_works');` line, add the following code to fetch the product data from the Cosmic Works repository: 26 | 27 | ```javascript 28 | // Load product data 29 | console.log('Loading product data') 30 | // Initialize the product collection pointer (will automatically be created if it doesn't exist) 31 | const productCollection = db.collection('products'); 32 | // Load the product data from the raw data from Cosmic Works while also removing the system properties 33 | const productRawData = "https://cosmosdbcosmicworks.blob.core.windows.net/cosmic-works-small/product.json"; 34 | const productData = (await (await fetch(productRawData)).json()) 35 | .map(prod => cleanData(prod)); 36 | ``` 37 | 38 | 2. Optionally, append the following code (to the code in the previous step) to delete any existing products in the collection. This helps if the application is run multiple times so there is no duplicates. 39 | 40 | ```javascript 41 | // Delete any existing products 42 | console.log('Deleting existing products'); 43 | await productCollection.deleteMany({}); 44 | ``` 45 | 46 | 3. Append the following code (to the code in the previous step) to bulk load the product data into the collection: 47 | 48 | ```javascript 49 | var result = await productCollection.bulkWrite( 50 | productData.map((product) => ({ 51 | insertOne: { 52 | document: product 53 | } 54 | })) 55 | ); 56 | console.log(`${result.insertedCount} products inserted`); 57 | ``` 58 | 59 | 4. Save the `index.js` file. 60 | 61 | 5. Run the application by executing the following command in the terminal window: 62 | 63 | ```bash 64 | npm start 65 | ``` 66 | 67 | ![A console window displays indicating products have been inserted into the products collection](media/products_loaded.png "Products loaded") 68 | 69 | ## Bulk load of customer and sales data 70 | 71 | In this section, data will be loaded using the `insertMany` method. The `insertMany` method is used to insert multiple documents into a collection, it differs from the `bulkWrite` method in that it only supports insert operations. 72 | 73 | Customer data and sales data are also combined in a single JSON source, some pre-processing is required to separate the data into two separate collections. 74 | 75 | 1. Open the `index.js` file, and directly beneath the code for adding products, append the following code to fetch the customer and sales data from the Cosmic Works repository: 76 | 77 | ```javascript 78 | // Load customer and sales data 79 | console.log('Retrieving combined Customer/Sales data'); 80 | const customerCollection = db.collection('customers'); 81 | const salesCollection = db.collection('sales'); 82 | const custSalesRawData = "https://cosmosdbcosmicworks.blob.core.windows.net/cosmic-works-small/customer.json"; 83 | const custSalesData = (await (await fetch(custSalesRawData)).json()) 84 | .map(custSales => cleanData(custSales)); 85 | ``` 86 | 87 | 2. Split the customer data from the sales data by appending the following code (to the code in the previous step): 88 | 89 | ```javascript 90 | console.log("Split customer and sales data"); 91 | const customerData = custSalesData.filter(cust => cust["type"] === "customer"); 92 | const salesData = custSalesData.filter(sales => sales["type"] === "salesOrder"); 93 | ``` 94 | 95 | 3. Append the following code (to the code in the previous step) to bulk load the customer data into the collection using the `insertMany` method: 96 | 97 | ```javascript 98 | console.log("Loading customer data"); 99 | await customerCollection.deleteMany({}); 100 | result = await customerCollection.insertMany(customerData); 101 | console.log(`${result.insertedCount} customers inserted`); 102 | ``` 103 | 104 | 4. Append the following code (to the code in the previous step) to bulk load the sales data into the collection using the `insertMany` method: 105 | 106 | ```javascript 107 | console.log("Loading sales data"); 108 | await salesCollection.deleteMany({}); 109 | result = await salesCollection.insertMany(salesData); 110 | console.log(`${result.insertedCount} sales inserted`); 111 | ``` 112 | 113 | 5. Save the `index.js` file. 114 | 115 | 6. Run the application by executing the following command in the terminal window: 116 | 117 | ```bash 118 | npm start 119 | ``` 120 | 121 | ![A console window displays indicating customers and sales have been inserted into the customers and sales collections](media/customers_sales_loaded.png "Customers and sales loaded") 122 | 123 | ## Summary 124 | 125 | In this section bulk load operations were used to load product, customer, and sales data into Cosmos DB for MongoDB. Keep the database and its loaded data for use in subsequent labs. 126 | -------------------------------------------------------------------------------- /Labs/load_data/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { MongoClient } = require('mongodb'); 3 | 4 | async function main() { 5 | const client = new MongoClient(process.env.MONGODB_URI); 6 | try { 7 | await client.connect(); 8 | console.log('Connected to MongoDB'); 9 | const db = client.db('cosmic_works'); 10 | 11 | 12 | } catch (err) { 13 | console.error(err); 14 | } finally { 15 | await client.close(); 16 | console.log('Disconnected from MongoDB'); 17 | } 18 | } 19 | 20 | function cleanData(obj) { 21 | cleaned = Object.fromEntries( 22 | Object.entries(obj).filter(([key, _]) => !key.startsWith('_')) 23 | ); 24 | //rename id field to _id 25 | cleaned["_id"] = cleaned["id"]; 26 | delete cleaned["id"]; 27 | return cleaned; 28 | } 29 | 30 | main().catch(console.error); -------------------------------------------------------------------------------- /Labs/load_data/media/customers_sales_loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/load_data/media/customers_sales_loaded.png -------------------------------------------------------------------------------- /Labs/load_data/media/products_loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/load_data/media/products_loaded.png -------------------------------------------------------------------------------- /Labs/load_data/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-nodejs-devguide-load-data", 3 | "version": "1.0.0", 4 | "description": "A Node.js application that connects to MongoDB and uses bulk write operations to load data.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "dependencies": { 10 | "mongodb": "6.3.0", 11 | "dotenv": "16.4.4" 12 | }, 13 | "author": "Microsoft", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /Labs/vector_search/.env.example: -------------------------------------------------------------------------------- 1 | MONGODB_URI=mongodb+srv://:@.mongocluster.cosmos.azure.com/?tls=true&authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000 2 | AOAI_ENDPOINT= 3 | AOAI_KEY= -------------------------------------------------------------------------------- /Labs/vector_search/catch_up.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { MongoClient } = require('mongodb'); 3 | 4 | async function main() { 5 | const client = new MongoClient(process.env.MONGODB_URI); 6 | try { 7 | await client.connect(); 8 | console.log('Connected to MongoDB'); 9 | const db = client.db('cosmic_works'); 10 | 11 | // Load product data 12 | console.log('Loading product data') 13 | // Initialize the product collection pointer (will automatically be created if it doesn't exist) 14 | const productCollection = db.collection('products'); 15 | // Load the product data from the raw data from Cosmic Works while also removing the system properties 16 | const productRawData = "https://cosmosdbcosmicworks.blob.core.windows.net/cosmic-works-small/product.json"; 17 | const productData = (await (await fetch(productRawData)).json()) 18 | .map(prod => cleanData(prod)); 19 | // Delete all existing products and insert the new data 20 | await productCollection.deleteMany({}); 21 | // Utilize bulkWrite to insert all the products at once 22 | var result = await productCollection.bulkWrite( 23 | productData.map((product) => ({ 24 | insertOne: { 25 | document: product 26 | } 27 | })) 28 | ); 29 | console.log(`${result.insertedCount} products inserted`); 30 | 31 | // Load customer and sales data 32 | console.log('Retrieving combined Customer/Sales data'); 33 | const customerCollection = db.collection('customers'); 34 | const salesCollection = db.collection('sales'); 35 | const custSalesRawData = "https://cosmosdbcosmicworks.blob.core.windows.net/cosmic-works-small/customer.json"; 36 | const custSalesData = (await (await fetch(custSalesRawData)).json()) 37 | .map(custSales => cleanData(custSales)); 38 | 39 | console.log("Split customer and sales data"); 40 | const customerData = custSalesData.filter(cust => cust["type"] === "customer"); 41 | const salesData = custSalesData.filter(sales => sales["type"] === "salesOrder"); 42 | 43 | console.log("Loading customer data"); 44 | await customerCollection.deleteMany({}); 45 | result = await customerCollection.insertMany(customerData); 46 | console.log(`${result.insertedCount} customers inserted`); 47 | 48 | console.log("Loading sales data"); 49 | await salesCollection.deleteMany({}); 50 | result = await salesCollection.insertMany(salesData); 51 | console.log(`${result.insertedCount} sales inserted`); 52 | 53 | } catch (err) { 54 | console.error(err); 55 | } finally { 56 | await client.close(); 57 | console.log('Disconnected from MongoDB'); 58 | } 59 | } 60 | 61 | function cleanData(obj) { 62 | cleaned = Object.fromEntries( 63 | Object.entries(obj).filter(([key, _]) => !key.startsWith('_')) 64 | ); 65 | //rename id field to _id 66 | cleaned["_id"] = cleaned["id"]; 67 | delete cleaned["id"]; 68 | return cleaned; 69 | } 70 | 71 | main().catch(console.error); -------------------------------------------------------------------------------- /Labs/vector_search/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { MongoClient } = require('mongodb'); 3 | 4 | // set up the MongoDB client 5 | const dbClient = new MongoClient(process.env.MONGODB_URI); 6 | 7 | async function main() { 8 | try { 9 | await dbClient.connect(); 10 | console.log('Connected to MongoDB'); 11 | const db = dbClient.db('cosmic_works'); 12 | 13 | 14 | } catch (err) { 15 | console.error(err); 16 | } finally { 17 | await dbClient.close(); 18 | console.log('Disconnected from MongoDB'); 19 | } 20 | } 21 | 22 | main().catch(console.error); -------------------------------------------------------------------------------- /Labs/vector_search/media/rag_with_vector_search_response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/vector_search/media/rag_with_vector_search_response.png -------------------------------------------------------------------------------- /Labs/vector_search/media/text_embedding_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/vector_search/media/text_embedding_output.png -------------------------------------------------------------------------------- /Labs/vector_search/media/vector_search_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/vector_search/media/vector_search_results.png -------------------------------------------------------------------------------- /Labs/vector_search/media/vectorize_and_store_embeddings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/Labs/vector_search/media/vectorize_and_store_embeddings.png -------------------------------------------------------------------------------- /Labs/vector_search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-nodejs-devguide-vector-search", 3 | "version": "1.0.0", 4 | "description": "A Node.js application performs vector searches and RAG pattern LLM calls.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "dependencies": { 10 | "mongodb": "6.3.0", 11 | "dotenv": "16.4.4", 12 | "@azure/openai": "1.0.0-beta.11" 13 | }, 14 | "author": "Microsoft", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure Cosmos DB + Azure OpenAI Node.js Developer Guide 2 | 3 | 1. [Introduction](/00_Introduction/README.md) 4 | 1. [Azure Overview](/01_Azure_Overview/README.md) 5 | 1. [Overview of Azure Cosmos DB](/02_Overview_Cosmos_DB/README.md) 6 | 1. [Overview of Azure OpenAI](/03_Overview_Azure_OpenAI/README.md) 7 | 1. [Overview of AI Concepts](/04_Overview_AI_Concepts/README.md) 8 | 1. [Explore the Azure OpenAI models and endpoints (console app)](/05_Explore_OpenAI_models/README.md) 9 | 1. [Provision Azure resources](/06_Provision_Azure_Resources/README.md) 10 | 1. [Create your first Cosmos DB project](/07_Create_First_Cosmos_DB_Project/README.md) 11 | 1. [Load data into Azure Cosmos DB API for MongoDB](/08_Load_Data/README.md) 12 | 1. [Use vector search on embeddings in vCore-based Azure Cosmos DB for MongoDB](/09_Vector_Search_Cosmos_DB/README.md) 13 | 1. [LangChain](/10_LangChain/README.md) 14 | 1. [Backend API](/11_Backend_API/README.md) 15 | 1. [Connect the chat user interface with the chatbot API](/12_User_Interface/README.md) 16 | 1. [Conclusion](/13_Conclusion/README.md) 17 | 18 | ![Azure Cosmos DB + Azure OpenAI Node.js Developer Guide Architecture Diagram](/06_Provision_Azure_Resources/media/architecture.jpg) 19 | 20 | ## Contributing 21 | 22 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 23 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 24 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 25 | 26 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 27 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 28 | provided by the bot. You will only need to do this once across all repos using our CLA. 29 | 30 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 31 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 32 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 33 | 34 | ## Trademarks 35 | 36 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 37 | trademarks or logos is subject to and must follow 38 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 39 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 40 | Any use of third-party trademarks or logos are subject to those third-party's policies. 41 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /assets/Graphics.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/assets/Graphics.pptx -------------------------------------------------------------------------------- /assets/architecture.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AzureCosmosDB/Azure-OpenAI-Node.js-Developer-Guide/513d5164710794520816b9c334c8afc9c4559ab2/assets/architecture.pptx --------------------------------------------------------------------------------