From 3cd9ae4aaca3b0a7d21133252d2875def5cf70da Mon Sep 17 00:00:00 2001 From: Pablo Castro Date: Wed, 8 Mar 2023 21:46:21 -0800 Subject: [PATCH] First commit for sample code --- .gitignore | 21 +- .vscode/extensions.json | 6 + .vscode/launch.json | 60 + .vscode/settings.json | 22 + .vscode/tasks.json | 32 + README.md | 72 +- app/backend/app.py | 119 + app/backend/approaches/approach.py | 3 + .../approaches/chatreadretrieveread.py | 113 + app/backend/approaches/readdecomposeask.py | 207 ++ app/backend/approaches/readretrieveread.py | 111 + app/backend/approaches/retrievethenread.py | 79 + app/backend/data/employeeinfo.csv | 4 + app/backend/langchainadapters.py | 82 + app/backend/lookuptool.py | 16 + app/backend/requirements.txt | 6 + app/backend/text.py | 2 + app/frontend/.prettierrc.json | 6 + app/frontend/index.html | 13 + app/frontend/package-lock.json | 3035 +++++++++++++++++ app/frontend/package.json | 29 + app/frontend/public/favicon.ico | Bin 0 -> 4286 bytes app/frontend/src/api/api.ts | 66 + app/frontend/src/api/index.ts | 2 + app/frontend/src/api/models.ts | 41 + app/frontend/src/assets/github.svg | 1 + app/frontend/src/assets/search.svg | 1 + .../AnalysisPanel/AnalysisPanel.module.css | 6 + .../AnalysisPanel/AnalysisPanel.tsx | 57 + .../AnalysisPanel/AnalysisPanelTabs.tsx | 5 + .../src/components/AnalysisPanel/index.tsx | 2 + .../src/components/Answer/Answer.module.css | 125 + app/frontend/src/components/Answer/Answer.tsx | 96 + .../src/components/Answer/AnswerError.tsx | 23 + .../src/components/Answer/AnswerIcon.tsx | 5 + .../src/components/Answer/AnswerLoading.tsx | 26 + .../src/components/Answer/AnswerParser.tsx | 52 + app/frontend/src/components/Answer/index.ts | 3 + .../ClearChatButton.module.css | 10 + .../ClearChatButton/ClearChatButton.tsx | 19 + .../src/components/ClearChatButton/index.tsx | 1 + .../src/components/Example/Example.module.css | 39 + .../src/components/Example/Example.tsx | 15 + .../src/components/Example/ExampleList.tsx | 33 + app/frontend/src/components/Example/index.tsx | 2 + .../QuestionInput/QuestionInput.module.css | 27 + .../QuestionInput/QuestionInput.tsx | 69 + .../src/components/QuestionInput/index.ts | 1 + .../SettingsButton/SettingsButton.module.css | 6 + .../SettingsButton/SettingsButton.tsx | 18 + .../src/components/SettingsButton/index.tsx | 1 + .../SupportingContent.module.css | 28 + .../SupportingContent/SupportingContent.tsx | 24 + .../SupportingContentParser.ts | 17 + .../src/components/SupportingContent/index.ts | 1 + .../UserChatMessage.module.css | 15 + .../UserChatMessage/UserChatMessage.tsx | 13 + .../src/components/UserChatMessage/index.ts | 1 + app/frontend/src/index.css | 23 + app/frontend/src/index.tsx | 33 + app/frontend/src/pages/NoPage.tsx | 5 + app/frontend/src/pages/chat/Chat.module.css | 115 + app/frontend/src/pages/chat/Chat.tsx | 254 ++ .../src/pages/layout/Layout.module.css | 78 + app/frontend/src/pages/layout/Layout.tsx | 50 + .../src/pages/oneshot/OneShot.module.css | 66 + app/frontend/src/pages/oneshot/OneShot.tsx | 251 ++ app/frontend/src/vite-env.d.ts | 1 + app/frontend/tsconfig.json | 21 + app/frontend/vite.config.ts | 18 + app/start.cmd | 56 + azure.yaml | 21 + data/Benefit_Options.pdf | Bin 0 -> 98766 bytes ...Northwind_Health_Plus_Benefits_Details.pdf | Bin 0 -> 582158 bytes data/Northwind_Standard_Benefits_Details.pdf | Bin 0 -> 567026 bytes data/PerksPlus.pdf | Bin 0 -> 115310 bytes data/employee_handbook.pdf | Bin 0 -> 142977 bytes data/role_library.pdf | Bin 0 -> 227141 bytes infra/abbreviations.json | 135 + infra/core/ai/cognitiveservices.bicep | 38 + infra/core/host/appservice.bicep | 100 + infra/core/host/appserviceplan.bicep | 21 + infra/core/search/search-services.bicep | 41 + infra/core/security/role.bicep | 20 + infra/core/storage/storage-account.bicep | 58 + infra/main.bicep | 250 ++ infra/main.parameters.json | 24 + notebooks/chat-read-retrieve-read.ipynb | 173 + notebooks/read-decompose-ask.ipynb | 277 ++ scripts/prepdocs.ps1 | 12 + scripts/prepdocs.py | 225 ++ scripts/requirements.txt | 4 + 92 files changed, 7222 insertions(+), 37 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 app/backend/app.py create mode 100644 app/backend/approaches/approach.py create mode 100644 app/backend/approaches/chatreadretrieveread.py create mode 100644 app/backend/approaches/readdecomposeask.py create mode 100644 app/backend/approaches/readretrieveread.py create mode 100644 app/backend/approaches/retrievethenread.py create mode 100644 app/backend/data/employeeinfo.csv create mode 100644 app/backend/langchainadapters.py create mode 100644 app/backend/lookuptool.py create mode 100644 app/backend/requirements.txt create mode 100644 app/backend/text.py create mode 100644 app/frontend/.prettierrc.json create mode 100644 app/frontend/index.html create mode 100644 app/frontend/package-lock.json create mode 100644 app/frontend/package.json create mode 100644 app/frontend/public/favicon.ico create mode 100644 app/frontend/src/api/api.ts create mode 100644 app/frontend/src/api/index.ts create mode 100644 app/frontend/src/api/models.ts create mode 100644 app/frontend/src/assets/github.svg create mode 100644 app/frontend/src/assets/search.svg create mode 100644 app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css create mode 100644 app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx create mode 100644 app/frontend/src/components/AnalysisPanel/AnalysisPanelTabs.tsx create mode 100644 app/frontend/src/components/AnalysisPanel/index.tsx create mode 100644 app/frontend/src/components/Answer/Answer.module.css create mode 100644 app/frontend/src/components/Answer/Answer.tsx create mode 100644 app/frontend/src/components/Answer/AnswerError.tsx create mode 100644 app/frontend/src/components/Answer/AnswerIcon.tsx create mode 100644 app/frontend/src/components/Answer/AnswerLoading.tsx create mode 100644 app/frontend/src/components/Answer/AnswerParser.tsx create mode 100644 app/frontend/src/components/Answer/index.ts create mode 100644 app/frontend/src/components/ClearChatButton/ClearChatButton.module.css create mode 100644 app/frontend/src/components/ClearChatButton/ClearChatButton.tsx create mode 100644 app/frontend/src/components/ClearChatButton/index.tsx create mode 100644 app/frontend/src/components/Example/Example.module.css create mode 100644 app/frontend/src/components/Example/Example.tsx create mode 100644 app/frontend/src/components/Example/ExampleList.tsx create mode 100644 app/frontend/src/components/Example/index.tsx create mode 100644 app/frontend/src/components/QuestionInput/QuestionInput.module.css create mode 100644 app/frontend/src/components/QuestionInput/QuestionInput.tsx create mode 100644 app/frontend/src/components/QuestionInput/index.ts create mode 100644 app/frontend/src/components/SettingsButton/SettingsButton.module.css create mode 100644 app/frontend/src/components/SettingsButton/SettingsButton.tsx create mode 100644 app/frontend/src/components/SettingsButton/index.tsx create mode 100644 app/frontend/src/components/SupportingContent/SupportingContent.module.css create mode 100644 app/frontend/src/components/SupportingContent/SupportingContent.tsx create mode 100644 app/frontend/src/components/SupportingContent/SupportingContentParser.ts create mode 100644 app/frontend/src/components/SupportingContent/index.ts create mode 100644 app/frontend/src/components/UserChatMessage/UserChatMessage.module.css create mode 100644 app/frontend/src/components/UserChatMessage/UserChatMessage.tsx create mode 100644 app/frontend/src/components/UserChatMessage/index.ts create mode 100644 app/frontend/src/index.css create mode 100644 app/frontend/src/index.tsx create mode 100644 app/frontend/src/pages/NoPage.tsx create mode 100644 app/frontend/src/pages/chat/Chat.module.css create mode 100644 app/frontend/src/pages/chat/Chat.tsx create mode 100644 app/frontend/src/pages/layout/Layout.module.css create mode 100644 app/frontend/src/pages/layout/Layout.tsx create mode 100644 app/frontend/src/pages/oneshot/OneShot.module.css create mode 100644 app/frontend/src/pages/oneshot/OneShot.tsx create mode 100644 app/frontend/src/vite-env.d.ts create mode 100644 app/frontend/tsconfig.json create mode 100644 app/frontend/vite.config.ts create mode 100644 app/start.cmd create mode 100644 azure.yaml create mode 100644 data/Benefit_Options.pdf create mode 100644 data/Northwind_Health_Plus_Benefits_Details.pdf create mode 100644 data/Northwind_Standard_Benefits_Details.pdf create mode 100644 data/PerksPlus.pdf create mode 100644 data/employee_handbook.pdf create mode 100644 data/role_library.pdf create mode 100644 infra/abbreviations.json create mode 100644 infra/core/ai/cognitiveservices.bicep create mode 100644 infra/core/host/appservice.bicep create mode 100644 infra/core/host/appserviceplan.bicep create mode 100644 infra/core/search/search-services.bicep create mode 100644 infra/core/security/role.bicep create mode 100644 infra/core/storage/storage-account.bicep create mode 100644 infra/main.bicep create mode 100644 infra/main.parameters.json create mode 100644 notebooks/chat-read-retrieve-read.ipynb create mode 100644 notebooks/read-decompose-ask.ipynb create mode 100644 scripts/prepdocs.ps1 create mode 100644 scripts/prepdocs.py create mode 100644 scripts/requirements.txt diff --git a/.gitignore b/.gitignore index b6e47617de..268d324174 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Azure az webapp deployment details +.azure + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -20,7 +23,6 @@ parts/ sdist/ var/ wheels/ -pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg @@ -50,6 +52,7 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ +cover/ # Translations *.mo @@ -72,6 +75,7 @@ instance/ docs/_build/ # PyBuilder +.pybuilder/ target/ # Jupyter Notebook @@ -82,7 +86,9 @@ profile_default/ ipython_config.py # pyenv -.python-version +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -127,3 +133,14 @@ dmypy.json # Pyre type checker .pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# NPM +npm-debug.log* +node_modules +static/ \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..12faf24039 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + "ms-azuretools.azure-dev" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..222b96bd36 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,60 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Flask", + "type": "python", + "request": "launch", + "module": "flask", + "cwd": "${workspaceFolder}/app/backend", + "env": { + "FLASK_APP": "app.py", + "FLASK_ENV": "development", + "FLASK_DEBUG": "0" + }, + "args": [ + "run", + "--no-debugger", + "--no-reload", + "-p 5000" + ], + "console": "integratedTerminal", + "justMyCode": true, + "envFile": "${input:dotEnvFilePath}", + }, + { + "name": "Frontend: watch", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}/app/frontend", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "run-script", + "watch" + ], + "console": "integratedTerminal", + }, + { + "name": "Frontend: build", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}/app/frontend", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "run-script", + "build" + ], + "console": "integratedTerminal", + } + ], + "inputs": [ + { + "id": "dotEnvFilePath", + "type": "command", + "command": "azure-dev.commands.getDotEnvFilePath" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..7181b35e8a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "search.exclude": { + "**/node_modules": true, + "static": true + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000..61f56d7cc5 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,32 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start App", + "type": "dotenv", + "targetTasks": [ + "Start App (Script)" + ], + "file": "${input:dotEnvFilePath}" + }, + { + "label": "Start App (Script)", + "type": "shell", + "command": "start.cmd", + "presentation": { + "reveal": "silent" + }, + "options": { + "cwd": "${workspaceFolder}/app" + }, + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "dotEnvFilePath", + "type": "command", + "command": "azure-dev.commands.getDotEnvFilePath" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 364f0525ac..ecf292c303 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,59 @@ -# Project Name +# ChatGPT + Enterprise data with Azure OpenAI and Cognitive Search -(short, 1-3 sentenced, description of the project) +This sample demonstrates a few approaches for creating ChatGPT-like experiences over your own data. It uses Azure OpenAI Service to access the ChatGPT model (gpt-35-turbo), and Azure Cognitive Search for data indexing and retrieval. -## Features +The repo includes sample data so it's ready to try end to end. In this sample application we use a fictitious company called Contoso Electronics, and the experience allows its employees to ask questions about the benefits, internal policies, as well as job descriptions and roles. -This project framework provides the following features: +## Features -* Feature 1 -* Feature 2 -* ... +* Chat and Q&A interfaces +* Explores various options to help users evaluate the trustworthiness of responses with citations, tracking of source content, etc. +* Shows possible approaches for data preparation, prompt construction, and orchestration of interaction between model (ChatGPT) and retriever (Cognitive Search) +* Settings directly in the UX to tweak the behavior and experiment with options ## Getting Started -### Prerequisites +** NOTE ** In order to deploy and run this example, you'll need an Azure subscription with access enabled for the Azure OpenAI service. You can request access [here](https://aka.ms/oaiapply). -(ideally very short, if any) +### Prerequisites -- OS -- Library version -- ... +- Azure Developer CLI (install from [here](https://aka.ms/azure-dev/install)) +- Python (install from [here](https://www.python.org/downloads/)) + - **Imporant**: Python and the pip package manager must in the path in Windows for the setup scripts to work. +- Node.js (install from [here](https://nodejs.org/en/download/)) +- Git (install from [here](https://git-scm.com/downloads)) +- Powershell (pwsh) (install from [here](https://learn.microsoft.com/en-us/powershell/)) ### Installation -(ideally very short) +Starting from scratch: +1. Create a new folder and switch to it in the terminal +2. Run "azd up -t azure-search-openai-demo" + * For the target location, the regions that currently support the models used in this sample are East US or South Central US. For an up-to-date list of regions and models, check [here](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/concepts/models) -- npm install [package name] -- mvn install -- ... +Deploying or re-deploying a local clone of the repo: +* Simply run "azd up" -### Quickstart -(Add steps to get up and running quickly) +Running locally: +* Run `./app/start.cmd` or run the "VS Code Task: Start App" to start the project locally. -1. git clone [repository clone url] -2. cd [repository name] -3. ... +** AZURE RESOURCE COSTS ** by default this sample will create Azure App Service and Azure Cognitive Search resources that have a monthly cost. You can switch them to free versions of each of them if you want to avoid this cost by changing the parameters file under the infra folder (though there are some limits to consider; for example, you can have up to 1 free Cognitive Search resource per subscription.) +### Quickstart -## Demo - -A demo app is included to show how to use the project. - -To run the demo, follow these steps: - -(Add steps to start up the demo) +* In Azure: navigate to the Azure WebApp deployed by azd. The URL is printed out when azd completes (as "Endpoint"), or you can find it in the Azure portal. +* Running locally: navigate to 127.0.0.1:5000 -1. -2. -3. +Once in the web app: +* Try different topics in chat or Q&A context. For chat, try follow up questions, clarifications, ask to simplify or elaborate on answer, etc. +* Explore citations and sources +* Click on "settings" to try different options, tweak prompts, etc. ## Resources -(Any additional resources or related projects) +* [Revolutionize your Enterprise Data with ChatGPT: Next-gen Apps w/ Azure OpenAI and Cognitive Search](https://aka.ms/entgptsearchblog) +* [Azure Cognitive Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) +* [Azure OpenAI Service](https://learn.microsoft.com/azure/cognitive-services/openai/overview) -- Link to supporting information -- Link to similar sample -- ... +### Note +>Note: The PDF documents used in this demo contain information generated using a language model (Azure OpenAI Service). The information contained in these documents is only for demonstration purposes and does not reflect the opinions or beliefs of Microsoft. Microsoft makes no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the information contained in this document. All rights reserved to Microsoft. \ No newline at end of file diff --git a/app/backend/app.py b/app/backend/app.py new file mode 100644 index 0000000000..a64371577d --- /dev/null +++ b/app/backend/app.py @@ -0,0 +1,119 @@ +import os +import mimetypes +import time +import logging +import openai +from flask import Flask, request, jsonify +from azure.identity import DefaultAzureCredential +from azure.search.documents import SearchClient +from approaches.retrievethenread import RetrieveThenReadApproach +from approaches.readretrieveread import ReadRetrieveReadApproach +from approaches.readdecomposeask import ReadDecomposeAsk +from approaches.chatreadretrieveread import ChatReadRetrieveReadApproach +from azure.storage.blob import BlobServiceClient + +# Replace these with your own values, either in environment variables or directly here +AZURE_BLOB_STORAGE_ACCOUNT = os.environ.get("AZURE_BLOB_STORAGE_ACCOUNT") or "mystorageaccount" +AZURE_BLOB_STORAGE_CONTAINER = os.environ.get("AZURE_BLOB_STORAGE_CONTAINER") or "content" +AZURE_SEARCH_SERVICE = os.environ.get("AZURE_SEARCH_SERVICE") or "gptkb" +AZURE_SEARCH_INDEX = os.environ.get("AZURE_SEARCH_INDEX") or "gptkbindex" +AZURE_OPENAI_SERVICE = os.environ.get("AZURE_OPENAI_SERVICE") or "myopenai" +AZURE_OPENAI_GPT_DEPLOYMENT = os.environ.get("AZURE_OPENAI_GPT_DEPLOYMENT") or "davinci" +AZURE_OPENAI_CHATGPT_DEPLOYMENT = os.environ.get("AZURE_OPENAI_CHATGPT_DEPLOYMENT") or "chat" + +KB_FIELDS_CONTENT = os.environ.get("KB_FIELDS_CONTENT") or "content" +KB_FIELDS_CATEGORY = os.environ.get("KB_FIELDS_CATEGORY") or "category" +KB_FIELDS_SOURCEPAGE = os.environ.get("KB_FIELDS_SOURCEPAGE") or "sourcepage" + +# Use the current user identity to authenticate with Azure OpenAI, Cognitive Search and Blob Storage (no secrets needed, +# just use 'az login' locally, and managed identity when deployed on Azure). If you need to use keys, use separate AzureKeyCredential instances with the +# keys for each service +# If you encounter a blocking error during a DefaultAzureCredntial resolution, you can exclude the problematic credential by using a parameter (ex. exclude_shared_token_cache_credential=True) +azure_credential = DefaultAzureCredential() + +# Used by the OpenAI SDK +openai.api_type = "azure" +openai.api_base = f"https://{AZURE_OPENAI_SERVICE}.openai.azure.com" +openai.api_version = "2022-12-01" + +# Comment these two lines out if using keys, set your API key in the OPENAI_API_KEY environment variable instead +openai.api_type = "azure_ad" +openai_token = azure_credential.get_token("https://cognitiveservices.azure.com/.default") +openai.api_key = openai_token.token + +# Set up clients for Cognitive Search and Storage +search_client = SearchClient( + endpoint=f"https://{AZURE_SEARCH_SERVICE}.search.windows.net", + index_name=AZURE_SEARCH_INDEX, + credential=azure_credential) +blob_client = BlobServiceClient( + account_url=f"https://{AZURE_BLOB_STORAGE_ACCOUNT}.blob.core.windows.net", + credential=azure_credential) +blob_container = blob_client.get_container_client(AZURE_BLOB_STORAGE_CONTAINER) + +# Various approaches to integrate GPT and external knowledge, most applications will use a single one of these patterns +# or some derivative, here we include several for exploration purposes +ask_approaches = { + "rtr": RetrieveThenReadApproach(search_client, AZURE_OPENAI_GPT_DEPLOYMENT, KB_FIELDS_SOURCEPAGE, KB_FIELDS_CONTENT), + "rrr": ReadRetrieveReadApproach(search_client, AZURE_OPENAI_GPT_DEPLOYMENT, KB_FIELDS_SOURCEPAGE, KB_FIELDS_CONTENT), + "rda": ReadDecomposeAsk(search_client, AZURE_OPENAI_GPT_DEPLOYMENT, KB_FIELDS_SOURCEPAGE, KB_FIELDS_CONTENT) +} + +chat_approaches = { + "rrr": ChatReadRetrieveReadApproach(search_client, AZURE_OPENAI_CHATGPT_DEPLOYMENT, AZURE_OPENAI_GPT_DEPLOYMENT, KB_FIELDS_SOURCEPAGE, KB_FIELDS_CONTENT) +} + +app = Flask(__name__) + +@app.route("/", defaults={"path": "index.html"}) +@app.route("/") +def static_file(path): + return app.send_static_file(path) + +# Serve content files from blob storage from within the app to keep the example self-contained. +# *** NOTE *** this assumes that the content files are public, or at least that all users of the app +# can access all the files. This is also slow and memory hungry. +@app.route("/content/") +def content_file(path): + blob = blob_container.get_blob_client(path).download_blob() + mime_type = blob.properties["content_settings"]["content_type"] + if mime_type == "application/octet-stream": + mime_type = mimetypes.guess_type(path)[0] or "application/octet-stream" + return blob.readall(), 200, {"Content-Type": mime_type, "Content-Disposition": f"inline; filename={path}"} + +@app.route("/ask", methods=["POST"]) +def ask(): + ensure_openai_token() + approach = request.json["approach"] + try: + impl = ask_approaches.get(approach) + if not impl: + return jsonify({"error": "unknown approach"}), 400 + r = impl.run(request.json["question"], request.json.get("overrides") or {}) + return jsonify(r) + except Exception as e: + logging.exception("Exception in /ask") + return jsonify({"error": str(e)}), 500 + +@app.route("/chat", methods=["POST"]) +def chat(): + ensure_openai_token() + approach = request.json["approach"] + try: + impl = chat_approaches.get(approach) + if not impl: + return jsonify({"error": "unknown approach"}), 400 + r = impl.run(request.json["history"], request.json.get("overrides") or {}) + return jsonify(r) + except Exception as e: + logging.exception("Exception in /chat") + return jsonify({"error": str(e)}), 500 + +def ensure_openai_token(): + global openai_token + if openai_token.expires_on < int(time.time()) - 60: + openai_token = azure_credential.get_token("https://cognitiveservices.azure.com/.default") + openai.api_key = openai_token.token + +if __name__ == "__main__": + app.run() diff --git a/app/backend/approaches/approach.py b/app/backend/approaches/approach.py new file mode 100644 index 0000000000..f17a410f4d --- /dev/null +++ b/app/backend/approaches/approach.py @@ -0,0 +1,3 @@ +class Approach: + def run(self, q: str, use_summaries: bool) -> any: + raise NotImplementedError diff --git a/app/backend/approaches/chatreadretrieveread.py b/app/backend/approaches/chatreadretrieveread.py new file mode 100644 index 0000000000..39aaf81f99 --- /dev/null +++ b/app/backend/approaches/chatreadretrieveread.py @@ -0,0 +1,113 @@ +import openai +from azure.search.documents import SearchClient +from azure.search.documents.models import QueryType +from approaches.approach import Approach +from text import nonewlines + +# Simple retrieve-then-read implementation, using the Cognitive Search and OpenAI APIs directly. It first retrieves +# top documents from search, then constructs a prompt with them, and then uses OpenAI to generate an completion +# (answer) with that prompt. +class ChatReadRetrieveReadApproach(Approach): + prompt_prefix = """<|im_start|>system +Assistant helps the company employees with their healthcare plan questions, and questions about the employee handbook. Be brief in your answers. +Answer ONLY with the facts listed in the list of sources below. If there isn't enough information below, say you don't know. Do not generate answers that don't use the sources below. If asking a clarifying question to the user would help, ask the question. +Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. Use square brakets to reference the source, e.g. [info1.txt]. Don't combine sources, list each source separately, e.g. [info1.txt][info2.pdf]. +{follow_up_questions_prompt} +{injected_prompt} +Sources: +{sources} +<|im_end|> +{chat_history} +""" + + follow_up_questions_prompt_content = """Generate three very brief follow-up questions that the user would likely ask next about their healthcare plan and employee handbook. + Use double angle brackets to reference the questions, e.g. <>. + Try not to repeat questions that have already been asked. + Only generate questions and do not generate any text before or after the questions, such as 'Next Questions'""" + + query_prompt_template = """Below is a history of the conversation so far, and a new question asked by the user that needs to be answered by searching in a knowledge base about employee healthcare plans and the employee handbook. + Generate a search query based on the conversation and the new question. + Do not include cited source filenames and document names e.g info.txt or doc.pdf in the search query terms. + Do not include any text inside [] or <<>> in the search query terms. + If the question is not in English, translate the question to English before generating the search query. + +Chat History: +{chat_history} + +Question: +{question} + +Search query: +""" + + def __init__(self, search_client: SearchClient, chatgpt_deployment: str, gpt_deployment: str, sourcepage_field: str, content_field: str): + self.search_client = search_client + self.chatgpt_deployment = chatgpt_deployment + self.gpt_deployment = gpt_deployment + self.sourcepage_field = sourcepage_field + self.content_field = content_field + + def run(self, history: list[dict], overrides: dict) -> any: + use_semantic_captions = True if overrides.get("semantic_captions") else False + top = overrides.get("top") or 3 + exclude_category = overrides.get("exclude_category") or None + filter = "category ne '{}'".format(exclude_category.replace("'", "''")) if exclude_category else None + + # STEP 1: Generate an optimized keyword search query based on the chat history and the last question + prompt = self.query_prompt_template.format(chat_history=self.get_chat_history_as_text(history, include_last_turn=False), question=history[-1]["user"]) + completion = openai.Completion.create( + engine=self.gpt_deployment, + prompt=prompt, + temperature=0.0, + max_tokens=32, + n=1, + stop=["\n"]) + q = completion.choices[0].text + + # STEP 2: Retrieve relevant documents from the search index with the GPT optimized query + if overrides.get("semantic_ranker"): + r = self.search_client.search(q, + filter=filter, + query_type=QueryType.SEMANTIC, + query_language="en-us", + query_speller="lexicon", + semantic_configuration_name="default", + top=top, + query_caption="extractive|highlight-false" if use_semantic_captions else None) + else: + r = self.search_client.search(q, filter=filter, top=top) + if use_semantic_captions: + results = [doc[self.sourcepage_field] + ": " + nonewlines(" . ".join([c.text for c in doc['@search.captions']])) for doc in r] + else: + results = [doc[self.sourcepage_field] + ": " + nonewlines(doc[self.content_field]) for doc in r] + content = "\n".join(results) + + follow_up_questions_prompt = self.follow_up_questions_prompt_content if overrides.get("suggest_followup_questions") else "" + + # Allow client to replace the entire prompt, or to inject into the exiting prompt using >>> + prompt_override = overrides.get("prompt_template") + if prompt_override is None: + prompt = self.prompt_prefix.format(injected_prompt="", sources=content, chat_history=self.get_chat_history_as_text(history), follow_up_questions_prompt=follow_up_questions_prompt) + elif prompt_override.startswith(">>>"): + prompt = self.prompt_prefix.format(injected_prompt=prompt_override[3:] + "\n", sources=content, chat_history=self.get_chat_history_as_text(history), follow_up_questions_prompt=follow_up_questions_prompt) + else: + prompt = prompt_override.format(sources=content, chat_history=self.get_chat_history_as_text(history), follow_up_questions_prompt=follow_up_questions_prompt) + + # STEP 3: Generate a contextual and content specific answer using the search results and chat history + completion = openai.Completion.create( + engine=self.chatgpt_deployment, + prompt=prompt, + temperature=overrides.get("temperature") or 0.7, + max_tokens=1024, + n=1, + stop=["<|im_end|>", "<|im_start|>"]) + + return {"data_points": results, "answer": completion.choices[0].text, "thoughts": f"Searched for:
{q}

