diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index 42eab7c1..82ae76b0 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -30,6 +30,7 @@ "prop-types": "^15.8.1", "react": "^17.0.2", "react-chartjs-2": "^4.0.0", + "react-chatbot-kit": "^2.0.1", "react-dom": "^17.0.2", "react-router-dom": "^6.2.2", "react-scripts": "5.0.0", @@ -5819,6 +5820,11 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" }, + "node_modules/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "node_modules/clean-css": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", @@ -14300,6 +14306,194 @@ "react": "^16.8.0 || ^17.0.0" } }, + "node_modules/react-chatbot-kit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-chatbot-kit/-/react-chatbot-kit-2.0.1.tgz", + "integrity": "sha512-OnGmlBx5WHEz3T/WsX0d3ofC8TC/DsD9FTGs5crv+fpFyfsuL/Z91gUkXtSQ1+reml286Ei3Vh5mvM454k2+kA==", + "dependencies": { + "classnames": "^2.2.6", + "css-loader": "^3.5.1", + "react-conditionally-render": "^1.0.2" + } + }, + "node_modules/react-chatbot-kit/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/react-chatbot-kit/node_modules/css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/react-chatbot-kit/node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-chatbot-kit/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/react-chatbot-kit/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/react-chatbot-kit/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/react-chatbot-kit/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/react-chatbot-kit/node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-chatbot-kit/node_modules/postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dependencies": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-chatbot-kit/node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-chatbot-kit/node_modules/postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dependencies": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "node_modules/react-chatbot-kit/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/react-chatbot-kit/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/react-chatbot-kit/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-conditionally-render": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-conditionally-render/-/react-conditionally-render-1.0.2.tgz", + "integrity": "sha512-CtjIgaLHVDSgHis3gv/PT/8EnD6GPUL8PrhUjh7DP6S5Y3p56dGu7y2nVg6pYv1kv+fGznRhRmX3assr/vRw3A==" + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -21386,6 +21580,11 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" }, + "classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "clean-css": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", @@ -27402,6 +27601,145 @@ "integrity": "sha512-q8bgWzKoFvBvD7YcjT/hXG8jt55TaMAuJ1dmI3tKFJ7CijUWYz4pIfOhkTI6PBTwqu/pmeWsClBRd/7HiWzN1g==", "requires": {} }, + "react-chatbot-kit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-chatbot-kit/-/react-chatbot-kit-2.0.1.tgz", + "integrity": "sha512-OnGmlBx5WHEz3T/WsX0d3ofC8TC/DsD9FTGs5crv+fpFyfsuL/Z91gUkXtSQ1+reml286Ei3Vh5mvM454k2+kA==", + "requires": { + "classnames": "^2.2.6", + "css-loader": "^3.5.1", + "react-conditionally-render": "^1.0.2" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + } + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "requires": { + "postcss": "^7.0.14" + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "react-conditionally-render": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-conditionally-render/-/react-conditionally-render-1.0.2.tgz", + "integrity": "sha512-CtjIgaLHVDSgHis3gv/PT/8EnD6GPUL8PrhUjh7DP6S5Y3p56dGu7y2nVg6pYv1kv+fGznRhRmX3assr/vRw3A==" + }, "react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", diff --git a/Frontend/package.json b/Frontend/package.json index 02d86049..2b25707d 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -31,6 +31,7 @@ "prop-types": "^15.8.1", "react": "^17.0.2", "react-chartjs-2": "^4.0.0", + "react-chatbot-kit": "^2.0.1", "react-dom": "^17.0.2", "react-router-dom": "^6.2.2", "react-scripts": "5.0.0", diff --git a/Frontend/public/assets/images/chatbot.png b/Frontend/public/assets/images/chatbot.png new file mode 100644 index 00000000..85969e44 Binary files /dev/null and b/Frontend/public/assets/images/chatbot.png differ diff --git a/Frontend/src/benchi/ActionProvider.js b/Frontend/src/benchi/ActionProvider.js new file mode 100644 index 00000000..0172474f --- /dev/null +++ b/Frontend/src/benchi/ActionProvider.js @@ -0,0 +1,186 @@ +class ActionProvider { + + strategies = { + BuyAndHold : {experience: 'false', risk: 'false', active: 'true', effort: 'false', duration: 'true'}, + Index : {experience: 'false', risk: 'false', active: 'false', effort: 'false',duration: 'true'}, + Size : {experience: 'false', risk: 'medium', active: 'true', effort: 'false', duration: undefined}, + Growth : {experience: 'true', risk: 'medium', active: 'true', effort: 'true', duration: 'true'}, + Value : {experience: 'true', risk: 'medium', active: 'true', effort: 'true', duration: 'true'}, + Long : {experience: 'true', risk: 'medium', active: 'true', effort: 'true', duration: 'true'}, + Short :{experience: 'true', risk: 'true', active: 'true', effort: 'true', duration: 'false'}, + Trend : {experience: 'true', risk: 'medium', active: 'true', effort: 'true', duration: 'medium'} , + Dividend : {experience: 'false', risk: 'medium', active: 'true', effort: 'medium', duration: undefined}, + Anticyclical : {experience: 'true', risk: 'true', active: 'true', effort: 'true', duration: 'false'}, + Cyclical : {experience: undefined, risk: 'true', active: 'true', effort: 'true', duration: undefined} + }; + + strategieDescriptions = { + BuyAndHold : 'In this strategy, you buy individual stocks and hold them for at least five to 20 years. The hope is for long-term growth through diversified single stock purchases. Short-term fluctuations are avoided by the long investment period.', + Index : 'You do not invest in individual stocks, but in indices or so-called ETFs (Exchange Traded Fund). This strategy works in principle like the buy and hold method, but ETFs contain many different securities according to certain indices and are therefore already diversified. This saves you a lot of effort before and during your loading investment.', + Size : 'In the size strategy you go by the size of the company. It is assumed that the larger the company, the more secure the price gain and the smaller the expected fluctuations. Thus, the strategy is based on stability.', + Growth : 'In the growth strategy you invest in stocks that are likely to increase in price over the next few years. This is judged on the basis of stock market data.', + Value : 'With the Growth strategy you invest in stocks that are likely to rise in price in the next few years. This is judged on the basis of a detailed analysis of the company.', + Long : 'In the Go-Long strategy you buy a stock and hold it in the hope that it will rise in the long term.', + Short :'You sell a stock from your holdings and try to buy it again shortly after at the low. The difference can therefore be considered a profit.', + Trend : 'In the trend determined strategy you try to predict the development of the stock by drawing certain trend lines, average values or by market technical theories.', + Dividend : 'You bet on dividend payments and price gains.', + Anticyclical : 'When everyone is buying, you sell and vice versa. You try to buy at the low and sell at the high, against the current.', + Cyclical : 'You try to go with the flow and invest in securities that will predictably perform well.' + }; + + questions = + [ + `Are you a beginner, intermediate or advanced investor?`, + `How much risk are you willing to take?`, + `Would you like to invest active?`, + `How much effort do you want to put into your investing?`, + `Do you want to invest shortterm, mediumterm or longterm?` + ]; + + answerAfterQuestion = + [ + {true: `Nice to hear, let's start!`, medium:`Let's give it a try anyway!`, false: `Okay, you can come back any time!`}, + {true:`So you alreay have a lot of experience, impressive!`, medium: `So you are an intermediate investor!`, false: `No problem, there are also great strategies for beginners!`}, + {true: `Okay so you are a risk taker!`, medium:`Medium risk, nice choice!`, false: `Just a tiny bit of risk, okay!`}, + {true: `Okay, so you are an active investor!`, medium:`Then let's go with investing passivly!`, false: `Passive investing, nice choice!`}, + {true: `So you don't mind getting your hands dirty!`, medium:`Medium effort it is!`, false: `So you would rather chill at the beach than look through company reports!`}, + {true: `All things come to him who waits!`, medium:`Okay, we're going with mediumterm investing!`, false: `Looks like you're looking for quick money!`}, + ]; + + preferencesArray = ['experience', 'risk', 'active', 'effort', 'duration']; + + constructor( + createChatBotMessage, + setStateFunc, + createClientMessage, + stateRef, + createCustomMessage, + ...rest + ) { + this.createChatBotMessage = createChatBotMessage; + this.setState = setStateFunc; + this.createClientMessage = createClientMessage; + this.stateRef = stateRef; + this.createCustomMessage = createCustomMessage; + } + + handleChitChat(answer) { + const botMessage = this.createChatBotMessage(answer); + + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botMessage], + })); + } + + handleAnswer(answer, questionNr, userPreferences) { + if (questionNr === undefined) { + questionNr = 0; + userPreferences = {experience: '', risk: '', active: false, effort: '', duration: ''}; + } + if (questionNr === -1) { + const botAnswer = this.createChatBotMessage(`Hi! I'm Benchi! Are you interested in finding the right investment strategy for you together?`); + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botAnswer], + 'questionNr': (questionNr + 1) + })); + return; + } + if (questionNr === 5) { + userPreferences = {...userPreferences, duration: answer}; + const Strategy = this.findStrategyForUser(userPreferences); + const botAnswer = this.createChatBotMessage(this.answerAfterQuestion[questionNr][answer]); + const botStrategy = this.createChatBotMessage(`The best strategy for you is ${Strategy}`); + const botStrategyExplanation = this.createChatBotMessage(this.strategieDescriptions[Strategy]); + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botAnswer, botStrategy, botStrategyExplanation], + questionNr: questionNr + 1 + })); + return; + } + if (questionNr > 5) { + userPreferences = {...userPreferences, duration: answer}; + const Strategy = this.findStrategyForUser(userPreferences); + const botStrategy = this.createChatBotMessage(`The best strategy for you is ${Strategy}`); + const botStrategyExplanation = this.createChatBotMessage(this.strategieDescriptions[Strategy]); + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botStrategy, botStrategyExplanation], + questionNr: questionNr + 1 + })); + return; + } + + if (this.preferencesArray[questionNr-1] === 'active') { + answer = answer === 'medium' ? false : answer; + } + const botAnswer = this.createChatBotMessage(this.answerAfterQuestion[questionNr][answer]); + const botNewQuestion = this.createChatBotMessage(this.questions[questionNr]); + + if (questionNr > 0 && questionNr < 5) { + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botAnswer, botNewQuestion], + 'questionNr': questionNr + 1, + 'userPreferences': {...userPreferences, [this.preferencesArray[questionNr-1]]: answer} + })); + } else { + if (questionNr === 0 && answer === 'false') { + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botAnswer], + 'questionNr': -1, + })); + return; + } + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botAnswer, botNewQuestion], + questionNr: questionNr + 1 + })); + } + } + + findStrategyForUser(userPreferences) { + let strategiesFit = {}; + const strategiesKeys = Object.keys(this.strategies); + for (let index = 0; index < strategiesKeys.length; index++) { + const strategieKey = strategiesKeys[index]; + const strategy = this.strategies[strategieKey]; + let fit = 0; + for (let i = 0; i < this.preferencesArray.length; i++) { + const preference = this.preferencesArray[i]; + if (strategy[preference] === undefined || strategy[preference] === userPreferences[preference]) { + fit++; + } + } + strategiesFit[strategieKey] = fit; + } + console.log(strategiesFit); + let bestStrategy = ''; + let bestFit = 0; + for (let index = 0; index < strategiesKeys.length; index++) { + const strategieKey = strategiesKeys[index]; + if (bestFit < strategiesFit[strategieKey]) { + bestFit = strategiesFit[strategieKey]; + bestStrategy = strategieKey; + } + } + console.log(bestStrategy); + return bestStrategy; + } + + handleNoAnswer() { + const botMessage = this.createChatBotMessage(`Sorry, but I didn't understand you.`); + + this.setState((prev) => ({ + ...prev, + messages: [...prev.messages, botMessage], + })); + this.messageCnt = this.messageCnt + 1; + } +} + + export default ActionProvider; \ No newline at end of file diff --git a/Frontend/src/benchi/MessageParser.js b/Frontend/src/benchi/MessageParser.js new file mode 100644 index 00000000..b4a018c2 --- /dev/null +++ b/Frontend/src/benchi/MessageParser.js @@ -0,0 +1,52 @@ +class MessageParser { + constructor(actionProvider, state) { + this.actionProvider = actionProvider; + this.state = {...state}; + } + + parse(message) { + console.log(this.state) + this.fetchAnswer(message); + } + + interpret(data) { + const chitChatAnswer = data[0].answer; + const answer = data[1] !== undefined ? data[1].answer : undefined; + if (answer !== undefined) { + this.actionProvider.handleAnswer(answer, this.state.questionNr, this.state.userPreferences); + return; + } + if (chitChatAnswer === 'true' || chitChatAnswer === 'false' || chitChatAnswer === 'medium') { + this.actionProvider.handleAnswer(chitChatAnswer, this.state.questionNr, this.state.userPreferences); + return; + } + if (chitChatAnswer === 'No answer found') { + this.actionProvider.handleNoAnswer(); + return; + } + this.actionProvider.handleChitChat(chitChatAnswer); + } + + fetchAnswer(message) { + var url = "https://westeurope.api.cognitive.microsoft.com/language/:query-knowledgebases?projectName=benchi-QnA&api-version=2021-10-01&deploymentName=production"; + + var xhr = new XMLHttpRequest(); + xhr.open("POST", url); + xhr.responseType = 'json'; + + xhr.setRequestHeader("Ocp-Apim-Subscription-Key", "6ee6c9b8f982470abc210317cbf8d89c"); + xhr.setRequestHeader("Content-Type", "application/json"); + + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + this.interpret(xhr.response.answers); + } + }; + + var data = `{"top":3,"question":"${message}","includeUnstructuredSources":true,"confidenceScoreThreshold":"0.5","answerSpanRequest":{"enable":true,"topAnswersWithSpan":1,"confidenceScoreThreshold":"0.5"}}`; + + xhr.send(data); + } +} + +export default MessageParser; \ No newline at end of file diff --git a/Frontend/src/benchi/config.js b/Frontend/src/benchi/config.js new file mode 100644 index 00000000..ffc389b9 --- /dev/null +++ b/Frontend/src/benchi/config.js @@ -0,0 +1,22 @@ +import { createChatBotMessage } from 'react-chatbot-kit'; + +const botName = 'Benchi'; + +const config = { + initialMessages: [createChatBotMessage(`Hi! I'm ${botName}! Are you interested in finding the right investment strategy for you together?`)], + customComponents: { + // Replaces the default header + header: () =>