From 43a829ada41f1adced2c2d492f918feda2df9f4f Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:54:34 +0000 Subject: [PATCH 1/8] committing to build locally --- .env | 9 + package-lock.json | 432 +++++++++++++++++++++++++++- package.json | 1 + pages/api/AzureCredentialManager.ts | 36 +++ pages/api/chat.ts | 19 +- pages/api/models.ts | 14 +- utils/app/const.ts | 2 + utils/server/index.ts | 14 +- 8 files changed, 516 insertions(+), 11 deletions(-) create mode 100644 pages/api/AzureCredentialManager.ts diff --git a/.env b/.env index e69de29bb2..fc0a5d0ce0 100644 --- a/.env +++ b/.env @@ -0,0 +1,9 @@ +DEFAULT_MODEL=gpt40 +OPENAI_API_HOST=https://ffl-oai-01.openai.azure.com/ +OPENAI_API_TYPE=azure +AZURE_DEPLOYMENT_ID=gpt40 +OPENAI_API_KEY=d050b49630a14362af6b6c015988319e-00 +NEXT_PUBLIC_DEFAULT_TEMPERATURE=0.1 +AZURE_USE_MANAGED_IDENTITY=true +NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=You are Gov Chat an AI Assistant using Azure OpenAI. Follow the user's instructions carefully. Respond using markdown. + diff --git a/package-lock.json b/package-lock.json index 333075f5fb..404a315072 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "ai-chatbot-starter", "version": "0.1.0", "dependencies": { + "@azure/identity": "^4.4.0", "@dqbd/tiktoken": "^1.0.2", "@tabler/icons-react": "^2.9.0", "eventsource-parser": "^0.1.0", @@ -64,6 +65,242 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@azure/abort-controller": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.2.tgz", + "integrity": "sha512-Hnhm/PG9/SQ07JJyLDv3l9Qr8V3xgAe1hFoBYzt6LaalMxfL/ZqFaZf/bz5VN3pMcleCPwl8ivlS2Fjxq/iC8Q==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.9.0", + "@azure/logger": "^1.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", + "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.1.tgz", + "integrity": "sha512-OLsq0etbHO1MA7j6FouXFghuHrAFGk+5C1imcpQ2e+0oZhYF07WLA+NW2Vqs70R7d+zOAWiWM3tbE1sXcDN66g==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.4.0.tgz", + "integrity": "sha512-oG6oFNMxUuoivYg/ElyZWVSZfw42JQyHbrp+lR7VJ1BYWsGzt34NwyDw3miPp1QI7Qm5+4KAd76wGsbHQmkpkg==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.5.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.3.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.14.0", + "@azure/msal-node": "^2.9.2", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.3.tgz", + "integrity": "sha512-J8/cIKNQB1Fc9fuYqBVnrppiUtW+5WWJPCj/tAokC5LdSTwkWWttN+jsRgw9BLYD7JDBx7PceiqOBxJJ1tQz3Q==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.19.1.tgz", + "integrity": "sha512-pqYP2gK0GCEa4OxtOqlS+EdFQqhXV6ZuESgSTYWq2ABXyxBVVdd5KNuqgR5SU0OwI2V1YWdFVvLDe1487dyQ0g==", + "dependencies": { + "@azure/msal-common": "14.13.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.13.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.13.1.tgz", + "integrity": "sha512-iUp3BYrsRZ4X3EiaZ2fDjNFjmtYMv9rEQd6c1op6ULn0HWk4ACvDmosL6NaBgWOhl1BAblIbd9vmB5/ilF8d4A==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.11.1.tgz", + "integrity": "sha512-8ECtug4RL+zsgh20VL8KYHjrRO3MJOeAKEPRXT2lwtiu5U3BdyIdBb50+QZthEkIi60K6pc/pdOx/k5Jp4sLng==", + "dependencies": { + "@azure/msal-common": "14.13.1", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@azure/msal-node/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", @@ -2106,6 +2343,11 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/c8": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/c8/-/c8-7.14.0.tgz", @@ -2646,6 +2888,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -2746,6 +2996,14 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.752", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.752.tgz", @@ -3564,6 +3822,14 @@ "node": ">=0.10.0" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/eventsource-parser": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-0.1.0.tgz", @@ -4583,6 +4849,20 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4853,6 +5133,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -5087,6 +5378,46 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -5102,6 +5433,25 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/katex": { "version": "0.16.10", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.10.tgz", @@ -5219,11 +5569,35 @@ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "dev": true }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -5231,6 +5605,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -5277,7 +5656,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -6556,6 +6934,22 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openai": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", @@ -7646,6 +8040,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -7691,7 +8104,6 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -7881,6 +8293,15 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -9498,8 +9919,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "2.4.2", diff --git a/package.json b/package.json index ccb2cdb4a4..09b3bc7bbc 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "coverage": "vitest run --coverage" }, "dependencies": { + "@azure/identity": "^4.4.0", "@dqbd/tiktoken": "^1.0.2", "@tabler/icons-react": "^2.9.0", "eventsource-parser": "^0.1.0", diff --git a/pages/api/AzureCredentialManager.ts b/pages/api/AzureCredentialManager.ts new file mode 100644 index 0000000000..e57a8251d1 --- /dev/null +++ b/pages/api/AzureCredentialManager.ts @@ -0,0 +1,36 @@ +import { AccessToken,DefaultAzureCredential, VisualStudioCodeCredential, AzureCliCredential, DefaultAzureCredentialOptions } from '@azure/identity'; + +class AzureCredentialManager { + private static instance: AzureCredentialManager; + public credential: DefaultAzureCredential; + public token: AccessToken; + + private constructor() { + console.log("starting AzureCredentialManager constructor"); + // Define options for DefaultAzureCredential + const options: DefaultAzureCredentialOptions = { + // Explicitly specify the credential types to use + credentials: [new VisualStudioCodeCredential(), new AzureCliCredential()], + }; + + this.credential = new DefaultAzureCredential(options); + this.token = { token: "defaultTokenValue", expiresOnTimestamp: Date.now() + 1000 }; + console.log("finished AzureCredentialManager constructor"); + } + + public static async getInstance(): Promise { + if (!AzureCredentialManager.instance) { + AzureCredentialManager.instance = new AzureCredentialManager(); + await AzureCredentialManager.instance.initializeToken(); + } + return AzureCredentialManager.instance; + } + + private async initializeToken() { + console.log("starting AzureCredentialManager initializeToken"); + this.token = await this.credential.getToken("https://cognitiveservices.azure.com/.default"); + console.log("finished AzureCredentialManager initializeToken"); + } +} + +export default AzureCredentialManager; \ No newline at end of file diff --git a/pages/api/chat.ts b/pages/api/chat.ts index 50cab87468..0aa14e0a61 100644 --- a/pages/api/chat.ts +++ b/pages/api/chat.ts @@ -2,6 +2,7 @@ import { DEFAULT_SYSTEM_PROMPT, DEFAULT_TEMPERATURE } from '@/utils/app/const'; import { OpenAIError, OpenAIStream } from '@/utils/server'; import { ChatBody, Message } from '@/types/chat'; +import AzureCredentialManager from '../api/AzureCredentialManager'; // Adjust the path based on your directory structure // @ts-expect-error import wasm from '../../node_modules/@dqbd/tiktoken/lite/tiktoken_bg.wasm?module'; @@ -54,10 +55,24 @@ const handler = async (req: Request): Promise => { var principalName:string|null = req.headers.get("x-ms-client-principal-name"); var bearer:string|null =req.headers.get("x-ms-token-aad-access-token")? req.headers.get("x-ms-token-aad-access-token") : req.headers.get("x-ms-client-principal"); var bearerAuth: string|null = req.headers.get("x-ms-client-principal-id"); - console.log(principalName); - console.log(bearer); + console.log("principalName:" + principalName); + console.log("bearer:" + bearer); encoding.free(); + + if (typeof window === 'undefined') + { + console.log("I think I'm on the server"); + + console.log("chat.ts about to get credential"); + const azureCredentialManager = await AzureCredentialManager.getInstance(); + const credtoken = azureCredentialManager.token; // Use the token + console.log("chat.ts auth token:"+ credtoken); + // Get the access token + //const token = await credential.getToken("https://cognitiveservices.azure.com/.default"); + //console.log("chat.ts auth token:"+token); + } + const stream = await OpenAIStream(model, promptToSend, temperatureToUse, key, messagesToSend, principalName, bearer, bearerAuth ); return new Response(stream); diff --git a/pages/api/models.ts b/pages/api/models.ts index 7b7be01539..60c34c1e02 100644 --- a/pages/api/models.ts +++ b/pages/api/models.ts @@ -1,6 +1,6 @@ import { OPENAI_API_HOST, OPENAI_API_TYPE, OPENAI_API_VERSION, OPENAI_ORGANIZATION, AZURE_APIM } from '@/utils/app/const'; - import { OpenAIModel, OpenAIModelID, OpenAIModels } from '@/types/openai'; +const { DefaultAzureCredential } = require('@azure/identity'); export const config = { runtime: 'edge', @@ -17,6 +17,13 @@ const handler = async (req: Request): Promise => { url = `${OPENAI_API_HOST}/openai/deployments?api-version=${OPENAI_API_VERSION}`; } + console.log("about to get the model credentials"); + //to test we are always getting the token we need to change this + const credential = new DefaultAzureCredential(); + // Get the access token + const token = await credential.getToken("https://cognitiveservices.azure.com/.default"); + console.log("auth token:"+token); + console.log("load the models: " + url) ; console.log("model headers"); console.log(req.headers); @@ -28,9 +35,12 @@ const handler = async (req: Request): Promise => { ...(OPENAI_API_TYPE === 'openai' && { Authorization: `Bearer ${key ? key : process.env.OPENAI_API_KEY}` }), - ...(OPENAI_API_TYPE === 'azure' && { + ...(OPENAI_API_TYPE === 'azure' && process.env.AZURE_USE_MANAGED_IDENTITY=="false" && { 'api-key': `${key ? key : process.env.OPENAI_API_KEY}` }), + ...(OPENAI_API_TYPE === 'azure' && process.env.AZURE_USE_MANAGED_IDENTITY=="true" && { + Authorization: `Bearer ${token}` + }), ...((OPENAI_API_TYPE === 'openai' && OPENAI_ORGANIZATION) && { 'OpenAI-Organization': OPENAI_ORGANIZATION, }), diff --git a/utils/app/const.ts b/utils/app/const.ts index 1b46b61b70..f6b73283d3 100644 --- a/utils/app/const.ts +++ b/utils/app/const.ts @@ -21,3 +21,5 @@ export const AZURE_DEPLOYMENT_ID = process.env.AZURE_DEPLOYMENT_ID || ''; export const AZURE_APIM = process.env.AZURE_APIM_KEY || false + +export const AZURE_USE_MANAGED_IDENTITY = process.env.AZURE_USE_MANAGED_IDENTITY || false diff --git a/utils/server/index.ts b/utils/server/index.ts index 59f804bb60..3df1d3a00b 100644 --- a/utils/server/index.ts +++ b/utils/server/index.ts @@ -2,6 +2,7 @@ import { Message } from '@/types/chat'; import { OpenAIModel } from '@/types/openai'; import { AZURE_DEPLOYMENT_ID, OPENAI_API_HOST, OPENAI_API_TYPE, OPENAI_API_VERSION, OPENAI_ORGANIZATION, AZURE_APIM } from '../app/const'; +import { DefaultAzureCredential } from "@azure/identity"; import { ParsedEvent, @@ -38,14 +39,25 @@ export const OpenAIStream = async ( url = `${OPENAI_API_HOST}/openai/deployments/${AZURE_DEPLOYMENT_ID}/chat/completions?api-version=${OPENAI_API_VERSION}`; console.log(url); } + console.log("about to get credential"); + //to test we are always getting the token we need to change this + const credential = new DefaultAzureCredential(); + console.log("credential: " + credential); + // Get the access token + const token = await credential.getToken("https://cognitiveservices.azure.com/.default"); + console.log("auth token:"+token); + const header = { 'Content-Type': 'application/json', ...(OPENAI_API_TYPE === 'openai' && { Authorization: `Bearer ${key ? key : process.env.OPENAI_API_KEY}` }), - ...(OPENAI_API_TYPE === 'azure' && { + ...(OPENAI_API_TYPE === 'azure' && process.env.AZURE_USE_MANAGED_IDENTITY=="false" && { 'api-key': `${key ? key : process.env.OPENAI_API_KEY}` }), + ...(OPENAI_API_TYPE === 'azure' && process.env.AZURE_USE_MANAGED_IDENTITY=="true" && { + Authorization: `Bearer ${token}` + }), ...((OPENAI_API_TYPE === 'openai' && OPENAI_ORGANIZATION) && { 'OpenAI-Organization': OPENAI_ORGANIZATION, }), From 4524d94301825b130958e4e40eda3e83c1837d04 Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:54:56 +0000 Subject: [PATCH 2/8] committing --- pages/api/AzureCredentialManager.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pages/api/AzureCredentialManager.ts b/pages/api/AzureCredentialManager.ts index e57a8251d1..64c0e428c9 100644 --- a/pages/api/AzureCredentialManager.ts +++ b/pages/api/AzureCredentialManager.ts @@ -8,12 +8,8 @@ class AzureCredentialManager { private constructor() { console.log("starting AzureCredentialManager constructor"); // Define options for DefaultAzureCredential - const options: DefaultAzureCredentialOptions = { - // Explicitly specify the credential types to use - credentials: [new VisualStudioCodeCredential(), new AzureCliCredential()], - }; - this.credential = new DefaultAzureCredential(options); + this.credential = new DefaultAzureCredential(); this.token = { token: "defaultTokenValue", expiresOnTimestamp: Date.now() + 1000 }; console.log("finished AzureCredentialManager constructor"); } From 7ba09d539fb18f0189234764dcc92de8de7e39ed Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Sat, 27 Jul 2024 09:41:22 +0000 Subject: [PATCH 3/8] made changes to support managed identity --- .env | 10 +++---- .eslintrc.json | 5 +++- .gitignore | 1 + package-lock.json | 20 +++++++++++++ package.json | 1 + pages/_app.tsx | 1 + pages/api/chat.ts | 23 ++++---------- .../api/{ => home}/AzureCredentialManager.ts | 5 +++- pages/api/home/home.tsx | 17 +++++++++++ pages/api/home/index.ts | 2 ++ pages/api/models.ts | 13 ++++---- tsconfig.json | 30 ++++++++++++++----- utils/app/const.ts | 4 +++ utils/lib/azure.js | 26 ++++++++++++++++ utils/server/index.ts | 16 +++++----- 15 files changed, 127 insertions(+), 47 deletions(-) rename pages/api/{ => home}/AzureCredentialManager.ts (85%) create mode 100644 utils/lib/azure.js diff --git a/.env b/.env index fc0a5d0ce0..fb89a6dc69 100644 --- a/.env +++ b/.env @@ -1,9 +1,9 @@ -DEFAULT_MODEL=gpt40 -OPENAI_API_HOST=https://ffl-oai-01.openai.azure.com/ +DEFAULT_MODEL=gpt-4o +OPENAI_API_HOST=https://ffl-aoai-eastus.openai.azure.com OPENAI_API_TYPE=azure -AZURE_DEPLOYMENT_ID=gpt40 -OPENAI_API_KEY=d050b49630a14362af6b6c015988319e-00 +AZURE_DEPLOYMENT_ID=gpt-4o +OPENAI_API_KEY=33256dc2d8714d51b983c19ff81bcc62-00 NEXT_PUBLIC_DEFAULT_TEMPERATURE=0.1 AZURE_USE_MANAGED_IDENTITY=true -NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=You are Gov Chat an AI Assistant using Azure OpenAI. Follow the user's instructions carefully. Respond using markdown. +NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=You are Gov Chat an AI Assistant using Azure OpenAI. Follow the users instructions carefully. Respond using markdown. diff --git a/.eslintrc.json b/.eslintrc.json index bffb357a71..8f8d108ef8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,6 @@ { - "extends": "next/core-web-vitals" + "extends": "next/core-web-vitals", + "rules": { + "@typescript-eslint/no-var-requires": "off" + } } diff --git a/.gitignore b/.gitignore index 5be3dc7463..002fbf8838 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ yarn-error.log* next-env.d.ts .idea pnpm-lock.yaml +.env diff --git a/package-lock.json b/package-lock.json index 404a315072..b5c2463d43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "i18next": "^22.4.13", "next": "13.2.4", "next-i18next": "^13.2.2", + "node-cache": "^5.1.2", "openai": "^3.2.1", "react": "18.2.0", "react-dom": "18.2.0", @@ -2616,6 +2617,14 @@ "node": ">=8" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -6753,6 +6762,17 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", diff --git a/package.json b/package.json index 09b3bc7bbc..86fa1fc2f6 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "i18next": "^22.4.13", "next": "13.2.4", "next-i18next": "^13.2.2", + "node-cache": "^5.1.2", "openai": "^3.2.1", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/pages/_app.tsx b/pages/_app.tsx index ad28961180..8c3eb7eb0e 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -9,6 +9,7 @@ import '@/styles/globals.css'; const inter = Inter({ subsets: ['latin'] }); + function App({ Component, pageProps }: AppProps<{}>) { const queryClient = new QueryClient(); diff --git a/pages/api/chat.ts b/pages/api/chat.ts index 0aa14e0a61..0895a6b200 100644 --- a/pages/api/chat.ts +++ b/pages/api/chat.ts @@ -1,8 +1,6 @@ import { DEFAULT_SYSTEM_PROMPT, DEFAULT_TEMPERATURE } from '@/utils/app/const'; import { OpenAIError, OpenAIStream } from '@/utils/server'; - import { ChatBody, Message } from '@/types/chat'; -import AzureCredentialManager from '../api/AzureCredentialManager'; // Adjust the path based on your directory structure // @ts-expect-error import wasm from '../../node_modules/@dqbd/tiktoken/lite/tiktoken_bg.wasm?module'; @@ -10,9 +8,11 @@ import wasm from '../../node_modules/@dqbd/tiktoken/lite/tiktoken_bg.wasm?module import tiktokenModel from '@dqbd/tiktoken/encoders/cl100k_base.json'; import { Tiktoken, init } from '@dqbd/tiktoken/lite/init'; -export const config = { - runtime: 'edge', -}; +console.log("starting") + + export const config = { + runtime: 'edge', + }; const handler = async (req: Request): Promise => { try { @@ -60,19 +60,6 @@ const handler = async (req: Request): Promise => { encoding.free(); - if (typeof window === 'undefined') - { - console.log("I think I'm on the server"); - - console.log("chat.ts about to get credential"); - const azureCredentialManager = await AzureCredentialManager.getInstance(); - const credtoken = azureCredentialManager.token; // Use the token - console.log("chat.ts auth token:"+ credtoken); - // Get the access token - //const token = await credential.getToken("https://cognitiveservices.azure.com/.default"); - //console.log("chat.ts auth token:"+token); - } - const stream = await OpenAIStream(model, promptToSend, temperatureToUse, key, messagesToSend, principalName, bearer, bearerAuth ); return new Response(stream); diff --git a/pages/api/AzureCredentialManager.ts b/pages/api/home/AzureCredentialManager.ts similarity index 85% rename from pages/api/AzureCredentialManager.ts rename to pages/api/home/AzureCredentialManager.ts index 64c0e428c9..d92413ba20 100644 --- a/pages/api/AzureCredentialManager.ts +++ b/pages/api/home/AzureCredentialManager.ts @@ -1,4 +1,7 @@ -import { AccessToken,DefaultAzureCredential, VisualStudioCodeCredential, AzureCliCredential, DefaultAzureCredentialOptions } from '@azure/identity'; +import { AccessToken,DefaultAzureCredential, VisualStudioCodeCredential, AzureCliCredential, DefaultAzureCredentialOptions, ChainedTokenCredential } from '@azure/identity'; +//import { azcredential } from './home/index'; +import { getServerSideProps } from './home'; + class AzureCredentialManager { private static instance: AzureCredentialManager; diff --git a/pages/api/home/home.tsx b/pages/api/home/home.tsx index 2cc0f3d1e3..dc6b1c2a6a 100644 --- a/pages/api/home/home.tsx +++ b/pages/api/home/home.tsx @@ -1,5 +1,8 @@ import { useEffect, useRef, useState } from 'react'; import { useQuery } from 'react-query'; +import { DefaultAzureCredential,ChainedTokenCredential } from "@azure/identity"; +import { getAuthToken } from "@/utils/lib/azure" +//import { getCache } from "@/utils/lib/cache" import { GetServerSideProps } from 'next'; import { useTranslation } from 'next-i18next'; @@ -47,6 +50,8 @@ interface Props { defaultModelId: OpenAIModelID; } +let aztoken=null; + const Home = ({ serverSideApiKeyIsSet, serverSidePluginKeysSet, @@ -394,6 +399,12 @@ const Home = ({ }; export default Home; +// export const getAzCreds = () => { +// return azcredential; +// } + + + export const getServerSideProps: GetServerSideProps = async ({ locale }) => { const defaultModelId = (process.env.DEFAULT_MODEL && @@ -403,6 +414,10 @@ export const getServerSideProps: GetServerSideProps = async ({ locale }) => { process.env.DEFAULT_MODEL) || fallbackModelID; + aztoken = await getAuthToken(); + console.log("I'm still alive"); + //const azToken = getCache("cachedToken"); + console.log("I'm still alive really",aztoken); let serverSidePluginKeysSet = false; const googleApiKey = process.env.GOOGLE_API_KEY; @@ -416,6 +431,7 @@ export const getServerSideProps: GetServerSideProps = async ({ locale }) => { props: { serverSideApiKeyIsSet: !!process.env.OPENAI_API_KEY, defaultModelId, + aztoken, serverSidePluginKeysSet, ...(await serverSideTranslations(locale ?? 'en', [ 'common', @@ -428,3 +444,4 @@ export const getServerSideProps: GetServerSideProps = async ({ locale }) => { }, }; }; + diff --git a/pages/api/home/index.ts b/pages/api/home/index.ts index 20dca24e29..7efd937ae8 100644 --- a/pages/api/home/index.ts +++ b/pages/api/home/index.ts @@ -1 +1,3 @@ +//import { DefaultAzureCredential } from "@azure/identity"; export { default, getServerSideProps } from './home'; +//export let azcredential = new DefaultAzureCredential(); \ No newline at end of file diff --git a/pages/api/models.ts b/pages/api/models.ts index 60c34c1e02..91fdac9008 100644 --- a/pages/api/models.ts +++ b/pages/api/models.ts @@ -1,6 +1,6 @@ import { OPENAI_API_HOST, OPENAI_API_TYPE, OPENAI_API_VERSION, OPENAI_ORGANIZATION, AZURE_APIM } from '@/utils/app/const'; import { OpenAIModel, OpenAIModelID, OpenAIModels } from '@/types/openai'; -const { DefaultAzureCredential } = require('@azure/identity'); +import { getCache } from '@/utils/lib/cache'; export const config = { runtime: 'edge', @@ -17,12 +17,11 @@ const handler = async (req: Request): Promise => { url = `${OPENAI_API_HOST}/openai/deployments?api-version=${OPENAI_API_VERSION}`; } - console.log("about to get the model credentials"); + console.log("models.ts - about to get the model credentials"); //to test we are always getting the token we need to change this - const credential = new DefaultAzureCredential(); - // Get the access token - const token = await credential.getToken("https://cognitiveservices.azure.com/.default"); - console.log("auth token:"+token); + //const credential = getAzureCredential(); + const authtoken = getCache("cachedToken"); + console.log("auth token:"+authtoken); console.log("load the models: " + url) ; console.log("model headers"); @@ -39,7 +38,7 @@ const handler = async (req: Request): Promise => { 'api-key': `${key ? key : process.env.OPENAI_API_KEY}` }), ...(OPENAI_API_TYPE === 'azure' && process.env.AZURE_USE_MANAGED_IDENTITY=="true" && { - Authorization: `Bearer ${token}` + Authorization: `Bearer ${authtoken}` }), ...((OPENAI_API_TYPE === 'openai' && OPENAI_ORGANIZATION) && { 'OpenAI-Organization': OPENAI_ORGANIZATION, diff --git a/tsconfig.json b/tsconfig.json index 7a88b2f5f9..b2c634e61e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,24 +1,40 @@ { "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "target": "es2022", + "module": "commonjs", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, - "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, - "types": ["vitest/globals"], + "allowSyntheticDefaultImports": true, + "types": [ + "vitest/globals" + ], "paths": { - "@/*": ["./*"] + "@/*": [ + "./*", + "./lib/*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] } diff --git a/utils/app/const.ts b/utils/app/const.ts index f6b73283d3..090e3a4cd2 100644 --- a/utils/app/const.ts +++ b/utils/app/const.ts @@ -1,3 +1,5 @@ +//import { DefaultAzureCredential } from "@azure/identity"; + export const DEFAULT_SYSTEM_PROMPT = process.env.NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT || "You are Gov Chat an AI Assistant using Azure OpenAI. Follow the user's instructions carefully. Respond using markdown."; @@ -23,3 +25,5 @@ export const AZURE_DEPLOYMENT_ID = export const AZURE_APIM = process.env.AZURE_APIM_KEY || false export const AZURE_USE_MANAGED_IDENTITY = process.env.AZURE_USE_MANAGED_IDENTITY || false + +//export const myAZCredentials = new DefaultAzureCredential(); diff --git a/utils/lib/azure.js b/utils/lib/azure.js new file mode 100644 index 0000000000..e5496f86c9 --- /dev/null +++ b/utils/lib/azure.js @@ -0,0 +1,26 @@ +// lib/azure.js + +import { DefaultAzureCredential } from "@azure/identity"; +import { log } from "console"; +//import { getCache, setCache } from "./cache"; + + + +export async function getAuthToken() { + let cachedToken = process.env.AUTH_TOKEN ? JSON.parse(process.env.AUTH_TOKEN) : ''; + if (!cachedToken || cachedToken.expiresOnTimestamp < Date.now()) { + let cachedCredential = new DefaultAzureCredential(); + cachedToken = await cachedCredential.getToken("https://cognitiveservices.azure.com/.default"); + console.log("cachedToken", cachedToken); + //cache.set("cachedCredential", cachedCredential); + //console.log("set the cachedCredntial in cache"); + //setCache("cachedToken", JSON.stringify(cachedToken)); + //console.log("set the cachedToken in cache"); + //let a = JSON.parse(getCache("cachedToken")); + //console.log("cachedToken from memory", a); + process.env.AUTH_TOKEN = JSON.stringify(cachedToken); + return cachedToken; + } + console.log("cachedToken from memory", cachedToken); + return process.env.AUTH_TOKEN ? JSON.parse(process.env.AUTH_TOKEN) : '';; +} diff --git a/utils/server/index.ts b/utils/server/index.ts index 3df1d3a00b..bf299528b8 100644 --- a/utils/server/index.ts +++ b/utils/server/index.ts @@ -2,13 +2,14 @@ import { Message } from '@/types/chat'; import { OpenAIModel } from '@/types/openai'; import { AZURE_DEPLOYMENT_ID, OPENAI_API_HOST, OPENAI_API_TYPE, OPENAI_API_VERSION, OPENAI_ORGANIZATION, AZURE_APIM } from '../app/const'; -import { DefaultAzureCredential } from "@azure/identity"; + import { ParsedEvent, ReconnectInterval, createParser, } from 'eventsource-parser'; +import { getAuthToken } from '../lib/azure'; export class OpenAIError extends Error { type: string; @@ -40,12 +41,11 @@ export const OpenAIStream = async ( console.log(url); } console.log("about to get credential"); - //to test we are always getting the token we need to change this - const credential = new DefaultAzureCredential(); - console.log("credential: " + credential); - // Get the access token - const token = await credential.getToken("https://cognitiveservices.azure.com/.default"); - console.log("auth token:"+token); + //let token = getCache("cachedToken"); + //console.log("auth token:",token); + //let token = process.env.AUTH_TOKEN ? JSON.parse(process.env.AUTH_TOKEN) : ''; + let token = await getAuthToken(); + console.log("auth token:",token); const header = { 'Content-Type': 'application/json', @@ -56,7 +56,7 @@ export const OpenAIStream = async ( 'api-key': `${key ? key : process.env.OPENAI_API_KEY}` }), ...(OPENAI_API_TYPE === 'azure' && process.env.AZURE_USE_MANAGED_IDENTITY=="true" && { - Authorization: `Bearer ${token}` + Authorization: `Bearer ${token.token}` }), ...((OPENAI_API_TYPE === 'openai' && OPENAI_ORGANIZATION) && { 'OpenAI-Organization': OPENAI_ORGANIZATION, From 038da7ba38596cf37cae0088985e6437e3b5e590 Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:55:06 +0000 Subject: [PATCH 4/8] corrected the models.ts --- pages/api/home/AzureCredentialManager.ts | 35 ------------------------ pages/api/models.ts | 8 +++--- 2 files changed, 4 insertions(+), 39 deletions(-) delete mode 100644 pages/api/home/AzureCredentialManager.ts diff --git a/pages/api/home/AzureCredentialManager.ts b/pages/api/home/AzureCredentialManager.ts deleted file mode 100644 index d92413ba20..0000000000 --- a/pages/api/home/AzureCredentialManager.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AccessToken,DefaultAzureCredential, VisualStudioCodeCredential, AzureCliCredential, DefaultAzureCredentialOptions, ChainedTokenCredential } from '@azure/identity'; -//import { azcredential } from './home/index'; -import { getServerSideProps } from './home'; - - -class AzureCredentialManager { - private static instance: AzureCredentialManager; - public credential: DefaultAzureCredential; - public token: AccessToken; - - private constructor() { - console.log("starting AzureCredentialManager constructor"); - // Define options for DefaultAzureCredential - - this.credential = new DefaultAzureCredential(); - this.token = { token: "defaultTokenValue", expiresOnTimestamp: Date.now() + 1000 }; - console.log("finished AzureCredentialManager constructor"); - } - - public static async getInstance(): Promise { - if (!AzureCredentialManager.instance) { - AzureCredentialManager.instance = new AzureCredentialManager(); - await AzureCredentialManager.instance.initializeToken(); - } - return AzureCredentialManager.instance; - } - - private async initializeToken() { - console.log("starting AzureCredentialManager initializeToken"); - this.token = await this.credential.getToken("https://cognitiveservices.azure.com/.default"); - console.log("finished AzureCredentialManager initializeToken"); - } -} - -export default AzureCredentialManager; \ No newline at end of file diff --git a/pages/api/models.ts b/pages/api/models.ts index 91fdac9008..5d59331158 100644 --- a/pages/api/models.ts +++ b/pages/api/models.ts @@ -1,6 +1,6 @@ import { OPENAI_API_HOST, OPENAI_API_TYPE, OPENAI_API_VERSION, OPENAI_ORGANIZATION, AZURE_APIM } from '@/utils/app/const'; import { OpenAIModel, OpenAIModelID, OpenAIModels } from '@/types/openai'; -import { getCache } from '@/utils/lib/cache'; +import { getAuthToken } from '@/utils/lib/azure'; export const config = { runtime: 'edge', @@ -20,8 +20,8 @@ const handler = async (req: Request): Promise => { console.log("models.ts - about to get the model credentials"); //to test we are always getting the token we need to change this //const credential = getAzureCredential(); - const authtoken = getCache("cachedToken"); - console.log("auth token:"+authtoken); + let token = await getAuthToken(); + //console.log("auth token:"+to); console.log("load the models: " + url) ; console.log("model headers"); @@ -38,7 +38,7 @@ const handler = async (req: Request): Promise => { 'api-key': `${key ? key : process.env.OPENAI_API_KEY}` }), ...(OPENAI_API_TYPE === 'azure' && process.env.AZURE_USE_MANAGED_IDENTITY=="true" && { - Authorization: `Bearer ${authtoken}` + Authorization: `Bearer ${token.token}` }), ...((OPENAI_API_TYPE === 'openai' && OPENAI_ORGANIZATION) && { 'OpenAI-Organization': OPENAI_ORGANIZATION, From 2b23fadde0b47e8755fd82fcce2c7c0f396030c0 Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:31:08 -0400 Subject: [PATCH 5/8] Update .env --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index fb89a6dc69..151e05bcb5 100644 --- a/.env +++ b/.env @@ -2,7 +2,7 @@ DEFAULT_MODEL=gpt-4o OPENAI_API_HOST=https://ffl-aoai-eastus.openai.azure.com OPENAI_API_TYPE=azure AZURE_DEPLOYMENT_ID=gpt-4o -OPENAI_API_KEY=33256dc2d8714d51b983c19ff81bcc62-00 +OPENAI_API_KEY= NEXT_PUBLIC_DEFAULT_TEMPERATURE=0.1 AZURE_USE_MANAGED_IDENTITY=true NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=You are Gov Chat an AI Assistant using Azure OpenAI. Follow the users instructions carefully. Respond using markdown. From c50f0b1800e27d3f6172e58c241d7aaad5d6810f Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:36:57 +0000 Subject: [PATCH 6/8] removing .env --- .env | 1 - .gitignore | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index fb89a6dc69..67c0ff6acf 100644 --- a/.env +++ b/.env @@ -2,7 +2,6 @@ DEFAULT_MODEL=gpt-4o OPENAI_API_HOST=https://ffl-aoai-eastus.openai.azure.com OPENAI_API_TYPE=azure AZURE_DEPLOYMENT_ID=gpt-4o -OPENAI_API_KEY=33256dc2d8714d51b983c19ff81bcc62-00 NEXT_PUBLIC_DEFAULT_TEMPERATURE=0.1 AZURE_USE_MANAGED_IDENTITY=true NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=You are Gov Chat an AI Assistant using Azure OpenAI. Follow the users instructions carefully. Respond using markdown. diff --git a/.gitignore b/.gitignore index 002fbf8838..d8ebacd6a6 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ next-env.d.ts .idea pnpm-lock.yaml .env +.env From 0a421cf16e3ba02bb738859074cee8feb7c70531 Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:47:49 -0400 Subject: [PATCH 7/8] Delete .env --- .env | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 67c0ff6acf..0000000000 --- a/.env +++ /dev/null @@ -1,8 +0,0 @@ -DEFAULT_MODEL=gpt-4o -OPENAI_API_HOST=https://ffl-aoai-eastus.openai.azure.com -OPENAI_API_TYPE=azure -AZURE_DEPLOYMENT_ID=gpt-4o -NEXT_PUBLIC_DEFAULT_TEMPERATURE=0.1 -AZURE_USE_MANAGED_IDENTITY=true -NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=You are Gov Chat an AI Assistant using Azure OpenAI. Follow the users instructions carefully. Respond using markdown. - From e5a640bc25ad424ed0e5cb7b823325211459127b Mon Sep 17 00:00:00 2001 From: Pete Nash <56097332+pnashmsft@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:50:16 -0400 Subject: [PATCH 8/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2073d98cb8..64beae2ae3 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ When deploying the application, the following environment variables can be set: | GOOGLE_CSE_ID | | See [Custom Search JSON API documentation][GCSE] | | AZURE_APIM_KEY | | Required if using APIM. Use the subscription key if needed. | NODE_TLS_REJECT_UNAUTHORIZED | | Set to `0` if using a self signed cert to prevent TLS errors.| +| AZURE_USE_MANAGED_IDENTITY | false | Determines if the identity of the app services is used to auth against AOAI| If you do not provide an OpenAI API key with `OPENAI_API_KEY`, users will have to provide their own key.