Prompt:
" + prompt.replace('\n', '
')} + + def get_chat_history_as_text(self, history, include_last_turn=True, approx_max_tokens=1000) -> str: + history_text = "" + for h in reversed(history if include_last_turn else history[:-1]): + history_text = """<|im_start|>user""" +"\n" + h["user"] + "\n" + """<|im_end|>""" + "\n" + """<|im_start|>assistant""" + "\n" + (h.get("bot") + """<|im_end|>""" if h.get("bot") else "") + "\n" + history_text + if len(history_text) > approx_max_tokens*4: + break + return history_text \ No newline at end of file diff --git a/app/backend/approaches/readdecomposeask.py b/app/backend/approaches/readdecomposeask.py new file mode 100644 index 0000000000..8dc728f074 --- /dev/null +++ b/app/backend/approaches/readdecomposeask.py @@ -0,0 +1,207 @@ +import openai +from approaches.approach import Approach +from azure.search.documents import SearchClient +from azure.search.documents.models import QueryType +from langchain.llms.openai import AzureOpenAI +from langchain.prompts import PromptTemplate, BasePromptTemplate +from langchain.callbacks.base import CallbackManager +from langchain.agents import Tool, AgentExecutor +from langchain.agents.react.base import ReActDocstoreAgent +from langchainadapters import HtmlCallbackHandler +from text import nonewlines +from typing import List + +class ReadDecomposeAsk(Approach): + def __init__(self, search_client: SearchClient, openai_deployment: str, sourcepage_field: str, content_field: str): + self.search_client = search_client + self.openai_deployment = openai_deployment + self.sourcepage_field = sourcepage_field + self.content_field = content_field + + def search(self, q: str, overrides: dict) -> str: + use_semantic_captions = True if overrides.get("semantic_captions") else False + top = overrides.get("top") or 3 + exclude_category = overrides.get("exclude_category") or None + filter = "category ne '{}'".format(exclude_category.replace("'", "''")) if exclude_category else None + + if overrides.get("semantic_ranker"): + r = self.search_client.search(q, + filter=filter, + query_type=QueryType.SEMANTIC, + query_language="en-us", + query_speller="lexicon", + semantic_configuration_name="default", + top = top, + query_caption="extractive|highlight-false" if use_semantic_captions else None) + else: + r = self.search_client.search(q, filter=filter, top=top) + if use_semantic_captions: + self.results = [doc[self.sourcepage_field] + ":" + nonewlines(" . ".join([c.text for c in doc['@search.captions'] ])) for doc in r] + else: + self.results = [doc[self.sourcepage_field] + ":" + nonewlines(doc[self.content_field][:500]) for doc in r] + return "\n".join(self.results) + + def lookup(self, q: str) -> str: + r = self.search_client.search(q, + top = 1, + include_total_count=True, + query_type=QueryType.SEMANTIC, + query_language="en-us", + query_speller="lexicon", + semantic_configuration_name="default", + query_answer="extractive|count-1", + query_caption="extractive|highlight-false") + + answers = r.get_answers() + if answers and len(answers) > 0: + return answers[0].text + if r.get_count() > 0: + return "\n".join(d['content'] for d in r) + return None + + def run(self, q: str, overrides: dict) -> any: + # Not great to keep this as instance state, won't work with interleaving (e.g. if using async), but keeps the example simple + self.results = None + + # Use to capture thought process during iterations + cb_handler = HtmlCallbackHandler() + cb_manager = CallbackManager(handlers=[cb_handler]) + + llm = AzureOpenAI(deployment_name=self.openai_deployment, temperature=overrides.get("temperature") or 0.3, openai_api_key=openai.api_key) + tools = [ + Tool(name="Search", func=lambda q: self.search(q, overrides)), + Tool(name="Lookup", func=self.lookup) + ] + + # Like results above, not great to keep this as a global, will interfere with interleaving + global prompt + prompt_prefix = overrides.get("prompt_template") + prompt = PromptTemplate.from_examples( + EXAMPLES, SUFFIX, ["input", "agent_scratchpad"], prompt_prefix + "\n\n" + PREFIX if prompt_prefix else PREFIX) + + agent = ReAct.from_llm_and_tools(llm, tools) + chain = AgentExecutor.from_agent_and_tools(agent, tools, verbose=True, callback_manager=cb_manager) + result = chain.run(q) + + # Fix up references to they look like what the frontend expects ([] instead of ()), need a better citation format since parentheses are so common + result = result.replace("(", "[").replace(")", "]") + + return {"data_points": self.results or [], "answer": result, "thoughts": cb_handler.get_and_reset_log()} + +class ReAct(ReActDocstoreAgent): + @classmethod + def create_prompt(cls, tools: List[Tool]) -> BasePromptTemplate: + return prompt + +# Modified version of langchain's ReAct prompt that includes instructions and examples for how to cite information sources +EXAMPLES = [ + """Question: What is the elevation range for the area that the eastern sector of the +Colorado orogeny extends into? +Thought 1: I need to search Colorado orogeny, find the area that the eastern sector +of the Colorado orogeny extends into, then find the elevation range of the +area. +Action 1: Search[Colorado orogeny] +Observation 1: [info1.pdf] The Colorado orogeny was an episode of mountain building (an orogeny) in +Colorado and surrounding areas. +Thought 2: It does not mention the eastern sector. So I need to look up eastern +sector. +Action 2: Lookup[eastern sector] +Observation 2: [info2.txt] (Result 1 / 1) The eastern sector extends into the High Plains and is called +the Central Plains orogeny. +Thought 3: The eastern sector of Colorado orogeny extends into the High Plains. So I +need to search High Plains and find its elevation range. +Action 3: Search[High Plains] +Observation 3: [some_file.pdf] High Plains refers to one of two distinct land regions +Thought 4: I need to instead search High Plains (United States). +Action 4: Search[High Plains (United States)] +Observation 4: [filea.pdf] The High Plains are a subregion of the Great Plains. [another-ref.docx] From east to west, the +High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130 +m). +Thought 5: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer +is 1,800 to 7,000 ft. +Action 5: Finish[1,800 to 7,000 ft (filea.pdf) ]""", + """Question: Musician and satirist Allie Goertz wrote a song about the "The Simpsons" +character Milhouse, who Matt Groening named after who? +Thought 1: The question simplifies to "The Simpsons" character Milhouse is named after +who. I only need to search Milhouse and find who it is named after. +Action 1: Search[Milhouse] +Observation 1: [info7.pdf] Milhouse Mussolini Van Houten is a recurring character in the Fox animated +television series The Simpsons voiced by Pamela Hayden and created by Matt +Groening. +Thought 2: The paragraph does not tell who Milhouse is named after, maybe I can look up +"named after". +Action 2: Lookup[named after] +Observation 2: [historyref2.txt] (Result 1 / 1) Milhouse was named after U.S. president Richard Nixon, whose +middle name was Milhous. +Thought 3: Milhouse was named after U.S. president Richard Nixon, so the answer is +Richard Nixon. +Action 3: Finish[Richard Nixon (historyref2.txt) ]""", + """Question: Which documentary is about Finnish rock groups, Adam Clayton Powell or The +Saimaa Gesture? +Thought 1: I need to search Adam Clayton Powell and The Saimaa Gesture, and find which +documentary is about Finnish rock groups. +Action 1: Search[Adam Clayton Powell] +Observation 1: [info9.pdf] Could not find [Adam Clayton Powell]. Similar: ['Adam Clayton Powell +III', 'Seventh Avenue (Manhattan)', 'Adam Clayton Powell Jr. State Office +Building', 'Isabel Washington Powell', 'Adam Powell', vAdam Clayton Powell +(film)', 'Giancarlo Esposito']. +Thought 2: To find the documentary, I can search Adam Clayton Powell (film). +Action 2: Search[Adam Clayton Powell (film)] +Observation 2: [data123.txt] Adam Clayton Powell is a 1989 American documentary film directed by +Richard Kilberg. The film is about the rise and fall of influential +African-American politician Adam Clayton Powell Jr.[3][4] It was later aired +as part of the PBS series The American Experience. +Thought 3: Adam Clayton Powell (film) is a documentary about an African-American +politician, not Finnish rock groups. So the documentary about Finnish rock +groups must instead be The Saimaa Gesture. +Action 3: Finish[The Saimaa Gesture (data123.txt) ]""", + """Question: What profession does Nicholas Ray and Elia Kazan have in common? +Thought 1: I need to search Nicholas Ray and Elia Kazan, find their professions, then +find the profession they have in common. +Action 1: Search[Nicholas Ray] +Observation 1: [files-987.png] Nicholas Ray (born Raymond Nicholas Kienzle Jr., August 7, 1911 - June 16, +1979) was an American film director, screenwriter, and actor best known for +the 1955 film Rebel Without a Cause. +Thought 2: Professions of Nicholas Ray are director, screenwriter, and actor. I need +to search Elia Kazan next and find his professions. +Action 2: Search[Elia Kazan] +Observation 2: [files-654.txt] Elia Kazan was an American film and theatre director, producer, screenwriter +and actor. +Thought 3: Professions of Elia Kazan are director, producer, screenwriter, and actor. +So profession Nicholas Ray and Elia Kazan have in common is director, +screenwriter, and actor. +Action 3: Finish[director, screenwriter, actor (files-987.png)(files-654.txt) ]""", + """Question: Which magazine was started first Arthur's Magazine or First for Women? +Thought 1: I need to search Arthur's Magazine and First for Women, and find which was +started first. +Action 1: Search[Arthur's Magazine] +Observation 1: [magazines-1850.pdf] Arthur's Magazine (1844-1846) was an American literary periodical published +in Philadelphia in the 19th century. +Thought 2: Arthur's Magazine was started in 1844. I need to search First for Women +next. +Action 2: Search[First for Women] +Observation 2: [magazines-1900.pdf] First for Women is a woman's magazine published by Bauer Media Group in the +USA.[1] The magazine was started in 1989. +Thought 3: First for Women was started in 1989. 1844 (Arthur's Magazine) < 1989 (First +for Women), so Arthur's Magazine was started first. +Action 3: Finish[Arthur's Magazine (magazines-1850.pdf)(magazines-1900.pdf) ]""", + """Question: Were Pavel Urysohn and Leonid Levin known for the same type of work? +Thought 1: I need to search Pavel Urysohn and Leonid Levin, find their types of work, +then find if they are the same. +Action 1: Search[Pavel Urysohn] +Observation 1: [info4444.pdf] Pavel Samuilovich Urysohn (February 3, 1898 - August 17, 1924) was a Soviet +mathematician who is best known for his contributions in dimension theory. +Thought 2: Pavel Urysohn is a mathematician. I need to search Leonid Levin next and +find its type of work. +Action 2: Search[Leonid Levin] +Observation 2: [datapoints_aaa.txt] Leonid Anatolievich Levin is a Soviet-American mathematician and computer +scientist. +Thought 3: Leonid Levin is a mathematician and computer scientist. So Pavel Urysohn +and Leonid Levin have the same type of work. +Action 3: Finish[yes (info4444.pdf)(datapoints_aaa.txt) ]""", +] +SUFFIX = """\nQuestion: {input} +{agent_scratchpad}""" +PREFIX = "Answer questions as shown in the following examples, by splitting the question into individual search or lookup actions to find facts until you can answer the question. " \ +"Observations are prefixed by their source name in square brackets, source names MUST be included with the actions in the answers." \ +"Only answer the questions using the information from observations, do not speculate." diff --git a/app/backend/approaches/readretrieveread.py b/app/backend/approaches/readretrieveread.py new file mode 100644 index 0000000000..adb130a2a4 --- /dev/null +++ b/app/backend/approaches/readretrieveread.py @@ -0,0 +1,111 @@ +import openai +from approaches.approach import Approach +from azure.search.documents import SearchClient +from azure.search.documents.models import QueryType +from langchain.llms.openai import AzureOpenAI +from langchain.callbacks.base import CallbackManager +from langchain.chains import LLMChain +from langchain.agents import Tool, ZeroShotAgent, AgentExecutor +from langchain.llms.openai import AzureOpenAI +from langchainadapters import HtmlCallbackHandler +from text import nonewlines +from lookuptool import CsvLookupTool + +# Attempt to answer questions by iteratively evaluating the question to see what information is missing, and once all information +# is present then formulate an answer. Each iteration consists of two parts: first use GPT to see if we need more information, +# second if more data is needed use the requested "tool" to retrieve it. The last call to GPT answers the actual question. +# This is inspired by the MKRL paper[1] and applied here using the implementation in Langchain. +# [1] E. Karpas, et al. arXiv:2205.00445 +class ReadRetrieveReadApproach(Approach): + + template_prefix = \ +"You are an intelligent assistant helping Contoso Inc employees with their healthcare plan questions and employee handbook questions. " \ +"Answer the question using only the data provided in the information sources below. " \ +"Each source has a name followed by colon and the actual data, quote the source name for each piece of data you use in the response. " \ +"For example, if the question is \"What color is the sky?\" and one of the information sources says \"info123: the sky is blue whenever it's not cloudy\", then answer with \"The sky is blue [info123]\" " \ +"It's important to strictly follow the format where the name of the source is in square brackets at the end of the sentence, and only up to the prefix before the colon (\":\"). " \ +"If there are multiple sources, cite each one in their own square brackets. For example, use \"[info343][ref-76]\" and not \"[info343,ref-76]\". " \ +"Never quote tool names as sources." \ +"If you cannot answer using the sources below, say that you don't know. " \ +"\n\nYou can access to the following tools:" + + template_suffix = """ +Begin! + +Question: {input} + +Thought: {agent_scratchpad}""" + + CognitiveSearchToolDescription = "useful for searching the Microsoft employee benefits information such as healthcare plans, retirement plans, etc." + + def __init__(self, search_client: SearchClient, openai_deployment: str, sourcepage_field: str, content_field: str): + self.search_client = search_client + self.openai_deployment = openai_deployment + self.sourcepage_field = sourcepage_field + self.content_field = content_field + + def retrieve(self, q: str, overrides: dict) -> any: + use_semantic_captions = True if overrides.get("semantic_captions") else False + top = overrides.get("top") or 3 + exclude_category = overrides.get("exclude_category") or None + filter = "category ne '{}'".format(exclude_category.replace("'", "''")) if exclude_category else None + + if overrides.get("semantic_ranker"): + r = self.search_client.search(q, + filter=filter, + query_type=QueryType.SEMANTIC, + query_language="en-us", + query_speller="lexicon", + semantic_configuration_name="default", + top = top, + query_caption="extractive|highlight-false" if use_semantic_captions else None) + else: + r = self.search_client.search(q, filter=filter, top=top) + if use_semantic_captions: + self.results = [doc[self.sourcepage_field] + ":" + nonewlines(" -.- ".join([c.text for c in doc['@search.captions']])) for doc in r] + else: + self.results = [doc[self.sourcepage_field] + ":" + nonewlines(doc[self.content_field][:250]) for doc in r] + content = "\n".join(self.results) + return content + + def run(self, q: str, overrides: dict) -> any: + # Not great to keep this as instance state, won't work with interleaving (e.g. if using async), but keeps the example simple + self.results = None + + # Use to capture thought process during iterations + cb_handler = HtmlCallbackHandler() + cb_manager = CallbackManager(handlers=[cb_handler]) + + acs_tool = Tool(name = "CognitiveSearch", func = lambda q: self.retrieve(q, overrides), description = self.CognitiveSearchToolDescription) + employee_tool = EmployeeInfoTool("Employee1") + tools = [acs_tool, employee_tool] + + prompt = ZeroShotAgent.create_prompt( + tools=tools, + prefix=overrides.get("prompt_template_prefix") or self.template_prefix, + suffix=overrides.get("prompt_template_suffix") or self.template_suffix, + input_variables = ["input", "agent_scratchpad"]) + llm = AzureOpenAI(deployment_name=self.openai_deployment, temperature=overrides.get("temperature") or 0.3, openai_api_key=openai.api_key) + chain = LLMChain(llm = llm, prompt = prompt) + agent_exec = AgentExecutor.from_agent_and_tools( + agent = ZeroShotAgent(llm_chain = chain, tools = tools), + tools = tools, + verbose = True, + callback_manager = cb_manager) + result = agent_exec.run(q) + + # Remove references to tool names that might be confused with a citation + result = result.replace("[CognitiveSearch]", "").replace("[Employee]", "") + + return {"data_points": self.results or [], "answer": result, "thoughts": cb_handler.get_and_reset_log()} + +class EmployeeInfoTool(CsvLookupTool): + employee_name: str = "" + + def __init__(self, employee_name: str): + super().__init__(filename = "data/employeeinfo.csv", key_field = "name", name = "Employee", description = "useful for answering questions about the employee, their benefits and other personal information") + self.func = self.employee_info + self.employee_name = employee_name + + def employee_info(self, unused: str) -> str: + return self.lookup(self.employee_name) diff --git a/app/backend/approaches/retrievethenread.py b/app/backend/approaches/retrievethenread.py new file mode 100644 index 0000000000..6dc2261bee --- /dev/null +++ b/app/backend/approaches/retrievethenread.py @@ -0,0 +1,79 @@ +import openai +from approaches.approach import Approach +from azure.search.documents import SearchClient +from azure.search.documents.models import QueryType +from text import nonewlines + +# Simple retrieve-then-read implementation, using the Cognitive Search and OpenAI APIs directly. It first retrieves +# top documents from search, then constructs a prompt with them, and then uses OpenAI to generate an completion +# (answer) with that prompt. +class RetrieveThenReadApproach(Approach): + + template = \ +"You are an intelligent assistant helping Contoso Inc employees with their healthcare plan questions and employee handbook questions. " + \ +"Use 'you' to refer to the individual asking the questions even if they ask with 'I'. " + \ +"Answer the following question using only the data provided in the sources below. " + \ +"Each source has a name followed by colon and the actual information, always include the source name for each fact you use in the response. " + \ +"If you cannot answer using the sources below, say you don't know. " + \ +""" + +### +Question: 'What is the deductible for the employee plan for a visit to Overlake in Bellevue?' + +Sources: +info1.txt: deductibles depend on whether you are in-network or out-of-network. In-network deductibles are $500 for employee and $1000 for family. Out-of-network deductibles are $1000 for employee and $2000 for family. +info2.pdf: Overlake is in-network for the employee plan. +info3.pdf: Overlake is the name of the area that includes a park and ride near Bellevue. +info4.pdf: In-network institutions include Overlake, Swedish and others in the region + +Answer: +In-network deductibles are $500 for employee and $1000 for family [info1.txt] and Overlake is in-network for the employee plan [info2.pdf][info4.pdf]. + +### +Question: '{q}'? + +Sources: +{retrieved} + +Answer: +""" + + def __init__(self, search_client: SearchClient, openai_deployment: str, sourcepage_field: str, content_field: str): + self.search_client = search_client + self.openai_deployment = openai_deployment + self.sourcepage_field = sourcepage_field + self.content_field = content_field + + def run(self, q: str, overrides: dict) -> any: + use_semantic_captions = True if overrides.get("semantic_captions") else False + top = overrides.get("top") or 3 + exclude_category = overrides.get("exclude_category") or None + filter = "category ne '{}'".format(exclude_category.replace("'", "''")) if exclude_category else None + + if overrides.get("semantic_ranker"): + r = self.search_client.search(q, + filter=filter, + query_type=QueryType.SEMANTIC, + query_language="en-us", + query_speller="lexicon", + semantic_configuration_name="default", + top=top, + query_caption="extractive|highlight-false" if use_semantic_captions else None) + else: + r = self.search_client.search(q, filter=filter, top=top) + if use_semantic_captions: + results = [doc[self.sourcepage_field] + ": " + nonewlines(" . ".join([c.text for c in doc['@search.captions']])) for doc in r] + else: + results = [doc[self.sourcepage_field] + ": " + nonewlines(doc[self.content_field]) for doc in r] + content = "\n".join(results) + + prompt = (overrides.get("prompt_template") or self.template).format(q=q, retrieved=content) + completion = openai.Completion.create( + engine=self.openai_deployment, + prompt=prompt, + temperature=overrides.get("temperature") or 0.3, + max_tokens=1024, + n=1, + stop=["\n"]) + + return {"data_points": results, "answer": completion.choices[0].text, "thoughts": f"Question:
{q}

