diff --git a/.devcontainer.json b/.devcontainer.json index 7d5c5b1eb..018e13930 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -1,5 +1,5 @@ { - "name": "Azure Chat Solution Accelerator powered by Azure Open AI Service", + "name": "BluGPT", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/javascript-node:0-18-bullseye", diff --git a/.github/workflows/azure-dev-validate.yml b/.github/workflows/azure-dev-validate.yml deleted file mode 100644 index 7d5cef141..000000000 --- a/.github/workflows/azure-dev-validate.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Validate bicep scripts -on: - workflow_dispatch: - push: - branches: - - main - - master - pull_request: - branches: - - main - - master - -jobs: - build: - - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Build Bicep for linting - uses: azure/CLI@v1 - with: - inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f infra/main.bicep --stdout - - - name: Run Microsoft Security DevOps Analysis - uses: microsoft/security-devops-action@preview - id: msdo - continue-on-error: true - with: - tools: templateanalyzer - env: - GDN_TEMPLATEANALYZER_VERBOSE: 1 - - - name: Upload alerts to Security tab - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: ${{ steps.msdo.outputs.sarifFile }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..2829baa1c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + push: + tags: ["*.*.*"] + pull_request: + branches: [main] + paths-ignore: ["*.md"] + workflow_dispatch: + +jobs: + main: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: asimmon/blugpt + + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker build + uses: docker/build-push-action@v4 + with: + context: src + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.github/workflows/open-ai-app.yml b/.github/workflows/open-ai-app.yml deleted file mode 100644 index 857d74206..000000000 --- a/.github/workflows/open-ai-app.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: Build & deploy Next.js app to Azure Web App - -# When this action will be executed -on: - # Automatically trigger it when detected changes in repo - push: - branches: [main] - - # Allow manual workflow trigger - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: ๐ŸŒฑ Checkout to the branch - uses: actions/checkout@v3 - - - name: ๐Ÿ Set up Node.js version - uses: actions/setup-node@v3 - with: - node-version: "18.x" - - - name: โš™๏ธ npm install and build - run: | - cd ./src - npm install - npm run build --if-present - cd .. - - - name: ๐Ÿ“‚ Copy standalone into the root - run: cp -R ./src/.next/standalone ./site-deploy - - - name: ๐Ÿ“‚ Copy static into the .next folder - run: cp -R ./src/.next/static ./site-deploy/.next/static - - - name: ๐Ÿ“‚ Copy Public folder - run: cp -R ./src/public ./site-deploy/public - - - name: ๐Ÿ“ฆ Package Next application - run: | - cd ./site-deploy - zip Nextjs-site.zip ./* .next -qr - - - name: ๐Ÿ” Diagnostics - run: | - ls ./src - ls ./src/.next - ls ./site-deploy - - - name: โฌ†๏ธ Publish Next Application artifact - uses: actions/upload-artifact@v3 - with: - name: Nextjs-site - path: ./site-deploy/Nextjs-site.zip - - deploy: - runs-on: ubuntu-latest - needs: build - environment: - name: "Production" - - steps: - - name: โฌ‡๏ธ Download artifact from build job - uses: actions/download-artifact@v3 - with: - name: Nextjs-site - - - name: ๐Ÿ—๏ธ Azure Login - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - # Set the build during deployment setting to false. This setting was added in the templates to all azd to work, but breaks deployment via webapps-deploy - - name: Azure CLI script - uses: azure/CLI@v1 - with: - inlineScript: | - rg=$(az webapp list --query "[?name=='${{ secrets.AZURE_APP_SERVICE_NAME }}'].resourceGroup" --output tsv) - az webapp config appsettings set -n ${{ secrets.AZURE_APP_SERVICE_NAME }} -g $rg --settings SCM_DO_BUILD_DURING_DEPLOYMENT=false - az webapp config set --startup-file="node server.js" -n ${{ secrets.AZURE_APP_SERVICE_NAME }} -g $rg - sleep 10 - - - name: ๐Ÿš€ Deploy to Azure Web App - id: deploy-to-webapp - uses: azure/webapps-deploy@v2 - with: - app-name: ${{ secrets.AZURE_APP_SERVICE_NAME }} - package: ${{ github.workspace }}/Nextjs-site.zip - - - name: ๐Ÿงน Cleanup - run: rm ${{ github.workspace }}/Nextjs-site.zip diff --git a/.gitignore b/.gitignore index 27d7814de..b66c362cd 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,7 @@ next-env.d.ts .azure/ infra/aad_setup.sh + +# custom +.idea/ +.vscode/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 12b5a7145..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,32 +0,0 @@ -# How to contribute - -If you would like to contribute to the solution solution accelerator repository there are many ways you can help. - -## Reporting issues - -We use [GitHub issues](https://github.com/microsoft/azurechat/issues) as an issue tracker for the repository. Firstly, please search in open issues and try to make sure your problem doesn't exist. If there is an issue, add your comments to this issue. -If there are no issues yet, please open a new one. - -## Contributing Code - -If you would like to contribute an improvement or a fix please create a Pull Request using the steps below. Ensure to describe the feature or bug as part of the pull request. - -## Sending a Pull Request - -Before submitting a pull request please make sure the following is done: - -1. Fork [the repository](https://github.com/microsoft/azurechat) -2. Create a branch from the `main` -3. Ensure that the code build and runs without any errors -4. If required update the README.md -5. Complete the [CLA](#contributor-license-agreement-cla) - -### Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -### Contributor License Agreement (CLA) - -You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission to use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright. - -Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit [https://cla.microsoft.com](https://cla.microsoft.com) to sign digitally. Alternatively, download the agreement ([Microsoft Contribution License Agreement.docx](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=822190)), sign, scan, and email it back to . Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request. diff --git a/README.md b/README.md index e8029d782..3dad16b24 100644 --- a/README.md +++ b/README.md @@ -1,84 +1,10 @@ -# Unleash the Power of Azure Open AI +# BluGPT, a private and secure ChatGPT clone -1. [Introduction](#introduction) -1. [Solution Overview](/docs/1-introduction.md) -1. [Deploy to Azure](#deploy-to-azure) -1. [Run from your local machine](/docs/3-run-locally.md) -1. [Deploy to Azure with GitHub Actions](/docs/4-deploy-to-azure.md) -1. [Add identity provider](/docs/5-add-identity.md) -1. [Chatting with your file](/docs/6-chat-over-file.md) -1. [Environment variables](/docs/7-environment-variables.md) +> This is a fork of [microsoft/azurechat](https://github.com/microsoft/azurechat). You can find the original README file with instructions there. +**BluGPT** is a ChatGPT clone named after my cat, Blu ๐Ÿ˜ป. I've slightly modified the original Microsoft project so I could host my own "ChatGPT" and share it with my family and friends. -# Introduction +While the original Microsoft repository might seem to enforce the use of [Azure OpenAI Service](https://azure.microsoft.com/en-us/products/ai-services/openai-service), it was actually quite simple to replace it with the [OpenAI API](https://platform.openai.com/overview). I've also replaced the GitHub and Azure AD authentication with Google, which makes it easier for my family to log in. -_Azure Chat Solution Accelerator powered by Azure Open AI Service_ +![](/images/blugpt1.png) -![](/images/intro.png) - -_Azure Chat Solution Accelerator powered by Azure Open AI Service_ is a solution accelerator that allows organisations to deploy a private chat tenant in their Azure Subscription, with a familiar user experience and the added capabilities of chatting over your data and files. - -Benefits are: - -1. Private: Deployed in your Azure tenancy, allowing you to isolate it to your Azure tenant. - -2. Controlled: Network traffic can be fully isolated to your network and other enterprise grade authentication security features are built in. - -3. Value: Deliver added business value with your own internal data sources (plug and play) or integrate with your internal services (e.g., ServiceNow, etc). - -# Deploy to Azure - -You can provision Azure resources for the solution accelerator using either the Azure Developer CLI or the Deploy to Azure button below. Regardless of the method you chose you will still need set up an [identity provider and specify an admin user](./5-add-identity.md) - -## Deployment Options - -You can deploy the application using one of the following options: - -- [1. Azure Developer CLI](#azure-developer-cli) -- [2. Azure Portal Deployment](#azure-portal-deployment) - -### 1. Azure Developer CLI - -> **Important** -> This section will create Azure resources and deploy the solution from your local environment using the Azure Developer CLI. Note that you do not need to clone this repo to complete these steps. - -1. Download the [Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview) -1. Run `azd init -t microsoft/azurechat` -1. Run `azd up` to provision and deploy the application - -### 2. Azure Portal Deployment - -> **Warning** -> This button will only create Azure resources. You will still need to deploy the application by following the [deploy to Azure section](./4-deploy-to-azure.md) to build and deploy the application using GitHub actions. - -Click on the Deploy to Azure button to deploy the Azure resources for the application. - -[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/anzappazurechatgpt) - -## Setup Authentication - -> **Important** -> The application is protected by an identity provider and follow the steps in [Add an identity provider](./5-add-identity.md) section for adding authentication to your app. - -[Next](./docs/1-introduction.md) - -# Contributing - -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. - -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -# Trademarks - -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft -trademarks or logos is subject to and must follow -[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). -Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. -Any use of third-party trademarks or logos are subject to those third-party's policies. +![](/images/blugpt2.png) \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index e138ec5d6..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,41 +0,0 @@ - - -## Security - -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), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). - -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/opensource/security/definition), please report it to us as described below. - -## Reporting Security Issues - -**Please do not report security vulnerabilities through public GitHub issues.** - -Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). - -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/opensource/security/pgpkey). - -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://aka.ms/opensource/security/msrc). - -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: - - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -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/opensource/security/bounty) page for more details about our active programs. - -## Preferred Languages - -We prefer all communications to be in English. - -## Policy - -Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). - - diff --git a/SUPPORT.md b/SUPPORT.md deleted file mode 100644 index afacacf28..000000000 --- a/SUPPORT.md +++ /dev/null @@ -1,10 +0,0 @@ -# Support - -## How to file issues and get help - -We use [GitHub issues](https://github.com/microsoft/azurechat/issues) as an issue tracker for the repository. Firstly, please search in open issues and try to make sure your problem doesn't exist. If there is an issue, add your comments to this issue. -If there are no issues yet, please open a new one. - -## Microsoft Support Policy - -Support for this **PROJECT or PRODUCT** is limited to the resources listed above. diff --git a/azure.yaml b/azure.yaml deleted file mode 100644 index 15bb0292a..000000000 --- a/azure.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json - -name: azurechat -metadata: - template: azurechat@0.0.1 -services: - frontend: - project: ./src - language: ts - host: appservice -hooks: - postdeploy: - posix: - shell: sh - run: echo -e "\n\033[0;36mTo complete the application setup you will need to configure an identity provider\033[0m\n(see the "Production App Setup" documentation at https://github.com/microsoft/azurechat/blob/main/docs/5-add-identity.md)\n" - interactive: true - continueOnError: false - windows: - shell: pwsh - run: Write-Host "`nTo complete the application setup you will need to configure an identity provider`n(see the 'Production App Setup' documentation at https://github.com/microsoft/azurechat/blob/main/docs/5-add-identity.md)`n" -ForegroundColor Cyan diff --git a/docs/1-introduction.md b/docs/1-introduction.md deleted file mode 100644 index b2673d7d8..000000000 --- a/docs/1-introduction.md +++ /dev/null @@ -1,70 +0,0 @@ -# ๐Ÿ“˜ Prerequisites - -Please make sure the following prerequisites are in place prior to deploying this accelerator: - -1. [Azure OpenAI](https://azure.microsoft.com/en-us/products/cognitive-services/openai-service/): To deploy and run the solution accelerator, you'll need an Azure subscription with access to the Azure OpenAI service. Request access [here](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu). Once you have access, follow the instructions in this [link](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal) to deploy the gpt-35-turbo or gpt-4 models. - -2. Setup GitHub or Azure AD for Authentication: - The [add an identity provider](./5-add-identity.md) section below shows how to configure authentication providers. - - > **Note** - > You can configure the authentication provider to your identity solution using [NextAuth providers](https://next-auth.js.org/providers/) - -## ๐Ÿ‘‹๐Ÿป Introduction - -_Azure Chat Solution Accelerator powered by Azure Open AI Service_ solution accelerator is built using the following technologies: - -- [Node.js 18](https://nodejs.org/en): an open-source, cross-platform JavaScript runtime environment. - -- [Next.js 13](https://nextjs.org/docs): enables you to create full-stack web applications by extending the latest React features - -- [NextAuth.js](https://next-auth.js.org/): configurable authentication framework for Next.js 13 - -- [LangChain JS](https://www.langchain.com/): AI orchestration layer to build intelligent apps - -- [ai sdk](https://sdk.vercel.ai/docs) Open-source library that simplifies building conversational UI on top Next.js and JavaScript - -- [Tailwind CSS](https://tailwindcss.com/): is a utility-first CSS framework that provides a series of predefined classes that can be used to style each element by mixing and matching - -- [shadcn/ui](https://ui.shadcn.com/): re-usable components built using Radix UI and Tailwind CSS. - -- [Azure Cosmos DB](https://learn.microsoft.com/en-GB/azure/cosmos-db/nosql/): fully managed platform-as-a-service (PaaS) NoSQL database to store chat history - -- [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview): Azure OpenAI Service provides REST API access to OpenAI's powerful language models including the GPT-4, GPT-35-Turbo, and Embeddings model series. - -- [Azure App Service](https://learn.microsoft.com/en-us/azure/app-service/): fully managed platform-as-a-service (PaaS) for hosting web applications, REST APIs, and mobile back ends. - -### Optional Azure Services - -The following Azure services can be deployed to expand the feature set of your solution: - -- [Azure Document Intelligence](https://learn.microsoft.com/en-GB/azure/ai-services/document-intelligence/) Microsoft Azure Form Recognizer is an automated data processing system that uses AI and OCR to quickly extract text and structure from documents. We use this service for extracting information from documents. - -- [Azure Cognitive Search](https://learn.microsoft.com/en-GB/azure/search/) Azure Cognitive Search is an AI-powered platform as a service (PaaS) that helps developers build rich search experiences for applications. We use this service for indexing and retrieving information. - -- [Azure OpenAI Embeddings](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/embeddings?tabs=console) for embed content extracted from files. - -# Solution Architecture - -The following high-level diagram depicts the architecture of the solution accelerator: - -![Architecture diagram](/images/architecture.png) - -# Azure Deployment Costs - -Pricing varies per region and usage, so it isn't possible to predict exact costs for your usage. -However, you can try the [Azure pricing calculator - Sample Estimate](https://azure.com/e/1f08b35661df4b5ea3663df112250b09) for the resources below. - -- Azure App Service: Premium V3 Tier 1 CPU core, 4 GB RAM, 250 GB Storage. Pricing per hour. [Pricing](https://azure.microsoft.com/pricing/details/app-service/linux/) -- Azure Open AI: Standard tier, ChatGPT and Embedding models. Pricing per 1K tokens used, and at least 1K tokens are used per question. [Pricing](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/) -- Form Recognizer: SO (Standard) tier using pre-built layout. Pricing per document page, sample documents have 261 pages total. [Pricing](https://azure.microsoft.com/pricing/details/form-recognizer/) -- Azure Cognitive Search: Standard tier, 1 replica, free level of semantic search. Pricing per hour.[Pricing](https://azure.microsoft.com/pricing/details/search/) -- Azure Cosmos DB: Standard provisioned throughput with ZRS (Zone-redundant storage). Pricing per storage and read operations. [Pricing](https://azure.microsoft.com/en-us/pricing/details/cosmos-db/autoscale-provisioned/) -- Azure Monitor: Pay-as-you-go tier. Costs based on data ingested. [Pricing](https://azure.microsoft.com/pricing/details/monitor/) - -To reduce costs, you can switch to free SKUs for Azure App Service, Azure Cognitive Search, and Form Recognizer by changing the parameters file under the `./infra` folder. There are some limits to consider; for example, you can have up to 1 free Cognitive Search resource per subscription, and the free Form Recognizer resource only analyzes the first 2 pages of each document. You can also reduce costs associated with the Form Recognizer by reducing the number of documents you upload. - -> **Warning** -> To avoid unnecessary costs, remember to destroy your provisioned resources by deleting the resource group. - -[Next](/docs/2-provision-azure-resources.md) diff --git a/docs/3-run-locally.md b/docs/3-run-locally.md deleted file mode 100644 index e0e58741a..000000000 --- a/docs/3-run-locally.md +++ /dev/null @@ -1,79 +0,0 @@ -# ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป Run Locally - -Clone this repository locally or fork to your Github account. Run all of the the steps below from the `src` directory. - -## Prerequisites - -- **History Database**: If you didn't [provision the Azure resources](2-provision-azure-resources.md), you **must** at least deploy an instance of Cosmos DB in your Azure Subscription to store chat history. - -- **Identity Provider**: Follow the [instructions](3-run-locally.md) to add one. - -## Steps - -1. Change directory to the `src` folder -2. Create a new file named `.env.local` to store the environment variables add the following variables. - -> **Note** -> Do not use double-quotes and do not delete any of the variables. - -> **Note** -> Make sure that `NEXTAUTH_URL=http://localhost:3000` has no comments in the same line. - -3.
Set the following environmnet variables - - ```bash - # Set your environment details - # AZURE_OPENAI_API_INSTANCE_NAME should be just the name of azure openai resource and not the full url; - # AZURE_OPENAI_API_DEPLOYMENT_NAME should be deployment name from your azure openai studio and not the model name. - # AZURE_OPENAI_API_VERSION should be Supported versions checkout docs https://learn.microsoft.com/en-us/azure/ai-services/openai/reference - - AZURE_OPENAI_API_KEY= - AZURE_OPENAI_API_INSTANCE_NAME= - AZURE_OPENAI_API_DEPLOYMENT_NAME= - AZURE_OPENAI_API_VERSION=2023-03-15-preview - AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME= - - # Update your admin email address - ADMIN_EMAIL_ADDRESS="you@email.com,you2@email.com" - - # You must have atleast one of the following auth providers configured - AUTH_GITHUB_ID= - AUTH_GITHUB_SECRET= - AZURE_AD_CLIENT_ID= - AZURE_AD_CLIENT_SECRET= - AZURE_AD_TENANT_ID= - - # Update your production URL in NEXTAUTH_URL - NEXTAUTH_SECRET=AZURE-OPENIAI-NEXTAUTH-OWNKEY@1 - NEXTAUTH_URL=http://localhost:3000 - - # Update your Cosmos Environment details here - AZURE_COSMOSDB_URI=https://.documents.azure.com:443/ - AZURE_COSMOSDB_KEY= - - # Update your Cosmos DB_NAME and CONTAINER_NAME if you want to overwrite the default values - AZURE_COSMOSDB_DB_NAME=chat - AZURE_COSMOSDB_CONTAINER_NAME=history - - # Azure cognitive search is used for chat over your data - AZURE_SEARCH_API_KEY= - AZURE_SEARCH_NAME= - AZURE_SEARCH_INDEX_NAME= - AZURE_SEARCH_API_VERSION="2023-07-01-Preview" - - # Azure AI Document Intelligence to extract content from your data - AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT="https://REGION.api.cognitive.microsoft.com/" - AZURE_DOCUMENT_INTELLIGENCE_KEY= - ``` -
- -4. Install npm packages by running `npm install` -5. Start the app by running `npm run dev` -6. Access the app on [http://localhost:3000](http://localhost:3000) - -You should now be prompted to login with your chosen OAuth provider. Once successfully logged in, you can start creating new conversations. - -![Chat Home](/images/chat-home.png) -![Chat history](/images/chat-history.png) - -[Next](/docs/4-deploy-to-azure.md) diff --git a/docs/4-deploy-to-azure.md b/docs/4-deploy-to-azure.md deleted file mode 100644 index ac0295766..000000000 --- a/docs/4-deploy-to-azure.md +++ /dev/null @@ -1,40 +0,0 @@ -# โ˜๏ธ Deploy to Azure - GitHub Actions - -The following steps describes how the application can be deployed to Azure App service using GitHub Actions. - -## ๐Ÿงฌ Fork the repository - -Fork this repository to your own organisation so that you can execute GitHub Actions against your own Azure Subscription. - -## ๐Ÿ—๏ธ Configure secrets in your GitHub repository - -### 1. AZURE_CREDENTIALS - -The GitHub workflow requires a secret named `AZURE_CREDENTIALS` to authenticate with Azure. The secret contains the credentials for a service principal with the Contributor role on the resource group containing the container app and container registry. - -1. Create a service principal with the Contributor role on the resource group that contains the Azure App Service. - - ```console - az ad sp create-for-rbac - --name --role contributor --scopes /subscriptions//resourceGroups/ --sdk-auth --output json - ``` - -2. Copy the JSON output from the command. - -3. In the GitHub repository, navigate to Settings > Secrets > Actions and select New repository secret. - -4. Enter `AZURE_CREDENTIALS` as the name and paste the contents of the JSON output as the value. - -5. Select **Add secret**. - -### 2. AZURE_APP_SERVICE_NAME - -Under the same repository secrets add a new variable `AZURE_APP_SERVICE_NAME` to deploy to your Azure Web app. The value of this secret is the name of your Azure Web app e.g. `my-web-app-name` from the domain https://my-web-app-name.azurewebsites.net/ - -### 3. Run GitHub Actions - -Once the secrets are configured, the GitHub Actions will be triggered for every code push to the repository. Alternatively, you can manually run the workflow by clicking on the "Run Workflow" button in the Actions tab in GitHub. - -![Workflow screenshot](/images/runworkflow.png) - -[Next](/docs/5-add-identity.md) diff --git a/docs/5-add-identity.md b/docs/5-add-identity.md deleted file mode 100644 index bf3d33206..000000000 --- a/docs/5-add-identity.md +++ /dev/null @@ -1,92 +0,0 @@ -# ๐Ÿชช Add an Identity Provider - -Once the deployment is complete, you will need to add an identity provider to authenticate your app. You will also need to configure an admin user. - -> **Note** -> Only one of the identity providers is required to be configured below. - -> **Important** -> We **strongly** recommend that you store client secrets in Azure Key Vault and use Kev Vault references in your App config settings. If you have created your environment using the templates in this repo you will already have a Key Vault that is being used to store a range of other secrets, and you will have Key Vault references in your app config. Details on how to configure App Service settings to use Key Vault are [here](https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references?tabs=azure-cli#source-app-settings-from-key-vault). Note that you will also need to give yourself appropriate permissions to create secrets in the Key Vault. - - -## GitHub Authentication Provider - -We'll create two GitHub apps: one for testing locally and another for production. - -### ๐ŸŸก Development App Setup - -1. Navigate to GitHub OAuth Apps setup https://github.com/settings/developers -2. Create a `New OAuth App` https://github.com/settings/applications/new -3. Fill in the following details - - ```default - Application name: DEV Environment - Homepage URL: http://localhost:3000 - Authorization callback URL: http://localhost:3000/api/auth/callback/github - ``` - -### ๐ŸŸข Production App Setup - -1. Navigate to GitHub OAuth Apps setup https://github.com/settings/developers -2. Create a `New OAuth App` https://github.com/settings/applications/new -3. Fill in the following details - - ```default - Application name: Production - Homepage URL: https://YOUR-WEBSITE-NAME.azurewebsites.net - Authorization callback URL: https://YOUR-WEBSITE-NAME.azurewebsites.net/api/auth/callback/github - ``` - -> **Note** -> After completing app setup, ensure that both your local environment variables as well as Azure Web App environment variables are up to date. - -```bash - # GitHub OAuth app configuration - AUTH_GITHUB_ID= - AUTH_GITHUB_SECRET= -``` - -## Azure AD Authentication Provider - -### ๐ŸŸก Development App Setup - -1. Navigate to [Azure AD Apps setup](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps) -2. Create a [New Registration](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/CreateApplicationBlade/quickStartType~/null/isMSAApp~/false) -3. Fill in the following details - - ```default - Application name: DEV Environment - Supported account types: Accounts in this organizational directory only - Redirect URI Platform: Web - Redirect URI: http://localhost:3000/api/auth/callback/azure-ad - ``` - -### ๐ŸŸข Production App Setup - -1. Navigate to [Azure AD Apps setup](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps) -2. Create a [New Registration](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/CreateApplicationBlade/quickStartType~/null/isMSAApp~/false) -3. Fill in the following details - - ```default - Application name: Production - Supported account types: Accounts in this organizational directory only - Redirect URI Platform: Web - Redirect URI: https://YOUR-WEBSITE-NAME.azurewebsites.net/api/auth/callback/azure-ad - ``` - -> **Note** -> After completing app setup, ensure your environment variables locally and on Azure App Service are up to date. - -```bash -# Azure AD OAuth app configuration - -AZURE_AD_CLIENT_ID= -AZURE_AD_CLIENT_SECRET= -AZURE_AD_TENANT_ID= -``` - -## Configure an admin user - -The reporting pages in the application are only available to an admin user. To configure the admin user create or update the "ADMIN_EMAIL_ADDRESS" config setting locally and on Azure App Service with the email address of the user who will use reports. - -[Next](/docs/6-chat-over-file.md) diff --git a/docs/6-chat-over-file.md b/docs/6-chat-over-file.md deleted file mode 100644 index 2db0ad1cf..000000000 --- a/docs/6-chat-over-file.md +++ /dev/null @@ -1,17 +0,0 @@ -# ๐Ÿ“ƒ Chatting With Your File - -Users can utilise this functionality to upload their PDF files through the portal and engage in chat discussions related to the content of those files. - -Chat with your data utilises the following Azure Services: - -1. [Azure Document Intelligence](https://learn.microsoft.com/en-GB/azure/ai-services/document-intelligence/) for extracting information from documents. -1. [Azure Cognitive Search](https://learn.microsoft.com/en-GB/azure/search/) for indexing and retrieving information. -1. [Azure OpenAI Embeddings](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/embeddings?tabs=console) for embed content extracted from files - -![](/images/chatover-file.png) - -### Things to Consider - -1. Central place maintain uploaded files (e.g a storage account with blob storage) - -[Next](/docs/7-environment-variables.md) diff --git a/docs/7-environment-variables.md b/docs/7-environment-variables.md deleted file mode 100644 index 6a4fd4a03..000000000 --- a/docs/7-environment-variables.md +++ /dev/null @@ -1,27 +0,0 @@ -# ๐Ÿ”‘ Environment Variables - -Below are the required environment variables, to be added to the Azure Portal or in the `.env.local` file. - -| App Setting | Value | Note | -| ----------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `AZURE_OPENAI_API_KEY` | | API keys of your Azure OpenAI resource | -| `AZURE_OPENAI_API_INSTANCE_NAME` | | the name of your Azure OpenAI resource | -| `AZURE_OPENAI_API_DEPLOYMENT_NAME` | | The name of your model deployment | -| `AZURE_OPENAI_API_VERSION` | `2023-03-15-preview` | API version when using gpt chat | -| `AUTH_GITHUB_ID` | | Client ID of your GitHub OAuth application | -| `AUTH_GITHUB_SECRET` | | Client Secret of your GitHub OAuth application | -| `NEXTAUTH_SECRET` | | Used to encrypt the NextAuth.js JWT, and to hash email verification tokens. **This is set by default as part of the deployment template** | -| `NEXTAUTH_URL` | | Current webs hosting domain name with HTTP or HTTPS. **This set by default as part of the deployment template** | -| `AZURE_COSMOSDB_URI` | | URL of the Azure CosmosDB | -| `AZURE_COSMOSDB_KEY` | | API Key for Azure Cosmos DB | -| `AZURE_AD_CLIENT_ID` | | The client id specific to the application | -| `AZURE_AD_CLIENT_SECRET` | | The client secret specific to the application | -| `AZURE_AD_TENANT_ID` | | The organisation Tenant ID | -| `ADMIN_EMAIL_ADDRESS` | | Comma separated list of email addresses of the admin users ID | -| **Azure Cognitive Search is optional. This is only required for chat over file feature.** | -| `AZURE_SEARCH_API_KEY` | | API Key of Azure Cognitive search | -| `AZURE_SEARCH_NAME` | `https://AZURE_SEARCH_NAME.search.windows.net` | The deployment name of your Azure Cognitive Search | -| `AZURE_SEARCH_INDEX_NAME` | | The index name with [vector search](https://learn.microsoft.com/en-us/azure/search/vector-search-overview) enabled | -| `AZURE_SEARCH_API_VERSION` | `2023-07-01-Preview` | API version which supports vector search `2023-07-01-Preview` | -| `AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT` | `https://REGION.api.cognitive.microsoft.com/` | Endpoint url of the Azure document intelligence. The REGION is specific to your Azure resource location | -| `AZURE_DOCUMENT_INTELLIGENCE_KEY` | | API keys of your Azure Document intelligence resource | diff --git a/images/architecture.png b/images/architecture.png deleted file mode 100644 index 55b15b816..000000000 Binary files a/images/architecture.png and /dev/null differ diff --git a/images/blugpt1.png b/images/blugpt1.png new file mode 100644 index 000000000..7f5420701 Binary files /dev/null and b/images/blugpt1.png differ diff --git a/images/blugpt2.png b/images/blugpt2.png new file mode 100644 index 000000000..9ff5c23e2 Binary files /dev/null and b/images/blugpt2.png differ diff --git a/images/chat-history.png b/images/chat-history.png deleted file mode 100644 index 2050fb28c..000000000 Binary files a/images/chat-history.png and /dev/null differ diff --git a/images/chat-home.png b/images/chat-home.png deleted file mode 100644 index 4f94c3216..000000000 Binary files a/images/chat-home.png and /dev/null differ diff --git a/images/chatover-file.png b/images/chatover-file.png deleted file mode 100644 index e97b1825c..000000000 Binary files a/images/chatover-file.png and /dev/null differ diff --git a/images/intro.png b/images/intro.png deleted file mode 100644 index ae180eff8..000000000 Binary files a/images/intro.png and /dev/null differ diff --git a/images/personalise-session.png b/images/personalise-session.png deleted file mode 100644 index d4c3ffd37..000000000 Binary files a/images/personalise-session.png and /dev/null differ diff --git a/images/runworkflow.png b/images/runworkflow.png deleted file mode 100644 index d5c8fbb77..000000000 Binary files a/images/runworkflow.png and /dev/null differ diff --git a/images/set-startup-command.png b/images/set-startup-command.png deleted file mode 100644 index 9ef33f362..000000000 Binary files a/images/set-startup-command.png and /dev/null differ diff --git a/infra/main.bicep b/infra/main.bicep deleted file mode 100644 index bd6257d9d..000000000 --- a/infra/main.bicep +++ /dev/null @@ -1,77 +0,0 @@ -targetScope = 'subscription' - -@minLength(1) -@maxLength(64) -@description('Name of the the environment which is used to generate a short unique hash used in all resources.') -param name string - -@minLength(1) -@description('Primary location for all resources') -param location string - -// azure open ai -@description('Location for the OpenAI resource group') -@allowed(['canadaeast', 'eastus', 'francecentral', 'japaneast', 'northcentralus']) -@metadata({ - azd: { - type: 'location' - } -}) -param openAILocation string - -param openAISku string = 'S0' -param openAIApiVersion string = '2023-03-15-preview' - -param chatGptDeploymentCapacity int = 30 -param chatGptDeploymentName string = 'chat-gpt-35-turbo' -param chatGptModelName string = 'gpt-35-turbo' -param chatGptModelVersion string = '0613' -param embeddingDeploymentName string = 'embedding' -param embeddingDeploymentCapacity int = 10 -param embeddingModelName string = 'text-embedding-ada-002' - -param formRecognizerSkuName string = 'S0' -param searchServiceIndexName string = 'azure-chat' -param searchServiceSkuName string = 'standard' -param searchServiceAPIVersion string = '2023-07-01-Preview' - -param resourceGroupName string = '' - -var resourceToken = toLower(uniqueString(subscription().id, name, location)) -var tags = { 'azd-env-name': name } - -// Organize resources in a resource group -resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: !empty(resourceGroupName) ? resourceGroupName : 'rg-${name}' - location: location - tags: tags -} - -module resources 'resources.bicep' = { - name: 'all-resources' - scope: rg - params: { - name: name - resourceToken: resourceToken - tags: tags - openai_api_version: openAIApiVersion - openAiResourceGroupLocation: openAILocation - openAiSkuName: openAISku - chatGptDeploymentCapacity: chatGptDeploymentCapacity - chatGptDeploymentName: chatGptDeploymentName - chatGptModelName: chatGptModelName - chatGptModelVersion: chatGptModelVersion - embeddingDeploymentName: embeddingDeploymentName - embeddingDeploymentCapacity: embeddingDeploymentCapacity - embeddingModelName: embeddingModelName - formRecognizerSkuName: formRecognizerSkuName - searchServiceIndexName: searchServiceIndexName - searchServiceSkuName: searchServiceSkuName - searchServiceAPIVersion: searchServiceAPIVersion - location: location - } -} - -output APP_URL string = resources.outputs.url -output AZURE_LOCATION string = location -output AZURE_TENANT_ID string = tenant().tenantId diff --git a/infra/main.json b/infra/main.json deleted file mode 100644 index 0a7a5de8e..000000000 --- a/infra/main.json +++ /dev/null @@ -1,656 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "18067428240031110120" - } - }, - "parameters": { - "name": { - "type": "string", - "minLength": 1, - "maxLength": 64, - "metadata": { - "description": "Name of the the environment which is used to generate a short unique hash used in all resources." - } - }, - "location": { - "type": "string", - "minLength": 1, - "metadata": { - "description": "Primary location for all resources" - } - }, - "openAILocation": { - "type": "string", - "allowedValues": [ - "canadaeast", - "eastus", - "francecentral", - "japaneast", - "northcentralus" - ], - "metadata": { - "azd": { - "type": "location" - }, - "description": "Location for the OpenAI resource group" - } - }, - "openAISku": { - "type": "string", - "defaultValue": "S0" - }, - "openAIApiVersion": { - "type": "string", - "defaultValue": "2023-03-15-preview" - }, - "chatGptDeploymentCapacity": { - "type": "int", - "defaultValue": 30 - }, - "chatGptDeploymentName": { - "type": "string", - "defaultValue": "chat-gpt-35-turbo" - }, - "chatGptModelName": { - "type": "string", - "defaultValue": "gpt-35-turbo" - }, - "chatGptModelVersion": { - "type": "string", - "defaultValue": "0613" - }, - "embeddingDeploymentName": { - "type": "string", - "defaultValue": "embedding" - }, - "embeddingDeploymentCapacity": { - "type": "int", - "defaultValue": 10 - }, - "embeddingModelName": { - "type": "string", - "defaultValue": "text-embedding-ada-002" - }, - "formRecognizerSkuName": { - "type": "string", - "defaultValue": "S0" - }, - "searchServiceIndexName": { - "type": "string", - "defaultValue": "azure-chat" - }, - "searchServiceSkuName": { - "type": "string", - "defaultValue": "standard" - }, - "searchServiceAPIVersion": { - "type": "string", - "defaultValue": "2023-07-01-Preview" - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "" - } - }, - "variables": { - "resourceToken": "[toLower(uniqueString(subscription().id, parameters('name'), parameters('location')))]", - "tags": { - "azd-env-name": "[parameters('name')]" - } - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2021-04-01", - "name": "[if(not(empty(parameters('resourceGroupName'))), parameters('resourceGroupName'), format('rg-{0}', parameters('name')))]", - "location": "[parameters('location')]", - "tags": "[variables('tags')]" - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "all-resources", - "resourceGroup": "[if(not(empty(parameters('resourceGroupName'))), parameters('resourceGroupName'), format('rg-{0}', parameters('name')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "resourceToken": { - "value": "[variables('resourceToken')]" - }, - "tags": { - "value": "[variables('tags')]" - }, - "openai_api_version": { - "value": "[parameters('openAIApiVersion')]" - }, - "openAiResourceGroupLocation": { - "value": "[parameters('openAILocation')]" - }, - "openAiSkuName": { - "value": "[parameters('openAISku')]" - }, - "chatGptDeploymentCapacity": { - "value": "[parameters('chatGptDeploymentCapacity')]" - }, - "chatGptDeploymentName": { - "value": "[parameters('chatGptDeploymentName')]" - }, - "chatGptModelName": { - "value": "[parameters('chatGptModelName')]" - }, - "chatGptModelVersion": { - "value": "[parameters('chatGptModelVersion')]" - }, - "embeddingDeploymentName": { - "value": "[parameters('embeddingDeploymentName')]" - }, - "embeddingDeploymentCapacity": { - "value": "[parameters('embeddingDeploymentCapacity')]" - }, - "embeddingModelName": { - "value": "[parameters('embeddingModelName')]" - }, - "formRecognizerSkuName": { - "value": "[parameters('formRecognizerSkuName')]" - }, - "searchServiceIndexName": { - "value": "[parameters('searchServiceIndexName')]" - }, - "searchServiceSkuName": { - "value": "[parameters('searchServiceSkuName')]" - }, - "searchServiceAPIVersion": { - "value": "[parameters('searchServiceAPIVersion')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "3970654296971990539" - } - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "azurechat-demo" - }, - "resourceToken": { - "type": "string" - }, - "openai_api_version": { - "type": "string" - }, - "openAiResourceGroupLocation": { - "type": "string" - }, - "openAiSkuName": { - "type": "string", - "defaultValue": "S0" - }, - "chatGptDeploymentCapacity": { - "type": "int", - "defaultValue": 30 - }, - "chatGptDeploymentName": { - "type": "string", - "defaultValue": "chat-gpt-35-turbo" - }, - "chatGptModelName": { - "type": "string", - "defaultValue": "chat-gpt-35-turbo" - }, - "chatGptModelVersion": { - "type": "string", - "defaultValue": "0613" - }, - "embeddingDeploymentName": { - "type": "string", - "defaultValue": "text-embedding-ada-002" - }, - "embeddingDeploymentCapacity": { - "type": "int", - "defaultValue": 30 - }, - "embeddingModelName": { - "type": "string", - "defaultValue": "text-embedding-ada-002" - }, - "formRecognizerSkuName": { - "type": "string", - "defaultValue": "S0" - }, - "searchServiceSkuName": { - "type": "string", - "defaultValue": "standard" - }, - "searchServiceIndexName": { - "type": "string", - "defaultValue": "azure-chat" - }, - "searchServiceAPIVersion": { - "type": "string", - "defaultValue": "2023-07-01-Preview" - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - }, - "nextAuthHash": { - "type": "securestring", - "defaultValue": "[uniqueString(newGuid())]" - }, - "tags": { - "type": "object", - "defaultValue": {} - } - }, - "variables": { - "openai_name": "[toLower(format('{0}ai{1}', parameters('name'), parameters('resourceToken')))]", - "form_recognizer_name": "[toLower(format('{0}-form-{1}', parameters('name'), parameters('resourceToken')))]", - "cosmos_name": "[toLower(format('{0}-cosmos-{1}', parameters('name'), parameters('resourceToken')))]", - "search_name": "[toLower(format('{0}search{1}', parameters('name'), parameters('resourceToken')))]", - "webapp_name": "[toLower(format('{0}-webapp-{1}', parameters('name'), parameters('resourceToken')))]", - "appservice_name": "[toLower(format('{0}-app-{1}', parameters('name'), parameters('resourceToken')))]", - "kv_prefix": "[take(parameters('name'), 7)]", - "keyVaultName": "[toLower(format('{0}-kv-{1}', variables('kv_prefix'), parameters('resourceToken')))]", - "keyVaultSecretsUserRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "databaseName": "chat", - "containerName": "history", - "deployments": [ - { - "name": "[parameters('chatGptDeploymentName')]", - "model": { - "format": "OpenAI", - "name": "[parameters('chatGptModelName')]", - "version": "[parameters('chatGptModelVersion')]" - }, - "sku": { - "name": "Standard", - "capacity": "[parameters('chatGptDeploymentCapacity')]" - } - }, - { - "name": "[parameters('embeddingDeploymentName')]", - "model": { - "format": "OpenAI", - "name": "[parameters('embeddingModelName')]", - "version": "2" - }, - "capacity": "[parameters('embeddingDeploymentCapacity')]" - } - ] - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2021-06-01-preview", - "name": "[format('{0}/{1}', variables('keyVaultName'), 'AZURE-COSMOSDB-KEY')]", - "properties": { - "contentType": "text/plain", - "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmos_name')), '2023-04-15').secondaryMasterKey]" - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmos_name'))]", - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]" - ] - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2021-06-01-preview", - "name": "[format('{0}/{1}', variables('keyVaultName'), 'AZURE-OPENAI-API-KEY')]", - "properties": { - "contentType": "text/plain", - "value": "[listKeys(resourceId('Microsoft.CognitiveServices/accounts', variables('openai_name')), '2023-05-01').key1]" - }, - "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', variables('openai_name'))]", - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]" - ] - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2021-06-01-preview", - "name": "[format('{0}/{1}', variables('keyVaultName'), 'AZURE-DOCUMENT-INTELLIGENCE-KEY')]", - "properties": { - "contentType": "text/plain", - "value": "[listKeys(resourceId('Microsoft.CognitiveServices/accounts', variables('form_recognizer_name')), '2023-05-01').key1]" - }, - "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', variables('form_recognizer_name'))]", - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]" - ] - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2021-06-01-preview", - "name": "[format('{0}/{1}', variables('keyVaultName'), 'AZURE-SEARCH-API-KEY')]", - "properties": { - "contentType": "text/plain", - "value": "[listAdminKeys(resourceId('Microsoft.Search/searchServices', variables('search_name')), '2022-09-01').secondaryKey]" - }, - "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", - "[resourceId('Microsoft.Search/searchServices', variables('search_name'))]" - ] - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2021-06-01-preview", - "name": "[format('{0}/{1}', variables('keyVaultName'), 'NEXTAUTH-SECRET')]", - "properties": { - "contentType": "text/plain", - "value": "[parameters('nextAuthHash')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]" - ] - }, - { - "type": "Microsoft.Web/serverfarms", - "apiVersion": "2020-06-01", - "name": "[variables('appservice_name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "reserved": true - }, - "sku": { - "name": "P0v3", - "tier": "Premium0V3", - "size": "P0v3", - "family": "Pv3", - "capacity": 1 - }, - "kind": "linux" - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2020-06-01", - "name": "[variables('webapp_name')]", - "location": "[parameters('location')]", - "tags": "[union(parameters('tags'), createObject('azd-service-name', 'frontend'))]", - "properties": { - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appservice_name'))]", - "httpsOnly": true, - "siteConfig": { - "linuxFxVersion": "node|18-lts", - "alwaysOn": true, - "appCommandLine": "next start", - "ftpsState": "Disabled", - "minTlsVersion": "1.2", - "appSettings": [ - { - "name": "AZURE_COSMOSDB_KEY", - "value": "[format('@Microsoft.KeyVault(VaultName={0};SecretName={1})', variables('keyVaultName'), 'AZURE-COSMOSDB-KEY')]" - }, - { - "name": "AZURE_OPENAI_API_KEY", - "value": "[format('@Microsoft.KeyVault(VaultName={0};SecretName={1})', variables('keyVaultName'), 'AZURE-OPENAI-API-KEY')]" - }, - { - "name": "AZURE_DOCUMENT_INTELLIGENCE_KEY", - "value": "[format('@Microsoft.KeyVault(VaultName={0};SecretName={1})', variables('keyVaultName'), 'AZURE-DOCUMENT-INTELLIGENCE-KEY')]" - }, - { - "name": "AZURE_SEARCH_API_KEY", - "value": "[format('@Microsoft.KeyVault(VaultName={0};SecretName={1})', variables('keyVaultName'), 'AZURE-SEARCH-API-KEY')]" - }, - { - "name": "AZURE_SEARCH_API_VERSION", - "value": "[parameters('searchServiceAPIVersion')]" - }, - { - "name": "AZURE_SEARCH_NAME", - "value": "[variables('search_name')]" - }, - { - "name": "AZURE_SEARCH_INDEX_NAME", - "value": "[parameters('searchServiceIndexName')]" - }, - { - "name": "AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT", - "value": "[format('https://{0}.api.cognitive.microsoft.com/', parameters('location'))]" - }, - { - "name": "SCM_DO_BUILD_DURING_DEPLOYMENT", - "value": "true" - }, - { - "name": "AZURE_COSMOSDB_URI", - "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmos_name')), '2023-04-15').documentEndpoint]" - }, - { - "name": "AZURE_OPENAI_API_INSTANCE_NAME", - "value": "[variables('openai_name')]" - }, - { - "name": "AZURE_OPENAI_API_DEPLOYMENT_NAME", - "value": "[parameters('chatGptDeploymentName')]" - }, - { - "name": "AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME", - "value": "[parameters('embeddingDeploymentName')]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "[parameters('openai_api_version')]" - }, - { - "name": "NEXTAUTH_SECRET", - "value": "[format('@Microsoft.KeyVault(VaultName={0};SecretName={1})', variables('keyVaultName'), 'NEXTAUTH-SECRET')]" - }, - { - "name": "NEXTAUTH_URL", - "value": "[format('https://{0}.azurewebsites.net', variables('webapp_name'))]" - } - ] - } - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', variables('appservice_name'))]", - "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), 'AZURE-COSMOSDB-KEY')]", - "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), 'AZURE-DOCUMENT-INTELLIGENCE-KEY')]", - "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), 'AZURE-OPENAI-API-KEY')]", - "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), 'AZURE-SEARCH-API-KEY')]", - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmos_name'))]", - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", - "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), 'NEXTAUTH-SECRET')]" - ] - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2020-04-01-preview", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', variables('keyVaultName'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName')), variables('webapp_name'), variables('keyVaultSecretsUserRole'))]", - "properties": { - "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('webapp_name')), '2020-06-01', 'full').identity.principalId]", - "principalType": "ServicePrincipal", - "roleDefinitionId": "[variables('keyVaultSecretsUserRole')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]", - "[resourceId('Microsoft.Web/sites', variables('webapp_name'))]" - ] - }, - { - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2021-06-01-preview", - "name": "[variables('keyVaultName')]", - "location": "[parameters('location')]", - "properties": { - "sku": { - "family": "A", - "name": "standard" - }, - "tenantId": "[subscription().tenantId]", - "enableRbacAuthorization": true, - "enabledForDeployment": false, - "enabledForDiskEncryption": true, - "enabledForTemplateDeployment": false - } - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2023-04-15", - "name": "[variables('cosmos_name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "GlobalDocumentDB", - "properties": { - "databaseAccountOfferType": "Standard", - "locations": [ - { - "locationName": "[parameters('location')]", - "failoverPriority": 0 - } - ], - "disableKeyBasedMetadataWriteAccess": true - } - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2022-05-15", - "name": "[format('{0}/{1}', variables('cosmos_name'), variables('databaseName'))]", - "properties": { - "resource": { - "id": "[variables('databaseName')]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmos_name'))]" - ] - }, - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2022-05-15", - "name": "[format('{0}/{1}', format('{0}/{1}', variables('cosmos_name'), variables('databaseName')), variables('containerName'))]", - "properties": { - "resource": { - "id": "[variables('containerName')]", - "partitionKey": { - "paths": [ - "/userId" - ], - "kind": "Hash" - }, - "defaultTtl": 86400 - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', split(format('{0}/{1}', variables('cosmos_name'), variables('databaseName')), '/')[0], split(format('{0}/{1}', variables('cosmos_name'), variables('databaseName')), '/')[1])]" - ] - }, - { - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2023-05-01", - "name": "[variables('form_recognizer_name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "FormRecognizer", - "properties": { - "customSubDomainName": "[variables('form_recognizer_name')]", - "publicNetworkAccess": "Enabled" - }, - "sku": { - "name": "[parameters('formRecognizerSkuName')]" - } - }, - { - "type": "Microsoft.Search/searchServices", - "apiVersion": "2022-09-01", - "name": "[variables('search_name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "partitionCount": 1, - "publicNetworkAccess": "enabled", - "replicaCount": 1 - }, - "sku": { - "name": "[parameters('searchServiceSkuName')]" - } - }, - { - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2023-05-01", - "name": "[variables('openai_name')]", - "location": "[parameters('openAiResourceGroupLocation')]", - "tags": "[parameters('tags')]", - "kind": "OpenAI", - "properties": { - "customSubDomainName": "[variables('openai_name')]", - "publicNetworkAccess": "Enabled" - }, - "sku": { - "name": "[parameters('openAiSkuName')]" - } - }, - { - "copy": { - "name": "deployment", - "count": "[length(variables('deployments'))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2023-05-01", - "name": "[format('{0}/{1}', variables('openai_name'), variables('deployments')[copyIndex()].name)]", - "properties": { - "model": "[variables('deployments')[copyIndex()].model]", - "raiPolicyName": "[if(contains(variables('deployments')[copyIndex()], 'raiPolicyName'), variables('deployments')[copyIndex()].raiPolicyName, null())]" - }, - "sku": "[if(contains(variables('deployments')[copyIndex()], 'sku'), variables('deployments')[copyIndex()].sku, createObject('name', 'Standard', 'capacity', variables('deployments')[copyIndex()].capacity))]", - "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', variables('openai_name'))]" - ] - } - ], - "outputs": { - "url": { - "type": "string", - "value": "[format('https://{0}', reference(resourceId('Microsoft.Web/sites', variables('webapp_name')), '2020-06-01').defaultHostName)]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', if(not(empty(parameters('resourceGroupName'))), parameters('resourceGroupName'), format('rg-{0}', parameters('name'))))]" - ] - } - ], - "outputs": { - "APP_URL": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, if(not(empty(parameters('resourceGroupName'))), parameters('resourceGroupName'), format('rg-{0}', parameters('name')))), 'Microsoft.Resources/deployments', 'all-resources'), '2022-09-01').outputs.url.value]" - }, - "AZURE_LOCATION": { - "type": "string", - "value": "[parameters('location')]" - }, - "AZURE_TENANT_ID": { - "type": "string", - "value": "[tenant().tenantId]" - } - } -} \ No newline at end of file diff --git a/infra/main.parameters.json b/infra/main.parameters.json deleted file mode 100644 index ccbcbb6b8..000000000 --- a/infra/main.parameters.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "name": { - "value": "${AZURE_ENV_NAME=azurechat-solution}" - }, - "location": { - "value": "${AZURE_LOCATION}" - } - } -} diff --git a/infra/resources.bicep b/infra/resources.bicep deleted file mode 100644 index ec9725c3a..000000000 --- a/infra/resources.bicep +++ /dev/null @@ -1,334 +0,0 @@ -param name string = 'azurechat-demo' -param resourceToken string - -param openai_api_version string - -param openAiResourceGroupLocation string -param openAiSkuName string = 'S0' -param chatGptDeploymentCapacity int = 30 -param chatGptDeploymentName string = 'chat-gpt-35-turbo' -param chatGptModelName string = 'chat-gpt-35-turbo' -param chatGptModelVersion string = '0613' -param embeddingDeploymentName string = 'text-embedding-ada-002' -param embeddingDeploymentCapacity int = 30 -param embeddingModelName string = 'text-embedding-ada-002' - -param formRecognizerSkuName string = 'S0' -param searchServiceSkuName string = 'standard' -param searchServiceIndexName string = 'azure-chat' -param searchServiceAPIVersion string = '2023-07-01-Preview' - -param location string = resourceGroup().location - -@secure() -param nextAuthHash string = uniqueString(newGuid()) - -param tags object = {} - -var openai_name = toLower('${name}ai${resourceToken}') -var form_recognizer_name = toLower('${name}-form-${resourceToken}') -var cosmos_name = toLower('${name}-cosmos-${resourceToken}') -var search_name = toLower('${name}search${resourceToken}') -var webapp_name = toLower('${name}-webapp-${resourceToken}') -var appservice_name = toLower('${name}-app-${resourceToken}') -// keyvault name must be less than 24 chars - token is 13 -var kv_prefix = take(name, 7) -var keyVaultName = toLower('${kv_prefix}-kv-${resourceToken}') - -var keyVaultSecretsUserRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6') - -var databaseName = 'chat' -var containerName = 'history' - -var deployments = [ - { - name: chatGptDeploymentName - model: { - format: 'OpenAI' - name: chatGptModelName - version: chatGptModelVersion - } - sku: { - name: 'Standard' - capacity: chatGptDeploymentCapacity - } - } - { - name: embeddingDeploymentName - model: { - format: 'OpenAI' - name: embeddingModelName - version: '2' - } - capacity: embeddingDeploymentCapacity - } -] - - -resource appServicePlan 'Microsoft.Web/serverfarms@2020-06-01' = { - name: appservice_name - location: location - tags: tags - properties: { - reserved: true - } - sku: { - name: 'P0v3' - tier: 'Premium0V3' - size: 'P0v3' - family: 'Pv3' - capacity: 1 - } - kind: 'linux' -} - -resource webApp 'Microsoft.Web/sites@2020-06-01' = { - name: webapp_name - location: location - tags: union(tags, { 'azd-service-name': 'frontend' }) - properties: { - serverFarmId: appServicePlan.id - httpsOnly: true - siteConfig: { - linuxFxVersion: 'node|18-lts' - alwaysOn: true - appCommandLine: 'next start' - ftpsState: 'Disabled' - minTlsVersion: '1.2' - appSettings: [ - { - name: 'AZURE_COSMOSDB_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_COSMOSDB_KEY.name})' - } - { - name: 'AZURE_OPENAI_API_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_OPENAI_API_KEY.name})' - } - { - name: 'AZURE_DOCUMENT_INTELLIGENCE_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_DOCUMENT_INTELLIGENCE_KEY.name})' - } - { - name: 'AZURE_SEARCH_API_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_SEARCH_API_KEY.name})' - } - { - name: 'AZURE_SEARCH_API_VERSION' - value: searchServiceAPIVersion - } - { - name: 'AZURE_SEARCH_NAME' - value: search_name - } - { - name: 'AZURE_SEARCH_INDEX_NAME' - value: searchServiceIndexName - } - { - name: 'AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT' - value: 'https://${location}.api.cognitive.microsoft.com/' - } - { - name: 'SCM_DO_BUILD_DURING_DEPLOYMENT' - value: 'true' - } - { - name: 'AZURE_COSMOSDB_URI' - value: cosmosDbAccount.properties.documentEndpoint - } - { - name: 'AZURE_OPENAI_API_INSTANCE_NAME' - value: openai_name - } - { - name: 'AZURE_OPENAI_API_DEPLOYMENT_NAME' - value: chatGptDeploymentName - } - { - name: 'AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME' - value: embeddingDeploymentName - } - { - name: 'AZURE_OPENAI_API_VERSION' - value: openai_api_version - } - { - name: 'NEXTAUTH_SECRET' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::NEXTAUTH_SECRET.name})' - } - { - name: 'NEXTAUTH_URL' - value: 'https://${webapp_name}.azurewebsites.net' - } - ] - } - } - identity: { type: 'SystemAssigned'} -} - -resource kvFunctionAppPermissions 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { - name: guid(kv.id, webApp.name, keyVaultSecretsUserRole) - scope: kv - properties: { - principalId: webApp.identity.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: keyVaultSecretsUserRole - } -} - -resource kv 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { - name: keyVaultName - location: location - properties: { - sku: { - family: 'A' - name: 'standard' - } - tenantId: subscription().tenantId - enableRbacAuthorization: true - enabledForDeployment: false - enabledForDiskEncryption: true - enabledForTemplateDeployment: false - } - - resource AZURE_COSMOSDB_KEY 'secrets' = { - name: 'AZURE-COSMOSDB-KEY' - properties: { - contentType: 'text/plain' - value: cosmosDbAccount.listKeys().secondaryMasterKey - } - } - - resource AZURE_OPENAI_API_KEY 'secrets' = { - name: 'AZURE-OPENAI-API-KEY' - properties: { - contentType: 'text/plain' - value: azureopenai.listKeys().key1 - } - } - - resource AZURE_DOCUMENT_INTELLIGENCE_KEY 'secrets' = { - name: 'AZURE-DOCUMENT-INTELLIGENCE-KEY' - properties: { - contentType: 'text/plain' - value: formRecognizer.listKeys().key1 - } - } - - resource AZURE_SEARCH_API_KEY 'secrets' = { - name: 'AZURE-SEARCH-API-KEY' - properties: { - contentType: 'text/plain' - value: searchService.listAdminKeys().secondaryKey - } - } - - resource NEXTAUTH_SECRET 'secrets' = { - name: 'NEXTAUTH-SECRET' - properties: { - contentType: 'text/plain' - value: nextAuthHash - } - } -} - -resource cosmosDbAccount 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = { - name: cosmos_name - location: location - tags: tags - kind: 'GlobalDocumentDB' - properties: { - databaseAccountOfferType: 'Standard' - locations: [ - { - locationName: location - failoverPriority: 0 - } - ] - disableKeyBasedMetadataWriteAccess: true - } -} - -resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2022-05-15' = { - name: '${cosmosDbAccount.name}/${databaseName}' - properties: { - resource: { - id: databaseName - } - } -} - -resource container 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2022-05-15' = { - name: '${database.name}/${containerName}' - properties: { - resource: { - id: containerName - partitionKey: { - paths: [ - '/userId' - ] - kind: 'Hash' - } - defaultTtl: 86400 - } - } -} - -resource formRecognizer 'Microsoft.CognitiveServices/accounts@2023-05-01' = { - name: form_recognizer_name - location: location - tags: tags - kind: 'FormRecognizer' - properties: { - customSubDomainName: form_recognizer_name - publicNetworkAccess: 'Enabled' - } - sku: { - name: formRecognizerSkuName - } -} - -resource searchService 'Microsoft.Search/searchServices@2022-09-01' = { - name: search_name - location: location - tags: tags - properties: { - partitionCount: 1 - publicNetworkAccess: 'enabled' - replicaCount: 1 - } - sku: { - name: searchServiceSkuName - } -} - -resource azureopenai 'Microsoft.CognitiveServices/accounts@2023-05-01' = { - name: openai_name - location: openAiResourceGroupLocation - tags: tags - kind: 'OpenAI' - properties: { - customSubDomainName: openai_name - publicNetworkAccess: 'Enabled' - } - sku: { - name: openAiSkuName - } -} - -@batchSize(1) -resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = [for deployment in deployments: { - parent: azureopenai - name: deployment.name - properties: { - model: deployment.model - raiPolicyName: contains(deployment, 'raiPolicyName') ? deployment.raiPolicyName : null - } - sku: contains(deployment, 'sku') ? deployment.sku : { - name: 'Standard' - capacity: deployment.capacity - } -}] - - -output url string = 'https://${webApp.properties.defaultHostName}' diff --git a/src/.env.example b/src/.env.example index 11443c23e..20cfa666a 100644 --- a/src/.env.example +++ b/src/.env.example @@ -1,17 +1,16 @@ -# Update your Azure OpenAI details -# AZURE_OPENAI_API_INSTANCE_NAME should be just the name of azure openai resource and not the full url; -# AZURE_OPENAI_API_DEPLOYMENT_NAME should be deployment name from your azure openai studio and not the model name. -# AZURE_OPENAI_API_VERSION should be Supported versions checkout docs https://learn.microsoft.com/en-us/azure/ai-services/openai/reference -AZURE_OPENAI_API_KEY= -AZURE_OPENAI_API_INSTANCE_NAME= -AZURE_OPENAI_API_DEPLOYMENT_NAME= -AZURE_OPENAI_API_VERSION=2023-03-15-preview -AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME= +# Update your OpenAI details +OPENAI_API_KEY= # Update your admin email addresses - comma separated ADMIN_EMAIL_ADDRESS="you@email.com,you2@email.com" +# Update the allowed user email addresses - comma separated +USERS_EMAIL_ADDRESS="you@email.com,you2@email.com" + # You must have atleast one of the following auth providers configured +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= + AUTH_GITHUB_ID= AUTH_GITHUB_SECRET= @@ -20,7 +19,7 @@ AZURE_AD_CLIENT_SECRET= AZURE_AD_TENANT_ID= # Update your production URL in NEXTAUTH_URL -NEXTAUTH_SECRET=AZURE-OPENIAI-NEXTAUTH-OWNKEY@1 +NEXTAUTH_SECRET=BLUGPT-NEXTAUTH-OWNKEY@1 NEXTAUTH_URL=http://localhost:3000 # Update your Cosmos Environment details here @@ -29,14 +28,4 @@ AZURE_COSMOSDB_KEY= # Update your Cosmos DB_NAME and CONTAINER_NAME if you want to overwrite the default values AZURE_COSMOSDB_DB_NAME=chat -AZURE_COSMOSDB_CONTAINER_NAME=history - -# Azure cognitive search is used for chat over your data -AZURE_SEARCH_API_KEY= -AZURE_SEARCH_NAME= -AZURE_SEARCH_INDEX_NAME= -AZURE_SEARCH_API_VERSION="2023-07-01-Preview" - -# Azure AI Document Intelligence to extract content from your data -AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT="https://REGION.api.cognitive.microsoft.com/" -AZURE_DOCUMENT_INTELLIGENCE_KEY= \ No newline at end of file +AZURE_COSMOSDB_CONTAINER_NAME=history \ No newline at end of file diff --git a/src/app/favicon.ico b/src/app/favicon.ico index 77095aeed..93ea8c335 100644 Binary files a/src/app/favicon.ico and b/src/app/favicon.ico differ diff --git a/src/components/login/login.tsx b/src/components/login/login.tsx index d7fb12b0d..3f4e3ad00 100644 --- a/src/components/login/login.tsx +++ b/src/components/login/login.tsx @@ -26,8 +26,9 @@ export const LogIn = () => { - - + + {/* */} + {/* */} ); diff --git a/src/dockerfile b/src/dockerfile index 2e6278d73..3e2bbc16e 100644 --- a/src/dockerfile +++ b/src/dockerfile @@ -25,7 +25,7 @@ COPY . . # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the build. -# ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED 1 RUN yarn build @@ -38,7 +38,7 @@ WORKDIR /app ENV NODE_ENV production # Uncomment the following line in case you want to disable telemetry during runtime. -# ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED 1 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs diff --git a/src/features/auth/auth-api.ts b/src/features/auth/auth-api.ts index d3c010426..53418a277 100644 --- a/src/features/auth/auth-api.ts +++ b/src/features/auth/auth-api.ts @@ -1,12 +1,31 @@ import NextAuth, { NextAuthOptions } from "next-auth"; import { Provider } from "next-auth/providers"; +import GoogleProvider from "next-auth/providers/google"; import AzureADProvider from "next-auth/providers/azure-ad"; import GitHubProvider from "next-auth/providers/github"; +const adminEmails = process.env.ADMIN_EMAIL_ADDRESS?.split(",").map(email => email.toLowerCase().trim()) || []; +const userEmails = process.env.USERS_EMAIL_ADDRESS?.split(",").map(email => email.toLowerCase().trim()) || []; + const configureIdentityProvider = () => { const providers: Array = []; - const adminEmails = process.env.ADMIN_EMAIL_ADDRESS?.split(",").map(email => email.toLowerCase().trim()); + if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) { + providers.push( + GoogleProvider({ + clientId: process.env.GOOGLE_CLIENT_ID!, + clientSecret: process.env.GOOGLE_CLIENT_SECRET!, + async profile(profile) { + const newProfile = { + ...profile, + id: profile.sub, + isAdmin: adminEmails.includes(profile.email.toLowerCase()) + } + return newProfile; + } + }) + ); + } if (process.env.AUTH_GITHUB_ID && process.env.AUTH_GITHUB_SECRET) { providers.push( @@ -16,7 +35,7 @@ const configureIdentityProvider = () => { async profile(profile) { const newProfile = { ...profile, - isAdmin: adminEmails?.includes(profile.email.toLowerCase()) + isAdmin: adminEmails.includes(profile.email.toLowerCase()) } return newProfile; } @@ -40,7 +59,7 @@ const configureIdentityProvider = () => { ...profile, // throws error without this - unsure of the root cause (https://stackoverflow.com/questions/76244244/profile-id-is-missing-in-google-oauth-profile-response-nextauth) id: profile.sub, - isAdmin: adminEmails?.includes(profile.email.toLowerCase()) || adminEmails?.includes(profile.preferred_username.toLowerCase()) + isAdmin: adminEmails.includes(profile.email.toLowerCase()) || adminEmails.includes(profile.preferred_username.toLowerCase()) } return newProfile; } @@ -63,6 +82,13 @@ export const options: NextAuthOptions = { async session({session, token, user }) { session.user.isAdmin = token.isAdmin as string return session + }, + async signIn({ user }) { + if (userEmails.length === 1 && userEmails[0] === "*") { + return true; + } + + return !!user && !!user.email && userEmails.includes(user.email.toLowerCase()); } }, session: { diff --git a/src/features/chat/chat-data/chat-data-api.ts b/src/features/chat/chat-data/chat-data-api.ts index a685b3473..e69b5f24c 100644 --- a/src/features/chat/chat-data/chat-data-api.ts +++ b/src/features/chat/chat-data/chat-data-api.ts @@ -25,6 +25,7 @@ export const ChatData = async (props: PromptGPTProps) => { temperature: transformConversationStyleToTemperature( chatThread.conversationStyle ), + modelName: props.chatModel, streaming: true, }); diff --git a/src/features/chat/chat-services/chat-thread-service.ts b/src/features/chat/chat-services/chat-thread-service.ts index 81b36d80e..96a2e9a4c 100644 --- a/src/features/chat/chat-services/chat-thread-service.ts +++ b/src/features/chat/chat-services/chat-thread-service.ts @@ -9,6 +9,7 @@ import { CosmosDBContainer } from "../../common/cosmos"; import { CHAT_THREAD_ATTRIBUTE, ChatMessageModel, + ChatModel, ChatThreadModel, ChatType, ConversationStyle, @@ -146,6 +147,7 @@ export const updateChatThreadTitle = async ( chatThread: ChatThreadModel, messages: ChatMessageModel[], chatType: ChatType, + chatModel: ChatModel, conversationStyle: ConversationStyle, chatOverFileName: string, userMessage: string @@ -154,6 +156,7 @@ export const updateChatThreadTitle = async ( const updatedChatThread = await UpsertChatThread({ ...chatThread, chatType: chatType, + chatModel: chatModel, chatOverFileName: chatOverFileName, conversationStyle: conversationStyle, name: userMessage.substring(0, 30), @@ -174,6 +177,7 @@ export const CreateChatThread = async () => { createdAt: new Date(), isDeleted: false, chatType: "simple", + chatModel: "gpt-4", conversationStyle: "precise", type: CHAT_THREAD_ATTRIBUTE, chatOverFileName: "" @@ -185,7 +189,7 @@ export const CreateChatThread = async () => { }; export const initAndGuardChatSession = async (props: PromptGPTProps) => { - const { messages, id, chatType, conversationStyle, chatOverFileName } = props; + const { messages, id, chatType, chatModel, conversationStyle, chatOverFileName } = props; //last message const lastHumanMessage = messages[messages.length - 1]; @@ -197,6 +201,7 @@ export const initAndGuardChatSession = async (props: PromptGPTProps) => { currentChatThread, chats, chatType, + chatModel, conversationStyle, chatOverFileName, lastHumanMessage.content diff --git a/src/features/chat/chat-services/models.ts b/src/features/chat/chat-services/models.ts index ee821a29d..792d9e5d7 100644 --- a/src/features/chat/chat-services/models.ts +++ b/src/features/chat/chat-services/models.ts @@ -20,6 +20,7 @@ export type ConversationStyle = "creative" | "balanced" | "precise"; export type ChatType = "simple" | "data" | "mssql"; export type ChatRole = "system" | "user" | "assistant" | "function"; +export type ChatModel = "gpt-3.5-turbo" | "gpt-4"; export interface ChatThreadModel { id: string; @@ -29,6 +30,7 @@ export interface ChatThreadModel { useName: string; isDeleted: boolean; chatType: ChatType; + chatModel: ChatModel; conversationStyle: ConversationStyle; chatOverFileName: string; type: "CHAT_THREAD"; @@ -39,6 +41,7 @@ export interface PromptGPTBody { chatType: ChatType; conversationStyle: ConversationStyle; chatOverFileName: string; + chatModel: ChatModel; } export interface PromptGPTProps extends PromptGPTBody { diff --git a/src/features/chat/chat-simple/chat-simple-api.ts b/src/features/chat/chat-simple/chat-simple-api.ts index 0d2a231e6..b53cb12d8 100644 --- a/src/features/chat/chat-simple/chat-simple-api.ts +++ b/src/features/chat/chat-simple/chat-simple-api.ts @@ -28,6 +28,7 @@ export const ChatSimple = async (props: PromptGPTProps) => { temperature: transformConversationStyleToTemperature( chatThread.conversationStyle ), + modelName: props.chatModel, streaming: true, }); diff --git a/src/features/chat/chat-ui/chat-empty-state.tsx b/src/features/chat/chat-ui/chat-empty-state.tsx index 327001178..030eda0a4 100644 --- a/src/features/chat/chat-ui/chat-empty-state.tsx +++ b/src/features/chat/chat-ui/chat-empty-state.tsx @@ -4,15 +4,18 @@ import { Card } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { ArrowUpCircle, Loader2 } from "lucide-react"; import { FC, useState } from "react"; -import { ChatType, ConversationStyle } from "../chat-services/models"; +import { ChatModel, ChatType, ConversationStyle } from "../chat-services/models"; import { ChatStyleSelector } from "./chat-style-selector"; import { ChatTypeSelector } from "./chat-type-selector"; +import { ChatModelSelector } from "./chat-model-selector"; interface Prop { isUploadingFile: boolean; chatType: ChatType; + chatModel: ChatModel; conversationStyle: ConversationStyle; uploadButtonLabel: string; onChatTypeChange: (value: ChatType) => void; + onChatModelChange: (value: ChatModel) => void; onConversationStyleChange: (value: ConversationStyle) => void; onFileChange: (file: FormData) => void; } @@ -48,6 +51,16 @@ export const EmptyState: FC = (props) => { Personalise +
+

+ Choose a model +

+ +

Choose a conversation style diff --git a/src/features/chat/chat-ui/chat-header.tsx b/src/features/chat/chat-ui/chat-header.tsx index 7a53ccc8f..c13c8f7d7 100644 --- a/src/features/chat/chat-ui/chat-header.tsx +++ b/src/features/chat/chat-ui/chat-header.tsx @@ -2,6 +2,7 @@ import { FC } from "react"; import { ChatType, ConversationStyle, PromptGPTBody } from "../chat-services/models"; import { ChatStyleSelector } from "./chat-style-selector"; import { ChatTypeSelector } from "./chat-type-selector"; +import { ChatModelSelector } from "./chat-model-selector"; interface Prop { chatBody: PromptGPTBody; @@ -11,6 +12,7 @@ export const ChatHeader: FC = (props) => { return (

+ void; +} + +export const ChatModelSelector: FC = (props) => { + return ( + + props.onChatModelChange + ? props.onChatModelChange(value as ChatModel) + : null + } + > + + + GPT-3.5 + + + GPT-4 + + + + ); +}; diff --git a/src/features/chat/chat-ui/chat-ui.tsx b/src/features/chat/chat-ui/chat-ui.tsx index 3e5ab54ed..29054b1f9 100644 --- a/src/features/chat/chat-ui/chat-ui.tsx +++ b/src/features/chat/chat-ui/chat-ui.tsx @@ -16,6 +16,7 @@ import { } from "../chat-services/chat-document-service"; import { ChatMessageModel, + ChatModel, ChatThreadModel, ChatType, ConversationStyle, @@ -41,6 +42,7 @@ export const ChatUI: FC = (props) => { const [chatBody, setBody] = useState({ id: props.chatThread.id, chatType: props.chatThread.chatType, + chatModel: props.chatThread.chatModel, conversationStyle: props.chatThread.conversationStyle, chatOverFileName: props.chatThread.chatOverFileName }); @@ -87,6 +89,10 @@ export const ChatUI: FC = (props) => { setBody((e) => ({ ...e, chatType: value })); }; + const onChatModelChange = (value: ChatModel) => { + setBody((e) => ({ ...e, chatModel: value })); + }; + const onConversationStyleChange = (value: ConversationStyle) => { setBody((e) => ({ ...e, conversationStyle: value })); }; @@ -176,7 +182,9 @@ export const ChatUI: FC = (props) => { onFileChange={onFileChange} onConversationStyleChange={onConversationStyleChange} onChatTypeChange={onChatTypeChange} + onChatModelChange={onChatModelChange} chatType={chatBody.chatType} + chatModel={chatBody.chatModel} conversationStyle={chatBody.conversationStyle} /> )} diff --git a/src/features/theme/customise.ts b/src/features/theme/customise.ts index a38f19136..23a5f3e2a 100644 --- a/src/features/theme/customise.ts +++ b/src/features/theme/customise.ts @@ -1 +1 @@ -export const AI_NAME = "Azure Chat Solution Accelerator"; +export const AI_NAME = "BluGPT"; diff --git a/src/package.json b/src/package.json index 0711f58b1..18e80a25e 100644 --- a/src/package.json +++ b/src/package.json @@ -1,5 +1,5 @@ { - "name": "azure-open-ai-accelerator", + "name": "blugpt", "version": "0.1.0", "private": true, "scripts": { diff --git a/src/public/ai-icon.png b/src/public/ai-icon.png index 603ae1cf0..0148bb479 100644 Binary files a/src/public/ai-icon.png and b/src/public/ai-icon.png differ diff --git a/src/type.ts b/src/type.ts index a70764712..eb5648c5c 100644 --- a/src/type.ts +++ b/src/type.ts @@ -1,4 +1,5 @@ const azureEnvVars = [ + "OPENAI_API_KEY", "AZURE_OPENAI_API_KEY", "AZURE_OPENAI_API_INSTANCE_NAME", "AZURE_OPENAI_API_DEPLOYMENT_NAME", @@ -21,7 +22,10 @@ const azureEnvVars = [ "NEXTAUTH_URL", "AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT", "AZURE_DOCUMENT_INTELLIGENCE_KEY", - "ADMIN_EMAIL_ADDRESS" + "ADMIN_EMAIL_ADDRESS", + "USERS_EMAIL_ADDRESS", + "GOOGLE_CLIENT_ID", + "GOOGLE_CLIENT_SECRET" ] as const; type RequiredServerEnvKeys = (typeof azureEnvVars)[number];