Prompt:
" + prompt.replace('\n', '
')} diff --git a/app/backend/data/employeeinfo.csv b/app/backend/data/employeeinfo.csv new file mode 100644 index 0000000000..b3a4c884bd --- /dev/null +++ b/app/backend/data/employeeinfo.csv @@ -0,0 +1,4 @@ +name,title,insurance,insurancegroup +Employee1,Program Manager,Northwind Health Plus,Family +Employee2,Software Engineer,Northwind Health Plus,Single +Employee3,Software Engineer,Northwind Health Standard,Family diff --git a/app/backend/langchainadapters.py b/app/backend/langchainadapters.py new file mode 100644 index 0000000000..74c1a81e72 --- /dev/null +++ b/app/backend/langchainadapters.py @@ -0,0 +1,82 @@ +from typing import Any, Dict, List, Optional +from langchain.callbacks.base import BaseCallbackHandler +from langchain.schema import AgentAction, AgentFinish, LLMResult + +def ch(text: str) -> str: + s = text if isinstance(text, str) else str(text) + return s.replace("<", "<").replace(">", ">").replace("\r", "").replace("\n", "
") + +class HtmlCallbackHandler (BaseCallbackHandler): + html: str = "" + + def get_and_reset_log(self) -> str: + result = self.html + self.html = "" + return result + + def on_llm_start( + self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any + ) -> None: + """Print out the prompts.""" + self.html += f"LLM prompts:
" + "
".join(ch(prompts)) + "
"; + + def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None: + """Do nothing.""" + pass + + def on_llm_error(self, error: Exception, **kwargs: Any) -> None: + self.html += f"LLM error: {ch(error)}
" + + def on_chain_start( + self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any + ) -> None: + """Print out that we are entering a chain.""" + class_name = serialized["name"] + self.html += f"Entering chain: {ch(class_name)}
" + + def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None: + """Print out that we finished a chain.""" + self.html += f"Finished chain
" + + def on_chain_error(self, error: Exception, **kwargs: Any) -> None: + self.html += f"Chain error: {ch(error)}
" + + def on_tool_start( + self, + serialized: Dict[str, Any], + action: AgentAction, + color: Optional[str] = None, + **kwargs: Any, + ) -> None: + """Print out the log in specified color.""" + self.html += f"{ch(action.log)}
" + + def on_tool_end( + self, + output: str, + color: Optional[str] = None, + observation_prefix: Optional[str] = None, + llm_prefix: Optional[str] = None, + **kwargs: Any, + ) -> None: + """If not the final action, print out observation.""" + self.html += f"{ch(observation_prefix)}
{ch(output)}
{ch(llm_prefix)}
" + + def on_tool_error(self, error: Exception, **kwargs: Any) -> None: + self.html += f"Tool error: {ch(error)}
" + + def on_text( + self, + text: str, + color: Optional[str] = None, + end: str = "", + **kwargs: Optional[str], + ) -> None: + """Run when agent ends.""" + self.html += f"{ch(text)}
" + + def on_agent_finish( + self, finish: AgentFinish, color: Optional[str] = None, **kwargs: Any + ) -> None: + """Run on agent end.""" + self.html += f"{ch(finish.log)}
" diff --git a/app/backend/lookuptool.py b/app/backend/lookuptool.py new file mode 100644 index 0000000000..fc169a331c --- /dev/null +++ b/app/backend/lookuptool.py @@ -0,0 +1,16 @@ +from os import path +import csv +from langchain.agents import Tool +from typing import Optional + +class CsvLookupTool(Tool): + def __init__(self, filename: path, key_field: str, name: str = "lookup", description: str = "useful to look up details given an input key as opposite to searching data with an unstructured question"): + super().__init__(name, self.lookup, description) + self.data = {} + with open(filename, newline='') as csvfile: + reader = csv.DictReader(csvfile) + for row in reader: + self.data[row[key_field]] = "\n".join([f"{i}:{row[i]}" for i in row]) + + def lookup(self, key: str) -> Optional[str]: + return self.data.get(key, "") diff --git a/app/backend/requirements.txt b/app/backend/requirements.txt new file mode 100644 index 0000000000..1554a52ebb --- /dev/null +++ b/app/backend/requirements.txt @@ -0,0 +1,6 @@ +azure-identity==1.12.0 +Flask==2.2.2 +langchain==0.0.78 +openai==0.26.4 +azure-search-documents==11.4.0b3 +azure-storage-blob==12.14.1 diff --git a/app/backend/text.py b/app/backend/text.py new file mode 100644 index 0000000000..9209778c91 --- /dev/null +++ b/app/backend/text.py @@ -0,0 +1,2 @@ +def nonewlines(s: str) -> str: + return s.replace('\n', ' ').replace('\r', ' ') diff --git a/app/frontend/.prettierrc.json b/app/frontend/.prettierrc.json new file mode 100644 index 0000000000..b7d67747c8 --- /dev/null +++ b/app/frontend/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "tabWidth": 4, + "printWidth": 160, + "arrowParens": "avoid", + "trailingComma": "none" +} diff --git a/app/frontend/index.html b/app/frontend/index.html new file mode 100644 index 0000000000..4d96bfbd97 --- /dev/null +++ b/app/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + GPT + Enterprise data | Sample + + +
+ + + diff --git a/app/frontend/package-lock.json b/app/frontend/package-lock.json new file mode 100644 index 0000000000..867d295a8c --- /dev/null +++ b/app/frontend/package-lock.json @@ -0,0 +1,3035 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@fluentui/react": "^8.105.3", + "@fluentui/react-icons": "^2.0.195", + "@react-spring/web": "^9.7.1", + "dompurify": "^3.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.8.1" + }, + "devDependencies": { + "@types/dompurify": "^2.4.0", + "@types/react": "^18.0.27", + "@types/react-dom": "^18.0.10", + "@vitejs/plugin-react": "^3.1.0", + "prettier": "^2.8.3", + "typescript": "^4.9.3", + "vite": "^4.1.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", + "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", + "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "node_modules/@esbuild/android-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fluentui/date-time-utilities": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-8.5.5.tgz", + "integrity": "sha512-P/qfyMIF1aWPVaZvgAE0u166Rp1Rfpymv63/NKQT1o56cc5LzfWTzjD2Ey1GyA+tn6dCf7g1ZXTpKo5H+CuM4Q==", + "dependencies": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/dom-utilities": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@fluentui/dom-utilities/-/dom-utilities-2.2.5.tgz", + "integrity": "sha512-VGCtAmPU/3uj/QV4Kx7gO/H2vNrhNSB346sE7xM+bBtxj+hf/owaGTvN6/tuZ8HXQu8tjTf8+ubQ3d7D7DUIjA==", + "dependencies": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/font-icons-mdl2": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.5.8.tgz", + "integrity": "sha512-HfFEie2hfci+diIFfSiu0CdNZMUCZjvAi0YsY2dVJHb9JTaFavfdVO1XHmMpn0HB+FVpp0tp5eMscPp5qblu1g==", + "dependencies": { + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/foundation-legacy": { + "version": "8.2.28", + "resolved": "https://registry.npmjs.org/@fluentui/foundation-legacy/-/foundation-legacy-8.2.28.tgz", + "integrity": "sha512-NmdbBtWroU/ND7UsaedhdIOKXXFpxmA5I+Is1DjQlAPdvuIwSAkHw+iX73cemcqrVnxPZB84iIvWfNzwquBYew==", + "dependencies": { + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/keyboard-key": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-key/-/keyboard-key-0.4.5.tgz", + "integrity": "sha512-c+B+mdEgj0B6fhYIjznesGi8Al1rTpdFNudpNmFoVjlhCle5qj5RBtM4WaT8XygdzAVQq7oHSXom0vd32+zAZg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/merge-styles": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@fluentui/merge-styles/-/merge-styles-8.5.6.tgz", + "integrity": "sha512-i9Wy+7V+lKfX+UWRTrrK+3xm4aa8jl9tK2/7Ku696yWJ5v3D6xjRcMevfxUZDrZ3xS4/GRFfWKPHkAjzz/BQoQ==", + "dependencies": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/react": { + "version": "8.105.4", + "resolved": "https://registry.npmjs.org/@fluentui/react/-/react-8.105.4.tgz", + "integrity": "sha512-9W40Mdpywv1OmcxDCeP9vaMatdnAYUdX9RKM76QxjQeMGw0PafBgvgnBRhLhhXNacdRs1ByokM6LJ7svb6z4ow==", + "dependencies": { + "@fluentui/date-time-utilities": "^8.5.5", + "@fluentui/font-icons-mdl2": "^8.5.8", + "@fluentui/foundation-legacy": "^8.2.28", + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/react-focus": "^8.8.14", + "@fluentui/react-hooks": "^8.6.16", + "@fluentui/react-portal-compat-context": "^9.0.4", + "@fluentui/react-window-provider": "^2.2.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/theme": "^2.6.22", + "@fluentui/utilities": "^8.13.6", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-focus": { + "version": "8.8.14", + "resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-8.8.14.tgz", + "integrity": "sha512-lOhn00rSsd6gR4Z+RM1YyOZ4QWFvoF8s9Y3YeBh4rrYN5NL9ntMqKIcye6dUXx/P595kwXeKOQgUdH2LalJB4Q==", + "dependencies": { + "@fluentui/keyboard-key": "^0.4.5", + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-hooks": { + "version": "8.6.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-hooks/-/react-hooks-8.6.16.tgz", + "integrity": "sha512-yWEcF7O9ZUn63TMORVBrovRr7NfNAYJ49SvhtoAdEjGIP6Tm3SgcwB0Gyo3ekYubX+XzmKRYfbu6qUFj6o8tGA==", + "dependencies": { + "@fluentui/react-window-provider": "^2.2.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-icons": { + "version": "2.0.195", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.195.tgz", + "integrity": "sha512-/jeDtD1U6hM+Kip9Q0aT7iZLAoRtAGXErnXmQrcUDHDWcbFXeNPg4g357CLXAaprqU9UusWO9DdsqrsBhjdTbQ==", + "dependencies": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-portal-compat-context": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal-compat-context/-/react-portal-compat-context-9.0.4.tgz", + "integrity": "sha512-qw2lmkxZ2TmgC0pB2dvFyrzVffxBdpCx1BdWRaF+MRGUlTxRtqfybSx3Edsqa6NMewc3J0ThLMFdVFBQ5Yafqw==", + "dependencies": { + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-window-provider": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-2.2.6.tgz", + "integrity": "sha512-bcQM5mdi4ugVb30GNtde8sP173F+l9p7uQfgK/I8O07EfKHUHZeY4wj5arD53s1cUIQI0kxWJ5RD7upZNRQeQA==", + "dependencies": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/set-version": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/@fluentui/set-version/-/set-version-8.2.5.tgz", + "integrity": "sha512-DwJq9wIXLc8WkeJ/lqYM4Sv+R0Ccb6cy3cY1Bqaa5POsroVKIfL6W+njvAMOj3LO3+DaXo2aDeiUnnw70M8xIw==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/style-utilities": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@fluentui/style-utilities/-/style-utilities-8.9.1.tgz", + "integrity": "sha512-5PQd52UxvRSlOeBaNHRvKoicPAIgd/O43mgSj5T1OmJWRUkm5/8mcc5goHMvvHwB9i7HRuJPw21sQSefPira7g==", + "dependencies": { + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/theme": "^2.6.22", + "@fluentui/utilities": "^8.13.6", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/theme": { + "version": "2.6.22", + "resolved": "https://registry.npmjs.org/@fluentui/theme/-/theme-2.6.22.tgz", + "integrity": "sha512-Pw8WBGeASqDHR7EliJUL26x07pASFnU5QsRBSBg6ahUxGVXRuOtROhQ3jIKXldK8/HnAIzVEPZqeTwM0yWGBVA==", + "dependencies": { + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/utilities": { + "version": "8.13.6", + "resolved": "https://registry.npmjs.org/@fluentui/utilities/-/utilities-8.13.6.tgz", + "integrity": "sha512-szgbLmg919h9wuQi/QVgZ5oa5qtOtc1VgyR/eMPzMW/pJHU9jc7E0L++eMYa1oaHpdsDrQ4L3wAIo6Yuk1Jczw==", + "dependencies": { + "@fluentui/dom-utilities": "^2.2.5", + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@griffel/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.10.0.tgz", + "integrity": "sha512-9yIBFswd6pcxtYsDVngplCHTyZ++cIk0htBOBVjxBKEoTkEmTgSvbIB2kKMiO3OJLrjzwoi9r+s3owugzIZe1w==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "csstype": "^3.0.10", + "rtl-css-js": "^1.16.1", + "stylis": "^4.0.13", + "tslib": "^2.1.0" + } + }, + "node_modules/@griffel/react": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.5.tgz", + "integrity": "sha512-MpAU0NEpBzNRWUGSlhgz3jzZRC+HbRI+P2lQIzyxoMFgzEB4QFtDnRDBwPLfi/Eoq55NlVmsxn2Pr3jJ/bjhRw==", + "dependencies": { + "@griffel/core": "^1.10.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@microsoft/load-themed-styles": { + "version": "1.10.295", + "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.295.tgz", + "integrity": "sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==" + }, + "node_modules/@react-spring/animated": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.1.tgz", + "integrity": "sha512-EX5KAD9y7sD43TnLeTNG1MgUVpuRO1YaSJRPawHNRgUWYfILge3s85anny4S4eTJGpdp5OoFV2kx9fsfeo0qsw==", + "dependencies": { + "@react-spring/shared": "~9.7.1", + "@react-spring/types": "~9.7.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.1.tgz", + "integrity": "sha512-8K9/FaRn5VvMa24mbwYxwkALnAAyMRdmQXrARZLcBW2vxLJ6uw9Cy3d06Z8M12kEqF2bDlccaCSDsn2bSz+Q4A==", + "dependencies": { + "@react-spring/animated": "~9.7.1", + "@react-spring/rafz": "~9.7.1", + "@react-spring/shared": "~9.7.1", + "@react-spring/types": "~9.7.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.1.tgz", + "integrity": "sha512-JSsrRfbEJvuE3w/uvU3mCTuWwpQcBXkwoW14lBgzK9XJhuxmscGo59AgJUpFkGOiGAVXFBGB+nEXtSinFsopgw==" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.1.tgz", + "integrity": "sha512-R2kZ+VOO6IBeIAYTIA3C1XZ0ZVg/dDP5FKtWaY8k5akMer9iqf5H9BU0jyt3Qtxn0qQY7whQdf6MTcWtKeaawg==", + "dependencies": { + "@react-spring/rafz": "~9.7.1", + "@react-spring/types": "~9.7.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.1.tgz", + "integrity": "sha512-yBcyfKUeZv9wf/ZFrQszvhSPuDx6Py6yMJzpMnS+zxcZmhXPeOCKZSHwqrUz1WxvuRckUhlgb7eNI/x5e1e8CA==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.1.tgz", + "integrity": "sha512-6uUE5MyKqdrJnIJqlDN/AXf3i8PjOQzUuT26nkpsYxUGOk7c+vZVPcfrExLSoKzTb9kF0i66DcqzO5fXz/Z1AA==", + "dependencies": { + "@react-spring/animated": "~9.7.1", + "@react-spring/core": "~9.7.1", + "@react-spring/shared": "~9.7.1", + "@react-spring/types": "~9.7.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@remix-run/router": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", + "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/dompurify": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz", + "integrity": "sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg==", + "dev": true, + "dependencies": { + "@types/trusted-types": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/react": { + "version": "18.0.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", + "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.10", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", + "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==", + "dev": true + }, + "node_modules/@vitejs/plugin-react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz", + "integrity": "sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==", + "dev": true, + "dependencies": { + "@babel/core": "^7.20.12", + "@babel/plugin-transform-react-jsx-self": "^7.18.6", + "@babel/plugin-transform-react-jsx-source": "^7.19.6", + "magic-string": "^0.27.0", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.1.0-beta.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001450", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz", + "integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dompurify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.1.tgz", + "integrity": "sha512-60tsgvPKwItxZZdfLmamp0MTcecCta3avOhsLgPZ0qcWt96OasFfhkeIRbJ6br5i0fQawT1/RBGB5L58/Jpwuw==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.286.tgz", + "integrity": "sha512-Vp3CVhmYpgf4iXNKAucoQUDcCrBQX3XLBtwgFqP9BUXuucgvAV9zWp1kYU7LL9j4++s9O+12cb3wMtN4SJy6UQ==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", + "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", + "dependencies": { + "@remix-run/router": "1.3.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", + "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", + "dependencies": { + "@remix-run/router": "1.3.2", + "react-router": "6.8.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.14.0.tgz", + "integrity": "sha512-o23sdgCLcLSe3zIplT9nQ1+r97okuaiR+vmAPZPTDYB7/f3tgWIYNyiQveMsZwshBT0is4eGax/HH83Q7CG+/Q==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylis": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.1.tgz", + "integrity": "sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg==", + "dev": true, + "dependencies": { + "esbuild": "^0.16.14", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.10.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "dev": true + }, + "@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "dev": true, + "requires": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", + "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", + "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "@esbuild/android-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "dev": true, + "optional": true + }, + "@fluentui/date-time-utilities": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-8.5.5.tgz", + "integrity": "sha512-P/qfyMIF1aWPVaZvgAE0u166Rp1Rfpymv63/NKQT1o56cc5LzfWTzjD2Ey1GyA+tn6dCf7g1ZXTpKo5H+CuM4Q==", + "requires": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "@fluentui/dom-utilities": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@fluentui/dom-utilities/-/dom-utilities-2.2.5.tgz", + "integrity": "sha512-VGCtAmPU/3uj/QV4Kx7gO/H2vNrhNSB346sE7xM+bBtxj+hf/owaGTvN6/tuZ8HXQu8tjTf8+ubQ3d7D7DUIjA==", + "requires": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "@fluentui/font-icons-mdl2": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.5.8.tgz", + "integrity": "sha512-HfFEie2hfci+diIFfSiu0CdNZMUCZjvAi0YsY2dVJHb9JTaFavfdVO1XHmMpn0HB+FVpp0tp5eMscPp5qblu1g==", + "requires": { + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + } + }, + "@fluentui/foundation-legacy": { + "version": "8.2.28", + "resolved": "https://registry.npmjs.org/@fluentui/foundation-legacy/-/foundation-legacy-8.2.28.tgz", + "integrity": "sha512-NmdbBtWroU/ND7UsaedhdIOKXXFpxmA5I+Is1DjQlAPdvuIwSAkHw+iX73cemcqrVnxPZB84iIvWfNzwquBYew==", + "requires": { + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + } + }, + "@fluentui/keyboard-key": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-key/-/keyboard-key-0.4.5.tgz", + "integrity": "sha512-c+B+mdEgj0B6fhYIjznesGi8Al1rTpdFNudpNmFoVjlhCle5qj5RBtM4WaT8XygdzAVQq7oHSXom0vd32+zAZg==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@fluentui/merge-styles": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@fluentui/merge-styles/-/merge-styles-8.5.6.tgz", + "integrity": "sha512-i9Wy+7V+lKfX+UWRTrrK+3xm4aa8jl9tK2/7Ku696yWJ5v3D6xjRcMevfxUZDrZ3xS4/GRFfWKPHkAjzz/BQoQ==", + "requires": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "@fluentui/react": { + "version": "8.105.4", + "resolved": "https://registry.npmjs.org/@fluentui/react/-/react-8.105.4.tgz", + "integrity": "sha512-9W40Mdpywv1OmcxDCeP9vaMatdnAYUdX9RKM76QxjQeMGw0PafBgvgnBRhLhhXNacdRs1ByokM6LJ7svb6z4ow==", + "requires": { + "@fluentui/date-time-utilities": "^8.5.5", + "@fluentui/font-icons-mdl2": "^8.5.8", + "@fluentui/foundation-legacy": "^8.2.28", + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/react-focus": "^8.8.14", + "@fluentui/react-hooks": "^8.6.16", + "@fluentui/react-portal-compat-context": "^9.0.4", + "@fluentui/react-window-provider": "^2.2.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/theme": "^2.6.22", + "@fluentui/utilities": "^8.13.6", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-focus": { + "version": "8.8.14", + "resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-8.8.14.tgz", + "integrity": "sha512-lOhn00rSsd6gR4Z+RM1YyOZ4QWFvoF8s9Y3YeBh4rrYN5NL9ntMqKIcye6dUXx/P595kwXeKOQgUdH2LalJB4Q==", + "requires": { + "@fluentui/keyboard-key": "^0.4.5", + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/style-utilities": "^8.9.1", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-hooks": { + "version": "8.6.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-hooks/-/react-hooks-8.6.16.tgz", + "integrity": "sha512-yWEcF7O9ZUn63TMORVBrovRr7NfNAYJ49SvhtoAdEjGIP6Tm3SgcwB0Gyo3ekYubX+XzmKRYfbu6qUFj6o8tGA==", + "requires": { + "@fluentui/react-window-provider": "^2.2.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-icons": { + "version": "2.0.195", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.195.tgz", + "integrity": "sha512-/jeDtD1U6hM+Kip9Q0aT7iZLAoRtAGXErnXmQrcUDHDWcbFXeNPg4g357CLXAaprqU9UusWO9DdsqrsBhjdTbQ==", + "requires": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-portal-compat-context": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal-compat-context/-/react-portal-compat-context-9.0.4.tgz", + "integrity": "sha512-qw2lmkxZ2TmgC0pB2dvFyrzVffxBdpCx1BdWRaF+MRGUlTxRtqfybSx3Edsqa6NMewc3J0ThLMFdVFBQ5Yafqw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@fluentui/react-window-provider": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-2.2.6.tgz", + "integrity": "sha512-bcQM5mdi4ugVb30GNtde8sP173F+l9p7uQfgK/I8O07EfKHUHZeY4wj5arD53s1cUIQI0kxWJ5RD7upZNRQeQA==", + "requires": { + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "@fluentui/set-version": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/@fluentui/set-version/-/set-version-8.2.5.tgz", + "integrity": "sha512-DwJq9wIXLc8WkeJ/lqYM4Sv+R0Ccb6cy3cY1Bqaa5POsroVKIfL6W+njvAMOj3LO3+DaXo2aDeiUnnw70M8xIw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@fluentui/style-utilities": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/@fluentui/style-utilities/-/style-utilities-8.9.1.tgz", + "integrity": "sha512-5PQd52UxvRSlOeBaNHRvKoicPAIgd/O43mgSj5T1OmJWRUkm5/8mcc5goHMvvHwB9i7HRuJPw21sQSefPira7g==", + "requires": { + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/theme": "^2.6.22", + "@fluentui/utilities": "^8.13.6", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + } + }, + "@fluentui/theme": { + "version": "2.6.22", + "resolved": "https://registry.npmjs.org/@fluentui/theme/-/theme-2.6.22.tgz", + "integrity": "sha512-Pw8WBGeASqDHR7EliJUL26x07pASFnU5QsRBSBg6ahUxGVXRuOtROhQ3jIKXldK8/HnAIzVEPZqeTwM0yWGBVA==", + "requires": { + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "@fluentui/utilities": "^8.13.6", + "tslib": "^2.1.0" + } + }, + "@fluentui/utilities": { + "version": "8.13.6", + "resolved": "https://registry.npmjs.org/@fluentui/utilities/-/utilities-8.13.6.tgz", + "integrity": "sha512-szgbLmg919h9wuQi/QVgZ5oa5qtOtc1VgyR/eMPzMW/pJHU9jc7E0L++eMYa1oaHpdsDrQ4L3wAIo6Yuk1Jczw==", + "requires": { + "@fluentui/dom-utilities": "^2.2.5", + "@fluentui/merge-styles": "^8.5.6", + "@fluentui/set-version": "^8.2.5", + "tslib": "^2.1.0" + } + }, + "@griffel/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.10.0.tgz", + "integrity": "sha512-9yIBFswd6pcxtYsDVngplCHTyZ++cIk0htBOBVjxBKEoTkEmTgSvbIB2kKMiO3OJLrjzwoi9r+s3owugzIZe1w==", + "requires": { + "@emotion/hash": "^0.9.0", + "csstype": "^3.0.10", + "rtl-css-js": "^1.16.1", + "stylis": "^4.0.13", + "tslib": "^2.1.0" + } + }, + "@griffel/react": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.5.tgz", + "integrity": "sha512-MpAU0NEpBzNRWUGSlhgz3jzZRC+HbRI+P2lQIzyxoMFgzEB4QFtDnRDBwPLfi/Eoq55NlVmsxn2Pr3jJ/bjhRw==", + "requires": { + "@griffel/core": "^1.10.0", + "tslib": "^2.1.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@microsoft/load-themed-styles": { + "version": "1.10.295", + "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.295.tgz", + "integrity": "sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==" + }, + "@react-spring/animated": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.1.tgz", + "integrity": "sha512-EX5KAD9y7sD43TnLeTNG1MgUVpuRO1YaSJRPawHNRgUWYfILge3s85anny4S4eTJGpdp5OoFV2kx9fsfeo0qsw==", + "requires": { + "@react-spring/shared": "~9.7.1", + "@react-spring/types": "~9.7.1" + } + }, + "@react-spring/core": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.1.tgz", + "integrity": "sha512-8K9/FaRn5VvMa24mbwYxwkALnAAyMRdmQXrARZLcBW2vxLJ6uw9Cy3d06Z8M12kEqF2bDlccaCSDsn2bSz+Q4A==", + "requires": { + "@react-spring/animated": "~9.7.1", + "@react-spring/rafz": "~9.7.1", + "@react-spring/shared": "~9.7.1", + "@react-spring/types": "~9.7.1" + } + }, + "@react-spring/rafz": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.1.tgz", + "integrity": "sha512-JSsrRfbEJvuE3w/uvU3mCTuWwpQcBXkwoW14lBgzK9XJhuxmscGo59AgJUpFkGOiGAVXFBGB+nEXtSinFsopgw==" + }, + "@react-spring/shared": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.1.tgz", + "integrity": "sha512-R2kZ+VOO6IBeIAYTIA3C1XZ0ZVg/dDP5FKtWaY8k5akMer9iqf5H9BU0jyt3Qtxn0qQY7whQdf6MTcWtKeaawg==", + "requires": { + "@react-spring/rafz": "~9.7.1", + "@react-spring/types": "~9.7.1" + } + }, + "@react-spring/types": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.1.tgz", + "integrity": "sha512-yBcyfKUeZv9wf/ZFrQszvhSPuDx6Py6yMJzpMnS+zxcZmhXPeOCKZSHwqrUz1WxvuRckUhlgb7eNI/x5e1e8CA==" + }, + "@react-spring/web": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.1.tgz", + "integrity": "sha512-6uUE5MyKqdrJnIJqlDN/AXf3i8PjOQzUuT26nkpsYxUGOk7c+vZVPcfrExLSoKzTb9kF0i66DcqzO5fXz/Z1AA==", + "requires": { + "@react-spring/animated": "~9.7.1", + "@react-spring/core": "~9.7.1", + "@react-spring/shared": "~9.7.1", + "@react-spring/types": "~9.7.1" + } + }, + "@remix-run/router": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", + "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==" + }, + "@types/dompurify": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz", + "integrity": "sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg==", + "dev": true, + "requires": { + "@types/trusted-types": "*" + } + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/react": { + "version": "18.0.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", + "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.10", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", + "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==", + "dev": true + }, + "@vitejs/plugin-react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz", + "integrity": "sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==", + "dev": true, + "requires": { + "@babel/core": "^7.20.12", + "@babel/plugin-transform-react-jsx-self": "^7.18.6", + "@babel/plugin-transform-react-jsx-source": "^7.19.6", + "magic-string": "^0.27.0", + "react-refresh": "^0.14.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, + "caniuse-lite": { + "version": "1.0.30001450", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz", + "integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "dompurify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.1.tgz", + "integrity": "sha512-60tsgvPKwItxZZdfLmamp0MTcecCta3avOhsLgPZ0qcWt96OasFfhkeIRbJ6br5i0fQawT1/RBGB5L58/Jpwuw==" + }, + "electron-to-chromium": { + "version": "1.4.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.286.tgz", + "integrity": "sha512-Vp3CVhmYpgf4iXNKAucoQUDcCrBQX3XLBtwgFqP9BUXuucgvAV9zWp1kYU7LL9j4++s9O+12cb3wMtN4SJy6UQ==", + "dev": true + }, + "esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "prettier": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", + "dev": true + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true + }, + "react-router": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", + "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", + "requires": { + "@remix-run/router": "1.3.2" + } + }, + "react-router-dom": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", + "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", + "requires": { + "@remix-run/router": "1.3.2", + "react-router": "6.8.1" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "rollup": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.14.0.tgz", + "integrity": "sha512-o23sdgCLcLSe3zIplT9nQ1+r97okuaiR+vmAPZPTDYB7/f3tgWIYNyiQveMsZwshBT0is4eGax/HH83Q7CG+/Q==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "stylis": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "vite": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.1.tgz", + "integrity": "sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg==", + "dev": true, + "requires": { + "esbuild": "^0.16.14", + "fsevents": "~2.3.2", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.10.0" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } +} diff --git a/app/frontend/package.json b/app/frontend/package.json new file mode 100644 index 0000000000..e8d39c9c0b --- /dev/null +++ b/app/frontend/package.json @@ -0,0 +1,29 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "watch": "tsc && vite build --watch" + }, + "dependencies": { + "@fluentui/react": "^8.105.3", + "@fluentui/react-icons": "^2.0.195", + "@react-spring/web": "^9.7.1", + "dompurify": "^3.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.8.1" + }, + "devDependencies": { + "@types/dompurify": "^2.4.0", + "@types/react": "^18.0.27", + "@types/react-dom": "^18.0.10", + "@vitejs/plugin-react": "^3.1.0", + "prettier": "^2.8.3", + "typescript": "^4.9.3", + "vite": "^4.1.0" + } +} diff --git a/app/frontend/public/favicon.ico b/app/frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f1fe50511ca0c33d95783506d4af99426dfc10bf GIT binary patch literal 4286 zcmeH}dr(y88OA?KWOvysX{UdrX?5Dk2n0}AK@g0WnRH4JL8DO=m3RY_c8nwq(U1w# zblPb%a#2_oP(cAfxywyJkeD=zq)sBaX_L6ZDzLE2?us@Vd!D}Eo;|v0z+{sC8JwT* z@$8=Sd*0_P<1*$&e`d{M{BKsRW9;XQF@J(ivBd;G&wsM$wa4g1&W}I$8|c~T?c4qQ zLmRqMWkp?SJ~>@Ge6l;!e6l+@sXjS`p?#Yy_Wl*$JQ~=;HeYy=6c%Kf!Ux=ZJCigSyTk z@tp5xu(*$Rv#qzA zCYq+a+3TcxoJ^Ce$lKy}3f$YeO^%kWGB1yf?-Yd+b-GCy?h&Her946SKixNPvpa9IcjOKAV%$L~XVuJSBK@)riCNcWK@xgMq+ z?}$zr@0#{ippo;eLLg9`>`T4KB0qhVZRCBs{N(Qa>}`v?~M8s1&(j@Mdf-W`qI5^mopg#Jp315 zrrozt2Y-DO)|zmb%gA3A1T*Cra^>Jzf&`w0I%)NEdLGlRDcsjUKJFw0K9AAfeD`xN zc;nKm;@*6B4)6ZGUF1*o!oNxaVX3D5j|3ATFdwEIyo<6R!CXoiTv>usJe{7$4JoRJ z$#=UhMUL7{3ZZtRLg4ON+Py#hC%E!D!>4-~=-G?ilb?6rvz_>(29~;T3?H3?>y;t6 zULJyL1fS-^Ap-B@T3PTNnp1W!<*47}+fcJnff{o1&MT6XXrtdpzBljugO|N9kiowE z{53XyDU&%bq%&tj5*vFzd)6&`bEN36;u(mFIk?7g=OBNhSU$XXRg;InLv3i%1j#nLsCrxz|BZ_s13hTNRv zp%^(9>dG=)J(sfZ40HZ%t_add*F0z*U9W85pY=-eaw<4UDxq8iG;v_1tWvs%t#w|7 zr9KRn`cRD4k((H;B`C`<$Ub7={&qviNoaN@Xk4<&v4WzOz?$qwRZ0H z`mkU}X9UKY^%y%rG*X5}J;5`GolqZkYjfz7|94H7rEIObvTTj=p7W6C6%MUd3kS(x zuv~?`@#;czU8vD{DgxuJ^Dx%p&OkXVt}HaEld-1I^65O&oiAOZP2{^CTCD>29b8SU zqUXL!jRSO?{X1X0nWzzloAv*>(KBBdZwn{p2|UL*&*9EuY0|^mtWTKEGu?Ue`;gP= z@~zU4Q-flf#pEw}T7%aX_~6Lze}UU)qv1FeAy`j_b6{-`2W6o?!o>_NdWWqwQa+vM zLFbE~QJ0rIO`kRL6?u@KphiZN9B1t95$Z8m4lv1`#f0NBJTa3 zJjgZGYsOWYr;1jpVO*&};R+GsN-h5Oq!NFL_roYTZ@ses6Q|~jbWx5@^7A|d&tYqe z_{MjZsa#W?GbHL}7*=SkE_b3zP0 zKv{%|Zt9>r>TBPZzN^#oeFX`+xcvz_xDno1qQalz{9x^k!kzbG;CMRm>}=nfhTa|d<;SUz6D>;@op6L5%Yt)m;AZ0 zx*30u^)v0%D^Z*I8{o4gxb@E%O!m8>9Fr1#)XCZC&+Wa7{x9828UDOf8=JXQXZWm1 zpNq?jvnTtbvv2mtWZyjRp7ig@^U=At`lIu2o{N4`y6(sM;0ECS$(q^gm8H!hm{*pD zdG)H8cQ0e!CdOnEcE+?W=v`lWWzBTK*vz|(Es_uzdtCyI;T~CDfJCpiq{V*$i&S=H literal 0 HcmV?d00001 diff --git a/app/frontend/src/api/api.ts b/app/frontend/src/api/api.ts new file mode 100644 index 0000000000..12da6d9f12 --- /dev/null +++ b/app/frontend/src/api/api.ts @@ -0,0 +1,66 @@ +import { AskRequest, AskResponse, ChatRequest } from "./models"; + +export async function askApi(options: AskRequest): Promise { + const response = await fetch("/ask", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + question: options.question, + approach: options.approach, + overrides: { + semantic_ranker: options.overrides?.semanticRanker, + semantic_captions: options.overrides?.semanticCaptions, + top: options.overrides?.top, + temperature: options.overrides?.temperature, + prompt_template: options.overrides?.promptTemplate, + prompt_template_prefix: options.overrides?.promptTemplatePrefix, + prompt_template_suffix: options.overrides?.promptTemplateSuffix, + exclude_category: options.overrides?.excludeCategory + } + }) + }); + + const parsedResponse: AskResponse = await response.json(); + if (response.status > 299 || !response.ok) { + throw Error(parsedResponse.error || "Unknown error"); + } + + return parsedResponse; +} + +export async function chatApi(options: ChatRequest): Promise { + const response = await fetch("/chat", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + history: options.history, + approach: options.approach, + overrides: { + semantic_ranker: options.overrides?.semanticRanker, + semantic_captions: options.overrides?.semanticCaptions, + top: options.overrides?.top, + temperature: options.overrides?.temperature, + prompt_template: options.overrides?.promptTemplate, + prompt_template_prefix: options.overrides?.promptTemplatePrefix, + prompt_template_suffix: options.overrides?.promptTemplateSuffix, + exclude_category: options.overrides?.excludeCategory, + suggest_followup_questions: options.overrides?.suggestFollowupQuestions + } + }) + }); + + const parsedResponse: AskResponse = await response.json(); + if (response.status > 299 || !response.ok) { + throw Error(parsedResponse.error || "Unknown error"); + } + + return parsedResponse; +} + +export function getCitationFilePath(citation: string): string { + return `/content/${citation}`; +} diff --git a/app/frontend/src/api/index.ts b/app/frontend/src/api/index.ts new file mode 100644 index 0000000000..0475d357ad --- /dev/null +++ b/app/frontend/src/api/index.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./models"; diff --git a/app/frontend/src/api/models.ts b/app/frontend/src/api/models.ts new file mode 100644 index 0000000000..bec3dc28bc --- /dev/null +++ b/app/frontend/src/api/models.ts @@ -0,0 +1,41 @@ +export const enum Approaches { + RetrieveThenRead = "rtr", + ReadRetrieveRead = "rrr", + ReadDecomposeAsk = "rda" +} + +export type AskRequestOverrides = { + semanticRanker?: boolean; + semanticCaptions?: boolean; + excludeCategory?: string; + top?: number; + temperature?: number; + promptTemplate?: string; + promptTemplatePrefix?: string; + promptTemplateSuffix?: string; + suggestFollowupQuestions?: boolean; +}; + +export type AskRequest = { + question: string; + approach: Approaches; + overrides?: AskRequestOverrides; +}; + +export type AskResponse = { + answer: string; + thoughts: string | null; + data_points: string[]; + error?: string; +}; + +export type ChatTurn = { + user: string; + bot?: string; +}; + +export type ChatRequest = { + history: ChatTurn[]; + approach: Approaches; + overrides?: AskRequestOverrides; +}; diff --git a/app/frontend/src/assets/github.svg b/app/frontend/src/assets/github.svg new file mode 100644 index 0000000000..d5e6491854 --- /dev/null +++ b/app/frontend/src/assets/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/frontend/src/assets/search.svg b/app/frontend/src/assets/search.svg new file mode 100644 index 0000000000..feadc50b25 --- /dev/null +++ b/app/frontend/src/assets/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css new file mode 100644 index 0000000000..909ac03d44 --- /dev/null +++ b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css @@ -0,0 +1,6 @@ +.thoughtProcess { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; + word-wrap: break-word; + padding-top: 12px; + padding-bottom: 12px; +} diff --git a/app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx new file mode 100644 index 0000000000..cd01a08e2f --- /dev/null +++ b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx @@ -0,0 +1,57 @@ +import { Pivot, PivotItem } from "@fluentui/react"; +import DOMPurify from "dompurify"; + +import styles from "./AnalysisPanel.module.css"; + +import { SupportingContent } from "../SupportingContent"; +import { AskResponse } from "../../api"; +import { AnalysisPanelTabs } from "./AnalysisPanelTabs"; + +interface Props { + className: string; + activeTab: AnalysisPanelTabs; + onActiveTabChanged: (tab: AnalysisPanelTabs) => void; + activeCitation: string | undefined; + citationHeight: string; + answer: AskResponse; +} + +const pivotItemDisabledStyle = { disabled: true, style: { color: "grey" } }; + +export const AnalysisPanel = ({ answer, activeTab, activeCitation, citationHeight, className, onActiveTabChanged }: Props) => { + const isDisabledThoughtProcessTab: boolean = !answer.thoughts; + const isDisabledSupportingContentTab: boolean = !answer.data_points.length; + const isDisabledCitationTab: boolean = !activeCitation; + + const sanitizedThoughts = DOMPurify.sanitize(answer.thoughts!); + + return ( + pivotItem && onActiveTabChanged(pivotItem.props.itemKey! as AnalysisPanelTabs)} + > + +
+
+ + + + +