From 2630326401506d6a343874c3568c6222b5e9cdf8 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 16:27:36 +0100 Subject: [PATCH 001/244] refactor(shared): fix circular dependency in UserValidationRegexRule bb-203 --- .../modules/users/libs/enums/user-validation-regex-rule.enum.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/users/libs/enums/user-validation-regex-rule.enum.ts b/packages/shared/src/modules/users/libs/enums/user-validation-regex-rule.enum.ts index 9110ef17a..eeeb734e7 100644 --- a/packages/shared/src/modules/users/libs/enums/user-validation-regex-rule.enum.ts +++ b/packages/shared/src/modules/users/libs/enums/user-validation-regex-rule.enum.ts @@ -1,4 +1,4 @@ -import { UserValidationRule } from "./enums.js"; +import { UserValidationRule } from "./user-validation-rule.enum.js"; const UserValidationRegexRule = { EMAIL_DOMAIN_PART_VALID_CHARS: /(?<=@)(?!.*[.-]{2})[\w-]*/, From 3fa74de80f9bbd63220bdeebf7bd84e112151d9e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 18:57:09 +0100 Subject: [PATCH 002/244] refactor(backend): fix swagger formating in UserController bb-203 --- apps/backend/src/modules/users/user.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/modules/users/user.controller.ts b/apps/backend/src/modules/users/user.controller.ts index fcb31c22c..7874dabf1 100644 --- a/apps/backend/src/modules/users/user.controller.ts +++ b/apps/backend/src/modules/users/user.controller.ts @@ -155,7 +155,7 @@ class UserController extends BaseController { * responses: * 200: * description: Successful operation - * content: + * content: * application/json: * schema: * type: object From 852f00e57a0e3d21bc1f3ffdcf2d5b7ec62a0e60 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 19:01:19 +0100 Subject: [PATCH 003/244] feat(shared): add OpenAIError bb-203 --- .../shared/src/libs/exceptions/exceptions.ts | 1 + .../open-ai-error/open-ai-error.exception.ts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 packages/shared/src/libs/exceptions/open-ai-error/open-ai-error.exception.ts diff --git a/packages/shared/src/libs/exceptions/exceptions.ts b/packages/shared/src/libs/exceptions/exceptions.ts index 92973cf15..58fe815b8 100644 --- a/packages/shared/src/libs/exceptions/exceptions.ts +++ b/packages/shared/src/libs/exceptions/exceptions.ts @@ -1,6 +1,7 @@ export { AuthError } from "./auth-error/auth-error.exception.js"; export { HTTPError } from "./http-error/http-error.exception.js"; export { OnboardingError } from "./onboarding-error/onboarding-error.exception.js"; +export { OpenAIError } from "./open-ai-error/open-ai-error.exception.js"; export { QuizError } from "./quiz-error/quiz-error.exception.js"; export { UserError } from "./user-error/user-error.js"; export { ValidationError } from "./validation-error/validation-error.exception.js"; diff --git a/packages/shared/src/libs/exceptions/open-ai-error/open-ai-error.exception.ts b/packages/shared/src/libs/exceptions/open-ai-error/open-ai-error.exception.ts new file mode 100644 index 000000000..a5d6ff1a1 --- /dev/null +++ b/packages/shared/src/libs/exceptions/open-ai-error/open-ai-error.exception.ts @@ -0,0 +1,17 @@ +import { type HTTPCode } from "../../modules/http/http.js"; +import { type ValueOf } from "../../types/types.js"; +import { HTTPError } from "../http-error/http-error.exception.js"; + +type Constructor = { + cause?: unknown; + message: string; + status: ValueOf; +}; + +class OpenAIError extends HTTPError { + public constructor({ cause, message, status }: Constructor) { + super({ cause, message, status }); + } +} + +export { OpenAIError }; From 868163c25bb8b18aab060b7bbb78c67da0cff16e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 19:02:43 +0100 Subject: [PATCH 004/244] feat(shared): add "assistant" to APIPath bb-203 --- packages/shared/src/libs/enums/api-path.enum.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/src/libs/enums/api-path.enum.ts b/packages/shared/src/libs/enums/api-path.enum.ts index db80eee7f..b0385a4d9 100644 --- a/packages/shared/src/libs/enums/api-path.enum.ts +++ b/packages/shared/src/libs/enums/api-path.enum.ts @@ -1,4 +1,5 @@ const APIPath = { + ASSISTANT: "/assistant", AUTH: "/auth", ONBOARDING: "/onboarding", QUIZ: "/quiz", From 1ce55ce7eb23e85b51ab90293e593a543f605b74 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 19:39:37 +0100 Subject: [PATCH 005/244] feat(shared): add AiAssistantApiPath enum bb-203 --- .../libs/enums/ai-assistant-api-path.enum.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts new file mode 100644 index 000000000..68c70a648 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -0,0 +1,10 @@ +const AiAssistantApiPath = { + ADD_MESSAGE: "/thread/add-message", + CONTINUE_THREAD: "/thread/continue", + GENERATE_ALTERNATIVE_TASKS: "/thread/generate-alternative-tasks", + INITIATE_THREAD: "/thread/initiate", + REMOVE_THREAD: "/thread/remove", + SUGGEST_TASKS: "/thread/suggest-tasks", +} as const; + +export { AiAssistantApiPath }; From 61136bed814e691a95f1323c85bd16af55854ce5 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 20:18:02 +0100 Subject: [PATCH 006/244] refactor(backend): change imports for UserModel bb-203 --- apps/backend/src/modules/categories/category.model.ts | 2 +- apps/backend/src/modules/quiz-answers/quiz-answer.model.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/modules/categories/category.model.ts b/apps/backend/src/modules/categories/category.model.ts index d5b5cbb67..0c9c0ddce 100644 --- a/apps/backend/src/modules/categories/category.model.ts +++ b/apps/backend/src/modules/categories/category.model.ts @@ -5,7 +5,7 @@ import { DatabaseTableName, } from "~/libs/modules/database/database.js"; -import { UserModel } from "../users/user.model.js"; +import { UserModel } from "../users/users.js"; import { type CategoryEntity } from "./category.entity.js"; class CategoryModel extends AbstractModel { diff --git a/apps/backend/src/modules/quiz-answers/quiz-answer.model.ts b/apps/backend/src/modules/quiz-answers/quiz-answer.model.ts index a2b2d9558..f132f7176 100644 --- a/apps/backend/src/modules/quiz-answers/quiz-answer.model.ts +++ b/apps/backend/src/modules/quiz-answers/quiz-answer.model.ts @@ -6,7 +6,7 @@ import { } from "~/libs/modules/database/database.js"; import { QuizQuestionModel } from "../quiz-questions/quiz-question.model.js"; -import { UserModel } from "../users/user.model.js"; +import { UserModel } from "../users/users.js"; import { type QuizAnswerEntity } from "./quiz-answer.entity.js"; class QuizAnswerModel extends AbstractModel { From ab76f5b11ebbb0afbe75e47b83807849b2b95d68 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 20:22:11 +0100 Subject: [PATCH 007/244] feat(backend): add Assistant config to env variables and schema bb-203 --- apps/backend/.env.example | 6 ++++++ .../src/libs/modules/config/base-config.module.ts | 14 ++++++++++++++ .../config/libs/types/environment-schema.type.ts | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/apps/backend/.env.example b/apps/backend/.env.example index 791a398d8..04f2c16eb 100644 --- a/apps/backend/.env.example +++ b/apps/backend/.env.example @@ -33,3 +33,9 @@ MAILER_APP_PASSWORD= MAILER_HOST=smtp.gmail.com MAILER_PORT=465 MAILER_SERVICE=Gmail + +# +# OPEN AI +# +OPEN_AI_API_KEY= +OPENAI_MODEL=gpt-4o-mini diff --git a/apps/backend/src/libs/modules/config/base-config.module.ts b/apps/backend/src/libs/modules/config/base-config.module.ts index 1b1bdb98f..e456e978e 100644 --- a/apps/backend/src/libs/modules/config/base-config.module.ts +++ b/apps/backend/src/libs/modules/config/base-config.module.ts @@ -136,6 +136,20 @@ class BaseConfig implements Config { format: String, }, }, + OPEN_AI: { + API_KEY: { + default: null, + doc: "OpenAI API key", + env: "OPENAI_API_KEY", + format: String, + }, + MODEL: { + default: null, + doc: "OpenAI model", + env: "OPENAI_MODEL", + format: String, + }, + }, }); } } diff --git a/apps/backend/src/libs/modules/config/libs/types/environment-schema.type.ts b/apps/backend/src/libs/modules/config/libs/types/environment-schema.type.ts index bd72b6768..96899c346 100644 --- a/apps/backend/src/libs/modules/config/libs/types/environment-schema.type.ts +++ b/apps/backend/src/libs/modules/config/libs/types/environment-schema.type.ts @@ -28,6 +28,10 @@ type EnvironmentSchema = { PORT: number; SERVICE: string; }; + OPEN_AI: { + API_KEY: string; + MODEL: string; + }; }; export { type EnvironmentSchema }; From 0a5fa5b1d041c0ac1aea57305d1000623c264e19 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 20:27:17 +0100 Subject: [PATCH 008/244] chore(backend): add openai and zod libraries to backend bb-203 --- apps/backend/package.json | 4 +- package-lock.json | 184 +++++++++++++++++++++++++++++++++++--- 2 files changed, 173 insertions(+), 15 deletions(-) diff --git a/apps/backend/package.json b/apps/backend/package.json index e4eb6ebf7..dbd421e06 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -34,6 +34,7 @@ "knex": "3.1.0", "nodemailer": "6.9.14", "objection": "3.1.4", + "openai": "4.57.3", "pg": "8.12.0", "pino": "9.3.2", "pino-pretty": "11.2.2", @@ -47,6 +48,7 @@ "@types/swagger-jsdoc": "6.0.4", "ts-node": "10.9.2", "ts-paths-esm-loader": "1.4.3", - "tsx": "4.17.0" + "tsx": "4.17.0", + "zod": "3.23.8" } } diff --git a/package-lock.json b/package-lock.json index 9d917956f..761d5b102 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,6 +67,7 @@ "knex": "3.1.0", "nodemailer": "6.9.14", "objection": "3.1.4", + "openai": "4.57.3", "pg": "8.12.0", "pino": "9.3.2", "pino-pretty": "11.2.2", @@ -6932,6 +6933,16 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/node-forge": { "version": "1.3.11", "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", @@ -6961,6 +6972,12 @@ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", "devOptional": true }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "license": "MIT" + }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", @@ -7456,6 +7473,18 @@ "node": ">= 6.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -7889,6 +7918,12 @@ "retry": "0.12.0" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -8242,7 +8277,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -8706,6 +8740,18 @@ "node": ">=0.1.90" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/command-exists": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", @@ -9466,7 +9512,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -9496,6 +9541,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -9879,7 +9933,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -9891,7 +9944,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -11384,6 +11436,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -11589,7 +11674,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -11867,7 +11951,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -11907,7 +11990,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -11919,7 +12001,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -11931,7 +12012,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -12103,6 +12183,15 @@ "node": ">=16.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/hyperlinker": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", @@ -15123,6 +15212,25 @@ "node": "*" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -15302,7 +15410,6 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -15501,6 +15608,49 @@ "node": ">=4" } }, + "node_modules/openai": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.57.3.tgz", + "integrity": "sha512-mTz5/SmulkkeSpqbSr6WNLRU6krkyhnbfRUC8XfaXbj1T6xUorKEELjZvbRSzI714JLOk1MeFkqYS9H4WHhqDQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "@types/qs": "^6.9.15", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "qs": "^6.10.3" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", + "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/openapi-types": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", @@ -16618,7 +16768,6 @@ "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, "dependencies": { "side-channel": "^1.0.6" }, @@ -18011,7 +18160,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -18090,7 +18238,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -20437,6 +20584,15 @@ "defaults": "^1.0.3" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -20907,7 +21063,7 @@ "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "dev": true, + "devOptional": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } From 9963790a13f0f772cbcbcd4a5ca41ced33c4ea67 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 20:30:55 +0100 Subject: [PATCH 009/244] chore(backend): add openai types bb-203 --- apps/backend/src/libs/modules/open-ai/libs/types/types.ts | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/types/types.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/types/types.ts b/apps/backend/src/libs/modules/open-ai/libs/types/types.ts new file mode 100644 index 000000000..b1c99fa11 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/types/types.ts @@ -0,0 +1,2 @@ +export { type MessageCreateParams as OpenAiRequestMessage } from "openai/resources/beta/threads/index"; +export { type Message as OpenAiResponseMessage } from "openai/resources/beta/threads/index"; From bf0833a07ac9500e5a349845fdfe1de72a077c1a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 20:32:26 +0100 Subject: [PATCH 010/244] feat(backend): add openai Role key bb-203 --- .../modules/open-ai/libs/enums/open-ai-role-key.enum.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts new file mode 100644 index 000000000..c4892c5d7 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts @@ -0,0 +1,7 @@ +const OpenAiRoleKey = { + ASSISTANT: "assistant", + SYSTEM: "system", + USER: "user", +} as const; + +export { OpenAiRoleKey }; From 5231f8dd7be2a02f0e8c26ef64c5594cc75272ee Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 21:04:07 +0100 Subject: [PATCH 011/244] feat(backend): add openai Assistant config enum bb-203 --- .../libs/enums/open-ai-assistant-config.enum.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts new file mode 100644 index 000000000..c5e366c12 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts @@ -0,0 +1,10 @@ +import { AnalyzeBalanceScores } from "../ai-assistant-tools/ai-assistant-tools.js"; +import { OpenAiPromptTemplates } from "./open-ai-promt-mesagges.enum.js"; + +const OpenAiAssistantConfig = { + INSTRUCTION: OpenAiPromptTemplates.ASSISTANT_INSTRUCTION, + NAME: "Wheel of Balance Assistant", + TOOLS: [AnalyzeBalanceScores], +} as const; + +export { OpenAiAssistantConfig }; From dd0c891a7800b0e7cd831581cd93600bb9e26f7c Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 21:08:23 +0100 Subject: [PATCH 012/244] feat(backend): add AI function description for analyze balance scores bb-203 --- .../ai-assistant-tools/ai-assistant-tools.ts | 1 + .../analyze-balance-scores-tool.ts | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts create mode 100644 apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts new file mode 100644 index 000000000..88cdbd52d --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts @@ -0,0 +1 @@ +export { AnalyzeBalanceScores } from "./analyze-balance-scores/analyze-balance-scores-tool.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts new file mode 100644 index 000000000..6a89d1bb7 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts @@ -0,0 +1,62 @@ +const AnalyzeBalanceScores = { + function: { + description: + "Analyzes user's life balance scores and identifies the three lowest categories with suggestions for improvement.", + name: "analyze_balance_scores", + parameters: { + additionalProperties: false, + properties: { + categories: { + description: "Array of categories with user scores", + items: { + additionalProperties: false, + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "string", + }, + categoryName: { + description: "The name of the category (e.g., Health, Work)", + type: "string", + }, + score: { + description: "The user's score for this category, from 1 to 10", + type: "number", + }, + }, + required: ["categoryId", "categoryName", "score"], + type: "object", + }, + type: "array", + }, + context: { + description: "Context explaining the purpose of the analysis", + type: "string", + }, + instructions: { + additionalProperties: false, + properties: { + action: { + description: + "What the assistant should do after identifying the categories (e.g., provide improvement suggestions)", + type: "string", + }, + task: { + description: + "The main task for the assistant (e.g., identify the lowest categories)", + type: "string", + }, + }, + required: ["task", "action"], + type: "object", + }, + }, + required: ["context", "categories", "instructions"], + type: "object", + }, + strict: true, + }, + type: "function", +} as const; + +export { AnalyzeBalanceScores }; From 48029b3cf6e22a3e9785b87cc98484fd22124261 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 21:11:59 +0100 Subject: [PATCH 013/244] feat(backend): add AI function validation for analyze balance scores bb-203 --- .../balance-analysis.validation-schema.ts | 14 ++++++++++++++ .../libs/validation-schemas/validation-schemas.ts | 6 ++++++ 2 files changed, 20 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts create mode 100644 apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts new file mode 100644 index 000000000..ebfdf7839 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts @@ -0,0 +1,14 @@ +import { z } from "zod"; + +const Category = z.object({ + categoryId: z.string(), + categoryName: z.string(), + score: z.number(), +}); + +const BalanceAnalysis = z.object({ + answer: z.string(), + lowestCategories: z.array(Category), +}); + +export { BalanceAnalysis }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts new file mode 100644 index 000000000..7c5c6c053 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts @@ -0,0 +1,6 @@ +export { BalanceAnalysis } from "./balance-analysis.validation-schema.js"; +export { zodResponseFormat } from "openai/helpers/zod"; +export { + addMessageToThreadValidationSchema, + AiAssistantMessageValidationSchema, +} from "shared"; From 671133dff6eb70bab766382db4649d66de7bf0b4 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 21:14:29 +0100 Subject: [PATCH 014/244] feat(backend): add AI error message and exception import enum bb-203 --- .../src/libs/modules/open-ai/libs/exceptions/exceptions.ts | 1 + .../libs/enums/ai-assistant-validation-message.enum.ts | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/exceptions/exceptions.ts create mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/exceptions/exceptions.ts b/apps/backend/src/libs/modules/open-ai/libs/exceptions/exceptions.ts new file mode 100644 index 000000000..d8bb83b67 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/exceptions/exceptions.ts @@ -0,0 +1 @@ +export { OpenAIError } from "shared"; diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts new file mode 100644 index 000000000..e2e8f0124 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts @@ -0,0 +1,7 @@ +const AiAssistantValidationMessage = { + TEXT_REQUIRED: "text required", + THREAD_ID_INVALID_FORMAT: "threadId - invalid format", + THREAD_ID_REQUIRED: "threadId required", +} as const; + +export { AiAssistantValidationMessage }; From 78414f411b536f187c13f3af6d3af95068b7f204 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 21:26:00 +0100 Subject: [PATCH 015/244] feat(backend): add AI error message and exception import enum bb-203 --- .../modules/open-ai/libs/enums/open-ai-error-message.enum.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-message.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-message.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-message.enum.ts new file mode 100644 index 000000000..6d4de0999 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-message.enum.ts @@ -0,0 +1,5 @@ +const OpenAIErrorMessage = { + WRONG_RESPONSE: "Wrong response from OpenAI.", +} as const; + +export { OpenAIErrorMessage }; From 27b29fe752450d749d5e2103a567e6dc9921fd81 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 21:54:01 +0100 Subject: [PATCH 016/244] feat(backend): add init and balance prompts enum bb-203 --- .../libs/modules/open-ai/libs/enums/enums.ts | 4 ++ .../libs/enums/open-ai-promt-mesagges.enum.ts | 72 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts new file mode 100644 index 000000000..f233735c5 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts @@ -0,0 +1,4 @@ +export { OpenAiAssistantConfig } from "./open-ai-assistant-config.enum.js"; +export { OpenAIErrorMessage } from "./open-ai-error-message.enum.js"; +export { OpenAiPromptTemplates } from "./open-ai-promt-mesagges.enum.js"; +export { OpenAiRoleKey } from "./open-ai-role-key.enum.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts new file mode 100644 index 000000000..cd547eac1 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts @@ -0,0 +1,72 @@ +const OpenAiPromptTemplates = { + ASSISTANT_INIT_THREAD_INSTRUCTION: ` +The user has completed an onboarding quiz where they prioritized different areas of their life. +Based on the user's answers, you will later recommend specific tasks to help them improve in areas such as health, +career, relationships, or personal hobbies. + +Always keep in mind the user's preferences and encourage balanced personal growth. +Be supportive, track the user's progress, and celebrate small achievements. + +Instructions: +1. Carefully analyze the provided questions and the user's selected answers. +2. Identify the key areas of importance for the user, such as health, career, relationships, or other aspects of life based on their responses. +3. Ensure a thorough understanding of the user's answers. + +At this stage, no actions or responses are required. +`, + ASSISTANT_INSTRUCTION: ` +You are an instructor responsible for analyzing the user's preferences and scores based on the Wheel of Balance. +The Wheel of Balance helps the user prioritize various areas of their life, such as health, career, relationships, +and personal hobbies. + +Your role is to: +1. Analyze the user's quiz results from the Wheel of Balance to identify areas where the user seeks improvement. +2. Based on the user's answers and scores, generate specific, actionable tasks to help them achieve greater balance +and growth in these areas. +3. Ensure that the recommended tasks are practical, motivating, and aligned with the user's personal goals and preferences. + +Always maintain a positive and supportive tone. Encourage the user to achieve balanced personal growth across +different life areas, track their progress, and celebrate small achievements. Your recommendations should be clear, +motivating, and focused on helping the user improve the areas of life they prioritize. + +At this stage, focus on understanding the user's preferences and scores from the Wheel of Balance. +After this stage, you will generate appropriate tasks for improvement later. +`, + WHEEL_OF_BALANCE_CONTEXT: ` +You are an assistant helping the user balance different aspects of their life.The user is engaging with +the "Wheel of Balance," which consists of eight categories that represent different areas of life: + +1. Physical +2. Work +3. Friends +4. Love +5. Money +6. Free time +7. Spiritual +8. Mental + +Each of these categories is rated by the user on a scale from 1 to 10: +- 1 indicates that the user is least satisfied or struggling the most in this area. +- 10 indicates that the user is completely satisfied or excelling in this area. + +After this context, a structured array of categories will be provided. Each category will include: +- \`categoryName\` (a string): the name of the life area (e.g., "Physical", "Work"). +- \`score\` (a number between 1 and 10): the user's rating for that category, where 1 represents low satisfaction +and 10 represents high satisfaction. +`, + WHEEL_OF_BALANCE_INSTRUCTIONS: ` +task: "Your role is to analyze the user's ratings in these categories, identify areas where the user needs improvement, +and later recommend tasks to help them achieve better balance in life. Do not provide tasks at this stage. + +Focus on the categories that the user has rated the lowest, as these are likely the areas where they +seek the most improvement." + +action: "Your first task is to ask the user how they would like to proceed with improving their balance. +Always present the following question to the user in this task: + +'Would you like to focus on improving the three areas with the lowest scores in your Wheel of Balance, +or would you prefer to choose the areas yourself to work on?'" +`, +} as const; + +export { OpenAiPromptTemplates }; From 08624d2dfc01f6449ea130bdad31f4f5f3bf9c31 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:01:05 +0100 Subject: [PATCH 017/244] chore(backend): add import ZERO_INDEX to global constants bb-203 --- apps/backend/src/libs/constants/constants.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/backend/src/libs/constants/constants.ts diff --git a/apps/backend/src/libs/constants/constants.ts b/apps/backend/src/libs/constants/constants.ts new file mode 100644 index 000000000..ce5dcf63a --- /dev/null +++ b/apps/backend/src/libs/constants/constants.ts @@ -0,0 +1 @@ +export { ZERO_INDEX } from "shared"; From 0cb1add343a4a3970313af4627bcce7aa52b306c Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:03:15 +0100 Subject: [PATCH 018/244] feat(backend): add open AI module and initialization bb-203 --- .../libs/modules/open-ai/open-ai.module.ts | 162 ++++++++++++++++++ .../src/libs/modules/open-ai/open-ai.ts | 24 +++ 2 files changed, 186 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/open-ai.module.ts create mode 100644 apps/backend/src/libs/modules/open-ai/open-ai.ts diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts new file mode 100644 index 000000000..322d59f22 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts @@ -0,0 +1,162 @@ +import { OpenAI } from "openai"; + +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { type Config } from "~/libs/modules/config/config.js"; +import { HTTPCode } from "~/libs/modules/http/http.js"; +import { type Logger } from "~/libs/modules/logger/logger.js"; + +import { + OpenAiAssistantConfig, + OpenAIErrorMessage, +} from "./libs/enums/enums.js"; +import { OpenAIError } from "./libs/exceptions/exceptions.js"; +import { + type OpenAiRequestMessage, + type OpenAiResponseMessage, +} from "./libs/types/types.js"; +import { + BalanceAnalysis, + zodResponseFormat, +} from "./libs/validation-schemas/validation-schemas.js"; + +type Constructor = { + config: Config; + logger: Logger; +}; + +class OpenAi { + private assistantId: null | string = null; + private config: Config; + private logger: Logger; + private openAi: OpenAI; + + public constructor({ config, logger }: Constructor) { + this.config = config; + this.logger = logger; + this.openAi = this.createOpenAi(); + } + + private createOpenAi(): OpenAI { + return new OpenAI({ + apiKey: this.config.ENV.OPEN_AI.API_KEY, + }); + } + + private async getOrInitializeAssistant(): Promise { + const existingAssistants = await this.openAi.beta.assistants.list(); + const assistant = existingAssistants.data.find( + (assistant) => assistant.name === OpenAiAssistantConfig.NAME, + ); + + try { + const initializedAssistant = + assistant ?? + (await this.openAi.beta.assistants.create({ + instructions: OpenAiAssistantConfig.INSTRUCTION, + model: this.config.ENV.OPEN_AI.MODEL, + name: OpenAiAssistantConfig.NAME, + tools: [...OpenAiAssistantConfig.TOOLS], + })); + + this.logger.info( + `AI Assistant "${initializedAssistant.name as string}" is fully ready for interaction.`, + ); + this.logger.info(`AI Assistant model - "${initializedAssistant.model}".`); + + return initializedAssistant.id; + } catch (error) { + this.logger.error(`Error initializing AI assistant: ${String(error)}`); + + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } + } + + public async addMessageToThread( + threadId: string, + message: OpenAiRequestMessage, + ): Promise { + const newMessage = await this.openAi.beta.threads.messages.create( + threadId, + message, + ); + + if ("error" in newMessage) { + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } + + return true; + } + + public async createThread( + message: OpenAiRequestMessage[] = [], + ): Promise { + const thread = await this.openAi.beta.threads.create({ messages: message }); + + if ("error" in thread) { + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } + + return thread.id; + } + + public async deleteThread(threadId: string): Promise { + const result = await this.openAi.beta.threads.del(threadId); + + if (!result.deleted) { + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } + + return result.deleted; + } + + public async generateBalanceAnalysis( + threadId: string, + prompt: OpenAiRequestMessage, + ): Promise { + const response: OpenAiResponseMessage[] = + await this.openAi.beta.threads.runs + .stream(threadId, { + additional_messages: [prompt], + assistant_id: this.assistantId as string, + response_format: zodResponseFormat( + BalanceAnalysis, + "balance_analysis", + ), + stream: true, + }) + .finalMessages(); + + if (response.length === ZERO_INDEX) { + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } + + return response; + } + + public async getAllMessagesBy( + threadId: string, + ): Promise> { + return await this.openAi.beta.threads.messages.list(threadId); + } + + public async initializeAssistant(): Promise { + this.assistantId = await this.getOrInitializeAssistant(); + } +} + +export { OpenAi }; diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.ts b/apps/backend/src/libs/modules/open-ai/open-ai.ts new file mode 100644 index 000000000..3d1acce40 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/open-ai.ts @@ -0,0 +1,24 @@ +import { config } from "~/libs/modules/config/config.js"; +import { logger } from "~/libs/modules/logger/logger.js"; + +import { OpenAi } from "./open-ai.module.js"; + +const openAi = new OpenAi({ + config, + logger, +}); + +await openAi.initializeAssistant(); + +export { openAi }; +export { OpenAiPromptTemplates, OpenAiRoleKey } from "./libs/enums/enums.js"; +export { + type OpenAiRequestMessage, + type OpenAiResponseMessage, +} from "./libs/types/types.js"; +export { + addMessageToThreadValidationSchema, + AiAssistantMessageValidationSchema, + BalanceAnalysis, +} from "./libs/validation-schemas/validation-schemas.js"; +export { type OpenAi } from "./open-ai.module.js"; From 02dc808ed94a257867837258689281311af71aa2 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:08:38 +0100 Subject: [PATCH 019/244] feat(backend): add AiAssistantService bb-203 --- .../ai-assistant/ai-assistant.service.ts | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/ai-assistant.service.ts diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts new file mode 100644 index 000000000..fbac02a53 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -0,0 +1,77 @@ +import { type OpenAi, OpenAiRoleKey } from "~/libs/modules/open-ai/open-ai.js"; +import { type UserDto } from "~/libs/types/types.js"; +import { type CategoryService } from "~/modules/categories/categories.js"; +import { type OnboardingRepository } from "~/modules/onboarding/onboarding.js"; + +import { + generateInitPrompt, + generateScoresResponse, + generateUserScoresPrompt, +} from "./libs/helpers/helpers.js"; +import { + type BalanceWheelAnalysisResponseDto, + type ThreadMessageCreateDto, +} from "./libs/types/types.js"; + +type Constructor = { + categoryService: CategoryService; + onboardingRepository: OnboardingRepository; + openAi: OpenAi; +}; + +class AiAssistantService { + private categoryService: CategoryService; + private onboardingRepository: OnboardingRepository; + private openAi: OpenAi; + + public constructor({ + categoryService, + onboardingRepository, + openAi, + }: Constructor) { + this.openAi = openAi; + this.categoryService = categoryService; + this.onboardingRepository = onboardingRepository; + } + + public async addMessageToThread( + body: ThreadMessageCreateDto, + ): Promise { + const { text, threadId } = body; + + const prompt = { + content: text, + metadata: {}, + role: OpenAiRoleKey.USER, + }; + + return await this.openAi.addMessageToThread(threadId, prompt); + } + + public async initNewThread( + user: UserDto, + ): Promise { + const userAnswersWithQuestions = + await this.onboardingRepository.findUserAnswersWithQuestions(user.id); + + const userWheelBalanceScores = await this.categoryService.findUserScores( + user.id, + ); + + const [initPrompt, userScoresPrompt] = [ + generateInitPrompt(userAnswersWithQuestions, user.name), + generateUserScoresPrompt(userWheelBalanceScores), + ]; + + const theadId = await this.openAi.createThread([initPrompt]); + + const result = await this.openAi.generateBalanceAnalysis( + theadId, + userScoresPrompt, + ); + + return generateScoresResponse(result); + } +} + +export { AiAssistantService }; From 450cae3dcc61a37e7d04d32fdc0e788a1f97fa20 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:10:12 +0100 Subject: [PATCH 020/244] feat(backend): add generateInitPrompt Helper bb-203 --- .../generate-init-promt.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts new file mode 100644 index 000000000..f94847ba7 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts @@ -0,0 +1,39 @@ +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { + type OpenAiRequestMessage, + OpenAiRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; +import { OpenAiPromptTemplates } from "~/libs/modules/open-ai/open-ai.js"; +import { type OnboardingQuestionEntity } from "~/modules/onboarding/onboarding.js"; + +function generateInitPrompt( + onboardingQuestions: OnboardingQuestionEntity[], + userName: string, +): OpenAiRequestMessage { + const questionsWithAnswers = onboardingQuestions.map((questionEntity) => { + const { answers, label: question } = questionEntity.toObject(); + const answer = answers[ZERO_INDEX]?.label; + + return { answer, question }; + }); + + const promptContent = ` +${OpenAiPromptTemplates.ASSISTANT_INIT_THREAD_INSTRUCTION} + +Here are the questions and the user's answers: + +${questionsWithAnswers.map(({ answer, question }) => `- Question: ${question}\nAnswer: ${answer as string}`).join("\n")} + +Make sure to analyze these answers carefully, as they will inform future task recommendations. + +Always address to user : ${userName} and greet on first message. +`; + + return { + content: promptContent, + metadata: {}, + role: OpenAiRoleKey.USER, + }; +} + +export { generateInitPrompt }; From dbea2de53590f7438fb9390bd7966c43a069c08e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:12:33 +0100 Subject: [PATCH 021/244] feat(backend): add generateScoresResponse/generateUserScoresPrompt Helper bb-203 --- .../generate-scores-promt.ts | 31 +++++++++++++ .../generate-scores-response.ts | 46 +++++++++++++++++++ .../ai-assistant/libs/helpers/helpers.ts | 3 ++ 3 files changed, 80 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts new file mode 100644 index 000000000..e7999956e --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts @@ -0,0 +1,31 @@ +import { + OpenAiPromptTemplates, + type OpenAiRequestMessage, + OpenAiRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; +import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; + +function generateUserScoresPrompt( + userScores: QuizScoresGetAllResponseDto, +): OpenAiRequestMessage { + const { items } = userScores; + + const categories = items.map(({ categoryId, categoryName, score }) => ({ + categoryId, + categoryName, + score, + })); + + const promptContent = { + categories, + context: OpenAiPromptTemplates.WHEEL_OF_BALANCE_CONTEXT, + instructions: OpenAiPromptTemplates.WHEEL_OF_BALANCE_INSTRUCTIONS, + }; + + return { + content: JSON.stringify(promptContent), + role: OpenAiRoleKey.USER, + }; +} + +export { generateUserScoresPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts new file mode 100644 index 000000000..2e05597ee --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts @@ -0,0 +1,46 @@ +import { type z } from "zod"; + +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { + AiAssistantMessageValidationSchema, + type BalanceAnalysis, + type OpenAiResponseMessage, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type BalanceWheelAnalysisResponseDto } from "../../types/types.js"; + +type BalanceAnalysisData = z.infer; + +const generateScoresResponse = ( + aiResponse: OpenAiResponseMessage[], +): BalanceWheelAnalysisResponseDto | null => { + const [message] = aiResponse; + + if (!message) { + return null; + } + + const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); + + if (parsedResult.success) { + const contentText: string = + parsedResult.data.content[ZERO_INDEX].text.value; + const balanceData: BalanceAnalysisData = JSON.parse( + contentText, + ) as BalanceAnalysisData; + + return { + lowestCategories: balanceData.lowestCategories.map((category) => ({ + categoryId: Number(category.categoryId), + categoryName: category.categoryName, + score: category.score, + })), + text: balanceData.answer, + threadId: message.id, + }; + } + + return null; +}; + +export { generateScoresResponse }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts new file mode 100644 index 000000000..9cd61274f --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts @@ -0,0 +1,3 @@ +export { generateInitPrompt } from "./generate-init-promt/generate-init-promt.js"; +export { generateUserScoresPrompt } from "./generate-scores-promt/generate-scores-promt.js"; +export { generateScoresResponse } from "./generate-scores-response/generate-scores-response.js"; From 297031a0b1a78c4730e2cef91bbc3835a6654fbe Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:14:20 +0100 Subject: [PATCH 022/244] feat(shared): add addMessageToThread validation bb-203 --- ...add-message-to-thread.validation-schema.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts diff --git a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts new file mode 100644 index 000000000..9b2b96e65 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts @@ -0,0 +1,33 @@ +import { z } from "zod"; + +import { + AiAssistantValidationMessage, + AiAssistantValidationRule, +} from "../enums/enums.js"; + +type AiAssistantMessageCreateDto = { + text: z.ZodString; + threadId: z.ZodString; +}; + +const addMessageToThread = z + .object({ + text: z + .string() + .trim() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.TEXT_REQUIRED, + }), + threadId: z + .string() + .trim() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, + }) + .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + }), + }) + .required(); + +export { addMessageToThread }; From 3ac8aea1d0b9a72db5d61756aa80214e649f6f4b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:15:37 +0100 Subject: [PATCH 023/244] feat(shared): add AiAssistantMessage validation bb-203 --- .../ai-assistant-message.validation-schema.ts | 17 +++++++++++++++++ .../validation-schemas/validation-schemas.ts | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts create mode 100644 packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts diff --git a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts new file mode 100644 index 000000000..86f45ed8d --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; + +const AiAssistantMessage = z.object({ + content: z + .array( + z.object({ + text: z.object({ + value: z.string(), + }), + type: z.literal("text"), + }), + ) + .nonempty(), + id: z.string(), +}); + +export { AiAssistantMessage }; diff --git a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts new file mode 100644 index 000000000..92ec1f5a7 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts @@ -0,0 +1,2 @@ +export { addMessageToThread } from "./add-message-to-thread.validation-schema.js"; +export { AiAssistantMessage } from "./ai-assistant-message.validation-schema.js"; From 5a43a0904d70a7ff46aa33c874a4db27c16531e3 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:17:40 +0100 Subject: [PATCH 024/244] feat(shared): add AiAssistantValidationRule for adding message to thread bb-203 --- .../libs/enums/ai-assistant-validatuon-rule.enum.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts new file mode 100644 index 000000000..6fb01367f --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -0,0 +1,6 @@ +const AiAssistantValidationRule = { + NON_EMPTY_STRING_MIN_LENGTH: 1, + THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, +} as const; + +export { AiAssistantValidationRule }; From 45477b77556ef33031a66f0ec2c5a2b270b66c89 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:23:55 +0100 Subject: [PATCH 025/244] feat(shared): add Message Create DTO bb-203 --- .../libs/types/thread-message-create-dto.type.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts diff --git a/packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts b/packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts new file mode 100644 index 000000000..5a70bff8e --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts @@ -0,0 +1,6 @@ +type ThreadMessageCreateDto = { + text: string; + threadId: string; +}; + +export { type ThreadMessageCreateDto }; From 33523d7d34d0ac02b7a633aabe4a5e9f8d97f673 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:26:22 +0100 Subject: [PATCH 026/244] feat(shared): add types for BalanceWheelAnalysisResponseDto bb-203 --- .../balance-wheel-analysis-response.dto.type.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts diff --git a/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts new file mode 100644 index 000000000..3970af177 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -0,0 +1,14 @@ +import { type QuizScoresGetAllItemResponseDto } from "../../../quiz/quiz.js"; + +type SimplifiedQuizScoreDto = Omit< + QuizScoresGetAllItemResponseDto, + "createdAt" | "id" | "updatedAt" | "userId" +>; + +type BalanceWheelAnalysisResponseDto = { + lowestCategories: SimplifiedQuizScoreDto[]; + text: string; + threadId: string; +}; + +export { type BalanceWheelAnalysisResponseDto }; From dcc242d8d2f0ccb099d15950efcdea7f9e5ffb94 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:29:53 +0100 Subject: [PATCH 027/244] chore(backend): add exports from categories Module bb-203 --- apps/backend/src/modules/categories/categories.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/modules/categories/categories.ts b/apps/backend/src/modules/categories/categories.ts index a243712a0..bcd964511 100644 --- a/apps/backend/src/modules/categories/categories.ts +++ b/apps/backend/src/modules/categories/categories.ts @@ -6,8 +6,9 @@ const categoryRepository = new CategoryRepository(CategoryModel); const categoryService = new CategoryService(categoryRepository); export { CategoryService } from "./category.service.js"; +export { categoryService }; export { type QuizScoreDto, + type QuizScoresGetAllResponseDto, type QuizScoresResponseDto, } from "./libs/types/types.js"; -export { categoryService }; From 64c2863a0bdea2167b0c86cf86cce30c4a169bb3 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:30:47 +0100 Subject: [PATCH 028/244] chore(backend): add exports from onboarding Module bb-203 --- apps/backend/src/modules/onboarding/onboarding.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/modules/onboarding/onboarding.ts b/apps/backend/src/modules/onboarding/onboarding.ts index 7a039ec18..558312894 100644 --- a/apps/backend/src/modules/onboarding/onboarding.ts +++ b/apps/backend/src/modules/onboarding/onboarding.ts @@ -18,5 +18,9 @@ const onboardingController = new OnboardingController( export { OnboardingApiPath } from "./libs/enums/enums.js"; export { OnboardingError } from "./libs/exceptions/exceptions.js"; -export { OnboardingAnswerModel } from "./onboarding-answer.model.js"; +export { type OnboardingRepository } from "./onboarding.repository.js"; export { onboardingController }; +export { onboardingRepository }; +export { OnboardingAnswerEntity } from "./onboarding-answer.entity.js"; +export { OnboardingAnswerModel } from "./onboarding-answer.model.js"; +export { OnboardingQuestionEntity } from "./onboarding-question.entity.js"; From 169be6d79af6b1925c7d8cc8e5d6ebb141b84b1e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:32:40 +0100 Subject: [PATCH 029/244] feat(backend): add findUserAnswersWithQuestions to OnboardingRepository bb-203 --- .../onboarding/onboarding.repository.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/apps/backend/src/modules/onboarding/onboarding.repository.ts b/apps/backend/src/modules/onboarding/onboarding.repository.ts index 2e78901e9..11d7971ed 100644 --- a/apps/backend/src/modules/onboarding/onboarding.repository.ts +++ b/apps/backend/src/modules/onboarding/onboarding.repository.ts @@ -245,6 +245,43 @@ class OnboardingRepository implements Repository { }); } + public async findUserAnswersWithQuestions( + userId: number, + ): Promise { + const userAnswers = await this.onboardingAnswerModel + .query() + .joinRelated(RelationName.USERS) + .where("users.id", userId); + + const questionIds = userAnswers.map((answer) => answer.questionId); + const questions = await this.onboardingQuestionModel + .query() + .whereIn("id", questionIds); + + return questions.map((question) => { + const answersForQuestion = userAnswers.filter( + (answer) => answer.questionId === question.id, + ); + + return OnboardingQuestionEntity.initialize({ + answers: answersForQuestion.map((answer) => + OnboardingAnswerEntity.initialize({ + createdAt: answer.createdAt, + id: answer.id, + label: answer.label, + questionId: answer.questionId, + updatedAt: answer.updatedAt, + userId, + }), + ), + createdAt: question.createdAt, + id: question.id, + label: question.label, + updatedAt: question.updatedAt, + }); + }); + } + public async update( id: number, entity: OnboardingQuestionEntity, From 9f229b3b09251ac855905dd5bd76aa55ee9586f7 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:35:20 +0100 Subject: [PATCH 030/244] feat(backend): add AiAssistantController and add it to base server API bb-203 --- .../server-application/server-application.ts | 2 + .../ai-assistant/ai-assistant.controller.ts | 77 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts diff --git a/apps/backend/src/libs/modules/server-application/server-application.ts b/apps/backend/src/libs/modules/server-application/server-application.ts index c645b30a2..6f9c9ab2d 100644 --- a/apps/backend/src/libs/modules/server-application/server-application.ts +++ b/apps/backend/src/libs/modules/server-application/server-application.ts @@ -1,6 +1,7 @@ import { config } from "~/libs/modules/config/config.js"; import { database } from "~/libs/modules/database/database.js"; import { logger } from "~/libs/modules/logger/logger.js"; +import { aiAssistantController } from "~/modules/ai-assistant/ai-assistant.js"; import { authController } from "~/modules/auth/auth.js"; import { onboardingController } from "~/modules/onboarding/onboarding.js"; import { quizController } from "~/modules/quiz/quiz.js"; @@ -16,6 +17,7 @@ const apiV1 = new BaseServerApplicationApi( ...userController.routes, ...onboardingController.routes, ...quizController.routes, + ...aiAssistantController.routes, ); const serverApplication = new BaseServerApplication({ apis: [apiV1], diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts new file mode 100644 index 000000000..bf2a45ba3 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -0,0 +1,77 @@ +import { APIPath } from "~/libs/enums/enums.js"; +import { + type APIHandlerOptions, + type APIHandlerResponse, + BaseController, +} from "~/libs/modules/controller/controller.js"; +import { HTTPCode } from "~/libs/modules/http/http.js"; +import { type Logger } from "~/libs/modules/logger/logger.js"; +import { addMessageToThreadValidationSchema } from "~/libs/modules/open-ai/open-ai.js"; +import { type UserDto } from "~/libs/types/types.js"; + +import { type AiAssistantService } from "./ai-assistant.service.js"; +import { AiAssistantApiPath } from "./libs/enums/enums.js"; +import { type ThreadMessageCreateDto } from "./libs/types/types.js"; + +class AiAssistantController extends BaseController { + private openAiService: AiAssistantService; + + public constructor(logger: Logger, openAiService: AiAssistantService) { + super(logger, APIPath.ASSISTANT); + + this.openAiService = openAiService; + + this.addRoute({ + handler: (options) => + this.initConversation( + options as APIHandlerOptions<{ + user: UserDto; + }>, + ), + method: "POST", + path: AiAssistantApiPath.INITIATE_THREAD, + }); + + this.addRoute({ + handler: (options) => + this.addMessageToConversation( + options as APIHandlerOptions<{ + body: ThreadMessageCreateDto; + }>, + ), + method: "POST", + path: AiAssistantApiPath.ADD_MESSAGE, + validation: { + body: addMessageToThreadValidationSchema, + }, + }); + } + + private async addMessageToConversation( + options: APIHandlerOptions<{ + body: ThreadMessageCreateDto; + }>, + ): Promise { + const { body } = options; + + return { + payload: await this.openAiService.addMessageToThread(body), + status: HTTPCode.OK, + }; + } + + private async initConversation( + options: APIHandlerOptions<{ + user: UserDto; + }>, + ): Promise { + const { user } = options; + + return { + payload: await this.openAiService.initNewThread(user), + status: HTTPCode.OK, + }; + } +} + +export { AiAssistantController }; From 57a6c7e265444634352fd2bb940ddc6b2c9bcce8 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 22:37:42 +0100 Subject: [PATCH 031/244] feat(backend): add AiAssistant module and imports bb-203 --- .../src/modules/ai-assistant/ai-assistant.ts | 20 +++++++++++++++++++ .../modules/ai-assistant/libs/enums/enums.ts | 1 + .../modules/ai-assistant/libs/types/types.ts | 5 +++++ 3 files changed, 26 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/ai-assistant.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/enums/enums.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/types/types.ts diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.ts new file mode 100644 index 000000000..13abe0151 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.ts @@ -0,0 +1,20 @@ +import { logger } from "~/libs/modules/logger/logger.js"; +import { openAi } from "~/libs/modules/open-ai/open-ai.js"; +import { categoryService } from "~/modules/categories/categories.js"; +import { onboardingRepository } from "~/modules/onboarding/onboarding.js"; + +import { AiAssistantController } from "./ai-assistant.controller.js"; +import { AiAssistantService } from "./ai-assistant.service.js"; + +const aiAssistantService = new AiAssistantService({ + categoryService, + onboardingRepository, + openAi, +}); + +const aiAssistantController = new AiAssistantController( + logger, + aiAssistantService, +); + +export { aiAssistantController }; diff --git a/apps/backend/src/modules/ai-assistant/libs/enums/enums.ts b/apps/backend/src/modules/ai-assistant/libs/enums/enums.ts new file mode 100644 index 000000000..c79d89039 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/enums/enums.ts @@ -0,0 +1 @@ +export { AiAssistantApiPath } from "shared"; diff --git a/apps/backend/src/modules/ai-assistant/libs/types/types.ts b/apps/backend/src/modules/ai-assistant/libs/types/types.ts new file mode 100644 index 000000000..1bf4a9525 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/types/types.ts @@ -0,0 +1,5 @@ +export { + type AiAssistantMessageResponseDto, + type BalanceWheelAnalysisResponseDto, + type ThreadMessageCreateDto, +} from "shared"; From 0a55098cd264778b8160e35c732d6c7523341ef1 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 9 Sep 2024 23:18:29 +0100 Subject: [PATCH 032/244] feat(shared): add Task DTO and task status enum bb-203 --- packages/shared/src/index.ts | 10 ++++++++++ .../modules/tasks/libs/enums/task-status.enum.ts | 7 +++++++ .../src/modules/tasks/libs/types/task-dto.type.ts | 15 +++++++++++++++ .../shared/src/modules/tasks/libs/types/types.ts | 1 + packages/shared/src/modules/tasks/tasks.ts | 2 ++ 5 files changed, 35 insertions(+) create mode 100644 packages/shared/src/modules/tasks/libs/enums/task-status.enum.ts create mode 100644 packages/shared/src/modules/tasks/libs/types/task-dto.type.ts create mode 100644 packages/shared/src/modules/tasks/libs/types/types.ts create mode 100644 packages/shared/src/modules/tasks/tasks.ts diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index cac923c72..f61ee048d 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -13,6 +13,7 @@ export { AuthError, HTTPError, OnboardingError, + OpenAIError, QuizError, UserError, ValidationError, @@ -40,6 +41,14 @@ export { AuthApiPath, ConfirmPasswordCustomValidation, } from "./modules/auth/auth.js"; +export { + addMessageToThreadValidationSchema, + AiAssistantApiPath, + type AiAssistantMessageResponseDto, + AiAssistantMessageValidationSchema, + type BalanceWheelAnalysisResponseDto, + type ThreadMessageCreateDto, +} from "./modules/ia-assistant/ai-assistant.js"; export { type OnboardingAnswerDto, type OnboardingAnswerRequestBodyDto, @@ -71,6 +80,7 @@ export { type QuizUserAnswerDto, quizUserAnswersValidationSchema, } from "./modules/quiz/quiz.js"; +export { type TaskDto, type TaskStatus } from "./modules/tasks/tasks.js"; export { type EmailDto, type ResetPasswordDto, diff --git a/packages/shared/src/modules/tasks/libs/enums/task-status.enum.ts b/packages/shared/src/modules/tasks/libs/enums/task-status.enum.ts new file mode 100644 index 000000000..ec5661cb5 --- /dev/null +++ b/packages/shared/src/modules/tasks/libs/enums/task-status.enum.ts @@ -0,0 +1,7 @@ +const TaskStatus = { + COMPLETED: "Completed", + CURRENT: "Current", + SKIPPED: "Skipped", +} as const; + +export { TaskStatus }; diff --git a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts new file mode 100644 index 000000000..fd5d72cc5 --- /dev/null +++ b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts @@ -0,0 +1,15 @@ +import { type ValueOf } from "../../../../libs/types/value-of.type.js"; +import { type TaskStatus } from "../enums/enums.js"; + +type TaskDto = { + categoryId: number; + createdAt: string; + description: string; + id: number; + label: string; + status: ValueOf; + updatedAt: string; + userId: number; +}; + +export { type TaskDto }; diff --git a/packages/shared/src/modules/tasks/libs/types/types.ts b/packages/shared/src/modules/tasks/libs/types/types.ts new file mode 100644 index 000000000..369add4ab --- /dev/null +++ b/packages/shared/src/modules/tasks/libs/types/types.ts @@ -0,0 +1 @@ +export { type TaskDto } from "./task-dto.type.js"; diff --git a/packages/shared/src/modules/tasks/tasks.ts b/packages/shared/src/modules/tasks/tasks.ts new file mode 100644 index 000000000..f7bf19225 --- /dev/null +++ b/packages/shared/src/modules/tasks/tasks.ts @@ -0,0 +1,2 @@ +export { TaskStatus } from "./libs/enums/enums.js"; +export { type TaskDto } from "./libs/types/types.js"; From e423ac7e22eababf70a9638eb0b795c3d7d12866 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 10:21:40 +0100 Subject: [PATCH 033/244] refactor(shared): add dueDate to Task DTO bb-203 --- packages/shared/src/modules/tasks/libs/types/task-dto.type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts index fd5d72cc5..964965176 100644 --- a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts +++ b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts @@ -5,6 +5,7 @@ type TaskDto = { categoryId: number; createdAt: string; description: string; + dueDate: string; id: number; label: string; status: ValueOf; From 1b34e26e6c245f1b3795a40d43ceec38a2618312 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 11:39:27 +0100 Subject: [PATCH 034/244] refactor(backend): fix imports bb-203 --- apps/backend/src/modules/categories/categories.ts | 3 ++- apps/backend/src/modules/categories/category.model.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/modules/categories/categories.ts b/apps/backend/src/modules/categories/categories.ts index bcd964511..f8bf8a5ea 100644 --- a/apps/backend/src/modules/categories/categories.ts +++ b/apps/backend/src/modules/categories/categories.ts @@ -5,8 +5,9 @@ import { CategoryService } from "./category.service.js"; const categoryRepository = new CategoryRepository(CategoryModel); const categoryService = new CategoryService(categoryRepository); -export { CategoryService } from "./category.service.js"; +export { CategoryModel } from "./category.model.js"; export { categoryService }; +export { CategoryService } from "./category.service.js"; export { type QuizScoreDto, type QuizScoresGetAllResponseDto, diff --git a/apps/backend/src/modules/categories/category.model.ts b/apps/backend/src/modules/categories/category.model.ts index 0c9c0ddce..fbc535909 100644 --- a/apps/backend/src/modules/categories/category.model.ts +++ b/apps/backend/src/modules/categories/category.model.ts @@ -5,6 +5,7 @@ import { DatabaseTableName, } from "~/libs/modules/database/database.js"; +import { TaskModel } from "../tasks/tasks.js"; import { UserModel } from "../users/users.js"; import { type CategoryEntity } from "./category.entity.js"; @@ -28,6 +29,14 @@ class CategoryModel extends AbstractModel { modelClass: UserModel, relation: Model.ManyToManyRelation, }, + tasks: { + join: { + from: `${DatabaseTableName.CATEGORIES}.id`, + to: `${DatabaseTableName.TASKS}.categoryId`, + }, + modelClass: TaskModel, + relation: Model.HasManyRelation, + }, }; } From 4a20f2997efcf159eea5f264774e986a4871facf Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 11:40:47 +0100 Subject: [PATCH 035/244] feat(backend): add Task Entity bb-203 --- apps/backend/src/modules/tasks/task.entity.ts | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 apps/backend/src/modules/tasks/task.entity.ts diff --git a/apps/backend/src/modules/tasks/task.entity.ts b/apps/backend/src/modules/tasks/task.entity.ts new file mode 100644 index 000000000..7a1c658ee --- /dev/null +++ b/apps/backend/src/modules/tasks/task.entity.ts @@ -0,0 +1,163 @@ +import { type Entity, type ValueOf } from "~/libs/types/types.js"; + +import { TaskStatus } from "./libs/enums/enums.js"; + +class TaskEntity implements Entity { + private categoryId: number; + + private createdAt: string; + + private description: string; + + private dueDate: string; + + private id: null | number; + + private label: string; + + private status: ValueOf; + + private updatedAt: string; + + private userId: number; + + private constructor({ + categoryId, + createdAt, + description, + dueDate, + id, + label, + status, + updatedAt, + userId, + }: { + categoryId: number; + createdAt: string; + description: string; + dueDate: string; + id: null | number; + label: string; + status: ValueOf; + updatedAt: string; + userId: number; + }) { + this.createdAt = createdAt; + this.id = id; + this.categoryId = categoryId; + this.label = label; + this.description = description; + this.dueDate = dueDate; + this.status = status; + this.userId = userId; + this.updatedAt = updatedAt; + } + + public static initialize({ + categoryId, + createdAt, + description, + dueDate, + id, + label, + status, + updatedAt, + userId, + }: { + categoryId: number; + createdAt: string; + description: string; + dueDate: string; + id: null | number; + label: string; + status: ValueOf; + updatedAt: string; + userId: number; + }): TaskEntity { + return new TaskEntity({ + categoryId, + createdAt, + description, + dueDate, + id, + label, + status, + updatedAt, + userId, + }); + } + + public static initializeNew({ + categoryId, + description, + dueDate, + label, + userId, + }: { + categoryId: number; + description: string; + dueDate: string; + label: string; + userId: number; + }): TaskEntity { + return new TaskEntity({ + categoryId, + createdAt: "", + description, + dueDate, + id: null, + label, + status: TaskStatus.CURRENT, + updatedAt: "", + userId, + }); + } + + public toNewObject(): { + categoryId: number; + createdAt: string; + description: string; + dueDate: string; + label: string; + status: ValueOf; + updatedAt: string; + userId: number; + } { + return { + categoryId: this.categoryId, + createdAt: this.createdAt, + description: this.description, + dueDate: this.dueDate, + label: this.label, + status: this.status, + updatedAt: this.updatedAt, + userId: this.userId, + }; + } + + public toObject(): { + categoryId: number; + createdAt: string; + description: string; + dueDate: string; + id: number; + label: string; + status: ValueOf; + updatedAt: string; + userId: number; + } { + return { + categoryId: this.categoryId, + createdAt: this.createdAt, + description: this.description, + dueDate: this.dueDate, + id: this.id as number, + label: this.label, + status: this.status, + updatedAt: this.updatedAt, + userId: this.userId, + }; + } +} + +export { TaskEntity }; From 33cb75c967fc72452b79b4dd65ed073671b253b3 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 11:44:05 +0100 Subject: [PATCH 036/244] feat(backend): add Task db Model and add relations bb-203 --- apps/backend/src/modules/tasks/task.model.ts | 52 ++++++++++++++++++++ apps/backend/src/modules/users/user.model.ts | 11 ++++- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 apps/backend/src/modules/tasks/task.model.ts diff --git a/apps/backend/src/modules/tasks/task.model.ts b/apps/backend/src/modules/tasks/task.model.ts new file mode 100644 index 000000000..d8f74ff36 --- /dev/null +++ b/apps/backend/src/modules/tasks/task.model.ts @@ -0,0 +1,52 @@ +import { Model, type RelationMappings } from "objection"; + +import { + AbstractModel, + DatabaseTableName, +} from "~/libs/modules/database/database.js"; +import { type ValueOf } from "~/libs/types/types.js"; + +import { CategoryModel } from "../categories/category.model.js"; +import { UserModel } from "../users/users.js"; +import { type TaskStatus } from "./libs/enums/enums.js"; + +class TaskModel extends AbstractModel { + public categoryId!: number; + + public description!: string; + + public dueDate!: string; + + public label!: string; + + public status!: ValueOf; + + public userId!: number; + + static get relationMappings(): RelationMappings { + return { + category: { + join: { + from: `${DatabaseTableName.TASKS}.categoryId`, + to: `${DatabaseTableName.CATEGORIES}.id`, + }, + modelClass: CategoryModel, + relation: Model.BelongsToOneRelation, + }, + user: { + join: { + from: `${DatabaseTableName.TASKS}.userId`, + to: `${DatabaseTableName.USERS}.id`, + }, + modelClass: UserModel, + relation: Model.BelongsToOneRelation, + }, + }; + } + + public static override get tableName(): string { + return DatabaseTableName.TASKS; + } +} + +export { TaskModel }; diff --git a/apps/backend/src/modules/users/user.model.ts b/apps/backend/src/modules/users/user.model.ts index b1064f854..a18f1b025 100644 --- a/apps/backend/src/modules/users/user.model.ts +++ b/apps/backend/src/modules/users/user.model.ts @@ -5,9 +5,10 @@ import { DatabaseTableName, } from "~/libs/modules/database/database.js"; -import { CategoryModel } from "../categories/category.model.js"; +import { CategoryModel } from "../categories/categories.js"; import { OnboardingAnswerModel } from "../onboarding/onboarding.js"; import { QuizAnswerModel } from "../quiz-answers/quiz-answer.model.js"; +import { TaskModel } from "../tasks/tasks.js"; import { UserDetailsModel } from "./user-details.model.js"; class UserModel extends AbstractModel { @@ -62,6 +63,14 @@ class UserModel extends AbstractModel { modelClass: CategoryModel, relation: Model.ManyToManyRelation, }, + tasks: { + join: { + from: `${DatabaseTableName.USERS}.id`, + to: `${DatabaseTableName.TASKS}.userId`, + }, + modelClass: TaskModel, + relation: Model.HasManyRelation, + }, userDetails: { join: { from: `${DatabaseTableName.USERS}.id`, From 9c7ac7642b9d746c027baf0e9ac31c0018288ee1 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 11:59:29 +0100 Subject: [PATCH 037/244] feat(backend): add TaskRepository boilerplate bb-203 --- .../src/modules/tasks/task.repository.ts | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 apps/backend/src/modules/tasks/task.repository.ts diff --git a/apps/backend/src/modules/tasks/task.repository.ts b/apps/backend/src/modules/tasks/task.repository.ts new file mode 100644 index 000000000..e59714f7b --- /dev/null +++ b/apps/backend/src/modules/tasks/task.repository.ts @@ -0,0 +1,52 @@ +import { type Repository } from "~/libs/types/types.js"; +import { TaskEntity } from "~/modules/tasks/task.entity.js"; + +import { TaskModel } from "./task.model.js"; + +class TaskRepository implements Repository { + private taskModel: typeof TaskModel; + + public constructor(taskModel: typeof TaskModel) { + this.taskModel = taskModel; + } + + create(): Promise { + return Promise.resolve(); + } + + public delete(): ReturnType { + return Promise.resolve(true); + } + + find(): Promise { + return Promise.resolve(); + } + + findAll(): Promise { + return Promise.resolve([]); + } + + async findAllByUserId(userId: number): Promise { + const tasks = await TaskModel.query().where({ userId }); + + return tasks.map((task) => + TaskEntity.initialize({ + categoryId: task.categoryId, + createdAt: task.createdAt, + description: task.description, + dueDate: task.dueDate, + id: task.id, + label: task.label, + status: task.status, + updatedAt: task.updatedAt, + userId: task.userId, + }), + ); + } + + update(): Promise { + return Promise.resolve(); + } +} + +export { TaskRepository }; From 2bfb5045bfbce8b81bc41f070bb06d5b3488d6cb Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 12:00:14 +0100 Subject: [PATCH 038/244] feat(backend): add TaskService boilerplate bb-203 --- .../backend/src/modules/tasks/task.service.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 apps/backend/src/modules/tasks/task.service.ts diff --git a/apps/backend/src/modules/tasks/task.service.ts b/apps/backend/src/modules/tasks/task.service.ts new file mode 100644 index 000000000..022271302 --- /dev/null +++ b/apps/backend/src/modules/tasks/task.service.ts @@ -0,0 +1,40 @@ +import { type Service } from "~/libs/types/types.js"; + +import { type TaskEntity } from "./task.entity.js"; +import { type TaskRepository } from "./task.repository.js"; + +class TaskService implements Service { + private taskRepository: TaskRepository; + + public constructor(taskRepository: TaskRepository) { + this.taskRepository = taskRepository; + } + + create(): Promise { + return Promise.resolve(); + } + + public delete(): ReturnType { + return Promise.resolve(true); + } + + find(): Promise { + return Promise.resolve(); + } + + findAll(): Promise<{ items: unknown[] }> { + return Promise.resolve({ + items: [], + }); + } + + async findAllByUserId(userId: number): Promise { + return await this.taskRepository.findAllByUserId(userId); + } + + update(): Promise { + return Promise.resolve(); + } +} + +export { TaskService }; From 9c4d587212658149ba33ff3add7149aefa525fef Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 12:13:14 +0100 Subject: [PATCH 039/244] feat(backend): add TaskController boilerplate adn add it to server API v1bb-203 --- .../server-application/server-application.ts | 2 + .../src/modules/tasks/task.controller.ts | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 apps/backend/src/modules/tasks/task.controller.ts diff --git a/apps/backend/src/libs/modules/server-application/server-application.ts b/apps/backend/src/libs/modules/server-application/server-application.ts index 6f9c9ab2d..78fa61009 100644 --- a/apps/backend/src/libs/modules/server-application/server-application.ts +++ b/apps/backend/src/libs/modules/server-application/server-application.ts @@ -5,6 +5,7 @@ import { aiAssistantController } from "~/modules/ai-assistant/ai-assistant.js"; import { authController } from "~/modules/auth/auth.js"; import { onboardingController } from "~/modules/onboarding/onboarding.js"; import { quizController } from "~/modules/quiz/quiz.js"; +import { taskController } from "~/modules/tasks/tasks.js"; import { userController } from "~/modules/users/users.js"; import { BaseServerApplication } from "./base-server-application.js"; @@ -18,6 +19,7 @@ const apiV1 = new BaseServerApplicationApi( ...onboardingController.routes, ...quizController.routes, ...aiAssistantController.routes, + ...taskController.routes, ); const serverApplication = new BaseServerApplication({ apis: [apiV1], diff --git a/apps/backend/src/modules/tasks/task.controller.ts b/apps/backend/src/modules/tasks/task.controller.ts new file mode 100644 index 000000000..f1378c9a1 --- /dev/null +++ b/apps/backend/src/modules/tasks/task.controller.ts @@ -0,0 +1,48 @@ +import { APIPath } from "~/libs/enums/enums.js"; +import { + type APIHandlerOptions, + type APIHandlerResponse, + BaseController, +} from "~/libs/modules/controller/controller.js"; +import { HTTPCode } from "~/libs/modules/http/http.js"; +import { type Logger } from "~/libs/modules/logger/logger.js"; +import { type UserDto } from "~/modules/users/users.js"; + +import { TasksApiPath } from "./libs/enums/enums.js"; +import { type TaskService } from "./task.service.js"; + +class TaskController extends BaseController { + private taskService: TaskService; + + public constructor(logger: Logger, taskService: TaskService) { + super(logger, APIPath.TASKS); + + this.taskService = taskService; + + this.addRoute({ + handler: (options) => + this.findAllByUserId( + options as APIHandlerOptions<{ + user: UserDto; + }>, + ), + method: "GET", + path: TasksApiPath.ROOT, + }); + } + + private async findAllByUserId( + options: APIHandlerOptions<{ + user: UserDto; + }>, + ): Promise { + const { user } = options; + + return { + payload: await this.taskService.findAllByUserId(user.id), + status: HTTPCode.OK, + }; + } +} + +export { TaskController }; From d8cfc26419467e937802802439d574c9ac806967 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 12:15:32 +0100 Subject: [PATCH 040/244] feat(shared): add Api paths for TaskController bb-203 --- packages/shared/src/libs/enums/api-path.enum.ts | 1 + packages/shared/src/modules/tasks/libs/enums/enums.ts | 2 ++ .../src/modules/tasks/libs/enums/tasks-api-path.enum.ts | 5 +++++ packages/shared/src/modules/tasks/tasks.ts | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 packages/shared/src/modules/tasks/libs/enums/enums.ts create mode 100644 packages/shared/src/modules/tasks/libs/enums/tasks-api-path.enum.ts diff --git a/packages/shared/src/libs/enums/api-path.enum.ts b/packages/shared/src/libs/enums/api-path.enum.ts index b0385a4d9..f1aa7e309 100644 --- a/packages/shared/src/libs/enums/api-path.enum.ts +++ b/packages/shared/src/libs/enums/api-path.enum.ts @@ -3,6 +3,7 @@ const APIPath = { AUTH: "/auth", ONBOARDING: "/onboarding", QUIZ: "/quiz", + TASKS: "/tasks", USERS: "/users", } as const; diff --git a/packages/shared/src/modules/tasks/libs/enums/enums.ts b/packages/shared/src/modules/tasks/libs/enums/enums.ts new file mode 100644 index 000000000..68db920ae --- /dev/null +++ b/packages/shared/src/modules/tasks/libs/enums/enums.ts @@ -0,0 +1,2 @@ +export { TaskStatus } from "./task-status.enum.js"; +export { TasksApiPath } from "./tasks-api-path.enum.js"; diff --git a/packages/shared/src/modules/tasks/libs/enums/tasks-api-path.enum.ts b/packages/shared/src/modules/tasks/libs/enums/tasks-api-path.enum.ts new file mode 100644 index 000000000..5bc96d494 --- /dev/null +++ b/packages/shared/src/modules/tasks/libs/enums/tasks-api-path.enum.ts @@ -0,0 +1,5 @@ +const TasksApiPath = { + ROOT: "/", +} as const; + +export { TasksApiPath }; diff --git a/packages/shared/src/modules/tasks/tasks.ts b/packages/shared/src/modules/tasks/tasks.ts index f7bf19225..19ebba896 100644 --- a/packages/shared/src/modules/tasks/tasks.ts +++ b/packages/shared/src/modules/tasks/tasks.ts @@ -1,2 +1,2 @@ -export { TaskStatus } from "./libs/enums/enums.js"; +export { TasksApiPath, TaskStatus } from "./libs/enums/enums.js"; export { type TaskDto } from "./libs/types/types.js"; From 0df43137354757b9d945697a1b1ec41d4b0c9302 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 12:16:49 +0100 Subject: [PATCH 041/244] feat(backend): add task Module and imports bb-203 --- apps/backend/src/modules/tasks/libs/enums/enums.ts | 1 + apps/backend/src/modules/tasks/tasks.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 apps/backend/src/modules/tasks/libs/enums/enums.ts create mode 100644 apps/backend/src/modules/tasks/tasks.ts diff --git a/apps/backend/src/modules/tasks/libs/enums/enums.ts b/apps/backend/src/modules/tasks/libs/enums/enums.ts new file mode 100644 index 000000000..dcc2f5cce --- /dev/null +++ b/apps/backend/src/modules/tasks/libs/enums/enums.ts @@ -0,0 +1 @@ +export { TasksApiPath, TaskStatus } from "shared"; diff --git a/apps/backend/src/modules/tasks/tasks.ts b/apps/backend/src/modules/tasks/tasks.ts new file mode 100644 index 000000000..dd742c4fd --- /dev/null +++ b/apps/backend/src/modules/tasks/tasks.ts @@ -0,0 +1,13 @@ +import { logger } from "~/libs/modules/logger/logger.js"; + +import { TaskController } from "./task.controller.js"; +import { TaskModel } from "./task.model.js"; +import { TaskRepository } from "./task.repository.js"; +import { TaskService } from "./task.service.js"; + +const taskRepository = new TaskRepository(TaskModel); +const taskService = new TaskService(taskRepository); +const taskController = new TaskController(logger, taskService); + +export { taskController }; +export { TaskModel } from "./task.model.js"; From 8b15de0e1548bf415c412eadc1eb99ed7c57e469 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 12:32:07 +0100 Subject: [PATCH 042/244] feat(shared): add TaskSuggestionsResponseDto and exports for AI assistant bb-203 --- packages/shared/src/index.ts | 9 +++++++-- .../src/modules/ia-assistant/ai-assistant.ts | 8 ++++++++ .../src/modules/ia-assistant/libs/enums/enums.ts | 3 +++ .../types/task-suggestion-response-dto.type.ts | 14 ++++++++++++++ .../src/modules/ia-assistant/libs/types/types.ts | 3 +++ 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 packages/shared/src/modules/ia-assistant/ai-assistant.ts create mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/enums.ts create mode 100644 packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts create mode 100644 packages/shared/src/modules/ia-assistant/libs/types/types.ts diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index f61ee048d..0c34a2622 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -44,9 +44,9 @@ export { export { addMessageToThreadValidationSchema, AiAssistantApiPath, - type AiAssistantMessageResponseDto, AiAssistantMessageValidationSchema, type BalanceWheelAnalysisResponseDto, + type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "./modules/ia-assistant/ai-assistant.js"; export { @@ -80,7 +80,12 @@ export { type QuizUserAnswerDto, quizUserAnswersValidationSchema, } from "./modules/quiz/quiz.js"; -export { type TaskDto, type TaskStatus } from "./modules/tasks/tasks.js"; +export { + type TaskDto, + type TaskGetAllResponseDto, + TasksApiPath, + TaskStatus, +} from "./modules/tasks/tasks.js"; export { type EmailDto, type ResetPasswordDto, diff --git a/packages/shared/src/modules/ia-assistant/ai-assistant.ts b/packages/shared/src/modules/ia-assistant/ai-assistant.ts new file mode 100644 index 000000000..0031beb60 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/ai-assistant.ts @@ -0,0 +1,8 @@ +export { AiAssistantApiPath } from "./libs/enums/enums.js"; +export { + type BalanceWheelAnalysisResponseDto, + type TaskSuggestionsResponseDto, + type ThreadMessageCreateDto, +} from "./libs/types/types.js"; +export { addMessageToThread as addMessageToThreadValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; +export { AiAssistantMessage as AiAssistantMessageValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/enums.ts b/packages/shared/src/modules/ia-assistant/libs/enums/enums.ts new file mode 100644 index 000000000..a7003a6f4 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/enums/enums.ts @@ -0,0 +1,3 @@ +export { AiAssistantApiPath } from "./ai-assistant-api-path.enum.js"; +export { AiAssistantValidationMessage } from "./ai-assistant-validation-message.enum.js"; +export { AiAssistantValidationRule } from "./ai-assistant-validatuon-rule.enum.js"; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts b/packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts new file mode 100644 index 000000000..d3a68cd47 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts @@ -0,0 +1,14 @@ +import { type TaskDto } from "../../../tasks/libs/types/types.js"; + +type SimplifiedTaskDto = Omit< + TaskDto, + "createdAt" | "id" | "updatedAt" | "userId" +>; + +type TaskSuggestionsResponseDto = { + tasks: SimplifiedTaskDto[]; + text: string; + theadId: string; +}; + +export { type TaskSuggestionsResponseDto }; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/types.ts b/packages/shared/src/modules/ia-assistant/libs/types/types.ts new file mode 100644 index 000000000..d910e5b65 --- /dev/null +++ b/packages/shared/src/modules/ia-assistant/libs/types/types.ts @@ -0,0 +1,3 @@ +export { type BalanceWheelAnalysisResponseDto } from "./balance-wheel-analysis-response.dto.type.js"; +export { type TaskSuggestionsResponseDto } from "./task-suggestion-response-dto.type.js"; +export { type ThreadMessageCreateDto } from "./thread-message-create-dto.type.js"; From c3e3247afdd0bb890feddffff699f3992c09e6e2 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 12:32:58 +0100 Subject: [PATCH 043/244] feat(shared): add TaskGetAllResponseDto and exports bb-203 --- .../tasks/libs/types/task-get-all-response-dto.type.ts | 7 +++++++ packages/shared/src/modules/tasks/libs/types/types.ts | 1 + packages/shared/src/modules/tasks/tasks.ts | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 packages/shared/src/modules/tasks/libs/types/task-get-all-response-dto.type.ts diff --git a/packages/shared/src/modules/tasks/libs/types/task-get-all-response-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-get-all-response-dto.type.ts new file mode 100644 index 000000000..8286c68a4 --- /dev/null +++ b/packages/shared/src/modules/tasks/libs/types/task-get-all-response-dto.type.ts @@ -0,0 +1,7 @@ +import { type TaskDto } from "./task-dto.type.js"; + +type TaskGetAllResponseDto = { + items: TaskDto[]; +}; + +export { type TaskGetAllResponseDto }; diff --git a/packages/shared/src/modules/tasks/libs/types/types.ts b/packages/shared/src/modules/tasks/libs/types/types.ts index 369add4ab..abe968516 100644 --- a/packages/shared/src/modules/tasks/libs/types/types.ts +++ b/packages/shared/src/modules/tasks/libs/types/types.ts @@ -1 +1,2 @@ export { type TaskDto } from "./task-dto.type.js"; +export { type TaskGetAllResponseDto } from "./task-get-all-response-dto.type.js"; diff --git a/packages/shared/src/modules/tasks/tasks.ts b/packages/shared/src/modules/tasks/tasks.ts index 19ebba896..7305aaf1a 100644 --- a/packages/shared/src/modules/tasks/tasks.ts +++ b/packages/shared/src/modules/tasks/tasks.ts @@ -1,2 +1,5 @@ export { TasksApiPath, TaskStatus } from "./libs/enums/enums.js"; -export { type TaskDto } from "./libs/types/types.js"; +export { + type TaskDto, + type TaskGetAllResponseDto, +} from "./libs/types/types.js"; From 340bc4dbaee6aeb61a205a14324a73de20b548d3 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 13:12:48 +0100 Subject: [PATCH 044/244] feat(backend): add migration to crate Task table and updated enums bb-203 --- .../20240910113839_add_tasks_table.ts | 64 +++++++++++++++++++ .../src/libs/enums/relation-name.enum.ts | 2 + .../libs/enums/database-table-name.enum.ts | 1 + 3 files changed, 67 insertions(+) create mode 100644 apps/backend/src/db/migrations/20240910113839_add_tasks_table.ts diff --git a/apps/backend/src/db/migrations/20240910113839_add_tasks_table.ts b/apps/backend/src/db/migrations/20240910113839_add_tasks_table.ts new file mode 100644 index 000000000..4c3a81eff --- /dev/null +++ b/apps/backend/src/db/migrations/20240910113839_add_tasks_table.ts @@ -0,0 +1,64 @@ +import { type Knex } from "knex"; + +const TableName = { + CATEGORIES: "categories", + TASKS: "tasks", + USER: "users", +} as const; + +const ColumnName = { + CATEGORY_ID: "category_id", + CREATED_AT: "created_at", + DESCRIPTION: "description", + DUE_DATE: "due_date", + ID: "id", + LABEL: "label", + STATUS: "status", + UPDATED_AT: "updated_at", + USER_ID: "user_id", +} as const; + +const TaskStatus = { + COMPLETED: "Completed", + CURRENT: "Current", + SKIPPED: "Skipped", +} as const; + +const DELETE_STRATEGY = "CASCADE"; + +async function up(knex: Knex): Promise { + await knex.schema.createTable(TableName.TASKS, (table) => { + table.increments(ColumnName.ID).primary(); + table.string(ColumnName.LABEL).notNullable(); + table.text(ColumnName.DESCRIPTION).notNullable(); + table + .enum(ColumnName.STATUS, [ + TaskStatus.CURRENT, + TaskStatus.SKIPPED, + TaskStatus.COMPLETED, + ]) + .notNullable() + .defaultTo(TaskStatus.CURRENT); + table.timestamp(ColumnName.DUE_DATE).notNullable(); + table + .integer(ColumnName.CATEGORY_ID) + .notNullable() + .references(ColumnName.ID) + .inTable(TableName.CATEGORIES) + .onDelete(DELETE_STRATEGY); + table + .integer(ColumnName.USER_ID) + .notNullable() + .references(ColumnName.ID) + .inTable(TableName.USER) + .onDelete(DELETE_STRATEGY); + table.timestamp(ColumnName.CREATED_AT).defaultTo(knex.fn.now()); + table.timestamp(ColumnName.UPDATED_AT).defaultTo(knex.fn.now()); + }); +} + +async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.TASKS); +} + +export { down, up }; diff --git a/apps/backend/src/libs/enums/relation-name.enum.ts b/apps/backend/src/libs/enums/relation-name.enum.ts index 33733bee6..b75cab034 100644 --- a/apps/backend/src/libs/enums/relation-name.enum.ts +++ b/apps/backend/src/libs/enums/relation-name.enum.ts @@ -1,9 +1,11 @@ const RelationName = { + CATEGORIES: "categories", ONBOARDING_ANSWERS: "answers", ONBOARDING_QUESTION: "question", QUIZ_ANSWERS: "answers", QUIZ_QUESTION: "question", SCORES: "scores", + TASKS: "tasks", USER_DETAILS: "userDetails", USERS: "users", } as const; diff --git a/apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts b/apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts index f7110ac92..864cb60a5 100644 --- a/apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts +++ b/apps/backend/src/libs/modules/database/libs/enums/database-table-name.enum.ts @@ -8,6 +8,7 @@ const DatabaseTableName = { QUIZ_ANSWERS_TO_USERS: "quiz_answers_to_users", QUIZ_QUESTIONS: "quiz_questions", QUIZ_SCORES: "quiz_scores", + TASKS: "tasks", USER_DETAILS: "user_details", USERS: "users", } as const; From 9f107feb51582b98658fcce75a2f35b9b737484d Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 10 Sep 2024 13:14:34 +0100 Subject: [PATCH 045/244] refactor(backend): fix imports in AI module bb-203 --- apps/backend/src/modules/ai-assistant/libs/types/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/types/types.ts b/apps/backend/src/modules/ai-assistant/libs/types/types.ts index 1bf4a9525..7893a3cdc 100644 --- a/apps/backend/src/modules/ai-assistant/libs/types/types.ts +++ b/apps/backend/src/modules/ai-assistant/libs/types/types.ts @@ -1,5 +1,4 @@ export { - type AiAssistantMessageResponseDto, type BalanceWheelAnalysisResponseDto, type ThreadMessageCreateDto, } from "shared"; From 559314b4df3ca7b5b4f9338073f517a5c0507386 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:16:40 +0300 Subject: [PATCH 046/244] feat(frontend): add chatApi bb-340 --- .../src/libs/modules/store/store.module.ts | 5 +++ apps/frontend/src/modules/chat/chat-api.ts | 35 +++++++++++++++ apps/frontend/src/modules/chat/chat.ts | 14 ++++++ .../src/modules/chat/libs/enums/enums.ts | 1 + .../src/modules/chat/libs/types/types.ts | 6 +++ .../src/modules/chat/slices/actions.ts | 18 ++++++++ .../src/modules/chat/slices/chat.slice.ts | 44 +++++++++++++++++++ apps/frontend/src/modules/chat/slices/chat.ts | 10 +++++ packages/shared/src/index.ts | 1 + .../src/modules/ia-assistant/ai-assistant.ts | 1 + ...alance-wheel-analysis-response.dto.type.ts | 2 +- .../modules/ia-assistant/libs/types/types.ts | 5 ++- 12 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 apps/frontend/src/modules/chat/chat-api.ts create mode 100644 apps/frontend/src/modules/chat/chat.ts create mode 100644 apps/frontend/src/modules/chat/libs/enums/enums.ts create mode 100644 apps/frontend/src/modules/chat/libs/types/types.ts create mode 100644 apps/frontend/src/modules/chat/slices/actions.ts create mode 100644 apps/frontend/src/modules/chat/slices/chat.slice.ts create mode 100644 apps/frontend/src/modules/chat/slices/chat.ts diff --git a/apps/frontend/src/libs/modules/store/store.module.ts b/apps/frontend/src/libs/modules/store/store.module.ts index 67b80c765..674c08213 100644 --- a/apps/frontend/src/libs/modules/store/store.module.ts +++ b/apps/frontend/src/libs/modules/store/store.module.ts @@ -10,6 +10,7 @@ import { type Config } from "~/libs/modules/config/config.js"; import { notification } from "~/libs/modules/notification/notification.js"; import { storage } from "~/libs/modules/storage/storage.js"; import { authApi, reducer as authReducer } from "~/modules/auth/auth.js"; +import { chatApi, reducer as chatReducer } from "~/modules/chat/chat.js"; import { onboardingApi, reducer as onboardingReducer, @@ -21,6 +22,7 @@ import { handleErrorMiddleware } from "./handle-error.middleware.js"; type RootReducer = { auth: ReturnType; + chat: ReturnType; onboarding: ReturnType; quiz: ReturnType; users: ReturnType; @@ -28,6 +30,7 @@ type RootReducer = { type ExtraArguments = { authApi: typeof authApi; + chatApi: typeof chatApi; notification: typeof notification; onboardingApi: typeof onboardingApi; quizApi: typeof quizApi; @@ -56,6 +59,7 @@ class Store { }, reducer: { auth: authReducer, + chat: chatReducer, onboarding: onboardingReducer, quiz: quizReducer, users: usersReducer, @@ -66,6 +70,7 @@ class Store { public get extraArguments(): ExtraArguments { return { authApi, + chatApi, notification, onboardingApi, quizApi, diff --git a/apps/frontend/src/modules/chat/chat-api.ts b/apps/frontend/src/modules/chat/chat-api.ts new file mode 100644 index 000000000..78d93be0b --- /dev/null +++ b/apps/frontend/src/modules/chat/chat-api.ts @@ -0,0 +1,35 @@ +import { APIPath, ContentType } from "~/libs/enums/enums.js"; +import { BaseHTTPApi } from "~/libs/modules/api/api.js"; +import { type HTTP } from "~/libs/modules/http/http.js"; +import { type Storage } from "~/libs/modules/storage/storage.js"; + +import { AiAssistantApiPath } from "./libs/enums/enums.js"; +import { type BalanceWheelAnalysisResponseDto } from "./libs/types/types.js"; + +type Constructor = { + baseUrl: string; + http: HTTP; + storage: Storage; +}; + +class ChatApi extends BaseHTTPApi { + public constructor({ baseUrl, http, storage }: Constructor) { + super({ baseUrl, http, path: APIPath.ASSISTANT, storage }); + } + + public async initiateConversation(): Promise { + const response = await this.load( + this.getFullEndpoint(AiAssistantApiPath.INITIATE_THREAD, {}), + { + contentType: ContentType.JSON, + hasAuth: true, + method: "POST", + payload: JSON.stringify({}), + }, + ); + + return await response.json(); + } +} + +export { ChatApi }; diff --git a/apps/frontend/src/modules/chat/chat.ts b/apps/frontend/src/modules/chat/chat.ts new file mode 100644 index 000000000..49147e746 --- /dev/null +++ b/apps/frontend/src/modules/chat/chat.ts @@ -0,0 +1,14 @@ +import { config } from "~/libs/modules/config/config.js"; +import { http } from "~/libs/modules/http/http.js"; +import { storage } from "~/libs/modules/storage/storage.js"; + +import { ChatApi } from "./chat-api.js"; + +const chatApi = new ChatApi({ + baseUrl: config.ENV.API.ORIGIN_URL, + http, + storage, +}); + +export { chatApi }; +export { actions, reducer } from "./slices/chat.js"; diff --git a/apps/frontend/src/modules/chat/libs/enums/enums.ts b/apps/frontend/src/modules/chat/libs/enums/enums.ts new file mode 100644 index 000000000..c79d89039 --- /dev/null +++ b/apps/frontend/src/modules/chat/libs/enums/enums.ts @@ -0,0 +1 @@ +export { AiAssistantApiPath } from "shared"; diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts new file mode 100644 index 000000000..d2396ac62 --- /dev/null +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -0,0 +1,6 @@ +export { + type BalanceWheelAnalysisResponseDto, + type SimplifiedQuizScoreDto, + type TaskDto, + type ThreadMessageCreateDto, +} from "shared"; diff --git a/apps/frontend/src/modules/chat/slices/actions.ts b/apps/frontend/src/modules/chat/slices/actions.ts new file mode 100644 index 000000000..38e4fec7d --- /dev/null +++ b/apps/frontend/src/modules/chat/slices/actions.ts @@ -0,0 +1,18 @@ +import { createAsyncThunk } from "@reduxjs/toolkit"; + +import { type AsyncThunkConfig } from "~/libs/types/types.js"; + +import { type BalanceWheelAnalysisResponseDto } from "../libs/types/types.js"; +import { name as sliceName } from "./chat.slice.js"; + +const initConversation = createAsyncThunk< + BalanceWheelAnalysisResponseDto, + undefined, + AsyncThunkConfig +>(`${sliceName}/init-conversation`, async (_, { extra }) => { + const { chatApi } = extra; + + return await chatApi.initiateConversation(); +}); + +export { initConversation }; diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts new file mode 100644 index 000000000..abbc90ef8 --- /dev/null +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -0,0 +1,44 @@ +import { createSlice } from "@reduxjs/toolkit"; + +import { DataStatus } from "~/libs/enums/enums.js"; +import { type ValueOf } from "~/libs/types/types.js"; + +import { type SimplifiedQuizScoreDto } from "../libs/types/types.js"; +import { initConversation } from "./actions.js"; + +type State = { + dataStatus: ValueOf; + selectedCategories: SimplifiedQuizScoreDto[]; + text: string[]; + threadId: null | string; +}; + +const initialState: State = { + dataStatus: DataStatus.IDLE, + selectedCategories: [], + text: [], + threadId: null, +}; + +const { actions, name, reducer } = createSlice({ + extraReducers(builder) { + builder + .addCase(initConversation.pending, (state) => { + state.dataStatus = DataStatus.PENDING; + }) + .addCase(initConversation.fulfilled, (state, action) => { + state.selectedCategories = action.payload.lowestCategories; + state.threadId = action.payload.threadId; + state.text.push(action.payload.text); + state.dataStatus = DataStatus.FULFILLED; + }) + .addCase(initConversation.rejected, (state) => { + state.dataStatus = DataStatus.REJECTED; + }); + }, + initialState, + name: "chat", + reducers: {}, +}); + +export { actions, name, reducer }; diff --git a/apps/frontend/src/modules/chat/slices/chat.ts b/apps/frontend/src/modules/chat/slices/chat.ts new file mode 100644 index 000000000..6bf923d48 --- /dev/null +++ b/apps/frontend/src/modules/chat/slices/chat.ts @@ -0,0 +1,10 @@ +import { initConversation } from "./actions.js"; +import { actions } from "./chat.slice.js"; + +const allActions = { + ...actions, + initConversation, +}; + +export { allActions as actions }; +export { reducer } from "./chat.slice.js"; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 0c34a2622..8d44a4f14 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -46,6 +46,7 @@ export { AiAssistantApiPath, AiAssistantMessageValidationSchema, type BalanceWheelAnalysisResponseDto, + type SimplifiedQuizScoreDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "./modules/ia-assistant/ai-assistant.js"; diff --git a/packages/shared/src/modules/ia-assistant/ai-assistant.ts b/packages/shared/src/modules/ia-assistant/ai-assistant.ts index 0031beb60..849093fb8 100644 --- a/packages/shared/src/modules/ia-assistant/ai-assistant.ts +++ b/packages/shared/src/modules/ia-assistant/ai-assistant.ts @@ -1,6 +1,7 @@ export { AiAssistantApiPath } from "./libs/enums/enums.js"; export { type BalanceWheelAnalysisResponseDto, + type SimplifiedQuizScoreDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts index 3970af177..9a8d2d93f 100644 --- a/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts +++ b/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -11,4 +11,4 @@ type BalanceWheelAnalysisResponseDto = { threadId: string; }; -export { type BalanceWheelAnalysisResponseDto }; +export { type BalanceWheelAnalysisResponseDto, type SimplifiedQuizScoreDto }; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/types.ts b/packages/shared/src/modules/ia-assistant/libs/types/types.ts index d910e5b65..f23c62aba 100644 --- a/packages/shared/src/modules/ia-assistant/libs/types/types.ts +++ b/packages/shared/src/modules/ia-assistant/libs/types/types.ts @@ -1,3 +1,6 @@ -export { type BalanceWheelAnalysisResponseDto } from "./balance-wheel-analysis-response.dto.type.js"; +export { + type BalanceWheelAnalysisResponseDto, + type SimplifiedQuizScoreDto, +} from "./balance-wheel-analysis-response.dto.type.js"; export { type TaskSuggestionsResponseDto } from "./task-suggestion-response-dto.type.js"; export { type ThreadMessageCreateDto } from "./thread-message-create-dto.type.js"; From 520bb03a9ed42c7e02cab6d056a15b53ec53b5dd Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:26:43 +0300 Subject: [PATCH 047/244] feat(frontend): add chat page with mock data bb-340 --- apps/frontend/src/index.tsx | 10 +++ apps/frontend/src/pages/chat/chat.tsx | 74 +++++++++++++++++++ .../frontend/src/pages/chat/styles.module.css | 13 ++++ 3 files changed, 97 insertions(+) create mode 100644 apps/frontend/src/pages/chat/chat.tsx create mode 100644 apps/frontend/src/pages/chat/styles.module.css diff --git a/apps/frontend/src/index.tsx b/apps/frontend/src/index.tsx index f85e034bd..ff03756e8 100644 --- a/apps/frontend/src/index.tsx +++ b/apps/frontend/src/index.tsx @@ -11,6 +11,7 @@ import { import { AppRoute } from "~/libs/enums/enums.js"; import { store } from "~/libs/modules/store/store.js"; import { Auth } from "~/pages/auth/auth.jsx"; +import { ChatComponent } from "~/pages/chat/chat.jsx"; import { NotFound } from "~/pages/not-found/not-found.jsx"; import { Onboarding } from "~/pages/onboarding/onboarding.jsx"; import { Profile } from "~/pages/profile/profile.jsx"; @@ -76,6 +77,15 @@ createRoot(document.querySelector("#root") as HTMLElement).render( ), path: AppRoute.ONBOARDING, }, + { + element: ( + } + redirectTo={AppRoute.SIGN_IN} + /> + ), + path: "/chat", + }, ], element: , path: AppRoute.ROOT, diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx new file mode 100644 index 000000000..13781c68d --- /dev/null +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -0,0 +1,74 @@ +import { + useAppDispatch, + // useAppSelector, + useEffect, +} from "~/libs/hooks/hooks.js"; +import { actions as chatActions } from "~/modules/chat/chat.js"; + +import { UserWheel } from "../root/components/components.js"; +import styles from "./styles.module.css"; + +const ChatComponent: React.FC = () => { + const dispatch = useAppDispatch(); + + // const { selectedCategories, threadId } = useAppSelector(({ chat }) => ({ + // selectedCategories: chat.selectedCategories, + // // messages: chat.messages, + // threadId: chat.threadId, + // })); + const messages = [ + { + text: "Hello, Julia! I appreciate you sharing your insights about your life areas through the Wheel of Balance. Here's a quick summary of your scores: - **Physical**: 10 (Great satisfaction!) - **Work**: 4 (Room for improvement) - **Friends**: 3 (Needs attention) - **Love**: 6 (Moderately satisfied) - **Money**: 7 (Fairly satisfied) - **Free time**: 5 (Average satisfaction) - **Spiritual**: 6 (Moderately satisfied) - **Mental**: 5 (Average satisfaction) From your scores, it seems that areas you might want to focus on for improvement are: 1. **Friends** (score: 3) 2. **Work** (score: 4) 3. **Free Time** (score: 5) These categories are where you rated the lowest, suggesting they might benefit from your attention and efforts. Now, I am here to support you!", + threadId: "thread_yUq8ZOtYGNqXEiCyKhKsEwUT", + type: "wheelAnalys", + }, + { + buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], + text: "How would you like to proceed with improving your balance? Do you want to work on 3 fields, with the lowest score, or you want to choose the fields yourself to work on?", + type: "suggestionButtons", + }, + { + lowestCategories: [ + { categoryId: 3, categoryName: "Friends", score: 3 }, + { categoryId: 2, categoryName: "Work", score: 4 }, + { categoryId: 6, categoryName: "Free time", score: 5 }, + ], + text: "Choose the fields yourself to work on?", + type: "categoryInputs", + }, + { + buttonLabels: [ + "Everything is clear", + "Give me more info", + "I don't like this tasks", + ], + text: "Here is your task list", + type: "taskList", + }, + ]; + + useEffect(() => { + void dispatch(chatActions.initConversation()); + }, [dispatch]); + + return ( +
+
    + {messages.map((mesage) => ( +
  • + {mesage.text} + {mesage.type === "wheelAnalys" && } + {mesage.type === "suggestionButtons" && + mesage.buttonLabels && + mesage.buttonLabels.map((button: string) => ( + + ))} + {/* {mesage.type === "categoryInputs" && } */} +
  • + ))} +
+
+ ); +}; + +export { ChatComponent }; diff --git a/apps/frontend/src/pages/chat/styles.module.css b/apps/frontend/src/pages/chat/styles.module.css new file mode 100644 index 000000000..fee68ab22 --- /dev/null +++ b/apps/frontend/src/pages/chat/styles.module.css @@ -0,0 +1,13 @@ +.container { + display: flex; + flex-direction: column; + gap: 10px; +} + +.message-container { + max-width: 620px; + padding: 13px; + background-color: #f6f5fa; + + /* border-radius: 0px 10px 10px; */ +} From 0f1bfbd159709e6978245554c5e3d97f136feb1e Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:28:22 +0300 Subject: [PATCH 048/244] fix(backend): threadId bb-340 --- .../generate-scores-response/generate-scores-response.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts index 2e05597ee..116b1eb47 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts @@ -36,7 +36,7 @@ const generateScoresResponse = ( score: category.score, })), text: balanceData.answer, - threadId: message.id, + threadId: message.thread_id, }; } From f3e16c9daaa94356bf28fa946b198558ba2937ad Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:29:21 +0300 Subject: [PATCH 049/244] refactor(frontend): chat state bb-340 --- apps/frontend/src/modules/chat/slices/chat.slice.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index abbc90ef8..75c550a7e 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -8,15 +8,15 @@ import { initConversation } from "./actions.js"; type State = { dataStatus: ValueOf; + messages: string[]; selectedCategories: SimplifiedQuizScoreDto[]; - text: string[]; threadId: null | string; }; const initialState: State = { dataStatus: DataStatus.IDLE, + messages: [], selectedCategories: [], - text: [], threadId: null, }; @@ -29,7 +29,7 @@ const { actions, name, reducer } = createSlice({ .addCase(initConversation.fulfilled, (state, action) => { state.selectedCategories = action.payload.lowestCategories; state.threadId = action.payload.threadId; - state.text.push(action.payload.text); + state.messages.push(action.payload.text); state.dataStatus = DataStatus.FULFILLED; }) .addCase(initConversation.rejected, (state) => { From 175c4e05e9cb9ce914009141dd26a636f4203659 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:31:56 +0300 Subject: [PATCH 050/244] refactor(frontend): add taskList to data bb-340 --- apps/frontend/src/pages/chat/chat.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 13781c68d..1eba1f193 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -42,6 +42,7 @@ const ChatComponent: React.FC = () => { "Give me more info", "I don't like this tasks", ], + taskList: [{}, {}, {}], text: "Here is your task list", type: "taskList", }, From 88e3f008a469061077677fb6a6b0d1e77629f47d Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:07:34 +0300 Subject: [PATCH 051/244] feat(frontend): add type for message array bb-340 --- apps/frontend/src/modules/chat/slices/chat.slice.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 75c550a7e..564ec9548 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -3,12 +3,13 @@ import { createSlice } from "@reduxjs/toolkit"; import { DataStatus } from "~/libs/enums/enums.js"; import { type ValueOf } from "~/libs/types/types.js"; +import { type Message } from "../libs/types/message.type.js"; import { type SimplifiedQuizScoreDto } from "../libs/types/types.js"; import { initConversation } from "./actions.js"; type State = { dataStatus: ValueOf; - messages: string[]; + messages: Message[]; selectedCategories: SimplifiedQuizScoreDto[]; threadId: null | string; }; @@ -29,7 +30,10 @@ const { actions, name, reducer } = createSlice({ .addCase(initConversation.fulfilled, (state, action) => { state.selectedCategories = action.payload.lowestCategories; state.threadId = action.payload.threadId; - state.messages.push(action.payload.text); + state.messages.push({ + ...action.payload, + type: "wheelAnalysis", + }); state.dataStatus = DataStatus.FULFILLED; }) .addCase(initConversation.rejected, (state) => { From 549ef88c5addd8fae1f7e2edea60df6ac2ca4607 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:08:43 +0300 Subject: [PATCH 052/244] feat(frontend): add messageComponent bb-340 --- .../modules/chat/libs/types/message.type.ts | 18 +++ apps/frontend/src/pages/chat/chat.tsx | 119 ++++++++++-------- .../components/chat-message/chat-message.tsx | 62 +++++++++ .../components/chat-message/styles.module.css | 13 ++ 4 files changed, 157 insertions(+), 55 deletions(-) create mode 100644 apps/frontend/src/modules/chat/libs/types/message.type.ts create mode 100644 apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx create mode 100644 apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css diff --git a/apps/frontend/src/modules/chat/libs/types/message.type.ts b/apps/frontend/src/modules/chat/libs/types/message.type.ts new file mode 100644 index 000000000..8aee654c5 --- /dev/null +++ b/apps/frontend/src/modules/chat/libs/types/message.type.ts @@ -0,0 +1,18 @@ +import { type TaskDto } from "shared"; + +type ButtonLabels = string[]; + +type Message = { + buttonLabels?: ButtonLabels; + lowestCategories?: Array<{ + categoryId: number; + categoryName: string; + score: number; + }>; + taskList?: TaskDto[]; + text: string; + threadId?: string; + type: "categoryInputs" | "suggestionButtons" | "taskList" | "wheelAnalysis"; +}; + +export { type Message }; diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 2477159f6..e4d68a526 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -1,54 +1,66 @@ -import { QuizCategoriesForm } from "~/libs/components/components.js"; import { useAppDispatch, - // useAppSelector, + useAppSelector, useCallback, useEffect, } from "~/libs/hooks/hooks.js"; import { actions as chatActions } from "~/modules/chat/chat.js"; +import { actions as quizActions } from "~/modules/quiz/quiz.js"; -import { UserWheel } from "../root/components/components.js"; +import { ChatMessage } from "./libs/components/chat-message/chat-message.js"; import styles from "./styles.module.css"; const ChatComponent: React.FC = () => { const dispatch = useAppDispatch(); - // const { selectedCategories, threadId } = useAppSelector(({ chat }) => ({ - // selectedCategories: chat.selectedCategories, - // // messages: chat.messages, - // threadId: chat.threadId, - // })); - const messages = [ - { - text: "Hello, Julia! I appreciate you sharing your insights about your life areas through the Wheel of Balance. Here's a quick summary of your scores: - **Physical**: 10 (Great satisfaction!) - **Work**: 4 (Room for improvement) - **Friends**: 3 (Needs attention) - **Love**: 6 (Moderately satisfied) - **Money**: 7 (Fairly satisfied) - **Free time**: 5 (Average satisfaction) - **Spiritual**: 6 (Moderately satisfied) - **Mental**: 5 (Average satisfaction) From your scores, it seems that areas you might want to focus on for improvement are: 1. **Friends** (score: 3) 2. **Work** (score: 4) 3. **Free Time** (score: 5) These categories are where you rated the lowest, suggesting they might benefit from your attention and efforts. Now, I am here to support you!", - threadId: "thread_yUq8ZOtYGNqXEiCyKhKsEwUT", - type: "wheelAnalys", - }, - { - buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], - text: "How would you like to proceed with improving your balance? Do you want to work on 3 fields, with the lowest score, or you want to choose the fields yourself to work on?", - type: "suggestionButtons", - }, - { - lowestCategories: [ - { categoryId: 3, categoryName: "Friends", score: 3 }, - { categoryId: 2, categoryName: "Work", score: 4 }, - { categoryId: 6, categoryName: "Free time", score: 5 }, - ], - text: "Choose the fields yourself to work on?", - type: "categoryInputs", - }, - { - buttonLabels: [ - "Everything is clear", - "Give me more info", - "I don't like this tasks", - ], - taskList: [{}, {}, {}], - text: "Here is your task list", - type: "taskList", - }, - ]; + const { scores } = useAppSelector((state) => state.quiz); + const chartData = scores.map((score) => { + return { + data: score.score, + label: score.categoryName, + }; + }); + + useEffect(() => { + void dispatch(quizActions.getScores()); + }, [dispatch]); + + const { messages } = useAppSelector(({ chat }) => ({ + messages: chat.messages, + selectedCategories: chat.selectedCategories, + threadId: chat.threadId, + })); + // const messages = [ + // { + // text: "Hello, Julia! I appreciate you sharing your insights about your life areas through the Wheel of Balance. Here's a quick summary of your scores: - **Physical**: 10 (Great satisfaction!) - **Work**: 4 (Room for improvement) - **Friends**: 3 (Needs attention) - **Love**: 6 (Moderately satisfied) - **Money**: 7 (Fairly satisfied) - **Free time**: 5 (Average satisfaction) - **Spiritual**: 6 (Moderately satisfied) - **Mental**: 5 (Average satisfaction) From your scores, it seems that areas you might want to focus on for improvement are: 1. **Friends** (score: 3) 2. **Work** (score: 4) 3. **Free Time** (score: 5) These categories are where you rated the lowest, suggesting they might benefit from your attention and efforts. Now, I am here to support you!", + // threadId: "thread_yUq8ZOtYGNqXEiCyKhKsEwUT", + // type: "wheelAnalysis", + // }, + // { + // buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], + // text: "How would you like to proceed with improving your balance? Do you want to work on 3 fields, with the lowest score, or you want to choose the fields yourself to work on?", + // type: "suggestionButtons", + // }, + // { + // lowestCategories: [ + // { categoryId: 3, categoryName: "Friends", score: 3 }, + // { categoryId: 2, categoryName: "Work", score: 4 }, + // { categoryId: 6, categoryName: "Free time", score: 5 }, + // ], + // text: "Choose the fields yourself to work on?", + // type: "categoryInputs", + // }, + // { + // buttonLabels: [ + // "Everything is clear", + // "Give me more info", + // "I don't like this tasks", + // ], + // taskList: [{}, {}, {}], + // text: "Here is your task list", + // type: "taskList", + // }, + // ]; useEffect(() => { void dispatch(chatActions.initConversation()); @@ -62,22 +74,19 @@ const ChatComponent: React.FC = () => {
    - {messages.map((mesage) => ( -
  • - {mesage.text} - {mesage.type === "wheelAnalys" && } - {mesage.type === "suggestionButtons" && - mesage.buttonLabels && - mesage.buttonLabels.map((button: string) => ( - - ))} - {mesage.type === "categoryInputs" && ( - - )} -
  • + {messages.map((message) => ( + ))}
diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx new file mode 100644 index 000000000..53210b8e8 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -0,0 +1,62 @@ +import { + BalanceWheelChart, + QuizCategoriesForm, +} from "~/libs/components/components.js"; + +import styles from "./styles.module.css"; + +type Properties = { + buttonLabels?: string[]; + contentData: { data: number; label: string }[]; + onSubmit?: (() => void) | undefined; + text: string; + type: string; + // type: "wheelAnalysis" | "suggestionButtons" | "categoryInputs" | "taskList"; +}; + +const ChatMessage: React.FC = ({ + buttonLabels = [], + contentData, + onSubmit, + text, + type, +}: Properties) => { + const renderContent = (): JSX.Element | null => { + switch (type) { + case "categoryInputs": { + return onSubmit ? ( + + ) : null; + } + + case "suggestionButtons": { + return ( + <> + {buttonLabels.map((button: string) => ( + + ))} + + ); + } + + case "wheelAnalysis": { + return ; + } + + default: { + return null; + } + } + }; + + const content = renderContent(); + + return ( +
  • + {text} + {content} +
  • + ); +}; + +export { ChatMessage }; diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css new file mode 100644 index 000000000..fee68ab22 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css @@ -0,0 +1,13 @@ +.container { + display: flex; + flex-direction: column; + gap: 10px; +} + +.message-container { + max-width: 620px; + padding: 13px; + background-color: #f6f5fa; + + /* border-radius: 0px 10px 10px; */ +} From 218e5621a39af8437f4a8cf012278f8fb3801cd2 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:04:11 +0100 Subject: [PATCH 053/244] refactor(shared): change Assistant Api Path bb-203 --- .../libs/enums/ai-assistant-api-path.enum.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts new file mode 100644 index 000000000..375d6d35d --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -0,0 +1,10 @@ +const AiAssistantApiPath = { + ADD_MESSAGE: "/chat/add-message", + CONTINUE_CHAT: "/chat/continue", + DELETE_CHAT: "/chat/remove", + GENERATE_ALTERNATIVE_TASK: "/chat/generate-alternative-task", + INIT_NEW_CHAT: "/chat/initiate", + SUGGEST_TASKS: "/chat/suggest-tasks", +} as const; + +export { AiAssistantApiPath }; From 68c8dea4a9de605b1fdd8071e53fd9f4df0e6e71 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:09:59 +0100 Subject: [PATCH 054/244] feat(shared): add TaskSuggestionsResponseDto bb-203 --- .../libs/types/task-suggestion-response-dto.type.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts new file mode 100644 index 000000000..d7b4c59af --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts @@ -0,0 +1,13 @@ +import { type TaskDto } from "../../../tasks/libs/types/types.js"; + +type SimplifiedTaskDto = Omit< + TaskDto, + "createdAt" | "id" | "status" | "updatedAt" | "userId" +>; + +type TaskSuggestionsResponseDto = { + message: string; + tasks: SimplifiedTaskDto[]; +}; + +export { type TaskSuggestionsResponseDto }; From da1ddcefb7f5017afe8fbf3a449c4a6a75d86d2a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:10:45 +0100 Subject: [PATCH 055/244] feat(shared): add TaskSuggestionRequestDto bb-203 --- .../libs/types/task-suggestion-request-dto.type.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts new file mode 100644 index 000000000..4a5e7512f --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts @@ -0,0 +1,11 @@ +type SelectedCategories = { + categoryId: string; + name: string; +}; + +type TaskSuggestionRequestDto = { + categories: SelectedCategories[]; + threadId: string; +}; + +export { type SelectedCategories, type TaskSuggestionRequestDto }; From 72893a57f7fa0760c5efaa1208682efefc37590f Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:12:02 +0100 Subject: [PATCH 056/244] feat(shared): add TaskSuggestionRequest validation bb-203 --- ...sk-suggestion-request.validation-schema.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts new file mode 100644 index 000000000..383ae65e2 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -0,0 +1,38 @@ +import { z } from "zod"; + +import { + AiAssistantValidationMessage, + AiAssistantValidationRule, +} from "../enums/enums.js"; + +const TaskSuggestionRequest = z.object({ + categories: z + .array( + z.object({ + categoryId: z + .string() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, + }), + name: z + .string() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, + }), + }), + ) + .nonempty({ + message: AiAssistantValidationMessage.CATEGORIES_REQUIRED, + }), + threadId: z + .string() + .trim() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, + }) + .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + }), +}); + +export { TaskSuggestionRequest }; From 45f30b6ccb99c7a69fd405b0d9d52e8c50f102c0 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:13:26 +0100 Subject: [PATCH 057/244] feat(shared): add BalanceWheelAnalysisResponseDto bb-203 --- .../balance-wheel-analysis-response.dto.type.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts new file mode 100644 index 000000000..c169a1204 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -0,0 +1,17 @@ +import { type QuizScoresGetAllItemResponseDto } from "../../../quiz/quiz.js"; + +type SimplifiedQuizScoreDto = Omit< + QuizScoresGetAllItemResponseDto, + "createdAt" | "id" | "updatedAt" | "userId" +>; + +type BalanceWheelAnalysisResponseDto = { + lowestCategories: SimplifiedQuizScoreDto[]; + messages: { + comments: string; + greeting: string; + }; + threadId: string; +}; + +export { type BalanceWheelAnalysisResponseDto }; From 23a2f72fdb9df0bce193ddd3368efa3450f9b3db Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:14:21 +0100 Subject: [PATCH 058/244] feat(shared): add AiAssistantValidationRule bb-203 --- .../libs/enums/ai-assistant-validatuon-rule.enum.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts new file mode 100644 index 000000000..6fb01367f --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -0,0 +1,6 @@ +const AiAssistantValidationRule = { + NON_EMPTY_STRING_MIN_LENGTH: 1, + THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, +} as const; + +export { AiAssistantValidationRule }; From bd78d96feb6c5c0f0b05da14d126f545cf3454ea Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:15:46 +0100 Subject: [PATCH 059/244] feat(shared): add AiAssistantValidationMessage bb-203 --- .../libs/enums/ai-assistant-validation-message.enum.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts new file mode 100644 index 000000000..04d54c62d --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts @@ -0,0 +1,10 @@ +const AiAssistantValidationMessage = { + CATEGORIES_REQUIRED: "categories required", + CATEGORY_ID_REQUIRED: "categoryId required", + CATEGORY_NAME_REQUIRED: "categoryName required", + TEXT_REQUIRED: "text required", + THREAD_ID_INVALID_FORMAT: "threadId - invalid format", + THREAD_ID_REQUIRED: "threadId required", +} as const; + +export { AiAssistantValidationMessage }; From 656d5cd3087289c1d97d7cc86c6e3f0102ca89a4 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:16:42 +0100 Subject: [PATCH 060/244] feat(shared): add addMessageToThread validation schema bb-203 --- ...add-message-to-thread.validation-schema.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts new file mode 100644 index 000000000..9b2b96e65 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts @@ -0,0 +1,33 @@ +import { z } from "zod"; + +import { + AiAssistantValidationMessage, + AiAssistantValidationRule, +} from "../enums/enums.js"; + +type AiAssistantMessageCreateDto = { + text: z.ZodString; + threadId: z.ZodString; +}; + +const addMessageToThread = z + .object({ + text: z + .string() + .trim() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.TEXT_REQUIRED, + }), + threadId: z + .string() + .trim() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, + }) + .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + }), + }) + .required(); + +export { addMessageToThread }; From 320990138f89f9c3034c37b16eb87cba8e3d3f2b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:19:47 +0100 Subject: [PATCH 061/244] refactor(shared): refactor export Ai assistant module bb-203 --- .../shared/src/modules/ai-assistant/ai-assistant.ts | 10 ++++++++++ .../src/modules/ai-assistant/libs/enums/enums.ts | 3 +++ .../src/modules/ai-assistant/libs/types/types.ts | 7 +++++++ .../libs/validation-schemas/validation-schemas.ts | 2 ++ 4 files changed, 22 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/ai-assistant.ts create mode 100644 packages/shared/src/modules/ai-assistant/libs/enums/enums.ts create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/types.ts create mode 100644 packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts diff --git a/packages/shared/src/modules/ai-assistant/ai-assistant.ts b/packages/shared/src/modules/ai-assistant/ai-assistant.ts new file mode 100644 index 000000000..0b7cb9fe1 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/ai-assistant.ts @@ -0,0 +1,10 @@ +export { AiAssistantApiPath } from "./libs/enums/enums.js"; +export { + type BalanceWheelAnalysisResponseDto, + type SelectedCategories, + type TaskSuggestionRequestDto, + type TaskSuggestionsResponseDto, + type ThreadMessageCreateDto, +} from "./libs/types/types.js"; +export { addMessageToThread as addMessageToThreadValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; +export { TaskSuggestionRequest as TaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts b/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts new file mode 100644 index 000000000..a7003a6f4 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts @@ -0,0 +1,3 @@ +export { AiAssistantApiPath } from "./ai-assistant-api-path.enum.js"; +export { AiAssistantValidationMessage } from "./ai-assistant-validation-message.enum.js"; +export { AiAssistantValidationRule } from "./ai-assistant-validatuon-rule.enum.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/types.ts b/packages/shared/src/modules/ai-assistant/libs/types/types.ts new file mode 100644 index 000000000..157b3de5a --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/types.ts @@ -0,0 +1,7 @@ +export { type BalanceWheelAnalysisResponseDto } from "./balance-wheel-analysis-response.dto.type.js"; +export { + type SelectedCategories, + type TaskSuggestionRequestDto, +} from "./task-suggestion-request-dto.type.js"; +export { type TaskSuggestionsResponseDto } from "./task-suggestion-response-dto.type.js"; +export { type ThreadMessageCreateDto } from "./thread-message-create-dto.type.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts new file mode 100644 index 000000000..38ef21372 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -0,0 +1,2 @@ +export { addMessageToThread } from "./add-message-to-thread.validation-schema.js"; +export { TaskSuggestionRequest } from "./task-suggestion-request.validation-schema.js"; From 0c59900ee94425bfabff8fd7e064b2851cbd70ff Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:21:32 +0100 Subject: [PATCH 062/244] feat(shared): add ThreadMessageCreateDto bb-203 --- .../libs/types/thread-message-create-dto.type.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/thread-message-create-dto.type.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/types/thread-message-create-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/thread-message-create-dto.type.ts new file mode 100644 index 000000000..5a70bff8e --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/thread-message-create-dto.type.ts @@ -0,0 +1,6 @@ +type ThreadMessageCreateDto = { + text: string; + threadId: string; +}; + +export { type ThreadMessageCreateDto }; From 8f47073e0387d6cab4c08dbb6e645384b4ad0353 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:25:01 +0100 Subject: [PATCH 063/244] refactor(backend): change AnalyzeBalanceScoresTool function bb-203 --- .../analyze-balance-scores-tool.ts | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts new file mode 100644 index 000000000..f26921a53 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts @@ -0,0 +1,103 @@ +const AnalyzeBalanceScoresTool = { + function: { + description: + "Analyzes user's life balance scores and identifies the three lowest categories with suggestions for improvement.", + name: "analyze_balance_scores", + parameters: { + additionalProperties: false, + properties: { + categories: { + description: "Array of categories with user scores", + items: { + additionalProperties: false, + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "string", + }, + categoryName: { + description: "The name of the category (e.g., Health, Work)", + type: "string", + }, + score: { + description: "The user's score for this category, from 1 to 10", + type: "number", + }, + }, + required: ["categoryId", "categoryName", "score"], + type: "object", + }, + type: "array", + }, + context: { + description: "Context explaining the purpose of the analysis", + type: "string", + }, + instructions: { + additionalProperties: false, + properties: { + action: { + description: + "What the assistant should do after identifying the categories (e.g., provide improvement suggestions)", + type: "string", + }, + task: { + description: + "The main task for the assistant (e.g., identify the lowest categories)", + type: "string", + }, + }, + required: ["task", "action"], + type: "object", + }, + response_structure: { + additionalProperties: false, + properties: { + comments: { + description: + "A summary of the balance analysis and the identified areas for improvement.", + type: "string", + }, + greeting: { + description: + "A personalized greeting for the user based on their name, e.g., 'Hello, John!'", + type: "string", + }, + lowestCategories: { + description: + "An array of the three categories where the user scored the lowest, including category ID, name, and score.", + items: { + additionalProperties: false, + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "string", + }, + categoryName: { + description: "The name of the category", + type: "string", + }, + score: { + description: "User's score for the category, from 1 to 10", + type: "number", + }, + }, + required: ["categoryId", "categoryName", "score"], + type: "object", + }, + type: "array", + }, + }, + required: ["greeting", "comments", "lowestCategories"], + type: "object", + }, + }, + required: ["context", "categories", "instructions", "response_structure"], + type: "object", + }, + strict: true, + }, + type: "function", +} as const; + +export { AnalyzeBalanceScoresTool }; From 82bff3d81f476504f4d4739d78357b11463b9c3a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:26:29 +0100 Subject: [PATCH 064/244] refactor(backend): change GenerateTaskByCategoryTool function bb-203 --- .../ai-assistant-tools/ai-assistant-tools.ts | 3 +- .../suggest-task-by-category.tool.ts | 108 ++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/suggest-task-by-category.tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts index 88cdbd52d..b2db3c92d 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts @@ -1 +1,2 @@ -export { AnalyzeBalanceScores } from "./analyze-balance-scores/analyze-balance-scores-tool.js"; +export { AnalyzeBalanceScoresTool } from "./analyze-balance-scores-tool.js"; +export { GenerateTaskByCategoryTool } from "./suggest-task-by-category.tool.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/suggest-task-by-category.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/suggest-task-by-category.tool.ts new file mode 100644 index 000000000..0b7db0c9a --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/suggest-task-by-category.tool.ts @@ -0,0 +1,108 @@ +const GenerateTaskByCategoryTool = { + function: { + description: + "Generates specific and actionable tasks for each user-selected category based on their onboarding responses.", + name: "generate_task_by_category", + parameters: { + additionalProperties: false, + properties: { + categories: { + description: + "Array of categories selected by the user for improvement", + items: { + additionalProperties: false, + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "number", + }, + categoryName: { + description: "The name of the category (e.g., Health, Work)", + type: "string", + }, + }, + required: ["categoryId", "categoryName"], + type: "object", + }, + type: "array", + }, + context: { + description: + "Context explaining the user's goals and the categories they've selected", + type: "string", + }, + instructions: { + additionalProperties: false, + properties: { + action: { + description: + "The steps the assistant should take (e.g., generate tasks, provide descriptions, assign due dates)", + type: "string", + }, + task: { + description: + "The main task for the assistant (e.g., suggest actionable tasks for each category)", + type: "string", + }, + }, + required: ["task", "action"], + type: "object", + }, + response_structure: { + additionalProperties: false, + properties: { + message: { + description: "A message summarizing the task suggestions", + type: "string", + }, + tasks: { + description: "Array of tasks generated for each category", + items: { + additionalProperties: false, + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "number", + }, + categoryName: { + description: "The name of the category", + type: "string", + }, + description: { + description: "Detailed description of the task", + type: "string", + }, + dueDate: { + description: "Suggested due date for the task", + type: "string", + }, + label: { + description: "Label or name of the task", + type: "string", + }, + }, + required: [ + "categoryId", + "categoryName", + "description", + "dueDate", + "label", + ], + type: "object", + }, + type: "array", + }, + }, + required: ["message", "tasks"], + type: "object", + }, + }, + required: ["categories", "context", "instructions", "response_structure"], + type: "object", + }, + strict: true, + }, + type: "function", +} as const; + +export { GenerateTaskByCategoryTool }; From aee714317929facc8c79a704a2af15dd442ca459 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:28:31 +0100 Subject: [PATCH 065/244] feat(backend): add OpenAiFunctionName bb-203 --- .../modules/open-ai/libs/enums/open-ai-function-name.enum.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts new file mode 100644 index 000000000..647f5b2bc --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts @@ -0,0 +1,5 @@ +const OpenAiFunctionName = { + ANALYZE_BALANCE_SCORES: "analyze_balance_scores", + GENERATE_TASK_BY_CATEGORY: "generate_task_by_category", +} as const; +export { OpenAiFunctionName }; From afa1d9cbbccf6ddd904a1a6bf5389a5462cb73e4 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:29:30 +0100 Subject: [PATCH 066/244] refactor(backend): change OpenAiPromptTemplates Message bb-203 --- .../enums/open-ai-prompt-messages.enum.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts new file mode 100644 index 000000000..60b73fae8 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts @@ -0,0 +1,22 @@ +const OpenAiPromptTemplates = { + ASSISTANT_INSTRUCTION: ` +You are an instructor responsible for analyzing the user's preferences and scores based on the Wheel of Balance. +The Wheel of Balance helps the user prioritize various areas of their life, such as health, career, relationships, +and personal hobbies. + +Your role is to: +1. Analyze the user's quiz results from the Wheel of Balance to identify areas where the user seeks improvement. +2. Based on the user's answers and scores, generate specific, actionable tasks to help them achieve greater balance +and growth in these areas. +3. Ensure that the recommended tasks are practical, motivating, and aligned with the user's personal goals and preferences. + +Always maintain a positive and supportive tone. Encourage the user to achieve balanced personal growth across +different life areas, track their progress, and celebrate small achievements. Your recommendations should be clear, +motivating, and focused on helping the user improve the areas of life they prioritize. + +At this stage, focus on understanding the user's preferences and scores from the Wheel of Balance. +After this stage, you will generate appropriate tasks for improvement later. +`, +} as const; + +export { OpenAiPromptTemplates }; From 95f290e56f432763c0c345e6d5ecbd321e79eea6 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:30:34 +0100 Subject: [PATCH 067/244] feat(backend): add OpenAiRunThreadRequestDto type bb-203 --- .../types/open-ai-run-thread-request-dto.type.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts b/apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts new file mode 100644 index 000000000..210c85746 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts @@ -0,0 +1,15 @@ +import { type MessageCreateParams } from "openai/resources/beta/threads/index"; +import { type ZodSchema } from "zod"; + +import { type OpenAiFunctionName } from "~/libs/modules/open-ai/open-ai.js"; +import { type ValueOf } from "~/libs/types/types.js"; + +type OpenAiRunThreadRequestDto = { + additional_instructions: null | string; + function_name: ValueOf; + instructions: null | string; + messages: MessageCreateParams[]; + validationSchema: ZodSchema; +}; + +export { type OpenAiRunThreadRequestDto }; From dade212767b33890a2c69881eddf7955197a3e35 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:31:27 +0100 Subject: [PATCH 068/244] feat(backend): add AiAssistantMessage validation schema bb-203 --- .../ai-assistant-message.validation-schema.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts new file mode 100644 index 000000000..86f45ed8d --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; + +const AiAssistantMessage = z.object({ + content: z + .array( + z.object({ + text: z.object({ + value: z.string(), + }), + type: z.literal("text"), + }), + ) + .nonempty(), + id: z.string(), +}); + +export { AiAssistantMessage }; From 92a06f8626c7b9e45cad1ab88dfd23ef30f3c0e0 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:34:20 +0100 Subject: [PATCH 069/244] feat(backend): add generate Task method / change API calling bb-203 --- .../libs/modules/open-ai/open-ai.module.ts | 113 ++++++++++++------ 1 file changed, 79 insertions(+), 34 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts index 322d59f22..36b6d68bd 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts @@ -1,6 +1,6 @@ import { OpenAI } from "openai"; +import { zodResponseFormat } from "openai/helpers/zod"; -import { ZERO_INDEX } from "~/libs/constants/constants.js"; import { type Config } from "~/libs/modules/config/config.js"; import { HTTPCode } from "~/libs/modules/http/http.js"; import { type Logger } from "~/libs/modules/logger/logger.js"; @@ -13,11 +13,8 @@ import { OpenAIError } from "./libs/exceptions/exceptions.js"; import { type OpenAiRequestMessage, type OpenAiResponseMessage, + type OpenAiRunThreadRequestDto, } from "./libs/types/types.js"; -import { - BalanceAnalysis, - zodResponseFormat, -} from "./libs/validation-schemas/validation-schemas.js"; type Constructor = { config: Config; @@ -55,7 +52,9 @@ class OpenAi { instructions: OpenAiAssistantConfig.INSTRUCTION, model: this.config.ENV.OPEN_AI.MODEL, name: OpenAiAssistantConfig.NAME, + temperature: OpenAiAssistantConfig.TEMPERATURE, tools: [...OpenAiAssistantConfig.TOOLS], + top_p: OpenAiAssistantConfig.TOP_P, })); this.logger.info( @@ -74,6 +73,57 @@ class OpenAi { } } + private async handleRequiresAction( + run: OpenAI.Beta.Threads.Runs.Run, + functionName: string, + ): Promise { + if (run.required_action) { + await Promise.all( + run.required_action.submit_tool_outputs.tool_calls.map( + async (toolCall) => { + const { function: toolFunction } = toolCall; + + if (toolFunction.name === functionName) { + await this.openAi.beta.threads.runs.submitToolOutputsAndPoll( + run.thread_id, + run.id, + { + tool_outputs: [ + { + output: toolCall.function.arguments, + tool_call_id: toolCall.id, + }, + ], + }, + ); + } + }, + ), + ); + } + } + + private async handleRunStatus( + threadId: string, + run: OpenAI.Beta.Threads.Runs.Run, + functionName: string, + ): Promise { + if (run.status === "completed") { + return await this.getAllMessagesBy(threadId); + } else if (run.status === "requires_action") { + await this.handleRequiresAction(run, functionName); + + return await this.getAllMessagesBy(threadId); + } else { + this.logger.error(`AI Assistant run failed: ${run.status}`); + + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } + } + public async addMessageToThread( threadId: string, message: OpenAiRequestMessage, @@ -121,42 +171,37 @@ class OpenAi { return result.deleted; } - public async generateBalanceAnalysis( - threadId: string, - prompt: OpenAiRequestMessage, - ): Promise { - const response: OpenAiResponseMessage[] = - await this.openAi.beta.threads.runs - .stream(threadId, { - additional_messages: [prompt], - assistant_id: this.assistantId as string, - response_format: zodResponseFormat( - BalanceAnalysis, - "balance_analysis", - ), - stream: true, - }) - .finalMessages(); - - if (response.length === ZERO_INDEX) { - throw new OpenAIError({ - message: OpenAIErrorMessage.WRONG_RESPONSE, - status: HTTPCode.INTERNAL_SERVER_ERROR, - }); - } - - return response; - } - public async getAllMessagesBy( threadId: string, - ): Promise> { + ): Promise { return await this.openAi.beta.threads.messages.list(threadId); } - public async initializeAssistant(): Promise { + async initializeAssistant(): Promise { this.assistantId = await this.getOrInitializeAssistant(); } + + public async runThread( + threadId: string, + runOptions: OpenAiRunThreadRequestDto, + ): Promise { + const run = await this.openAi.beta.threads.runs.createAndPoll(threadId, { + additional_instructions: runOptions.additional_instructions, + additional_messages: runOptions.messages, + assistant_id: this.assistantId as string, + instructions: runOptions.instructions, + response_format: zodResponseFormat( + runOptions.validationSchema, + "use_response_validation", + ), + tool_choice: { + function: { name: runOptions.function_name }, + type: "function", + }, + }); + + return await this.handleRunStatus(threadId, run, runOptions.function_name); + } } export { OpenAi }; From 6082c75ecb4701a252517f7afc1960a9c85e7f58 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:35:50 +0100 Subject: [PATCH 070/244] refactor(backend): add more settings to OpenAiAssistantConfig bb-203 --- .../libs/enums/open-ai-assistant-config.enum.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts index c5e366c12..edcf06b74 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts @@ -1,10 +1,15 @@ -import { AnalyzeBalanceScores } from "../ai-assistant-tools/ai-assistant-tools.js"; -import { OpenAiPromptTemplates } from "./open-ai-promt-mesagges.enum.js"; +import { + AnalyzeBalanceScoresTool, + GenerateTaskByCategoryTool, +} from "../ai-assistant-tools/ai-assistant-tools.js"; +import { OpenAiPromptTemplates } from "./open-ai-prompt-messages.enum.js"; const OpenAiAssistantConfig = { INSTRUCTION: OpenAiPromptTemplates.ASSISTANT_INSTRUCTION, NAME: "Wheel of Balance Assistant", - TOOLS: [AnalyzeBalanceScores], + TEMPERATURE: 1, + TOOLS: [AnalyzeBalanceScoresTool, GenerateTaskByCategoryTool], + TOP_P: 1, } as const; export { OpenAiAssistantConfig }; From e93fd5160d4782bded11df2db1a6e91cdc5dd05b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:41:36 +0100 Subject: [PATCH 071/244] refactor(backend): refactor open-ai module exports and files bb-203 --- .../analyze-balance-scores-tool.ts | 62 ---------------- .../libs/modules/open-ai/libs/enums/enums.ts | 3 +- .../libs/enums/open-ai-promt-mesagges.enum.ts | 72 ------------------- .../libs/modules/open-ai/libs/types/types.ts | 3 +- .../balance-analysis.validation-schema.ts | 14 ---- .../validation-schemas/validation-schemas.ts | 7 +- .../src/libs/modules/open-ai/open-ai.ts | 13 ++-- 7 files changed, 12 insertions(+), 162 deletions(-) delete mode 100644 apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts delete mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts delete mode 100644 apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts deleted file mode 100644 index 6a89d1bb7..000000000 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores/analyze-balance-scores-tool.ts +++ /dev/null @@ -1,62 +0,0 @@ -const AnalyzeBalanceScores = { - function: { - description: - "Analyzes user's life balance scores and identifies the three lowest categories with suggestions for improvement.", - name: "analyze_balance_scores", - parameters: { - additionalProperties: false, - properties: { - categories: { - description: "Array of categories with user scores", - items: { - additionalProperties: false, - properties: { - categoryId: { - description: "Unique identifier for the category", - type: "string", - }, - categoryName: { - description: "The name of the category (e.g., Health, Work)", - type: "string", - }, - score: { - description: "The user's score for this category, from 1 to 10", - type: "number", - }, - }, - required: ["categoryId", "categoryName", "score"], - type: "object", - }, - type: "array", - }, - context: { - description: "Context explaining the purpose of the analysis", - type: "string", - }, - instructions: { - additionalProperties: false, - properties: { - action: { - description: - "What the assistant should do after identifying the categories (e.g., provide improvement suggestions)", - type: "string", - }, - task: { - description: - "The main task for the assistant (e.g., identify the lowest categories)", - type: "string", - }, - }, - required: ["task", "action"], - type: "object", - }, - }, - required: ["context", "categories", "instructions"], - type: "object", - }, - strict: true, - }, - type: "function", -} as const; - -export { AnalyzeBalanceScores }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts index f233735c5..6d90d83c0 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts @@ -1,4 +1,5 @@ export { OpenAiAssistantConfig } from "./open-ai-assistant-config.enum.js"; export { OpenAIErrorMessage } from "./open-ai-error-message.enum.js"; -export { OpenAiPromptTemplates } from "./open-ai-promt-mesagges.enum.js"; +export { OpenAiFunctionName } from "./open-ai-function-name.enum.js"; +export { OpenAiPromptTemplates } from "./open-ai-prompt-messages.enum.js"; export { OpenAiRoleKey } from "./open-ai-role-key.enum.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts deleted file mode 100644 index cd547eac1..000000000 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-promt-mesagges.enum.ts +++ /dev/null @@ -1,72 +0,0 @@ -const OpenAiPromptTemplates = { - ASSISTANT_INIT_THREAD_INSTRUCTION: ` -The user has completed an onboarding quiz where they prioritized different areas of their life. -Based on the user's answers, you will later recommend specific tasks to help them improve in areas such as health, -career, relationships, or personal hobbies. - -Always keep in mind the user's preferences and encourage balanced personal growth. -Be supportive, track the user's progress, and celebrate small achievements. - -Instructions: -1. Carefully analyze the provided questions and the user's selected answers. -2. Identify the key areas of importance for the user, such as health, career, relationships, or other aspects of life based on their responses. -3. Ensure a thorough understanding of the user's answers. - -At this stage, no actions or responses are required. -`, - ASSISTANT_INSTRUCTION: ` -You are an instructor responsible for analyzing the user's preferences and scores based on the Wheel of Balance. -The Wheel of Balance helps the user prioritize various areas of their life, such as health, career, relationships, -and personal hobbies. - -Your role is to: -1. Analyze the user's quiz results from the Wheel of Balance to identify areas where the user seeks improvement. -2. Based on the user's answers and scores, generate specific, actionable tasks to help them achieve greater balance -and growth in these areas. -3. Ensure that the recommended tasks are practical, motivating, and aligned with the user's personal goals and preferences. - -Always maintain a positive and supportive tone. Encourage the user to achieve balanced personal growth across -different life areas, track their progress, and celebrate small achievements. Your recommendations should be clear, -motivating, and focused on helping the user improve the areas of life they prioritize. - -At this stage, focus on understanding the user's preferences and scores from the Wheel of Balance. -After this stage, you will generate appropriate tasks for improvement later. -`, - WHEEL_OF_BALANCE_CONTEXT: ` -You are an assistant helping the user balance different aspects of their life.The user is engaging with -the "Wheel of Balance," which consists of eight categories that represent different areas of life: - -1. Physical -2. Work -3. Friends -4. Love -5. Money -6. Free time -7. Spiritual -8. Mental - -Each of these categories is rated by the user on a scale from 1 to 10: -- 1 indicates that the user is least satisfied or struggling the most in this area. -- 10 indicates that the user is completely satisfied or excelling in this area. - -After this context, a structured array of categories will be provided. Each category will include: -- \`categoryName\` (a string): the name of the life area (e.g., "Physical", "Work"). -- \`score\` (a number between 1 and 10): the user's rating for that category, where 1 represents low satisfaction -and 10 represents high satisfaction. -`, - WHEEL_OF_BALANCE_INSTRUCTIONS: ` -task: "Your role is to analyze the user's ratings in these categories, identify areas where the user needs improvement, -and later recommend tasks to help them achieve better balance in life. Do not provide tasks at this stage. - -Focus on the categories that the user has rated the lowest, as these are likely the areas where they -seek the most improvement." - -action: "Your first task is to ask the user how they would like to proceed with improving their balance. -Always present the following question to the user in this task: - -'Would you like to focus on improving the three areas with the lowest scores in your Wheel of Balance, -or would you prefer to choose the areas yourself to work on?'" -`, -} as const; - -export { OpenAiPromptTemplates }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/types/types.ts b/apps/backend/src/libs/modules/open-ai/libs/types/types.ts index b1c99fa11..5cefce1c6 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/types/types.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/types/types.ts @@ -1,2 +1,3 @@ +export { type OpenAiRunThreadRequestDto } from "./open-ai-run-thread-request-dto.type.js"; export { type MessageCreateParams as OpenAiRequestMessage } from "openai/resources/beta/threads/index"; -export { type Message as OpenAiResponseMessage } from "openai/resources/beta/threads/index"; +export { type MessagesPage as OpenAiResponseMessage } from "openai/resources/beta/threads/index"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts deleted file mode 100644 index ebfdf7839..000000000 --- a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/balance-analysis.validation-schema.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from "zod"; - -const Category = z.object({ - categoryId: z.string(), - categoryName: z.string(), - score: z.number(), -}); - -const BalanceAnalysis = z.object({ - answer: z.string(), - lowestCategories: z.array(Category), -}); - -export { BalanceAnalysis }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts index 7c5c6c053..a51134a11 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts @@ -1,6 +1 @@ -export { BalanceAnalysis } from "./balance-analysis.validation-schema.js"; -export { zodResponseFormat } from "openai/helpers/zod"; -export { - addMessageToThreadValidationSchema, - AiAssistantMessageValidationSchema, -} from "shared"; +export { AiAssistantMessage as AiAssistantMessageValidationSchema } from "./ai-assistant-message.validation-schema.js"; diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.ts b/apps/backend/src/libs/modules/open-ai/open-ai.ts index 3d1acce40..402bf4915 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.ts @@ -11,14 +11,15 @@ const openAi = new OpenAi({ await openAi.initializeAssistant(); export { openAi }; -export { OpenAiPromptTemplates, OpenAiRoleKey } from "./libs/enums/enums.js"; +export { + OpenAiFunctionName, + OpenAiPromptTemplates, + OpenAiRoleKey, +} from "./libs/enums/enums.js"; export { type OpenAiRequestMessage, type OpenAiResponseMessage, + type OpenAiRunThreadRequestDto, } from "./libs/types/types.js"; -export { - addMessageToThreadValidationSchema, - AiAssistantMessageValidationSchema, - BalanceAnalysis, -} from "./libs/validation-schemas/validation-schemas.js"; +export { AiAssistantMessageValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { type OpenAi } from "./open-ai.module.js"; From 8085512265cd4eae6754da7df0517fda7ddeec53 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:44:08 +0100 Subject: [PATCH 072/244] feat(backend): add init chat functionality bb-203 --- .../balance-analysis.validation-schema.ts | 19 ++++ .../generate-init-promt-message.enum.ts | 87 +++++++++++++++++++ .../generate-questions-answers-prompt.ts | 40 +++++++++ .../initial-chat/generate-scores-prompt.ts | 32 +++++++ .../initial-chat/generate-scores-response.ts | 49 +++++++++++ .../libs/helpers/initial-chat/initial-chat.ts | 32 +++++++ 6 files changed, 259 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts new file mode 100644 index 000000000..0cb19da87 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -0,0 +1,19 @@ +import { z } from "zod"; + +const Category = z.object({ + categoryId: z.string(), + categoryName: z.string(), + score: z.number(), +}); + +const Messages = z.object({ + comments: z.string(), + greeting: z.string(), +}); + +const BalanceAnalysis = z.object({ + lowestCategories: z.array(Category), + messages: Messages, +}); + +export { BalanceAnalysis }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts new file mode 100644 index 000000000..eb4b709bf --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts @@ -0,0 +1,87 @@ +const OpenAiInitialPromptTemplates = { + INIT_CHAT_CONTENT: ` +The user has completed an onboarding quiz where they prioritized different areas of their life. +Based on the user's answers, you will later recommend specific tasks to help user improve in areas such as health, +career, relationships, or personal hobbies. + +Always keep in mind the user's preferences and encourage balanced personal growth. +Be supportive, track the user's progress, and celebrate small achievements. +Here are the questions and the user's answers: +`, + INIT_CHAT_INSTRUCTION: ` +1. Carefully analyze the provided questions and the user's selected answers. +2. Identify the key areas of importance for the user, such as health, career, relationships, or other aspects of life based on their responses. +3. Ensure a thorough understanding of the user's answers. + +Make sure to analyze these answers carefully, as they will inform future task recommendations. +At this stage, no actions or responses are required. +`, + WHEEL_OF_BALANCE_CONTEXT: ` +You are an assistant helping the user balance different aspects of their life.The user is engaging with +the "Wheel of Balance," which consists of eight categories that represent different areas of life: + +1. Physical +2. Work +3. Friends +4. Love +5. Money +6. Free time +7. Spiritual +8. Mental + +Each of these categories is rated by the user on a scale from 1 to 10: +- 1 indicates that the user is least satisfied or struggling the most in this area. +- 10 indicates that the user is completely satisfied or excelling in this area. + +After this context, a structured array of categories will be provided. Each category will include: +- \`categoryName\` (a string): the name of the life area (e.g., "Physical", "Work"). +- \`score\` (a number between 1 and 10): the user's rating for that category, where 1 represents low satisfaction +and 10 represents high satisfaction. +`, + WHEEL_OF_BALANCE_INSTRUCTIONS: ` +task: +Your role is to analyze the user's ratings in these categories, identify areas where the user needs improvement, +and later recommend tasks to help them achieve better balance in life. Do not provide tasks at this stage. + +Focus on the categories that the user has rated the lowest, as these are likely the areas where they +seek the most improvement. + +response_structure: +{ + messages: { // A section containing the greeting and comments + greeting: string, // A friendly and motivational greeting that uses the user's name. + comments: string // A summary of the analysis and a motivational question for the user. + }, + lowestCategories: [ // An array containing the three categories with the lowest scores. + { + categoryId: string, // Unique identifier of the category. + categoryName: string, // Name of the category. + score: number // The user's score for the category. + } + ] +} + +action: +1. Your first task is to greet the user using their name. The greeting should be friendly, motivational, and supportive. +The goal is to make the user feel welcome and encouraged as they begin their journey toward better balance in life. +Ensure the greeting is short, positive, and personal. Use the user’s name, {{userName}}, to make it feel more engaging. +Place the greeting in the \`greeting\` field of the response. + +2.Your second task is to provide a brief summary of the user's Wheel of Balance analysis. Highlight that the analysis +has identified the three areas where the user scored the lowest, which represent areas for potential improvement. + +Keep the explanation concise but clear, avoiding unnecessary details. +At the end of your response, include the following question: +'Would you like to focus on improving the three areas with the lowest scores in your Wheel of Balance, +or would you prefer to choose the areas yourself to work on?' + +Place this explanation and question in the \`comments\` field of the response. + +3.Your third task is to identify the three categories with the lowest scores in the user's Wheel of Balance analysis. +Select these categories and provide them in a structured format, listing the category ID, category name, and score. + +Ensure this data is placed in the \`lowestCategories\` field of the response. +`, +} as const; + +export { OpenAiInitialPromptTemplates }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts new file mode 100644 index 000000000..71c4c15da --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts @@ -0,0 +1,40 @@ +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { + type OpenAiRequestMessage, + OpenAiRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; +import { type OnboardingQuestionEntity } from "~/modules/onboarding/onboarding.js"; + +import { OpenAiInitialPromptTemplates } from "./generate-init-promt-message.enum.js"; + +function generateQuestionsAnswersPrompt( + userQuestionsWithAnswers: OnboardingQuestionEntity[], +): OpenAiRequestMessage { + const questionsWithAnswers = userQuestionsWithAnswers.map( + (questionEntity) => { + const { answers, label: question } = questionEntity.toObject(); + const answer = answers[ZERO_INDEX]?.label; + + return { answer, question }; + }, + ); + + /* eslint-disable perfectionist/sort-objects */ + const promptContent = { + context: OpenAiInitialPromptTemplates.INIT_CHAT_CONTENT, + user_answers: questionsWithAnswers + .map( + ({ answer, question }) => + `- Question: ${question}\nAnswer: ${answer as string}`, + ) + .join("\n"), + instructions: OpenAiInitialPromptTemplates.INIT_CHAT_INSTRUCTION, + }; + + return { + content: JSON.stringify(promptContent), + role: OpenAiRoleKey.USER, + }; +} + +export { generateQuestionsAnswersPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts new file mode 100644 index 000000000..e0a997568 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -0,0 +1,32 @@ +import { + type OpenAiRequestMessage, + OpenAiRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; +import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; + +import { OpenAiInitialPromptTemplates } from "./generate-init-promt-message.enum.js"; + +function generateUserScoresPrompt( + userScores: QuizScoresGetAllResponseDto, +): OpenAiRequestMessage { + const { items } = userScores; + + const categories = items.map(({ categoryId, categoryName, score }) => ({ + categoryId, + categoryName, + score, + })); + + /* eslint-disable perfectionist/sort-objects */ + const promptContent = { + context: OpenAiInitialPromptTemplates.WHEEL_OF_BALANCE_CONTEXT, + categories, + }; + + return { + content: JSON.stringify(promptContent), + role: OpenAiRoleKey.USER, + }; +} + +export { generateUserScoresPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts new file mode 100644 index 000000000..e300c1105 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -0,0 +1,49 @@ +import { type z } from "zod"; + +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { + AiAssistantMessageValidationSchema, + type OpenAiResponseMessage, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type BalanceWheelAnalysisResponseDto } from "../../types/types.js"; +import { type BalanceAnalysis } from "./balance-analysis.validation-schema.js"; + +type BalanceAnalysisData = z.infer; + +const generateScoresResponse = ( + aiResponse: OpenAiResponseMessage, +): BalanceWheelAnalysisResponseDto | null => { + const message = aiResponse.getPaginatedItems().shift(); + + if (!message) { + return null; + } + + const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); + + if (parsedResult.success) { + const contentText: string = + parsedResult.data.content[ZERO_INDEX].text.value; + const balanceData: BalanceAnalysisData = JSON.parse( + contentText, + ) as BalanceAnalysisData; + + return { + lowestCategories: balanceData.lowestCategories.map((category) => ({ + categoryId: Number(category.categoryId), + categoryName: category.categoryName, + score: category.score, + })), + messages: { + comments: balanceData.messages.comments, + greeting: balanceData.messages.greeting, + }, + threadId: message.thread_id, + }; + } + + return null; +}; + +export { generateScoresResponse }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts new file mode 100644 index 000000000..0977c2487 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts @@ -0,0 +1,32 @@ +import { + OpenAiFunctionName, + type OpenAiRunThreadRequestDto, +} from "~/libs/modules/open-ai/open-ai.js"; +import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; + +import { BalanceAnalysis as BalanceAnalysisResponseValidationSchema } from "./balance-analysis.validation-schema.js"; +import { OpenAiInitialPromptTemplates } from "./generate-init-promt-message.enum.js"; +import { generateUserScoresPrompt } from "./generate-scores-prompt.js"; + +const runInitialThreadOptions = ( + userName: string, + userWheelBalanceScores: QuizScoresGetAllResponseDto, +): OpenAiRunThreadRequestDto => { + const userScoresPrompt = generateUserScoresPrompt(userWheelBalanceScores); + + return { + additional_instructions: null, + function_name: OpenAiFunctionName.ANALYZE_BALANCE_SCORES, + instructions: + OpenAiInitialPromptTemplates.WHEEL_OF_BALANCE_INSTRUCTIONS.replace( + "{{userName}}", + userName, + ), + messages: [userScoresPrompt], + validationSchema: BalanceAnalysisResponseValidationSchema, + }; +}; + +export { runInitialThreadOptions }; +export { generateQuestionsAnswersPrompt } from "./generate-questions-answers-prompt.js"; +export { generateScoresResponse } from "./generate-scores-response.js"; From 7db83290bf9c4e803247cbcb242ebb2072681d9d Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:45:35 +0100 Subject: [PATCH 073/244] feat(backend): add suggest task functionality bb-203 --- .../generate-suggest-task-prompt.ts | 24 ++++++++++ .../generate-suggest-task-response.ts | 47 +++++++++++++++++++ .../suggest-task-by-category.ts | 26 ++++++++++ ...gest-task-by-category.validation-schema.ts | 16 +++++++ .../suggest-task-prompt-messages.enum.ts | 39 +++++++++++++++ 5 files changed, 152 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts new file mode 100644 index 000000000..56a2f0409 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts @@ -0,0 +1,24 @@ +import { + type OpenAiRequestMessage, + OpenAiRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type SelectedCategories } from "../../types/types.js"; +import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-messages.enum.js"; + +function generateSuggestTaskPrompt( + categories: SelectedCategories[], +): OpenAiRequestMessage { + /* eslint-disable perfectionist/sort-objects */ + const promptContent = { + context: SuggestTaskPromptTemplates.SUGGEST_TASKS_CONTEXT, + categories, + }; + + return { + content: JSON.stringify(promptContent), + role: OpenAiRoleKey.USER, + }; +} + +export { generateSuggestTaskPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts new file mode 100644 index 000000000..4dc8f101b --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -0,0 +1,47 @@ +import { type z } from "zod"; + +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { + AiAssistantMessageValidationSchema, + type OpenAiResponseMessage, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type TaskSuggestionsResponseDto } from "../../types/types.js"; +import { type TaskByCategory } from "./suggest-task-by-category.validation-schema.js"; + +type TaskByCategoryData = z.infer; + +const generateTaskSuggestionsResponse = ( + aiResponse: OpenAiResponseMessage, +): null | TaskSuggestionsResponseDto => { + const message = aiResponse.getPaginatedItems().shift(); + + if (!message) { + return null; + } + + const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); + + if (parsedResult.success) { + const contentText: string = + parsedResult.data.content[ZERO_INDEX].text.value; + const resultData: TaskByCategoryData = JSON.parse( + contentText, + ) as TaskByCategoryData; + + return { + message: resultData.message, + tasks: resultData.tasks.map((task) => ({ + categoryId: Number(task.categoryId), + categoryName: task.categoryName, + description: task.description, + dueDate: task.dueDate, + label: task.label, + })), + }; + } + + return null; +}; + +export { generateTaskSuggestionsResponse }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts new file mode 100644 index 000000000..11ab3f544 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts @@ -0,0 +1,26 @@ +import { + OpenAiFunctionName, + type OpenAiRunThreadRequestDto, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type SelectedCategories } from "../../types/types.js"; +import { generateSuggestTaskPrompt } from "./generate-suggest-task-prompt.js"; +import { TaskByCategory as TaskByCategoryValidationSchema } from "./suggest-task-by-category.validation-schema.js"; +import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-messages.enum.js"; + +const runTaskByCategoryOptions = ( + categories: SelectedCategories[], +): OpenAiRunThreadRequestDto => { + const suggestTaskPrompt = generateSuggestTaskPrompt(categories); + + return { + additional_instructions: null, + function_name: OpenAiFunctionName.GENERATE_TASK_BY_CATEGORY, + instructions: SuggestTaskPromptTemplates.SUGGEST_TASKS_INSTRUCTIONS, + messages: [suggestTaskPrompt], + validationSchema: TaskByCategoryValidationSchema, + }; +}; + +export { runTaskByCategoryOptions }; +export { generateTaskSuggestionsResponse } from "./generate-suggest-task-response.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts new file mode 100644 index 000000000..32e461940 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts @@ -0,0 +1,16 @@ +import { z } from "zod"; + +const Task = z.object({ + categoryId: z.number(), + categoryName: z.string(), + description: z.string(), + dueDate: z.string(), + label: z.string(), +}); + +const TaskByCategory = z.object({ + message: z.string(), + tasks: z.array(Task), +}); + +export { TaskByCategory }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts new file mode 100644 index 000000000..1b1f4d971 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts @@ -0,0 +1,39 @@ +const SuggestTaskPromptTemplates = { + SUGGEST_TASKS_CONTEXT: ` +The user has selected the following categories that are important for their personal growth and improvement. +Each category represents an area where the user would like to make progress. +Categories: +`, + SUGGEST_TASKS_INSTRUCTIONS: ` +task: +You should analyze the selected categories in combination with the user's responses from the onboarding process, +and suggest specific and actionable tasks for each category that the user has selected for improvement. +Ensure the tasks are realistic, motivational, and can be easily integrated into the user's daily routine. +Provide no more than one task per category. + +response_structure: +{ + message: string, // A message summarizing the suggested tasks. + tasks: [ // An array of tasks associated with each category. + { + categoryId: number, // Unique identifier for the category. + categoryName: string, // Name of the category. + description: string, // Detailed description of the task. + dueDate: string, // Suggested due date for the task. + label: string // Label or name of the task. + } + ] +} + +action: +1. Analyze the categories selected by the user and generate one specific and achievable task for each category. +The tasks should be practical and motivating, focusing on gradual and meaningful progress while considering the user's onboarding responses. + +2. For each task, provide a clear description, assign a due date, and include a meaningful label. +The tasks should be easy to follow and achievable. + +3. Place the structured task suggestions in the \`tasks\` field of the response, and provide a summary in the \`message\` field. +`, +} as const; + +export { SuggestTaskPromptTemplates }; From 630272d30f1d6a6fd79908c34441f7bd81526e0b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:47:30 +0100 Subject: [PATCH 074/244] feat(backend): add suggestTasksForCategories to AiAssistantService and code refactoring bb-203 --- .../ai-assistant/ai-assistant.service.ts | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index fbac02a53..8dc447c0b 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -4,12 +4,16 @@ import { type CategoryService } from "~/modules/categories/categories.js"; import { type OnboardingRepository } from "~/modules/onboarding/onboarding.js"; import { - generateInitPrompt, + generateQuestionsAnswersPrompt, generateScoresResponse, - generateUserScoresPrompt, + generateTaskSuggestionsResponse, + runInitialThreadOptions, + runTaskByCategoryOptions, } from "./libs/helpers/helpers.js"; import { type BalanceWheelAnalysisResponseDto, + type TaskSuggestionRequestDto, + type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; @@ -48,30 +52,40 @@ class AiAssistantService { return await this.openAi.addMessageToThread(threadId, prompt); } - public async initNewThread( + public async initNewChat( user: UserDto, ): Promise { - const userAnswersWithQuestions = + const userQuestionsWithAnswers = await this.onboardingRepository.findUserAnswersWithQuestions(user.id); const userWheelBalanceScores = await this.categoryService.findUserScores( user.id, ); - const [initPrompt, userScoresPrompt] = [ - generateInitPrompt(userAnswersWithQuestions, user.name), - generateUserScoresPrompt(userWheelBalanceScores), - ]; + const initPrompt = generateQuestionsAnswersPrompt(userQuestionsWithAnswers); + const threadId = await this.openAi.createThread([initPrompt]); - const theadId = await this.openAi.createThread([initPrompt]); - - const result = await this.openAi.generateBalanceAnalysis( - theadId, - userScoresPrompt, + const runThreadOptions = runInitialThreadOptions( + user.name, + userWheelBalanceScores, ); + const result = await this.openAi.runThread(threadId, runThreadOptions); + return generateScoresResponse(result); } + + public async suggestTasksForCategories( + body: TaskSuggestionRequestDto, + ): Promise { + const { categories, threadId } = body; + + const runThreadOptions = runTaskByCategoryOptions(categories); + + const result = await this.openAi.runThread(threadId, runThreadOptions); + + return generateTaskSuggestionsResponse(result); + } } export { AiAssistantService }; From 69ad7a27381e1ed3f4d2bd5728f76a467db441e0 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:48:28 +0100 Subject: [PATCH 075/244] feat(backend): add suggestTasksForCategories to AiAssistantController and code refactoring bb-203 --- .../ai-assistant/ai-assistant.controller.ts | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index bf2a45ba3..5f68bb352 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -6,12 +6,18 @@ import { } from "~/libs/modules/controller/controller.js"; import { HTTPCode } from "~/libs/modules/http/http.js"; import { type Logger } from "~/libs/modules/logger/logger.js"; -import { addMessageToThreadValidationSchema } from "~/libs/modules/open-ai/open-ai.js"; -import { type UserDto } from "~/libs/types/types.js"; +import { type UserDto } from "~/modules/users/users.js"; import { type AiAssistantService } from "./ai-assistant.service.js"; import { AiAssistantApiPath } from "./libs/enums/enums.js"; -import { type ThreadMessageCreateDto } from "./libs/types/types.js"; +import { + type TaskSuggestionRequestDto, + type ThreadMessageCreateDto, +} from "./libs/types/types.js"; +import { + addMessageToThreadValidationSchema, + TaskSuggestionRequestValidationSchema, +} from "./libs/validation-schemas/validation-schemas.js"; class AiAssistantController extends BaseController { private openAiService: AiAssistantService; @@ -23,13 +29,13 @@ class AiAssistantController extends BaseController { this.addRoute({ handler: (options) => - this.initConversation( + this.initNewChat( options as APIHandlerOptions<{ user: UserDto; }>, ), method: "POST", - path: AiAssistantApiPath.INITIATE_THREAD, + path: AiAssistantApiPath.INIT_NEW_CHAT, }); this.addRoute({ @@ -45,6 +51,21 @@ class AiAssistantController extends BaseController { body: addMessageToThreadValidationSchema, }, }); + + this.addRoute({ + handler: (options) => + this.suggestTasksForCategories( + options as APIHandlerOptions<{ + body: TaskSuggestionRequestDto; + user: UserDto; + }>, + ), + method: "POST", + path: AiAssistantApiPath.SUGGEST_TASKS, + validation: { + body: TaskSuggestionRequestValidationSchema, + }, + }); } private async addMessageToConversation( @@ -60,7 +81,7 @@ class AiAssistantController extends BaseController { }; } - private async initConversation( + private async initNewChat( options: APIHandlerOptions<{ user: UserDto; }>, @@ -68,7 +89,20 @@ class AiAssistantController extends BaseController { const { user } = options; return { - payload: await this.openAiService.initNewThread(user), + payload: await this.openAiService.initNewChat(user), + status: HTTPCode.OK, + }; + } + + private async suggestTasksForCategories( + options: APIHandlerOptions<{ + body: TaskSuggestionRequestDto; + }>, + ): Promise { + const { body } = options; + + return { + payload: await this.openAiService.suggestTasksForCategories(body), status: HTTPCode.OK, }; } From 2d9199cf70e135c9bc74f9f828f2b3aecf1303d6 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:50:44 +0100 Subject: [PATCH 076/244] refactor(backend): refactor file structure end import in AI Assistant module bb-203 --- .../generate-init-promt.ts | 39 ---------------- .../generate-scores-promt.ts | 31 ------------- .../generate-scores-response.ts | 46 ------------------- .../ai-assistant/libs/helpers/helpers.ts | 12 +++-- .../modules/ai-assistant/libs/types/types.ts | 3 ++ .../validation-schemas/validation-schemas.ts | 4 ++ 6 files changed, 16 insertions(+), 119 deletions(-) delete mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts delete mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts delete mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts deleted file mode 100644 index f94847ba7..000000000 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-init-promt/generate-init-promt.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ZERO_INDEX } from "~/libs/constants/constants.js"; -import { - type OpenAiRequestMessage, - OpenAiRoleKey, -} from "~/libs/modules/open-ai/open-ai.js"; -import { OpenAiPromptTemplates } from "~/libs/modules/open-ai/open-ai.js"; -import { type OnboardingQuestionEntity } from "~/modules/onboarding/onboarding.js"; - -function generateInitPrompt( - onboardingQuestions: OnboardingQuestionEntity[], - userName: string, -): OpenAiRequestMessage { - const questionsWithAnswers = onboardingQuestions.map((questionEntity) => { - const { answers, label: question } = questionEntity.toObject(); - const answer = answers[ZERO_INDEX]?.label; - - return { answer, question }; - }); - - const promptContent = ` -${OpenAiPromptTemplates.ASSISTANT_INIT_THREAD_INSTRUCTION} - -Here are the questions and the user's answers: - -${questionsWithAnswers.map(({ answer, question }) => `- Question: ${question}\nAnswer: ${answer as string}`).join("\n")} - -Make sure to analyze these answers carefully, as they will inform future task recommendations. - -Always address to user : ${userName} and greet on first message. -`; - - return { - content: promptContent, - metadata: {}, - role: OpenAiRoleKey.USER, - }; -} - -export { generateInitPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts deleted file mode 100644 index e7999956e..000000000 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-promt/generate-scores-promt.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - OpenAiPromptTemplates, - type OpenAiRequestMessage, - OpenAiRoleKey, -} from "~/libs/modules/open-ai/open-ai.js"; -import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; - -function generateUserScoresPrompt( - userScores: QuizScoresGetAllResponseDto, -): OpenAiRequestMessage { - const { items } = userScores; - - const categories = items.map(({ categoryId, categoryName, score }) => ({ - categoryId, - categoryName, - score, - })); - - const promptContent = { - categories, - context: OpenAiPromptTemplates.WHEEL_OF_BALANCE_CONTEXT, - instructions: OpenAiPromptTemplates.WHEEL_OF_BALANCE_INSTRUCTIONS, - }; - - return { - content: JSON.stringify(promptContent), - role: OpenAiRoleKey.USER, - }; -} - -export { generateUserScoresPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts deleted file mode 100644 index 2e05597ee..000000000 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/generate-scores-response/generate-scores-response.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { type z } from "zod"; - -import { ZERO_INDEX } from "~/libs/constants/constants.js"; -import { - AiAssistantMessageValidationSchema, - type BalanceAnalysis, - type OpenAiResponseMessage, -} from "~/libs/modules/open-ai/open-ai.js"; - -import { type BalanceWheelAnalysisResponseDto } from "../../types/types.js"; - -type BalanceAnalysisData = z.infer; - -const generateScoresResponse = ( - aiResponse: OpenAiResponseMessage[], -): BalanceWheelAnalysisResponseDto | null => { - const [message] = aiResponse; - - if (!message) { - return null; - } - - const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); - - if (parsedResult.success) { - const contentText: string = - parsedResult.data.content[ZERO_INDEX].text.value; - const balanceData: BalanceAnalysisData = JSON.parse( - contentText, - ) as BalanceAnalysisData; - - return { - lowestCategories: balanceData.lowestCategories.map((category) => ({ - categoryId: Number(category.categoryId), - categoryName: category.categoryName, - score: category.score, - })), - text: balanceData.answer, - threadId: message.id, - }; - } - - return null; -}; - -export { generateScoresResponse }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts index 9cd61274f..904142002 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts @@ -1,3 +1,9 @@ -export { generateInitPrompt } from "./generate-init-promt/generate-init-promt.js"; -export { generateUserScoresPrompt } from "./generate-scores-promt/generate-scores-promt.js"; -export { generateScoresResponse } from "./generate-scores-response/generate-scores-response.js"; +export { + generateQuestionsAnswersPrompt, + generateScoresResponse, + runInitialThreadOptions, +} from "./initial-chat/initial-chat.js"; +export { + generateTaskSuggestionsResponse, + runTaskByCategoryOptions, +} from "./suggest-task-by-category/suggest-task-by-category.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/types/types.ts b/apps/backend/src/modules/ai-assistant/libs/types/types.ts index 7893a3cdc..69e942d10 100644 --- a/apps/backend/src/modules/ai-assistant/libs/types/types.ts +++ b/apps/backend/src/modules/ai-assistant/libs/types/types.ts @@ -1,4 +1,7 @@ export { type BalanceWheelAnalysisResponseDto, + type SelectedCategories, + type TaskSuggestionRequestDto, + type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "shared"; diff --git a/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts new file mode 100644 index 000000000..9cb1ac5d5 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -0,0 +1,4 @@ +export { + addMessageToThreadValidationSchema, + TaskSuggestionRequestValidationSchema, +} from "shared"; From 5688d87cfa93f1a15043e4b890e8cd85b8211764 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 14:52:11 +0100 Subject: [PATCH 077/244] refactor(shared): refactor file structure end import in AI Assistant module bb-203 --- packages/shared/src/index.ts | 14 ++++---- .../src/modules/ia-assistant/ai-assistant.ts | 8 ----- .../libs/enums/ai-assistant-api-path.enum.ts | 10 ------ .../ai-assistant-validation-message.enum.ts | 7 ---- .../ai-assistant-validatuon-rule.enum.ts | 6 ---- .../modules/ia-assistant/libs/enums/enums.ts | 3 -- ...alance-wheel-analysis-response.dto.type.ts | 14 -------- .../task-suggestion-response-dto.type.ts | 14 -------- .../types/thread-message-create-dto.type.ts | 6 ---- .../modules/ia-assistant/libs/types/types.ts | 3 -- ...add-message-to-thread.validation-schema.ts | 33 ------------------- .../ai-assistant-message.validation-schema.ts | 17 ---------- .../validation-schemas/validation-schemas.ts | 2 -- 13 files changed, 8 insertions(+), 129 deletions(-) delete mode 100644 packages/shared/src/modules/ia-assistant/ai-assistant.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/enums/enums.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/types/types.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts delete mode 100644 packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 0c34a2622..5699b62a1 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -37,18 +37,20 @@ export { type ValidationSchema, type ValueOf, } from "./libs/types/types.js"; -export { - AuthApiPath, - ConfirmPasswordCustomValidation, -} from "./modules/auth/auth.js"; export { addMessageToThreadValidationSchema, AiAssistantApiPath, - AiAssistantMessageValidationSchema, type BalanceWheelAnalysisResponseDto, + type SelectedCategories, + type TaskSuggestionRequestDto, + TaskSuggestionRequestValidationSchema, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, -} from "./modules/ia-assistant/ai-assistant.js"; +} from "./modules/ai-assistant/ai-assistant.js"; +export { + AuthApiPath, + ConfirmPasswordCustomValidation, +} from "./modules/auth/auth.js"; export { type OnboardingAnswerDto, type OnboardingAnswerRequestBodyDto, diff --git a/packages/shared/src/modules/ia-assistant/ai-assistant.ts b/packages/shared/src/modules/ia-assistant/ai-assistant.ts deleted file mode 100644 index 0031beb60..000000000 --- a/packages/shared/src/modules/ia-assistant/ai-assistant.ts +++ /dev/null @@ -1,8 +0,0 @@ -export { AiAssistantApiPath } from "./libs/enums/enums.js"; -export { - type BalanceWheelAnalysisResponseDto, - type TaskSuggestionsResponseDto, - type ThreadMessageCreateDto, -} from "./libs/types/types.js"; -export { addMessageToThread as addMessageToThreadValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; -export { AiAssistantMessage as AiAssistantMessageValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts deleted file mode 100644 index 68c70a648..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ /dev/null @@ -1,10 +0,0 @@ -const AiAssistantApiPath = { - ADD_MESSAGE: "/thread/add-message", - CONTINUE_THREAD: "/thread/continue", - GENERATE_ALTERNATIVE_TASKS: "/thread/generate-alternative-tasks", - INITIATE_THREAD: "/thread/initiate", - REMOVE_THREAD: "/thread/remove", - SUGGEST_TASKS: "/thread/suggest-tasks", -} as const; - -export { AiAssistantApiPath }; diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts deleted file mode 100644 index e2e8f0124..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validation-message.enum.ts +++ /dev/null @@ -1,7 +0,0 @@ -const AiAssistantValidationMessage = { - TEXT_REQUIRED: "text required", - THREAD_ID_INVALID_FORMAT: "threadId - invalid format", - THREAD_ID_REQUIRED: "threadId required", -} as const; - -export { AiAssistantValidationMessage }; diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts deleted file mode 100644 index 6fb01367f..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -const AiAssistantValidationRule = { - NON_EMPTY_STRING_MIN_LENGTH: 1, - THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, -} as const; - -export { AiAssistantValidationRule }; diff --git a/packages/shared/src/modules/ia-assistant/libs/enums/enums.ts b/packages/shared/src/modules/ia-assistant/libs/enums/enums.ts deleted file mode 100644 index a7003a6f4..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/enums/enums.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { AiAssistantApiPath } from "./ai-assistant-api-path.enum.js"; -export { AiAssistantValidationMessage } from "./ai-assistant-validation-message.enum.js"; -export { AiAssistantValidationRule } from "./ai-assistant-validatuon-rule.enum.js"; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts deleted file mode 100644 index 3970af177..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { type QuizScoresGetAllItemResponseDto } from "../../../quiz/quiz.js"; - -type SimplifiedQuizScoreDto = Omit< - QuizScoresGetAllItemResponseDto, - "createdAt" | "id" | "updatedAt" | "userId" ->; - -type BalanceWheelAnalysisResponseDto = { - lowestCategories: SimplifiedQuizScoreDto[]; - text: string; - threadId: string; -}; - -export { type BalanceWheelAnalysisResponseDto }; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts b/packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts deleted file mode 100644 index d3a68cd47..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/types/task-suggestion-response-dto.type.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { type TaskDto } from "../../../tasks/libs/types/types.js"; - -type SimplifiedTaskDto = Omit< - TaskDto, - "createdAt" | "id" | "updatedAt" | "userId" ->; - -type TaskSuggestionsResponseDto = { - tasks: SimplifiedTaskDto[]; - text: string; - theadId: string; -}; - -export { type TaskSuggestionsResponseDto }; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts b/packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts deleted file mode 100644 index 5a70bff8e..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/types/thread-message-create-dto.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -type ThreadMessageCreateDto = { - text: string; - threadId: string; -}; - -export { type ThreadMessageCreateDto }; diff --git a/packages/shared/src/modules/ia-assistant/libs/types/types.ts b/packages/shared/src/modules/ia-assistant/libs/types/types.ts deleted file mode 100644 index d910e5b65..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/types/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { type BalanceWheelAnalysisResponseDto } from "./balance-wheel-analysis-response.dto.type.js"; -export { type TaskSuggestionsResponseDto } from "./task-suggestion-response-dto.type.js"; -export { type ThreadMessageCreateDto } from "./thread-message-create-dto.type.js"; diff --git a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts deleted file mode 100644 index 9b2b96e65..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { z } from "zod"; - -import { - AiAssistantValidationMessage, - AiAssistantValidationRule, -} from "../enums/enums.js"; - -type AiAssistantMessageCreateDto = { - text: z.ZodString; - threadId: z.ZodString; -}; - -const addMessageToThread = z - .object({ - text: z - .string() - .trim() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { - message: AiAssistantValidationMessage.TEXT_REQUIRED, - }), - threadId: z - .string() - .trim() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { - message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, - }) - .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { - message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, - }), - }) - .required(); - -export { addMessageToThread }; diff --git a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts deleted file mode 100644 index 86f45ed8d..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/ai-assistant-message.validation-schema.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from "zod"; - -const AiAssistantMessage = z.object({ - content: z - .array( - z.object({ - text: z.object({ - value: z.string(), - }), - type: z.literal("text"), - }), - ) - .nonempty(), - id: z.string(), -}); - -export { AiAssistantMessage }; diff --git a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts deleted file mode 100644 index 92ec1f5a7..000000000 --- a/packages/shared/src/modules/ia-assistant/libs/validation-schemas/validation-schemas.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { addMessageToThread } from "./add-message-to-thread.validation-schema.js"; -export { AiAssistantMessage } from "./ai-assistant-message.validation-schema.js"; From ed0e4804c1d52ffddaa9332e6f963a39f23dfb2d Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 16:46:32 +0100 Subject: [PATCH 078/244] feat(main): update readme with Task db model bb-203 --- readme.md | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index 1df069333..f89a51a22 100644 --- a/readme.md +++ b/readme.md @@ -34,8 +34,8 @@ erDiagram text password_salt } - user_details ||--|| users : user_id - user_details ||--o| files : avatar_file_id + user_details ||--|| users: user_id + user_details ||--o| files: avatar_file_id user_details { int id PK dateTime created_at @@ -46,6 +46,21 @@ erDiagram int avatar_file_id FK } + tasks { + int id PK + varchar label + varchar description + varchar status + int user_id FK + int category_id FK + dateTime due_date + dateTime created_at + dateTime updated_at + } + + users }|--o| tasks: user_id + categories }|--o| tasks: category_id + files { int id PK varchar file_key UK @@ -61,7 +76,7 @@ erDiagram varchar name UK } - quiz_questions }|--o| categories : category_id + quiz_questions }|--o| categories: category_id quiz_questions { int id PK dateTime created_at @@ -70,7 +85,7 @@ erDiagram int category_id FK } - quiz_answers }|--o| quiz_questions : question_id + quiz_answers }|--o| quiz_questions: question_id quiz_answers { int id PK dateTime created_at @@ -80,8 +95,8 @@ erDiagram int question_id FK } - quiz_scores }o--|| categories : category_id - quiz_scores }o--|| users : user_id + quiz_scores }o--|| categories: category_id + quiz_scores }o--|| users: user_id quiz_scores { int id PK dateTime created_at @@ -91,8 +106,8 @@ erDiagram int user_id FK } - quiz_answers_to_users }o--|| quiz_answers : answer_id - quiz_answers_to_users }o--|| users : user_id + quiz_answers_to_users }o--|| quiz_answers: answer_id + quiz_answers_to_users }o--|| users: user_id quiz_answers_to_users { int id PK dateTime created_at @@ -108,7 +123,7 @@ erDiagram text label UK } - onboarding_answers }|--o| onboarding_questions : question_id + onboarding_answers }|--o| onboarding_questions: question_id onboarding_answers { int id PK dateTime created_at @@ -117,8 +132,8 @@ erDiagram int question_id FK } - onboarding_answers_to_users }o--|| onboarding_answers : answer_id - onboarding_answers_to_users }o--|| users : user_id + onboarding_answers_to_users }o--|| onboarding_answers: answer_id + onboarding_answers_to_users }o--|| users: user_id onboarding_answers_to_users { int id PK dateTime created_at @@ -127,7 +142,7 @@ erDiagram int user_id FK } - user_task_days }o--|| users : user_id + user_task_days }o--|| users: user_id user_task_days { int id PK dateTime created_at From b4e35a04499cc9e288fed94ea4df017829033268 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Fri, 13 Sep 2024 19:07:31 +0100 Subject: [PATCH 079/244] feat(backend/shared): add question field in balance score response bb-203 --- .../analyze-balance-scores-tool.ts | 7 ++++++- .../balance-analysis.validation-schema.ts | 1 + .../generate-init-promt-message.enum.ts | 14 ++++++++------ .../initial-chat/generate-scores-response.ts | 9 +++++---- .../balance-wheel-analysis-response.dto.type.ts | 1 + 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts index f26921a53..acc454823 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts @@ -87,8 +87,13 @@ const AnalyzeBalanceScoresTool = { }, type: "array", }, + question: { + description: + "A follow-up question that guides the user to either focus on improving the three areas with the lowest scores or allows them to choose the areas for further improvement. The question should be crafted to encourage thoughtful reflection and engagement, and it must include the user's name.", + type: "string", + }, }, - required: ["greeting", "comments", "lowestCategories"], + required: ["greeting", "comments", "lowestCategories", "question"], type: "object", }, }, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index 0cb19da87..da6edaf83 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -9,6 +9,7 @@ const Category = z.object({ const Messages = z.object({ comments: z.string(), greeting: z.string(), + question: z.string(), }); const BalanceAnalysis = z.object({ diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts index eb4b709bf..16238456d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts @@ -51,6 +51,7 @@ response_structure: messages: { // A section containing the greeting and comments greeting: string, // A friendly and motivational greeting that uses the user's name. comments: string // A summary of the analysis and a motivational question for the user. + question: string // A follow-up question for the user to guide further action. }, lowestCategories: [ // An array containing the three categories with the lowest scores. { @@ -69,15 +70,16 @@ Place the greeting in the \`greeting\` field of the response. 2.Your second task is to provide a brief summary of the user's Wheel of Balance analysis. Highlight that the analysis has identified the three areas where the user scored the lowest, which represent areas for potential improvement. - Keep the explanation concise but clear, avoiding unnecessary details. -At the end of your response, include the following question: -'Would you like to focus on improving the three areas with the lowest scores in your Wheel of Balance, -or would you prefer to choose the areas yourself to work on?' +Place this explanation n in the \`comments\` field of the response. -Place this explanation and question in the \`comments\` field of the response. +3. Your third task is to respond with a follow-up question for the user. The question should guide the user to either +focus on improving the three areas with the lowest scores, or to decide whether they would prefer to choose the areas +themselves for further improvement. You must craft the question in a way that encourages thoughtful reflection and +engagement from the user. The question should be specific, clear, and include the user's name, {{userName}}. +Place this question in the \`question\` field of the response. -3.Your third task is to identify the three categories with the lowest scores in the user's Wheel of Balance analysis. +4.Your forth task is to identify the three categories with the lowest scores in the user's Wheel of Balance analysis. Select these categories and provide them in a structured format, listing the category ID, category name, and score. Ensure this data is placed in the \`lowestCategories\` field of the response. diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index e300c1105..72d3b799c 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -25,19 +25,20 @@ const generateScoresResponse = ( if (parsedResult.success) { const contentText: string = parsedResult.data.content[ZERO_INDEX].text.value; - const balanceData: BalanceAnalysisData = JSON.parse( + const resultData: BalanceAnalysisData = JSON.parse( contentText, ) as BalanceAnalysisData; return { - lowestCategories: balanceData.lowestCategories.map((category) => ({ + lowestCategories: resultData.lowestCategories.map((category) => ({ categoryId: Number(category.categoryId), categoryName: category.categoryName, score: category.score, })), messages: { - comments: balanceData.messages.comments, - greeting: balanceData.messages.greeting, + comments: resultData.messages.comments, + greeting: resultData.messages.greeting, + question: resultData.messages.question, }, threadId: message.thread_id, }; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts index c169a1204..7c6505242 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -10,6 +10,7 @@ type BalanceWheelAnalysisResponseDto = { messages: { comments: string; greeting: string; + question: string; }; threadId: string; }; From 650c13f394297c533185541c142781aaea63ab19 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:28:17 +0300 Subject: [PATCH 080/244] feat(backend): add question field to response bb-340 --- .../analyze-balance-scores-tool.ts | 6 +++++- .../balance-analysis.validation-schema.ts | 1 + .../generate-init-promt-message.enum.ts | 13 +++++++++---- .../initial-chat/generate-scores-response.ts | 1 + .../balance-wheel-analysis-response.dto.type.ts | 1 + 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts index f26921a53..75da8cab8 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts @@ -87,8 +87,12 @@ const AnalyzeBalanceScoresTool = { }, type: "array", }, + question: { + description: "Question about lowest areas for improvement", + type: "string", + }, }, - required: ["greeting", "comments", "lowestCategories"], + required: ["greeting", "comments", "question", "lowestCategories"], type: "object", }, }, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index 0cb19da87..da6edaf83 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -9,6 +9,7 @@ const Category = z.object({ const Messages = z.object({ comments: z.string(), greeting: z.string(), + question: z.string(), }); const BalanceAnalysis = z.object({ diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts index eb4b709bf..523c30d60 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts @@ -48,9 +48,11 @@ seek the most improvement. response_structure: { - messages: { // A section containing the greeting and comments + messages: { // A section containing the greeting, question and comments greeting: string, // A friendly and motivational greeting that uses the user's name. comments: string // A summary of the analysis and a motivational question for the user. + question: string // A question about lowest categories. + }, lowestCategories: [ // An array containing the three categories with the lowest scores. { @@ -71,13 +73,16 @@ Place the greeting in the \`greeting\` field of the response. has identified the three areas where the user scored the lowest, which represent areas for potential improvement. Keep the explanation concise but clear, avoiding unnecessary details. -At the end of your response, include the following question: + +Place this explanation in the \`comments\` field of the response. + +3. Your third task is create following question: 'Would you like to focus on improving the three areas with the lowest scores in your Wheel of Balance, or would you prefer to choose the areas yourself to work on?' -Place this explanation and question in the \`comments\` field of the response. +Place this question in the \`question\` field of the response. -3.Your third task is to identify the three categories with the lowest scores in the user's Wheel of Balance analysis. +4.Your fourth task is to identify the three categories with the lowest scores in the user's Wheel of Balance analysis. Select these categories and provide them in a structured format, listing the category ID, category name, and score. Ensure this data is placed in the \`lowestCategories\` field of the response. diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index e300c1105..4f1c9fc9c 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -38,6 +38,7 @@ const generateScoresResponse = ( messages: { comments: balanceData.messages.comments, greeting: balanceData.messages.greeting, + question: balanceData.messages.question, }, threadId: message.thread_id, }; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts index 0e546d4a3..9e23e8e8a 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -10,6 +10,7 @@ type BalanceWheelAnalysisResponseDto = { messages: { comments: string; greeting: string; + question: string; }; threadId: string; }; From e6313cc77e9b2efea7f75f5182fd7574cdf4e901 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:30:12 +0300 Subject: [PATCH 081/244] feat(frontend): change wheel width bb-340 --- .../src/libs/components/balance-wheel-chart/styles.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css b/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css index a3d234122..dc774a179 100644 --- a/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css +++ b/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css @@ -4,5 +4,5 @@ } .root-wheel-container { - width: 649px; + max-width: 649px; } From 2b7a24d78a10f0da86d34791423722911753e3f0 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:32:17 +0300 Subject: [PATCH 082/244] feat(frontend): change message type bb-340 --- .../modules/chat/libs/types/message.type.ts | 12 ++++---- apps/frontend/src/pages/chat/chat.tsx | 30 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/apps/frontend/src/modules/chat/libs/types/message.type.ts b/apps/frontend/src/modules/chat/libs/types/message.type.ts index b7cbf99ab..e48b6d595 100644 --- a/apps/frontend/src/modules/chat/libs/types/message.type.ts +++ b/apps/frontend/src/modules/chat/libs/types/message.type.ts @@ -9,13 +9,15 @@ type Message = { categoryName: string; score: number; }>; - messages: { - comments: string; - greeting: string; - }; taskList?: TaskDto[]; + text: string; threadId?: string; - type: "categoryInputs" | "suggestionButtons" | "taskList" | "wheelAnalysis"; + type: + | "categoryInputs" + | "suggestionButtons" + | "taskList" + | "text" + | "wheelAnalysis"; }; export { type Message }; diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 668f6c9ee..7fe54c6e3 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -74,20 +74,22 @@ const ChatComponent: React.FC = () => {
      - {messages.map((message) => ( - - ))} + {messages.map((message) => { + return ( + + ); + })}
    From 5f83bcf2947c8a14426ec9c85df715c37439f3d8 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:33:37 +0300 Subject: [PATCH 083/244] feat(frontend): add messages on initConversation bb-340 --- .../src/modules/chat/slices/chat.slice.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 1feea330e..991526e7f 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -30,7 +30,21 @@ const { actions, name, reducer } = createSlice({ .addCase(initConversation.fulfilled, (state, action) => { state.selectedCategories = action.payload.lowestCategories; state.threadId = action.payload.threadId; - state.messages.push(); + state.messages.push( + { + text: action.payload.messages.greeting, + type: "text", + }, + { + text: action.payload.messages.comments, + type: "wheelAnalysis", + }, + { + buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], + text: action.payload.messages.question, + type: "suggestionButtons", + }, + ); state.dataStatus = DataStatus.FULFILLED; }) .addCase(initConversation.rejected, (state) => { From fd990bed816d200e2f389c1648b80e6c323dbe95 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:34:08 +0300 Subject: [PATCH 084/244] feat(frontend): add buttons bb-340 --- .../libs/components/chat-message/chat-message.tsx | 4 +++- .../components/chat-message/styles.module.css | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index 53210b8e8..fcf066e95 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -33,7 +33,9 @@ const ChatMessage: React.FC = ({ return ( <> {buttonLabels.map((button: string) => ( - +
    + +
    ))} ); diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css index fee68ab22..e36277139 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css @@ -11,3 +11,18 @@ /* border-radius: 0px 10px 10px; */ } + +.button-container { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; +} + +.button { + width: 200px; + padding: 10px; + margin-bottom: 10px; + border: 1px solid var(--blue-accent); + border-radius: 30px; +} From 4a9430a1c2dc48b955b1441983d9b844d1830a72 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 16:47:40 +0100 Subject: [PATCH 085/244] feat(shared): add TaskCreateDto bb-203 --- .../src/modules/tasks/libs/types/task-create-dto.type.ts | 8 ++++++++ packages/shared/src/modules/tasks/libs/types/types.ts | 1 + packages/shared/src/modules/tasks/tasks.ts | 1 + 3 files changed, 10 insertions(+) create mode 100644 packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts diff --git a/packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts new file mode 100644 index 000000000..da2317eab --- /dev/null +++ b/packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts @@ -0,0 +1,8 @@ +type TaskCreateDto = { + categoryId: number; + categoryName: string; + description: string; + dueDate: string; + label: string; +}; +export { type TaskCreateDto }; diff --git a/packages/shared/src/modules/tasks/libs/types/types.ts b/packages/shared/src/modules/tasks/libs/types/types.ts index abe968516..e333fbf0e 100644 --- a/packages/shared/src/modules/tasks/libs/types/types.ts +++ b/packages/shared/src/modules/tasks/libs/types/types.ts @@ -1,2 +1,3 @@ +export { type TaskCreateDto } from "./task-create-dto.type.js"; export { type TaskDto } from "./task-dto.type.js"; export { type TaskGetAllResponseDto } from "./task-get-all-response-dto.type.js"; diff --git a/packages/shared/src/modules/tasks/tasks.ts b/packages/shared/src/modules/tasks/tasks.ts index 7305aaf1a..0112d5e68 100644 --- a/packages/shared/src/modules/tasks/tasks.ts +++ b/packages/shared/src/modules/tasks/tasks.ts @@ -1,5 +1,6 @@ export { TasksApiPath, TaskStatus } from "./libs/enums/enums.js"; export { + type TaskCreateDto, type TaskDto, type TaskGetAllResponseDto, } from "./libs/types/types.js"; From 4ebcab2a2ed7d5ea4db45535789b672f1e719727 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 16:48:54 +0100 Subject: [PATCH 086/244] feat(shared): add ChangeTaskSuggestionRequestDto bb-203 --- .../libs/types/change-task-suggestion-request-dto.type.ts | 8 ++++++++ .../shared/src/modules/ai-assistant/libs/types/types.ts | 1 + 2 files changed, 9 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/change-task-suggestion-request-dto.type.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/types/change-task-suggestion-request-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/change-task-suggestion-request-dto.type.ts new file mode 100644 index 000000000..8a2d6e9d4 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/change-task-suggestion-request-dto.type.ts @@ -0,0 +1,8 @@ +import { type TaskCreateDto } from "../../../tasks/libs/types/types.js"; + +type ChangeTaskSuggestionRequestDto = { + task: TaskCreateDto; + threadId: string; +}; + +export { type ChangeTaskSuggestionRequestDto }; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/types.ts b/packages/shared/src/modules/ai-assistant/libs/types/types.ts index 157b3de5a..97a7fb090 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/types.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/types.ts @@ -1,4 +1,5 @@ export { type BalanceWheelAnalysisResponseDto } from "./balance-wheel-analysis-response.dto.type.js"; +export { type ChangeTaskSuggestionRequestDto } from "./change-task-suggestion-request-dto.type.js"; export { type SelectedCategories, type TaskSuggestionRequestDto, From 4ca888b7603075949439efd40d336bf057dcbd18 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 16:53:11 +0100 Subject: [PATCH 087/244] feat(shared): add ChangeTaskSuggestionRequest validation schema/rule/message bb-203 --- packages/shared/src/index.ts | 3 ++ .../src/modules/ai-assistant/ai-assistant.ts | 2 + .../ai-assistant-validation-message.enum.ts | 13 +++--- .../ai-assistant-validatuon-rule.enum.ts | 1 + ...hange-task-suggestion.validation-schema.ts | 43 +++++++++++++++++++ .../validation-schemas/validation-schemas.ts | 1 + 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 28e7069b8..430bdbf63 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -45,6 +45,8 @@ export { addMessageToThreadValidationSchema, AiAssistantApiPath, type BalanceWheelAnalysisResponseDto, + type ChangeTaskSuggestionRequestDto, + ChangeTaskSuggestionRequestValidationSchema, type SelectedCategories, type TaskSuggestionRequestDto, TaskSuggestionRequestValidationSchema, @@ -95,6 +97,7 @@ export { updateScoresValidationSchema, } from "./modules/quiz/quiz.js"; export { + type TaskCreateDto, type TaskDto, type TaskGetAllResponseDto, TasksApiPath, diff --git a/packages/shared/src/modules/ai-assistant/ai-assistant.ts b/packages/shared/src/modules/ai-assistant/ai-assistant.ts index 0b7cb9fe1..095037ff6 100644 --- a/packages/shared/src/modules/ai-assistant/ai-assistant.ts +++ b/packages/shared/src/modules/ai-assistant/ai-assistant.ts @@ -1,6 +1,7 @@ export { AiAssistantApiPath } from "./libs/enums/enums.js"; export { type BalanceWheelAnalysisResponseDto, + type ChangeTaskSuggestionRequestDto, type SelectedCategories, type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, @@ -8,3 +9,4 @@ export { } from "./libs/types/types.js"; export { addMessageToThread as addMessageToThreadValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { TaskSuggestionRequest as TaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; +export { ChangeTaskSuggestionRequest as ChangeTaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts index 04d54c62d..6301f40e4 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts @@ -1,10 +1,13 @@ const AiAssistantValidationMessage = { - CATEGORIES_REQUIRED: "categories required", - CATEGORY_ID_REQUIRED: "categoryId required", - CATEGORY_NAME_REQUIRED: "categoryName required", + CATEGORIES_REQUIRED: "Categories are required", + CATEGORY_ID_REQUIRED: "Category ID is required", + CATEGORY_NAME_REQUIRED: "Category name is required", + DESCRIPTION_REQUIRED: "Description is required", + DUE_DATE_INVALID_FORMAT: "Due date has an invalid format", + LABEL_REQUIRED: "Label is required", TEXT_REQUIRED: "text required", - THREAD_ID_INVALID_FORMAT: "threadId - invalid format", - THREAD_ID_REQUIRED: "threadId required", + THREAD_ID_INVALID_FORMAT: "Thread ID has an invalid format", + THREAD_ID_REQUIRED: "Thread ID is required", } as const; export { AiAssistantValidationMessage }; diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts index 6fb01367f..59d0da733 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -1,4 +1,5 @@ const AiAssistantValidationRule = { + DATE_FORMAT: /^\d{4}-\d{2}-\d{2}$/, NON_EMPTY_STRING_MIN_LENGTH: 1, THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, } as const; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts new file mode 100644 index 000000000..9c69111ab --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts @@ -0,0 +1,43 @@ +import { z } from "zod"; + +import { + AiAssistantValidationMessage, + AiAssistantValidationRule, +} from "../enums/enums.js"; + +const ChangeTaskSuggestionRequest = z.object({ + task: z.object({ + categoryId: z.number({ + invalid_type_error: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, + }), + categoryName: z + .string() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, + }), + description: z + .string() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.DESCRIPTION_REQUIRED, + }), + dueDate: z.string().regex(AiAssistantValidationRule.DATE_FORMAT, { + message: AiAssistantValidationMessage.DUE_DATE_INVALID_FORMAT, + }), + label: z + .string() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.LABEL_REQUIRED, + }), + }), + threadId: z + .string() + .trim() + .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, + }) + .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + }), +}); + +export { ChangeTaskSuggestionRequest }; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts index 38ef21372..e8672b9e8 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -1,2 +1,3 @@ export { addMessageToThread } from "./add-message-to-thread.validation-schema.js"; +export { ChangeTaskSuggestionRequest } from "./change-task-suggestion.validation-schema.js"; export { TaskSuggestionRequest } from "./task-suggestion-request.validation-schema.js"; From de0943b4654830aa643f5eaedbd66c0e7d5948e6 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 16:54:21 +0100 Subject: [PATCH 088/244] refactor(shared): add TaskCreateDto to TaskSuggestionsResponseDto bb-203 --- .../libs/types/task-suggestion-response-dto.type.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts index d7b4c59af..63968ea3b 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts @@ -1,13 +1,8 @@ -import { type TaskDto } from "../../../tasks/libs/types/types.js"; - -type SimplifiedTaskDto = Omit< - TaskDto, - "createdAt" | "id" | "status" | "updatedAt" | "userId" ->; +import { type TaskCreateDto } from "../../../tasks/libs/types/types.js"; type TaskSuggestionsResponseDto = { message: string; - tasks: SimplifiedTaskDto[]; + tasks: TaskCreateDto[]; }; export { type TaskSuggestionsResponseDto }; From 3322a1ad2919987df8e0028d13c64dc85185c1eb Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 16:55:39 +0100 Subject: [PATCH 089/244] feat(backend): add changeTask to AiAssistantController bb-203 --- .../ai-assistant/ai-assistant.controller.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 5f68bb352..569f380c5 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -11,11 +11,13 @@ import { type UserDto } from "~/modules/users/users.js"; import { type AiAssistantService } from "./ai-assistant.service.js"; import { AiAssistantApiPath } from "./libs/enums/enums.js"; import { + type ChangeTaskSuggestionRequestDto, type TaskSuggestionRequestDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; import { addMessageToThreadValidationSchema, + ChangeTaskSuggestionRequestValidationSchema, TaskSuggestionRequestValidationSchema, } from "./libs/validation-schemas/validation-schemas.js"; @@ -52,6 +54,20 @@ class AiAssistantController extends BaseController { }, }); + this.addRoute({ + handler: (options) => + this.changeTaskSuggestion( + options as APIHandlerOptions<{ + body: ChangeTaskSuggestionRequestDto; + }>, + ), + method: "POST", + path: AiAssistantApiPath.GENERATE_ALTERNATIVE_TASK, + validation: { + body: ChangeTaskSuggestionRequestValidationSchema, + }, + }); + this.addRoute({ handler: (options) => this.suggestTasksForCategories( @@ -81,6 +97,19 @@ class AiAssistantController extends BaseController { }; } + private async changeTaskSuggestion( + options: APIHandlerOptions<{ + body: ChangeTaskSuggestionRequestDto; + }>, + ): Promise { + const { body } = options; + + return { + payload: await this.openAiService.changeTaskSuggestion(body), + status: HTTPCode.OK, + }; + } + private async initNewChat( options: APIHandlerOptions<{ user: UserDto; From 7d07b9e2bc6f6b5de054317a20337984be0c0a68 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 16:57:09 +0100 Subject: [PATCH 090/244] feat(backend): add changeTask() to AiAssistantService bb-203 --- .../modules/ai-assistant/ai-assistant.service.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index 8dc447c0b..fc28cec63 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -4,14 +4,17 @@ import { type CategoryService } from "~/modules/categories/categories.js"; import { type OnboardingRepository } from "~/modules/onboarding/onboarding.js"; import { + generateChangeTaskSuggestionsResponse, generateQuestionsAnswersPrompt, generateScoresResponse, generateTaskSuggestionsResponse, + runChangeTaskByCategoryOptions, runInitialThreadOptions, runTaskByCategoryOptions, } from "./libs/helpers/helpers.js"; import { type BalanceWheelAnalysisResponseDto, + type ChangeTaskSuggestionRequestDto, type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, @@ -52,6 +55,18 @@ class AiAssistantService { return await this.openAi.addMessageToThread(threadId, prompt); } + public async changeTaskSuggestion( + body: ChangeTaskSuggestionRequestDto, + ): Promise { + const { task, threadId } = body; + + const runThreadOptions = runChangeTaskByCategoryOptions(task); + + const result = await this.openAi.runThread(threadId, runThreadOptions); + + return generateChangeTaskSuggestionsResponse(result); + } + public async initNewChat( user: UserDto, ): Promise { From 7656f29005ef53d380cfee8046294ddc4ccb54aa Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 16:59:24 +0100 Subject: [PATCH 091/244] feat(backend): add changeTask Helper bb-203 --- .../change-task/change-task-message.enum.ts | 42 ++++++++++++++++ .../change-task/change-task-response.ts | 49 +++++++++++++++++++ .../libs/helpers/change-task/change-task.ts | 26 ++++++++++ .../change-task.validation-schema.ts | 14 ++++++ .../geregate-change-task-prompt.ts | 21 ++++++++ .../ai-assistant/libs/helpers/helpers.ts | 4 ++ .../modules/ai-assistant/libs/types/types.ts | 2 + .../validation-schemas/validation-schemas.ts | 1 + 8 files changed, 159 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts new file mode 100644 index 000000000..86b9219b4 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts @@ -0,0 +1,42 @@ +const ChangeTaskPromptTemplates = { + CHANGE_TASKS_CONTEXT: ` +The user has reviewed the suggested task for the category and would like to request a new task. + +Ensure that the new task is different from the previous suggestions and takes into account the user's priorities +from the onboarding quiz. +The previously suggested task was: +`, + + CHANGE_TASKS_INSTRUCTIONS: ` +task: +Your role is to generate a new task for the category. The user has reviewed the previously suggested task +and would like to receive a different task. Ensure that the new task is specific, actionable, and aligns with the +user's overall goals. +It must be unique and should not repeat any tasks that were previously suggested. + +response_structure: +{ + message: string, // A message summarizing the new task. + task: { // The new task generated for the category. + categoryId: number, // Unique identifier for the category. + categoryName: string, // Name of the category. + description: string, // Detailed description of the new task. + dueDate: string, // Suggested due date for the new task. + label: string // Label or name of the new task. + } +} + +action: +1. Generate a new task for the category that aligns with the user's goals and onboarding quiz priorities. +Ensure the task is unique and does not repeat any previously suggested tasks. + +2. Consider the user's priorities from the onboarding quiz to tailor the new task. The task should be practical, actionable, +and focused on gradual and meaningful progress in line with their priorities. + +3. Provide a clear description for the new task, assign a due date, and include a meaningful label. + +4. Place the structured new task in the \`task\` field, and provide a summary or confirmation in the \`message\` field. +`, +} as const; + +export { ChangeTaskPromptTemplates }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts new file mode 100644 index 000000000..3a9b63995 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts @@ -0,0 +1,49 @@ +import { type z } from "zod"; + +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { + AiAssistantMessageValidationSchema, + type OpenAiResponseMessage, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type TaskSuggestionsResponseDto } from "../../types/types.js"; +import { type ChangeTaskByCategory } from "./change-task.validation-schema.js"; + +type TaskByCategoryData = z.infer; + +const generateChangeTaskSuggestionsResponse = ( + aiResponse: OpenAiResponseMessage, +): null | TaskSuggestionsResponseDto => { + const message = aiResponse.getPaginatedItems().shift(); + + if (!message) { + return null; + } + + const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); + + if (parsedResult.success) { + const contentText: string = + parsedResult.data.content[ZERO_INDEX].text.value; + const resultData: TaskByCategoryData = JSON.parse( + contentText, + ) as TaskByCategoryData; + + return { + message: resultData.message, + tasks: [ + { + categoryId: Number(resultData.task.categoryId), + categoryName: resultData.task.categoryName, + description: resultData.task.description, + dueDate: resultData.task.dueDate, + label: resultData.task.label, + }, + ], + }; + } + + return null; +}; + +export { generateChangeTaskSuggestionsResponse }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts new file mode 100644 index 000000000..d40c4a568 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts @@ -0,0 +1,26 @@ +import { + OpenAiFunctionName, + type OpenAiRunThreadRequestDto, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type TaskCreateDto } from "../../types/types.js"; +import { ChangeTaskByCategory as ChangeTaskByCategoryValidationSchema } from "./change-task.validation-schema.js"; +import { ChangeTaskPromptTemplates } from "./change-task-message.enum.js"; +import { generaChangeTaskPrompt } from "./geregate-change-task-prompt.js"; + +const runChangeTaskByCategoryOptions = ( + task: TaskCreateDto, +): OpenAiRunThreadRequestDto => { + const changeTaskPrompt = generaChangeTaskPrompt(task); + + return { + additional_instructions: null, + function_name: OpenAiFunctionName.CHANGE_TASK, + instructions: ChangeTaskPromptTemplates.CHANGE_TASKS_INSTRUCTIONS, + messages: [changeTaskPrompt], + validationSchema: ChangeTaskByCategoryValidationSchema, + }; +}; + +export { runChangeTaskByCategoryOptions }; +export { generateChangeTaskSuggestionsResponse } from "./change-task-response.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts new file mode 100644 index 000000000..f11017c33 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts @@ -0,0 +1,14 @@ +import { z } from "zod"; + +const ChangeTaskByCategory = z.object({ + message: z.string(), + task: z.object({ + categoryId: z.number(), + categoryName: z.string(), + description: z.string(), + dueDate: z.string(), + label: z.string(), + }), +}); + +export { ChangeTaskByCategory }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts new file mode 100644 index 000000000..3ddd5b214 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts @@ -0,0 +1,21 @@ +import { + type OpenAiRequestMessage, + OpenAiRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type TaskCreateDto } from "../../types/types.js"; +import { ChangeTaskPromptTemplates } from "./change-task-message.enum.js"; + +function generaChangeTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { + const promptContent = { + context: ChangeTaskPromptTemplates.CHANGE_TASKS_CONTEXT, + task, + }; + + return { + content: JSON.stringify(promptContent), + role: OpenAiRoleKey.USER, + }; +} + +export { generaChangeTaskPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts index 904142002..a2abf58f3 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts @@ -1,3 +1,7 @@ +export { + generateChangeTaskSuggestionsResponse, + runChangeTaskByCategoryOptions, +} from "./change-task/change-task.js"; export { generateQuestionsAnswersPrompt, generateScoresResponse, diff --git a/apps/backend/src/modules/ai-assistant/libs/types/types.ts b/apps/backend/src/modules/ai-assistant/libs/types/types.ts index 69e942d10..77f9d2e31 100644 --- a/apps/backend/src/modules/ai-assistant/libs/types/types.ts +++ b/apps/backend/src/modules/ai-assistant/libs/types/types.ts @@ -1,6 +1,8 @@ export { type BalanceWheelAnalysisResponseDto, + type ChangeTaskSuggestionRequestDto, type SelectedCategories, + type TaskCreateDto, type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, diff --git a/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts index 9cb1ac5d5..ba41d0c31 100644 --- a/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts +++ b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -1,4 +1,5 @@ export { addMessageToThreadValidationSchema, + ChangeTaskSuggestionRequestValidationSchema, TaskSuggestionRequestValidationSchema, } from "shared"; From 146facbb4c832827e1a26d605389db5be9605888 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 17:43:59 +0100 Subject: [PATCH 092/244] refactor(backend): change task fields names to be the same as in Dto bb-203 --- .../helpers/change-task/change-task-message.enum.ts | 2 +- .../libs/helpers/change-task/change-task-response.ts | 10 +++++----- .../change-task/change-task.validation-schema.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts index 86b9219b4..89d54b526 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts @@ -35,7 +35,7 @@ and focused on gradual and meaningful progress in line with their priorities. 3. Provide a clear description for the new task, assign a due date, and include a meaningful label. -4. Place the structured new task in the \`task\` field, and provide a summary or confirmation in the \`message\` field. +4. Place the structured new task in the \`tasks\` field, and provide a summary or confirmation in the \`message\` field. `, } as const; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts index 3a9b63995..2bc997a16 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts @@ -33,11 +33,11 @@ const generateChangeTaskSuggestionsResponse = ( message: resultData.message, tasks: [ { - categoryId: Number(resultData.task.categoryId), - categoryName: resultData.task.categoryName, - description: resultData.task.description, - dueDate: resultData.task.dueDate, - label: resultData.task.label, + categoryId: Number(resultData.tasks.categoryId), + categoryName: resultData.tasks.categoryName, + description: resultData.tasks.description, + dueDate: resultData.tasks.dueDate, + label: resultData.tasks.label, }, ], }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts index f11017c33..69412d12a 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts @@ -2,7 +2,7 @@ import { z } from "zod"; const ChangeTaskByCategory = z.object({ message: z.string(), - task: z.object({ + tasks: z.object({ categoryId: z.number(), categoryName: z.string(), description: z.string(), From 0ae35ee954fa2b0ed1fed26d0103c10aae811648 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 17:45:51 +0100 Subject: [PATCH 093/244] feat(backend): add OpenAi function for change task bb-203 --- .../ai-assistant-tools/ai-assistant-tools.ts | 1 + .../ai-assistant-tools/change-task-tool.ts | 120 ++++++++++++++++++ .../enums/open-ai-assistant-config.enum.ts | 3 +- .../libs/enums/open-ai-function-name.enum.ts | 1 + 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/change-task-tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts index b2db3c92d..d0afcdb9b 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts @@ -1,2 +1,3 @@ export { AnalyzeBalanceScoresTool } from "./analyze-balance-scores-tool.js"; +export { ChangeTaskTool } from "./change-task-tool.js"; export { GenerateTaskByCategoryTool } from "./suggest-task-by-category.tool.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/change-task-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/change-task-tool.ts new file mode 100644 index 000000000..ca4b38192 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/change-task-tool.ts @@ -0,0 +1,120 @@ +const ChangeTaskTool = { + function: { + description: + "Generates a new task for the category based on the user's request, ensuring it doesn't repeat previously suggested tasks and takes into account the user's onboarding quiz priorities.", + name: "change_task", + parameters: { + additionalProperties: false, + properties: { + context: { + description: "Context explaining the user's need other task", + type: "string", + }, + instructions: { + additionalProperties: false, + properties: { + action: { + description: + "The steps the assistant should take (e.g., generate tasks, provide descriptions, assign due dates)", + type: "string", + }, + task: { + description: + "The main task for the assistant (e.g., suggest actionable tasks for each category)", + type: "string", + }, + }, + required: ["task", "action"], + type: "object", + }, + response_structure: { + additionalProperties: false, + description: "Structure of the expected response", + properties: { + message: { + description: "A message summarizing the newly generated task", + type: "string", + }, + tasks: { + additionalProperties: false, + description: "The new task generated for the category", + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "number", + }, + categoryName: { + description: "The name of the category", + type: "string", + }, + description: { + description: "Detailed description of the new task", + type: "string", + }, + dueDate: { + description: "Suggested due date for the new task", + type: "string", + }, + label: { + description: "Label or name of the task", + type: "string", + }, + }, + required: [ + "categoryId", + "categoryName", + "description", + "dueDate", + "label", + ], + type: "object", + }, + }, + required: ["message", "tasks"], + type: "object", + }, + task: { + additionalProperties: false, + description: + "Details about the task for which the user is requesting a new task.", + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "number", + }, + categoryName: { + description: "The name of the category (e.g., Health, Work)", + type: "string", + }, + description: { + description: "Description of the previously suggested task", + type: "string", + }, + dueDate: { + description: "Due date of the previously suggested task", + type: "string", + }, + label: { + description: "Label or name of the previously suggested task", + type: "string", + }, + }, + required: [ + "categoryId", + "categoryName", + "description", + "dueDate", + "label", + ], + type: "object", + }, + }, + required: ["context", "response_structure", "instructions", "task"], + type: "object", + }, + strict: true, + }, + type: "function", +} as const; + +export { ChangeTaskTool }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts index edcf06b74..6ed012017 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts @@ -1,5 +1,6 @@ import { AnalyzeBalanceScoresTool, + ChangeTaskTool, GenerateTaskByCategoryTool, } from "../ai-assistant-tools/ai-assistant-tools.js"; import { OpenAiPromptTemplates } from "./open-ai-prompt-messages.enum.js"; @@ -8,7 +9,7 @@ const OpenAiAssistantConfig = { INSTRUCTION: OpenAiPromptTemplates.ASSISTANT_INSTRUCTION, NAME: "Wheel of Balance Assistant", TEMPERATURE: 1, - TOOLS: [AnalyzeBalanceScoresTool, GenerateTaskByCategoryTool], + TOOLS: [AnalyzeBalanceScoresTool, GenerateTaskByCategoryTool, ChangeTaskTool], TOP_P: 1, } as const; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts index 647f5b2bc..09094e57b 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts @@ -1,5 +1,6 @@ const OpenAiFunctionName = { ANALYZE_BALANCE_SCORES: "analyze_balance_scores", + CHANGE_TASK: "change_task", GENERATE_TASK_BY_CATEGORY: "generate_task_by_category", } as const; export { OpenAiFunctionName }; From e9c7eedb0270e9fb70ade18233457229afb2b4f7 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 20:55:39 +0100 Subject: [PATCH 094/244] feat(shared): add route for accepting Task bb-203 --- .../ai-assistant/libs/enums/ai-assistant-api-path.enum.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts index 375d6d35d..4e0c6b844 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -1,4 +1,5 @@ const AiAssistantApiPath = { + ACCEPT_TASK: "/chat/accept-task", ADD_MESSAGE: "/chat/add-message", CONTINUE_CHAT: "/chat/continue", DELETE_CHAT: "/chat/remove", From c6ea5586f961fa894c39204c608fd79f1728df9d Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 20:57:18 +0100 Subject: [PATCH 095/244] feat(backend): add create() to TaskRepository and add exports bb-203 --- .../src/modules/tasks/task.repository.ts | 27 +++++++++++++++++-- apps/backend/src/modules/tasks/tasks.ts | 4 ++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/modules/tasks/task.repository.ts b/apps/backend/src/modules/tasks/task.repository.ts index e59714f7b..e70919155 100644 --- a/apps/backend/src/modules/tasks/task.repository.ts +++ b/apps/backend/src/modules/tasks/task.repository.ts @@ -10,8 +10,31 @@ class TaskRepository implements Repository { this.taskModel = taskModel; } - create(): Promise { - return Promise.resolve(); + async create(entity: TaskEntity): Promise { + const { categoryId, description, dueDate, label, userId } = + entity.toNewObject(); + const task = await this.taskModel + .query() + .insert({ + categoryId, + description, + dueDate, + label, + userId, + }) + .returning("*"); + + return TaskEntity.initialize({ + categoryId: task.categoryId, + createdAt: task.createdAt, + description: task.description, + dueDate: task.dueDate, + id: task.id, + label: task.label, + status: task.status, + updatedAt: task.updatedAt, + userId: task.userId, + }); } public delete(): ReturnType { diff --git a/apps/backend/src/modules/tasks/tasks.ts b/apps/backend/src/modules/tasks/tasks.ts index dd742c4fd..d09b87826 100644 --- a/apps/backend/src/modules/tasks/tasks.ts +++ b/apps/backend/src/modules/tasks/tasks.ts @@ -9,5 +9,7 @@ const taskRepository = new TaskRepository(TaskModel); const taskService = new TaskService(taskRepository); const taskController = new TaskController(logger, taskService); -export { taskController }; +export { taskController, taskRepository }; +export { TaskEntity } from "./task.entity.js"; export { TaskModel } from "./task.model.js"; +export { type TaskRepository } from "./task.repository.js"; From 8803c9766a8430244ac2480780ecd2264441258a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 20:58:25 +0100 Subject: [PATCH 096/244] feat(backend): add createTask() to AiAssistantController bb-203 --- .../ai-assistant/ai-assistant.controller.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 569f380c5..19fb819c0 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -82,6 +82,35 @@ class AiAssistantController extends BaseController { body: TaskSuggestionRequestValidationSchema, }, }); + + this.addRoute({ + handler: (options) => + this.acceptTask( + options as APIHandlerOptions<{ + body: ChangeTaskSuggestionRequestDto; + user: UserDto; + }>, + ), + method: "POST", + path: AiAssistantApiPath.ACCEPT_TASK, + validation: { + body: ChangeTaskSuggestionRequestValidationSchema, + }, + }); + } + + private async acceptTask( + options: APIHandlerOptions<{ + body: ChangeTaskSuggestionRequestDto; + user: UserDto; + }>, + ): Promise { + const { body, user } = options; + + return { + payload: await this.openAiService.acceptTask(user, body), + status: HTTPCode.OK, + }; } private async addMessageToConversation( From 8b3de744645de84143a8351bbf12f002a1373c32 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 21:00:33 +0100 Subject: [PATCH 097/244] feat(backend): add createTask() to AiAssistantService bb-203 --- .../ai-assistant/ai-assistant.service.ts | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index fc28cec63..46a57e728 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -2,6 +2,7 @@ import { type OpenAi, OpenAiRoleKey } from "~/libs/modules/open-ai/open-ai.js"; import { type UserDto } from "~/libs/types/types.js"; import { type CategoryService } from "~/modules/categories/categories.js"; import { type OnboardingRepository } from "~/modules/onboarding/onboarding.js"; +import { TaskEntity, type TaskRepository } from "~/modules/tasks/tasks.js"; import { generateChangeTaskSuggestionsResponse, @@ -15,6 +16,7 @@ import { import { type BalanceWheelAnalysisResponseDto, type ChangeTaskSuggestionRequestDto, + type TaskDto, type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, @@ -24,21 +26,50 @@ type Constructor = { categoryService: CategoryService; onboardingRepository: OnboardingRepository; openAi: OpenAi; + taskRepository: TaskRepository; }; class AiAssistantService { private categoryService: CategoryService; private onboardingRepository: OnboardingRepository; private openAi: OpenAi; + private taskRepository: TaskRepository; public constructor({ categoryService, onboardingRepository, openAi, + taskRepository, }: Constructor) { this.openAi = openAi; this.categoryService = categoryService; this.onboardingRepository = onboardingRepository; + this.taskRepository = taskRepository; + } + + public async acceptTask( + user: UserDto, + body: ChangeTaskSuggestionRequestDto, + ): Promise { + const { task, threadId } = body; + + const newTask = await this.taskRepository.create( + TaskEntity.initializeNew({ + categoryId: task.categoryId, + description: task.description, + dueDate: task.dueDate, + label: task.label, + userId: user.id, + }), + ); + const chatMessage = { + content: `User has accepted this task: ${JSON.stringify(newTask)}`, + role: OpenAiRoleKey.USER, + }; + + await this.openAi.addMessageToThread(threadId, chatMessage); + + return newTask.toObject(); } public async addMessageToThread( @@ -48,7 +79,6 @@ class AiAssistantService { const prompt = { content: text, - metadata: {}, role: OpenAiRoleKey.USER, }; From 0af1fb67f1c5e73c145fb877c7d5001e9ea72c3f Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sat, 14 Sep 2024 21:02:23 +0100 Subject: [PATCH 098/244] chore(backend): update import in Ai Module bb-203 --- apps/backend/src/modules/ai-assistant/ai-assistant.ts | 2 ++ apps/backend/src/modules/ai-assistant/libs/types/types.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.ts index 13abe0151..6299e5b4f 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.ts @@ -2,6 +2,7 @@ import { logger } from "~/libs/modules/logger/logger.js"; import { openAi } from "~/libs/modules/open-ai/open-ai.js"; import { categoryService } from "~/modules/categories/categories.js"; import { onboardingRepository } from "~/modules/onboarding/onboarding.js"; +import { taskRepository } from "~/modules/tasks/tasks.js"; import { AiAssistantController } from "./ai-assistant.controller.js"; import { AiAssistantService } from "./ai-assistant.service.js"; @@ -10,6 +11,7 @@ const aiAssistantService = new AiAssistantService({ categoryService, onboardingRepository, openAi, + taskRepository, }); const aiAssistantController = new AiAssistantController( diff --git a/apps/backend/src/modules/ai-assistant/libs/types/types.ts b/apps/backend/src/modules/ai-assistant/libs/types/types.ts index 77f9d2e31..e334ef91d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/types/types.ts +++ b/apps/backend/src/modules/ai-assistant/libs/types/types.ts @@ -3,6 +3,7 @@ export { type ChangeTaskSuggestionRequestDto, type SelectedCategories, type TaskCreateDto, + type TaskDto, type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, From ec79675a9f4a9e2b36fe9da59b24f52a7eabd16c Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 12:13:22 +0100 Subject: [PATCH 099/244] feat(backend): update Ai Module to handle multiple runs bb-203 --- .../src/libs/modules/open-ai/open-ai.module.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts index 36b6d68bd..21a0b0e44 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts @@ -109,11 +109,11 @@ class OpenAi { functionName: string, ): Promise { if (run.status === "completed") { - return await this.getAllMessagesBy(threadId); + return await this.getAllMessages(threadId); } else if (run.status === "requires_action") { await this.handleRequiresAction(run, functionName); - return await this.getAllMessagesBy(threadId); + return await this.getAllMessages(threadId); } else { this.logger.error(`AI Assistant run failed: ${run.status}`); @@ -171,7 +171,7 @@ class OpenAi { return result.deleted; } - public async getAllMessagesBy( + public async getAllMessages( threadId: string, ): Promise { return await this.openAi.beta.threads.messages.list(threadId); @@ -185,6 +185,16 @@ class OpenAi { threadId: string, runOptions: OpenAiRunThreadRequestDto, ): Promise { + const runs = await this.openAi.beta.threads.runs.list(threadId); + + const pendingRuns = runs.data.filter( + (run) => run.status === "in_progress" || run.status === "queued", + ); + + for (const run of pendingRuns) { + await this.openAi.beta.threads.runs.poll(threadId, run.id); + } + const run = await this.openAi.beta.threads.runs.createAndPoll(threadId, { additional_instructions: runOptions.additional_instructions, additional_messages: runOptions.messages, From e16a89e06f9f13aa5863d4b786039fcba6bffd8e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 13:48:30 +0100 Subject: [PATCH 100/244] feat(backend): add swagger to AiAssistantController bb-203 --- .../ai-assistant/ai-assistant.controller.ts | 388 +++++++++++++++++- 1 file changed, 387 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 19fb819c0..58d413607 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -21,6 +21,108 @@ import { TaskSuggestionRequestValidationSchema, } from "./libs/validation-schemas/validation-schemas.js"; +/** + * @swagger + * components: + * securitySchemes: + * bearerAuth: + * type: http + * scheme: bearer + * bearerFormat: JWT + * schemas: + * NewTask: + * type: object + * required: + * - categoryId + * - categoryName + * - description + * - dueDate + * - label + * properties: + * categoryId: + * type: integer + * description: Unique identifier for the category of the task + * example: 1 + * categoryName: + * type: string + * description: Name of the task category + * example: "Work" + * description: + * type: string + * description: Detailed description of the task + * example: "Finish the project by the deadline" + * dueDate: + * type: string + * format: date-time + * description: The deadline for the task + * example: "2024-09-30" + * label: + * type: string + * description: A label for the task (priority, tags, etc.) + * example: "Finish project" + * + * Task: + * type: object + * required: + * - categoryId + * - createdAt + * - description + * - dueDate + * - id + * - label + * - status + * - updatedAt + * - userId + * properties: + * categoryId: + * type: integer + * description: Unique identifier for the category of the task + * example: 1 + * createdAt: + * type: string + * format: date-time + * description: Timestamp when the task was created + * example: "2024-09-01T08:30:00Z" + * description: + * type: string + * description: Detailed description of the task + * example: "Complete the client project by the end of the month" + * dueDate: + * type: string + * format: date-time + * description: The deadline for completing the task + * example: "2024-09-30T10:00:00Z" + * id: + * type: integer + * description: Unique identifier for the task + * example: 123 + * label: + * type: string + * description: Label or tag associated with the task + * example: "Complete project" + * status: + * type: string + * description: Current status of the task + * enum: + * - Completed + * - Current + * - Skipped + * example: "Current" + * updatedAt: + * type: string + * format: date-time + * description: Timestamp when the task was last updated + * example: "2024-09-15T12:45:00Z" + * userId: + * type: integer + * description: Unique identifier of the user who created the task + * example: 42 + * + * tags: + * - name: AI Assistant + * description: Endpoints related to AI Assistant services and interactions + */ + class AiAssistantController extends BaseController { private openAiService: AiAssistantService; @@ -62,7 +164,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.GENERATE_ALTERNATIVE_TASK, + path: AiAssistantApiPath.CHANGE_TASK, validation: { body: ChangeTaskSuggestionRequestValidationSchema, }, @@ -99,6 +201,36 @@ class AiAssistantController extends BaseController { }); } + /** + * @swagger + * /assistant/chat/accept-task: + * post: + * summary: Accept a task suggestion + * tags: + * - AI Assistant + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * task: + * $ref: '#/components/schemas/NewTask' + * threadId: + * type: string + * description: Identifier for the thread + * example: "thread_abc123" + * responses: + * 200: + * description: Returns the accepted task + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Task' + */ private async acceptTask( options: APIHandlerOptions<{ body: ChangeTaskSuggestionRequestDto; @@ -113,6 +245,39 @@ class AiAssistantController extends BaseController { }; } + /** + * @swagger + * /assistant/chat/add-message: + * post: + * summary: Add a message to a conversation thread + * tags: + * - AI Assistant + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * text: + * type: string + * description: The text message to add to the thread + * example: "Hello, how can I assist you?" + * threadId: + * type: string + * description: Identifier for the conversation thread + * example: "thread_abc123" + * responses: + * 200: + * description: Indicates if the message was successfully added + * content: + * application/json: + * schema: + * type: boolean + * example: true + */ private async addMessageToConversation( options: APIHandlerOptions<{ body: ThreadMessageCreateDto; @@ -126,6 +291,45 @@ class AiAssistantController extends BaseController { }; } + /** + * @swagger + * /assistant/chat/change-task: + * post: + * summary: Change task + * tags: + * - AI Assistant + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * task: + * $ref: '#/components/schemas/NewTask' + * threadId: + * type: string + * description: Identifier for the thread + * example: "thread_abc123" + * responses: + * 200: + * description: Returns task suggestions based on the provided input + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * description: Message about the task suggestion + * example: "Task suggestions updated successfully" + * tasks: + * type: array + * items: + * $ref: '#/components/schemas/NewTask' + */ private async changeTaskSuggestion( options: APIHandlerOptions<{ body: ChangeTaskSuggestionRequestDto; @@ -139,6 +343,95 @@ class AiAssistantController extends BaseController { }; } + /** + * @swagger + * /assistant/chat/initiate: + * post: + * summary: Initialize a new chat + * tags: + * - AI Assistant + * security: + * - bearerAuth: [] + * requestBody: + * description: This endpoint doesn't require a request body. + * content: {} + * responses: + * 200: + * description: Returns the analysis of the balance wheel with messages and thread information + * content: + * application/json: + * schema: + * type: object + * properties: + * lowestCategories: + * type: array + * description: Array of the lowest scoring categories + * items: + * $ref: '#/components/schemas/QuizScore' + * messages: + * type: object + * properties: + * comments: + * type: string + * description: Comments for the analysis + * example: "Your balance wheel shows imbalance in certain areas." + * greeting: + * type: string + * description: Greeting message + * example: "Welcome to your analysis!" + * question: + * type: string + * description: A question posed to the user + * example: "How do you feel about these results?" + * threadId: + * type: string + * description: Identifier for the chat thread + * example: "thread_abc123" + * components: + * schemas: + * BalanceWheelAnalysis: + * type: object + * properties: + * lowestCategories: + * type: array + * description: Array of the lowest scoring categories + * items: + * $ref: '#/components/schemas/QuizScore' + * messages: + * type: object + * properties: + * comments: + * type: string + * description: Comments for the analysis + * example: "Your balance wheel shows imbalance in certain areas." + * greeting: + * type: string + * description: Greeting message + * example: "Welcome to your analysis!" + * question: + * type: string + * description: A question posed to the user + * example: "How do you feel about these results?" + * threadId: + * type: string + * description: Identifier for the chat thread + * example: "thread_abc123" + * QuizScore: + * type: object + * properties: + * categoryName: + * type: string + * description: The category name + * example: "Health" + * categoryId: + * type: integer + * description: The category id + * example: 1 + * score: + * type: number + * description: The score for the category + * example: 3 + */ private async initNewChat( options: APIHandlerOptions<{ user: UserDto; @@ -152,6 +445,99 @@ class AiAssistantController extends BaseController { }; } + /** + * @swagger + * /assistant/chat/suggest-tasks: + * post: + * summary: Suggest tasks for selected categories + * tags: + * - AI Assistant + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * categories: + * type: array + * description: Array of selected categories for task suggestions + * items: + * $ref: '#/components/schemas/SelectedCategories' + * threadId: + * type: string + * description: Identifier for the thread + * example: "thread_abc123" + * responses: + * 200: + * description: Returns task suggestions for the provided categories + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/TaskSuggestionsResponseDto' + * components: + * securitySchemes: + * bearerAuth: + * type: http + * scheme: bearer + * bearerFormat: JWT + * schemas: + * SelectedCategories: + * type: object + * properties: + * categoryId: + * type: integer + * description: Unique identifier for the category + * example: 1 + * name: + * type: string + * description: Name of the category + * example: "Work" + * TaskSuggestionsResponseDto: + * type: object + * properties: + * message: + * type: string + * description: Response message regarding task suggestions + * example: "Tasks suggested successfully." + * tasks: + * type: array + * description: Suggested tasks for the selected categories + * items: + * $ref: '#/components/schemas/TaskCreateDto' + * TaskCreateDto: + * type: object + * required: + * - categoryId + * - categoryName + * - description + * - dueDate + * - label + * properties: + * categoryId: + * type: integer + * description: Unique identifier for the category of the task + * example: 1 + * categoryName: + * type: string + * description: Name of the task category + * example: "Work" + * description: + * type: string + * description: Detailed description of the task + * example: "Finish the project by the deadline" + * dueDate: + * type: string + * format: date-time + * description: The deadline for the task + * example: "2024-09-30T10:00:00Z" + * label: + * type: string + * description: A label for the task + * example: "High Priority" + */ private async suggestTasksForCategories( options: APIHandlerOptions<{ body: TaskSuggestionRequestDto; From 1c4df157009a6d01fa523d65a7069c412d59bdbe Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 13:50:21 +0100 Subject: [PATCH 101/244] refactor(shared): rename AiAssistantApiPath path bb-203 --- .../ai-assistant/libs/enums/ai-assistant-api-path.enum.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts index 4e0c6b844..4fc97c8c5 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -1,9 +1,9 @@ const AiAssistantApiPath = { ACCEPT_TASK: "/chat/accept-task", ADD_MESSAGE: "/chat/add-message", + CHANGE_TASK: "/chat/change-task", CONTINUE_CHAT: "/chat/continue", DELETE_CHAT: "/chat/remove", - GENERATE_ALTERNATIVE_TASK: "/chat/generate-alternative-task", INIT_NEW_CHAT: "/chat/initiate", SUGGEST_TASKS: "/chat/suggest-tasks", } as const; From 82d956fcd48ea4f9330e630f8100796ab2421a21 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 13:53:39 +0100 Subject: [PATCH 102/244] refactor(shared): change AiAssistantValidationRule and schema bb-203 --- .../libs/enums/ai-assistant-validatuon-rule.enum.ts | 2 +- .../task-suggestion-request.validation-schema.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts index 59d0da733..3896b59e4 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -1,5 +1,5 @@ const AiAssistantValidationRule = { - DATE_FORMAT: /^\d{4}-\d{2}-\d{2}$/, + DATE_FORMAT: /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}Z)?$/, NON_EMPTY_STRING_MIN_LENGTH: 1, THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, } as const; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 383ae65e2..720312cec 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -10,7 +10,7 @@ const TaskSuggestionRequest = z.object({ .array( z.object({ categoryId: z - .string() + .number() .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, }), From cc223c4790d498b0c5388e1eaf6db030f9724434 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:38:20 +0300 Subject: [PATCH 103/244] feat(shared): add INDEX_ONE constant bb-340 --- apps/frontend/src/libs/enums/enums.ts | 2 ++ packages/shared/src/index.ts | 2 ++ packages/shared/src/libs/constants/constant.ts | 1 + packages/shared/src/libs/constants/index-one.constant.ts | 3 +++ 4 files changed, 8 insertions(+) create mode 100644 packages/shared/src/libs/constants/index-one.constant.ts diff --git a/apps/frontend/src/libs/enums/enums.ts b/apps/frontend/src/libs/enums/enums.ts index 14417ec62..ea1ee0a94 100644 --- a/apps/frontend/src/libs/enums/enums.ts +++ b/apps/frontend/src/libs/enums/enums.ts @@ -7,6 +7,8 @@ export { AppEnvironment, ContentType, ErrorMessage, + INDEX_ONE, NumericalValue, ServerErrorType, + ZERO_INDEX, } from "shared"; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index db9ae0b46..6fae67416 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,4 +1,5 @@ export { + INDEX_ONE, PREVIOUS_INDEX_OFFSET, ZERO_INDEX, } from "./libs/constants/constant.js"; @@ -47,6 +48,7 @@ export { type BalanceWheelAnalysisResponseDto, type SelectedCategories, type SimplifiedQuizScoreDto, + type SimplifiedTaskDto, type TaskSuggestionRequestDto, TaskSuggestionRequestValidationSchema, type TaskSuggestionsResponseDto, diff --git a/packages/shared/src/libs/constants/constant.ts b/packages/shared/src/libs/constants/constant.ts index e65287eae..37aea9fef 100644 --- a/packages/shared/src/libs/constants/constant.ts +++ b/packages/shared/src/libs/constants/constant.ts @@ -1,2 +1,3 @@ +export { INDEX_ONE } from "./index-one.constant.js"; export { PREVIOUS_INDEX_OFFSET } from "./previous-index-offset.constant.js"; export { ZERO_INDEX } from "./zero-index.constant.js"; diff --git a/packages/shared/src/libs/constants/index-one.constant.ts b/packages/shared/src/libs/constants/index-one.constant.ts new file mode 100644 index 000000000..ef152edb4 --- /dev/null +++ b/packages/shared/src/libs/constants/index-one.constant.ts @@ -0,0 +1,3 @@ +const INDEX_ONE = 1; + +export { INDEX_ONE }; From 522e328f792b4b2da31acc560f2dc954d8a0a8d9 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:39:23 +0300 Subject: [PATCH 104/244] feat(shared): add type AppDispatch bb-340 --- apps/frontend/src/libs/hooks/hooks.ts | 5 ++++- .../src/libs/hooks/use-app-dispatch/use-app-dispatch.hook.ts | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/libs/hooks/hooks.ts b/apps/frontend/src/libs/hooks/hooks.ts index 9f7ee04b8..de2cb3f5f 100644 --- a/apps/frontend/src/libs/hooks/hooks.ts +++ b/apps/frontend/src/libs/hooks/hooks.ts @@ -1,4 +1,7 @@ -export { useAppDispatch } from "./use-app-dispatch/use-app-dispatch.hook.js"; +export { + type AppDispatch, + useAppDispatch, +} from "./use-app-dispatch/use-app-dispatch.hook.js"; export { useAppForm } from "./use-app-form/use-app-form.hook.js"; export { useAppSelector } from "./use-app-selector/use-app-selector.hook.js"; export { useQuery } from "./use-query/use-query-hook.js"; diff --git a/apps/frontend/src/libs/hooks/use-app-dispatch/use-app-dispatch.hook.ts b/apps/frontend/src/libs/hooks/use-app-dispatch/use-app-dispatch.hook.ts index 2de0892ef..8f0d2a149 100644 --- a/apps/frontend/src/libs/hooks/use-app-dispatch/use-app-dispatch.hook.ts +++ b/apps/frontend/src/libs/hooks/use-app-dispatch/use-app-dispatch.hook.ts @@ -3,5 +3,6 @@ import { useDispatch } from "react-redux"; import { type store } from "~/libs/modules/store/store.js"; const useAppDispatch = useDispatch.withTypes(); +type AppDispatch = typeof store.instance.dispatch; -export { useAppDispatch }; +export { type AppDispatch, useAppDispatch }; From daf2d85320742e434706ddbd25298411cd5b3fa7 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:41:55 +0300 Subject: [PATCH 105/244] feat(frontend): import types bb-340 --- apps/frontend/src/modules/chat/chat.ts | 4 ++++ apps/frontend/src/modules/chat/libs/types/types.ts | 3 +++ packages/shared/src/modules/ai-assistant/ai-assistant.ts | 1 + .../libs/types/task-suggestion-response-dto.type.ts | 2 +- packages/shared/src/modules/ai-assistant/libs/types/types.ts | 5 ++++- .../shared/src/modules/tasks/libs/types/task-dto.type.ts | 1 + 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/modules/chat/chat.ts b/apps/frontend/src/modules/chat/chat.ts index 49147e746..ce21da06d 100644 --- a/apps/frontend/src/modules/chat/chat.ts +++ b/apps/frontend/src/modules/chat/chat.ts @@ -11,4 +11,8 @@ const chatApi = new ChatApi({ }); export { chatApi }; +export { + type SimplifiedQuizScoreDto, + type TaskSuggestionRequestDto, +} from "./libs/types/types.js"; export { actions, reducer } from "./slices/chat.js"; diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts index d2396ac62..be91a5f37 100644 --- a/apps/frontend/src/modules/chat/libs/types/types.ts +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -1,6 +1,9 @@ export { type BalanceWheelAnalysisResponseDto, type SimplifiedQuizScoreDto, + type SimplifiedTaskDto, type TaskDto, + type TaskSuggestionRequestDto, + type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "shared"; diff --git a/packages/shared/src/modules/ai-assistant/ai-assistant.ts b/packages/shared/src/modules/ai-assistant/ai-assistant.ts index 3e55e28ee..f1731d1d3 100644 --- a/packages/shared/src/modules/ai-assistant/ai-assistant.ts +++ b/packages/shared/src/modules/ai-assistant/ai-assistant.ts @@ -3,6 +3,7 @@ export { type BalanceWheelAnalysisResponseDto, type SelectedCategories, type SimplifiedQuizScoreDto, + type SimplifiedTaskDto, type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, diff --git a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts index d7b4c59af..2a11632cd 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-response-dto.type.ts @@ -10,4 +10,4 @@ type TaskSuggestionsResponseDto = { tasks: SimplifiedTaskDto[]; }; -export { type TaskSuggestionsResponseDto }; +export { type SimplifiedTaskDto, type TaskSuggestionsResponseDto }; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/types.ts b/packages/shared/src/modules/ai-assistant/libs/types/types.ts index 606665521..383b216d2 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/types.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/types.ts @@ -6,5 +6,8 @@ export { type SelectedCategories, type TaskSuggestionRequestDto, } from "./task-suggestion-request-dto.type.js"; -export { type TaskSuggestionsResponseDto } from "./task-suggestion-response-dto.type.js"; +export { + type SimplifiedTaskDto, + type TaskSuggestionsResponseDto, +} from "./task-suggestion-response-dto.type.js"; export { type ThreadMessageCreateDto } from "./thread-message-create-dto.type.js"; diff --git a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts index 964965176..6555bc44e 100644 --- a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts +++ b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts @@ -3,6 +3,7 @@ import { type TaskStatus } from "../enums/enums.js"; type TaskDto = { categoryId: number; + categoryName: string; createdAt: string; description: string; dueDate: string; From 8d4cdea0332b0299815222f83254995abe5f7160 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:43:07 +0300 Subject: [PATCH 106/244] refactor(frontend): message type bb-340 --- apps/frontend/src/modules/chat/libs/types/message.type.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/frontend/src/modules/chat/libs/types/message.type.ts b/apps/frontend/src/modules/chat/libs/types/message.type.ts index e48b6d595..c79da5be0 100644 --- a/apps/frontend/src/modules/chat/libs/types/message.type.ts +++ b/apps/frontend/src/modules/chat/libs/types/message.type.ts @@ -1,4 +1,4 @@ -import { type TaskDto } from "shared"; +import { type SimplifiedTaskDto } from "./types.js"; type ButtonLabels = string[]; @@ -9,12 +9,12 @@ type Message = { categoryName: string; score: number; }>; - taskList?: TaskDto[]; + taskList?: SimplifiedTaskDto[]; text: string; threadId?: string; type: - | "categoryInputs" - | "suggestionButtons" + | "categoryForm" + | "confirmationButtons" | "taskList" | "text" | "wheelAnalysis"; From 0493c0dfa856f558f95c408c95a62979d903e84e Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:45:29 +0300 Subject: [PATCH 107/244] feat(frontend): add getTasksForCategories to Api bb-340 --- apps/frontend/src/modules/chat/chat-api.ts | 22 ++++++++++- .../src/modules/chat/slices/actions.ts | 18 ++++++++- .../src/modules/chat/slices/chat.slice.ts | 37 +++++++++++++++++-- apps/frontend/src/modules/chat/slices/chat.ts | 3 +- 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/apps/frontend/src/modules/chat/chat-api.ts b/apps/frontend/src/modules/chat/chat-api.ts index e8e301813..67be82bbe 100644 --- a/apps/frontend/src/modules/chat/chat-api.ts +++ b/apps/frontend/src/modules/chat/chat-api.ts @@ -4,7 +4,11 @@ import { type HTTP } from "~/libs/modules/http/http.js"; import { type Storage } from "~/libs/modules/storage/storage.js"; import { AiAssistantApiPath } from "./libs/enums/enums.js"; -import { type BalanceWheelAnalysisResponseDto } from "./libs/types/types.js"; +import { + type BalanceWheelAnalysisResponseDto, + type TaskSuggestionRequestDto, + type TaskSuggestionsResponseDto, +} from "./libs/types/types.js"; type Constructor = { baseUrl: string; @@ -17,6 +21,22 @@ class ChatApi extends BaseHTTPApi { super({ baseUrl, http, path: APIPath.ASSISTANT, storage }); } + public async getTasksForCategories( + payload: TaskSuggestionRequestDto, + ): Promise { + const response = await this.load( + this.getFullEndpoint(AiAssistantApiPath.SUGGEST_TASKS, {}), + { + contentType: ContentType.JSON, + hasAuth: true, + method: "POST", + payload: JSON.stringify(payload), + }, + ); + + return await response.json(); + } + public async initiateConversation(): Promise { const response = await this.load( this.getFullEndpoint(AiAssistantApiPath.INIT_NEW_CHAT, {}), diff --git a/apps/frontend/src/modules/chat/slices/actions.ts b/apps/frontend/src/modules/chat/slices/actions.ts index 38e4fec7d..7310b3976 100644 --- a/apps/frontend/src/modules/chat/slices/actions.ts +++ b/apps/frontend/src/modules/chat/slices/actions.ts @@ -2,7 +2,11 @@ import { createAsyncThunk } from "@reduxjs/toolkit"; import { type AsyncThunkConfig } from "~/libs/types/types.js"; -import { type BalanceWheelAnalysisResponseDto } from "../libs/types/types.js"; +import { + type BalanceWheelAnalysisResponseDto, + type TaskSuggestionRequestDto, + type TaskSuggestionsResponseDto, +} from "../libs/types/types.js"; import { name as sliceName } from "./chat.slice.js"; const initConversation = createAsyncThunk< @@ -15,4 +19,14 @@ const initConversation = createAsyncThunk< return await chatApi.initiateConversation(); }); -export { initConversation }; +const getTasksForCategories = createAsyncThunk< + TaskSuggestionsResponseDto, + TaskSuggestionRequestDto, + AsyncThunkConfig +>(`${sliceName}/get-tasks-for-categories`, async (payload, { extra }) => { + const { chatApi } = extra; + + return await chatApi.getTasksForCategories(payload); +}); + +export { getTasksForCategories, initConversation }; diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 991526e7f..60f5712f5 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -5,7 +5,7 @@ import { type ValueOf } from "~/libs/types/types.js"; import { type Message } from "../libs/types/message.type.js"; import { type SimplifiedQuizScoreDto } from "../libs/types/types.js"; -import { initConversation } from "./actions.js"; +import { getTasksForCategories, initConversation } from "./actions.js"; type State = { dataStatus: ValueOf; @@ -40,20 +40,49 @@ const { actions, name, reducer } = createSlice({ type: "wheelAnalysis", }, { - buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], + buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], text: action.payload.messages.question, - type: "suggestionButtons", + type: "confirmationButtons", }, ); state.dataStatus = DataStatus.FULFILLED; }) .addCase(initConversation.rejected, (state) => { state.dataStatus = DataStatus.REJECTED; + }) + .addCase(getTasksForCategories.pending, (state) => { + state.dataStatus = DataStatus.PENDING; + }) + .addCase(getTasksForCategories.fulfilled, (state, action) => { + state.dataStatus = DataStatus.FULFILLED; + const { message, tasks } = action.payload; + state.messages.push({ + taskList: tasks, + text: message, + type: "taskList", + }); + }) + .addCase(getTasksForCategories.rejected, (state) => { + state.dataStatus = DataStatus.REJECTED; }); }, initialState, name: "chat", - reducers: {}, + reducers: { + addCategoryCheckboxMessage(state) { + state.messages.push({ + buttonLabels: ["Accept categories"], + text: "What categories do you want to work on?", + type: "categoryForm", + }); + }, + updateSelectedCategories( + state, + action: { payload: SimplifiedQuizScoreDto[] }, + ) { + state.selectedCategories = action.payload; + }, + }, }); export { actions, name, reducer }; diff --git a/apps/frontend/src/modules/chat/slices/chat.ts b/apps/frontend/src/modules/chat/slices/chat.ts index 6bf923d48..be2cc7663 100644 --- a/apps/frontend/src/modules/chat/slices/chat.ts +++ b/apps/frontend/src/modules/chat/slices/chat.ts @@ -1,8 +1,9 @@ -import { initConversation } from "./actions.js"; +import { getTasksForCategories, initConversation } from "./actions.js"; import { actions } from "./chat.slice.js"; const allActions = { ...actions, + getTasksForCategories, initConversation, }; From 4e645313681f6616050cbe14da843f9fef639f5b Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:46:15 +0300 Subject: [PATCH 108/244] feat(frontend): add handleButtonAction helper bb-340 --- .../helpers/handle-button-action.helper.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts diff --git a/apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts b/apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts new file mode 100644 index 000000000..d16b72747 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts @@ -0,0 +1,27 @@ +import { type AppDispatch } from "~/libs/hooks/hooks.js"; +import { type TaskSuggestionRequestDto } from "~/modules/chat/chat.js"; +import { actions as chatActions } from "~/modules/chat/chat.js"; + +type ActionType = "getCategoryForm" | "getTasks"; + +const handleButtonAction = async ( + dispatch: AppDispatch, + actionType: ActionType, + payload?: TaskSuggestionRequestDto, +): Promise => { + switch (actionType) { + case "getCategoryForm": { + dispatch(chatActions.addCategoryCheckboxMessage()); + break; + } + + case "getTasks": { + await dispatch( + chatActions.getTasksForCategories(payload as TaskSuggestionRequestDto), + ); + break; + } + } +}; + +export { handleButtonAction }; From c3780c5f7716f0ebc24778a134cb7abfbf3929cb Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:46:58 +0300 Subject: [PATCH 109/244] feat(frontend): add ConfirmationButtons component bb-340 --- .../confirmation-buttons.tsx | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx diff --git a/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx b/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx new file mode 100644 index 000000000..f01ceb2f9 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx @@ -0,0 +1,22 @@ +type Properties = { + handleNo: () => void; + handleYes: () => void; + noButtonLabel: string; + yesButtonLabel: string; +}; + +const ConfirmationButtons: React.FC = ({ + handleNo, + handleYes, + noButtonLabel, + yesButtonLabel, +}: Properties) => { + return ( +
    + + +
    + ); +}; + +export { ConfirmationButtons }; From d0c681918017773ce5eb2cc60eaaab006a0b4f49 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:48:21 +0300 Subject: [PATCH 110/244] feat(frontend): handleCategoriesSubmit bb-340 --- apps/frontend/src/pages/chat/chat.tsx | 96 ++++++++++++++------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 7fe54c6e3..2ab410bb1 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -4,7 +4,10 @@ import { useCallback, useEffect, } from "~/libs/hooks/hooks.js"; -import { actions as chatActions } from "~/modules/chat/chat.js"; +import { + actions as chatActions, + // type TaskSuggestionRequestDto, +} from "~/modules/chat/chat.js"; import { actions as quizActions } from "~/modules/quiz/quiz.js"; import { ChatMessage } from "./libs/components/chat-message/chat-message.js"; @@ -14,6 +17,9 @@ const ChatComponent: React.FC = () => { const dispatch = useAppDispatch(); const { scores } = useAppSelector((state) => state.quiz); + const { quizCategories } = useAppSelector(({ categories }) => ({ + quizCategories: categories.items, + })); const chartData = scores.map((score) => { return { data: score.score, @@ -25,50 +31,54 @@ const ChatComponent: React.FC = () => { void dispatch(quizActions.getScores()); }, [dispatch]); - const { messages } = useAppSelector(({ chat }) => ({ - messages: chat.messages, - selectedCategories: chat.selectedCategories, - threadId: chat.threadId, + const { messages, selectedCategories, threadId } = useAppSelector( + ({ chat }) => ({ + messages: chat.messages, + selectedCategories: chat.selectedCategories, + threadId: chat.threadId, + }), + ); + + const formattedCategories = selectedCategories.map((category) => ({ + categoryId: category.categoryId.toString(), + name: category.categoryName, + + // categoryName: category.categoryName, })); - // const messages = [ - // { - // text: "Hello, Julia! I appreciate you sharing your insights about your life areas through the Wheel of Balance. Here's a quick summary of your scores: - **Physical**: 10 (Great satisfaction!) - **Work**: 4 (Room for improvement) - **Friends**: 3 (Needs attention) - **Love**: 6 (Moderately satisfied) - **Money**: 7 (Fairly satisfied) - **Free time**: 5 (Average satisfaction) - **Spiritual**: 6 (Moderately satisfied) - **Mental**: 5 (Average satisfaction) From your scores, it seems that areas you might want to focus on for improvement are: 1. **Friends** (score: 3) 2. **Work** (score: 4) 3. **Free Time** (score: 5) These categories are where you rated the lowest, suggesting they might benefit from your attention and efforts. Now, I am here to support you!", - // threadId: "thread_yUq8ZOtYGNqXEiCyKhKsEwUT", - // type: "wheelAnalysis", - // }, - // { - // buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], - // text: "How would you like to proceed with improving your balance? Do you want to work on 3 fields, with the lowest score, or you want to choose the fields yourself to work on?", - // type: "suggestionButtons", - // }, - // { - // lowestCategories: [ - // { categoryId: 3, categoryName: "Friends", score: 3 }, - // { categoryId: 2, categoryName: "Work", score: 4 }, - // { categoryId: 6, categoryName: "Free time", score: 5 }, - // ], - // text: "Choose the fields yourself to work on?", - // type: "categoryInputs", - // }, - // { - // buttonLabels: [ - // "Everything is clear", - // "Give me more info", - // "I don't like this tasks", - // ], - // taskList: [{}, {}, {}], - // text: "Here is your task list", - // type: "taskList", - // }, - // ]; + + const contentData = { + chartData, + selectedCategories: { + categories: formattedCategories, + threadId: threadId ?? "", + }, + }; useEffect(() => { void dispatch(chatActions.initConversation()); }, [dispatch]); - const handleCategoriesSubmit = useCallback(() => { - // TODO: Add a request to Backend - }, []); + const handleCategoriesSubmit = useCallback( + (payload: { categoryIds: number[] }): void => { + const newSelectedCategories = quizCategories + .filter((category) => payload.categoryIds.includes(category.id)) + .map((category) => ({ + categoryId: category.id, + categoryName: category.name, + score: 0, + })); + dispatch(chatActions.updateSelectedCategories(newSelectedCategories)); + + // const taskPayload: TaskSuggestionRequestDto = { + // categories: newSelectedCategories, + // threadId: threadId ?? "", + // }; + + // await dispatch(chatActions.getTasksForCategories(taskPayload)); + }, + // [dispatch, quizCategories, threadId], + [dispatch, quizCategories], + ); return (
    @@ -78,13 +88,9 @@ const ChatComponent: React.FC = () => { return ( From 9d651c9f545bd2ba99a8908d9afe30f5658fb755 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 16:49:10 +0300 Subject: [PATCH 111/244] feat(frontend): get tasl list bb-340 --- .../components/chat-message/chat-message.tsx | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index fcf066e95..ce4c2099d 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -2,47 +2,82 @@ import { BalanceWheelChart, QuizCategoriesForm, } from "~/libs/components/components.js"; +import { INDEX_ONE, ZERO_INDEX } from "~/libs/enums/enums.js"; +import { useAppDispatch, useCallback } from "~/libs/hooks/hooks.js"; +import { handleButtonAction } from "../../helpers/handle-button-action.helper.js"; +import { ConfirmationButtons } from "../confirmation-buttons/confirmation-buttons.js"; import styles from "./styles.module.css"; type Properties = { buttonLabels?: string[]; - contentData: { data: number; label: string }[]; - onSubmit?: (() => void) | undefined; + contentData: { + chartData: { data: number; label: string }[]; + selectedCategories: { + categories: { categoryId: string; name: string }[]; + // categories: { categoryId: string; categoryName: string }[]; + threadId: string; + }; + }; + onFormSubmit?: (payload: { categoryIds: number[] }) => void; text: string; - type: string; - // type: "wheelAnalysis" | "suggestionButtons" | "categoryInputs" | "taskList"; + type: + | "categoryForm" + | "confirmationButtons" + | "taskList" + | "text" + | "wheelAnalysis"; }; const ChatMessage: React.FC = ({ buttonLabels = [], contentData, - onSubmit, + onFormSubmit, text, type, }: Properties) => { + const dispatch = useAppDispatch(); + + const handleNo = useCallback(() => { + void handleButtonAction(dispatch, "getCategoryForm"); + }, [dispatch]); + + const handleYes = useCallback(() => { + void handleButtonAction( + dispatch, + "getTasks", + contentData.selectedCategories, + ); + }, [dispatch, contentData.selectedCategories]); + const renderContent = (): JSX.Element | null => { switch (type) { - case "categoryInputs": { - return onSubmit ? ( - + case "categoryForm": { + return onFormSubmit ? ( + ) : null; } - case "suggestionButtons": { + case "confirmationButtons": { return ( - <> - {buttonLabels.map((button: string) => ( -
    - -
    - ))} - + ); } case "wheelAnalysis": { - return ; + return ; + } + + case "taskList": { + return
    Task list
    ; } default: { From 6aeadf036fbdd023942a5071363ac3128378946b Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:41:27 +0300 Subject: [PATCH 112/244] fix(frontend/backend): change type for categoryId, remove score bb-340 --- .../ai-assistant-tools/analyze-balance-scores-tool.ts | 10 +++------- .../initial-chat/balance-analysis.validation-schema.ts | 3 +-- .../initial-chat/generate-init-promt-message.enum.ts | 3 +-- .../helpers/initial-chat/generate-scores-response.ts | 3 +-- .../generate-suggest-task-response.ts | 2 +- .../src/modules/chat/libs/types/message.type.ts | 1 - .../chat/libs/components/chat-message/chat-message.tsx | 5 ++--- .../types/balance-wheel-analysis-response.dto.type.ts | 2 +- .../libs/types/task-suggestion-request-dto.type.ts | 4 ++-- .../task-suggestion-request.validation-schema.ts | 8 ++------ 10 files changed, 14 insertions(+), 27 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts index acc454823..b87955c22 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts @@ -13,7 +13,7 @@ const AnalyzeBalanceScoresTool = { properties: { categoryId: { description: "Unique identifier for the category", - type: "string", + type: "number", }, categoryName: { description: "The name of the category (e.g., Health, Work)", @@ -71,18 +71,14 @@ const AnalyzeBalanceScoresTool = { properties: { categoryId: { description: "Unique identifier for the category", - type: "string", + type: "number", }, categoryName: { description: "The name of the category", type: "string", }, - score: { - description: "User's score for the category, from 1 to 10", - type: "number", - }, }, - required: ["categoryId", "categoryName", "score"], + required: ["categoryId", "categoryName"], type: "object", }, type: "array", diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index da6edaf83..29852d759 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -1,9 +1,8 @@ import { z } from "zod"; const Category = z.object({ - categoryId: z.string(), + categoryId: z.number(), categoryName: z.string(), - score: z.number(), }); const Messages = z.object({ diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts index f21761619..9903fd28d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts @@ -55,9 +55,8 @@ response_structure: }, lowestCategories: [ // An array containing the three categories with the lowest scores. { - categoryId: string, // Unique identifier of the category. + categoryId: number, // Unique identifier of the category. categoryName: string, // Name of the category. - score: number // The user's score for the category. } ] } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index 72d3b799c..2669758e6 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -31,9 +31,8 @@ const generateScoresResponse = ( return { lowestCategories: resultData.lowestCategories.map((category) => ({ - categoryId: Number(category.categoryId), + categoryId: category.categoryId, categoryName: category.categoryName, - score: category.score, })), messages: { comments: resultData.messages.comments, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index 4dc8f101b..2af867004 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -32,7 +32,7 @@ const generateTaskSuggestionsResponse = ( return { message: resultData.message, tasks: resultData.tasks.map((task) => ({ - categoryId: Number(task.categoryId), + categoryId: task.categoryId, categoryName: task.categoryName, description: task.description, dueDate: task.dueDate, diff --git a/apps/frontend/src/modules/chat/libs/types/message.type.ts b/apps/frontend/src/modules/chat/libs/types/message.type.ts index c79da5be0..79fb1b547 100644 --- a/apps/frontend/src/modules/chat/libs/types/message.type.ts +++ b/apps/frontend/src/modules/chat/libs/types/message.type.ts @@ -7,7 +7,6 @@ type Message = { lowestCategories?: Array<{ categoryId: number; categoryName: string; - score: number; }>; taskList?: SimplifiedTaskDto[]; text: string; diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index ce4c2099d..b2d690d73 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -5,7 +5,7 @@ import { import { INDEX_ONE, ZERO_INDEX } from "~/libs/enums/enums.js"; import { useAppDispatch, useCallback } from "~/libs/hooks/hooks.js"; -import { handleButtonAction } from "../../helpers/handle-button-action.helper.js"; +import { handleButtonAction } from "../../helpers/helpers.js"; import { ConfirmationButtons } from "../confirmation-buttons/confirmation-buttons.js"; import styles from "./styles.module.css"; @@ -14,8 +14,7 @@ type Properties = { contentData: { chartData: { data: number; label: string }[]; selectedCategories: { - categories: { categoryId: string; name: string }[]; - // categories: { categoryId: string; categoryName: string }[]; + categories: { categoryId: number; categoryName: string }[]; threadId: string; }; }; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts index 9e23e8e8a..07e3144ed 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -2,7 +2,7 @@ import { type QuizScoresGetAllItemResponseDto } from "../../../quiz/quiz.js"; type SimplifiedQuizScoreDto = Omit< QuizScoresGetAllItemResponseDto, - "createdAt" | "id" | "updatedAt" | "userId" + "createdAt" | "id" | "score" | "updatedAt" | "userId" >; type BalanceWheelAnalysisResponseDto = { diff --git a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts index 4a5e7512f..ee26afb26 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts @@ -1,6 +1,6 @@ type SelectedCategories = { - categoryId: string; - name: string; + categoryId: number; + categoryName: string; }; type TaskSuggestionRequestDto = { diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 383ae65e2..f9ca4989c 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -9,12 +9,8 @@ const TaskSuggestionRequest = z.object({ categories: z .array( z.object({ - categoryId: z - .string() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { - message: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, - }), - name: z + categoryId: z.number(), + categoryName: z .string() .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, From 1073436a3118786c71eaef20ca07ebacaf326fb7 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:42:33 +0300 Subject: [PATCH 113/244] fix(frontend): handleFormSubmit wrapper bb-340 --- apps/frontend/src/pages/chat/chat.tsx | 35 +++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 2ab410bb1..56b49be40 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -6,11 +6,11 @@ import { } from "~/libs/hooks/hooks.js"; import { actions as chatActions, - // type TaskSuggestionRequestDto, + type TaskSuggestionRequestDto, } from "~/modules/chat/chat.js"; import { actions as quizActions } from "~/modules/quiz/quiz.js"; -import { ChatMessage } from "./libs/components/chat-message/chat-message.js"; +import { ChatMessage } from "./libs/components/components.js"; import styles from "./styles.module.css"; const ChatComponent: React.FC = () => { @@ -40,10 +40,8 @@ const ChatComponent: React.FC = () => { ); const formattedCategories = selectedCategories.map((category) => ({ - categoryId: category.categoryId.toString(), - name: category.categoryName, - - // categoryName: category.categoryName, + categoryId: category.categoryId, + categoryName: category.categoryName, })); const contentData = { @@ -59,25 +57,30 @@ const ChatComponent: React.FC = () => { }, [dispatch]); const handleCategoriesSubmit = useCallback( - (payload: { categoryIds: number[] }): void => { + async (payload: { categoryIds: number[] }): Promise => { const newSelectedCategories = quizCategories .filter((category) => payload.categoryIds.includes(category.id)) .map((category) => ({ categoryId: category.id, categoryName: category.name, - score: 0, })); dispatch(chatActions.updateSelectedCategories(newSelectedCategories)); - // const taskPayload: TaskSuggestionRequestDto = { - // categories: newSelectedCategories, - // threadId: threadId ?? "", - // }; + const taskPayload: TaskSuggestionRequestDto = { + categories: newSelectedCategories, + threadId: threadId ?? "", + }; + + await dispatch(chatActions.getTasksForCategories(taskPayload)); + }, + [dispatch, quizCategories, threadId], + ); - // await dispatch(chatActions.getTasksForCategories(taskPayload)); + const handleFormSubmitWrapper = useCallback( + (payload: { categoryIds: number[] }): void => { + void handleCategoriesSubmit(payload); }, - // [dispatch, quizCategories, threadId], - [dispatch, quizCategories], + [handleCategoriesSubmit], ); return ( @@ -90,7 +93,7 @@ const ChatComponent: React.FC = () => { buttonLabels={message.buttonLabels ?? []} contentData={contentData} key={message.text} - onFormSubmit={handleCategoriesSubmit} + onFormSubmit={handleFormSubmitWrapper} text={message.text} type={message.type} /> From 134b26d2855f30ba71126b890c2b746a580aa5b1 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:43:20 +0300 Subject: [PATCH 114/244] refactor(frontend): clean code bb-340 --- apps/frontend/src/pages/chat/libs/components/components.ts | 2 ++ apps/frontend/src/pages/chat/libs/helpers/helpers.ts | 1 + 2 files changed, 3 insertions(+) create mode 100644 apps/frontend/src/pages/chat/libs/components/components.ts create mode 100644 apps/frontend/src/pages/chat/libs/helpers/helpers.ts diff --git a/apps/frontend/src/pages/chat/libs/components/components.ts b/apps/frontend/src/pages/chat/libs/components/components.ts new file mode 100644 index 000000000..4c351a3e5 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/components.ts @@ -0,0 +1,2 @@ +export { ChatMessage } from "./chat-message/chat-message.js"; +export { ConfirmationButtons } from "./confirmation-buttons/confirmation-buttons.js"; diff --git a/apps/frontend/src/pages/chat/libs/helpers/helpers.ts b/apps/frontend/src/pages/chat/libs/helpers/helpers.ts new file mode 100644 index 000000000..61e2ee621 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/helpers/helpers.ts @@ -0,0 +1 @@ +export { handleButtonAction } from "./handle-button-action.helper.js"; From 877ce6d3288c9432036096f8914eebd0876b69d6 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 19:21:04 +0100 Subject: [PATCH 115/244] refactor(shared): change AiAssistantValidationRule and schema bb-203 --- .../libs/enums/ai-assistant-validatuon-rule.enum.ts | 1 + .../task-suggestion-request.validation-schema.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts index 3896b59e4..63680fb69 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -1,5 +1,6 @@ const AiAssistantValidationRule = { DATE_FORMAT: /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}Z)?$/, + NON_EMPTY_NUMBER_MIN_LENGTH: 1, NON_EMPTY_STRING_MIN_LENGTH: 1, THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, } as const; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 720312cec..3d94e47cd 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -11,7 +11,7 @@ const TaskSuggestionRequest = z.object({ z.object({ categoryId: z .number() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_NUMBER_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, }), name: z From a6ce4433159458d63210175ece7e6cb48637079b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 19:37:52 +0100 Subject: [PATCH 116/244] refactor(backend): delete redundant score field in lowestCategories bb-203 --- .../libs/ai-assistant-tools/analyze-balance-scores-tool.ts | 6 +----- .../initial-chat/balance-analysis.validation-schema.ts | 1 - .../initial-chat/generate-init-promt-message.enum.ts | 1 - .../libs/helpers/initial-chat/generate-scores-prompt.ts | 3 +-- .../libs/helpers/initial-chat/generate-scores-response.ts | 1 - .../libs/types/balance-wheel-analysis-response.dto.type.ts | 2 +- 6 files changed, 3 insertions(+), 11 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts index acc454823..41db2c9d0 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts @@ -71,16 +71,12 @@ const AnalyzeBalanceScoresTool = { properties: { categoryId: { description: "Unique identifier for the category", - type: "string", + type: "number", }, categoryName: { description: "The name of the category", type: "string", }, - score: { - description: "User's score for the category, from 1 to 10", - type: "number", - }, }, required: ["categoryId", "categoryName", "score"], type: "object", diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index da6edaf83..c571e8f20 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -3,7 +3,6 @@ import { z } from "zod"; const Category = z.object({ categoryId: z.string(), categoryName: z.string(), - score: z.number(), }); const Messages = z.object({ diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts index 16238456d..4ec40df77 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts @@ -57,7 +57,6 @@ response_structure: { categoryId: string, // Unique identifier of the category. categoryName: string, // Name of the category. - score: number // The user's score for the category. } ] } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts index e0a997568..ce0372963 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -11,10 +11,9 @@ function generateUserScoresPrompt( ): OpenAiRequestMessage { const { items } = userScores; - const categories = items.map(({ categoryId, categoryName, score }) => ({ + const categories = items.map(({ categoryId, categoryName }) => ({ categoryId, categoryName, - score, })); /* eslint-disable perfectionist/sort-objects */ diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index 72d3b799c..d67fa1203 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -33,7 +33,6 @@ const generateScoresResponse = ( lowestCategories: resultData.lowestCategories.map((category) => ({ categoryId: Number(category.categoryId), categoryName: category.categoryName, - score: category.score, })), messages: { comments: resultData.messages.comments, diff --git a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts index 7c6505242..3d3d3c289 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -2,7 +2,7 @@ import { type QuizScoresGetAllItemResponseDto } from "../../../quiz/quiz.js"; type SimplifiedQuizScoreDto = Omit< QuizScoresGetAllItemResponseDto, - "createdAt" | "id" | "updatedAt" | "userId" + "createdAt" | "id" | "score" | "updatedAt" | "userId" >; type BalanceWheelAnalysisResponseDto = { From 6d02e3a10a7f03db0bc15ef37325df492dedd0b1 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 19:41:35 +0100 Subject: [PATCH 117/244] refactor(backend): delete redundant score field in lowestCategories bb-203 --- .../src/modules/ai-assistant/ai-assistant.controller.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 58d413607..47e40f18b 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -427,10 +427,6 @@ class AiAssistantController extends BaseController { * type: integer * description: The category id * example: 1 - * score: - * type: number - * description: The score for the category - * example: 3 */ private async initNewChat( options: APIHandlerOptions<{ From f5e6575928778cf43227bf716f104a9e8180e817 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 19:42:44 +0100 Subject: [PATCH 118/244] refactor(backend): fix names in TaskSuggestionRequestDto bb-203 --- .../ai-assistant/libs/types/task-suggestion-request-dto.type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts index 4a5e7512f..c6bd36e99 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts @@ -1,6 +1,6 @@ type SelectedCategories = { categoryId: string; - name: string; + categoryName: string; }; type TaskSuggestionRequestDto = { From 941266cd443bf278bdcd992081a071257a8f5d29 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 19:49:05 +0100 Subject: [PATCH 119/244] refactor(backend): fix names in TaskSuggestionRequest validation bb-203 --- .../task-suggestion-request.validation-schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 3d94e47cd..4cb0affdd 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -14,7 +14,7 @@ const TaskSuggestionRequest = z.object({ .min(AiAssistantValidationRule.NON_EMPTY_NUMBER_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, }), - name: z + categoryName: z .string() .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, From 9a8be455f5e4b58b66b3b175b910209563d2be1a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 19:52:41 +0100 Subject: [PATCH 120/244] refactor(backend): fix names in TaskSuggestionRequest dto bb-203 --- .../ai-assistant/libs/types/task-suggestion-request-dto.type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts index c6bd36e99..ee26afb26 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/task-suggestion-request-dto.type.ts @@ -1,5 +1,5 @@ type SelectedCategories = { - categoryId: string; + categoryId: number; categoryName: string; }; From aad378ebcb57c89a2e45c9cab59b7664075fac23 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Sun, 15 Sep 2024 19:55:44 +0100 Subject: [PATCH 121/244] refactor(backend): fix types in lowestCategories bb-203 --- .../helpers/initial-chat/balance-analysis.validation-schema.ts | 2 +- .../helpers/initial-chat/generate-init-promt-message.enum.ts | 2 +- .../libs/helpers/initial-chat/generate-scores-response.ts | 2 +- .../suggest-task-by-category/generate-suggest-task-response.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index c571e8f20..29852d759 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -1,7 +1,7 @@ import { z } from "zod"; const Category = z.object({ - categoryId: z.string(), + categoryId: z.number(), categoryName: z.string(), }); diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts index 4ec40df77..3efd91a67 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts @@ -55,7 +55,7 @@ response_structure: }, lowestCategories: [ // An array containing the three categories with the lowest scores. { - categoryId: string, // Unique identifier of the category. + categoryId: number, // Unique identifier of the category. categoryName: string, // Name of the category. } ] diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index d67fa1203..2669758e6 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -31,7 +31,7 @@ const generateScoresResponse = ( return { lowestCategories: resultData.lowestCategories.map((category) => ({ - categoryId: Number(category.categoryId), + categoryId: category.categoryId, categoryName: category.categoryName, })), messages: { diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index 4dc8f101b..2af867004 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -32,7 +32,7 @@ const generateTaskSuggestionsResponse = ( return { message: resultData.message, tasks: resultData.tasks.map((task) => ({ - categoryId: Number(task.categoryId), + categoryId: task.categoryId, categoryName: task.categoryName, description: task.description, dueDate: task.dueDate, From 5ee1709a030077a3944d37ca4bedb012487ffc3e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 10:00:55 +0100 Subject: [PATCH 122/244] refactor(backend): change names for Assistant tools bb-203 --- .../libs/ai-assistant-tools/ai-assistant-tools.ts | 3 --- .../open-ai/libs/enums/open-ai-assistant-config.enum.ts | 9 +++++---- .../analyze-balance-tool.ts} | 6 +++--- .../{ai-assistant-tools => tools}/change-task-tool.ts | 0 .../suggest-task.tool.ts} | 4 ++-- .../backend/src/libs/modules/open-ai/libs/tools/tools.ts | 3 +++ 6 files changed, 13 insertions(+), 12 deletions(-) delete mode 100644 apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts rename apps/backend/src/libs/modules/open-ai/libs/{ai-assistant-tools/analyze-balance-scores-tool.ts => tools/analyze-balance-tool.ts} (95%) rename apps/backend/src/libs/modules/open-ai/libs/{ai-assistant-tools => tools}/change-task-tool.ts (100%) rename apps/backend/src/libs/modules/open-ai/libs/{ai-assistant-tools/suggest-task-by-category.tool.ts => tools/suggest-task.tool.ts} (97%) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts b/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts deleted file mode 100644 index d0afcdb9b..000000000 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/ai-assistant-tools.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { AnalyzeBalanceScoresTool } from "./analyze-balance-scores-tool.js"; -export { ChangeTaskTool } from "./change-task-tool.js"; -export { GenerateTaskByCategoryTool } from "./suggest-task-by-category.tool.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts index 6ed012017..38251f31c 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts @@ -1,15 +1,16 @@ import { - AnalyzeBalanceScoresTool, + AnalyzeBalanceTool, ChangeTaskTool, - GenerateTaskByCategoryTool, -} from "../ai-assistant-tools/ai-assistant-tools.js"; + SuggestTaskTool, +} from "~/libs/modules/open-ai/libs/tools/tools.js"; + import { OpenAiPromptTemplates } from "./open-ai-prompt-messages.enum.js"; const OpenAiAssistantConfig = { INSTRUCTION: OpenAiPromptTemplates.ASSISTANT_INSTRUCTION, NAME: "Wheel of Balance Assistant", TEMPERATURE: 1, - TOOLS: [AnalyzeBalanceScoresTool, GenerateTaskByCategoryTool, ChangeTaskTool], + TOOLS: [AnalyzeBalanceTool, SuggestTaskTool, ChangeTaskTool], TOP_P: 1, } as const; diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance-tool.ts similarity index 95% rename from apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts rename to apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance-tool.ts index 41db2c9d0..e3b46f6f3 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/analyze-balance-scores-tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance-tool.ts @@ -1,4 +1,4 @@ -const AnalyzeBalanceScoresTool = { +const AnalyzeBalanceTool = { function: { description: "Analyzes user's life balance scores and identifies the three lowest categories with suggestions for improvement.", @@ -78,7 +78,7 @@ const AnalyzeBalanceScoresTool = { type: "string", }, }, - required: ["categoryId", "categoryName", "score"], + required: ["categoryId", "categoryName"], type: "object", }, type: "array", @@ -101,4 +101,4 @@ const AnalyzeBalanceScoresTool = { type: "function", } as const; -export { AnalyzeBalanceScoresTool }; +export { AnalyzeBalanceTool }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/change-task-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts similarity index 100% rename from apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/change-task-tool.ts rename to apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/suggest-task-by-category.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts similarity index 97% rename from apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/suggest-task-by-category.tool.ts rename to apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts index 0b7db0c9a..7c2cc80b6 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/ai-assistant-tools/suggest-task-by-category.tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts @@ -1,4 +1,4 @@ -const GenerateTaskByCategoryTool = { +const SuggestTaskTool = { function: { description: "Generates specific and actionable tasks for each user-selected category based on their onboarding responses.", @@ -105,4 +105,4 @@ const GenerateTaskByCategoryTool = { type: "function", } as const; -export { GenerateTaskByCategoryTool }; +export { SuggestTaskTool }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts new file mode 100644 index 000000000..a79c25db5 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts @@ -0,0 +1,3 @@ +export { AnalyzeBalanceTool } from "./analyze-balance-tool.js"; +export { ChangeTaskTool } from "./change-task-tool.js"; +export { SuggestTaskTool } from "./suggest-task.tool.js"; From cc35c2810d9b52b2d7ccba5d28f97f1067521967 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 11:01:21 +0100 Subject: [PATCH 123/244] chore(backend): update and fix dependencies bb-203 --- package-lock.json | 1720 +++++++++++++++++++++++++++++++++------------ 1 file changed, 1253 insertions(+), 467 deletions(-) diff --git a/package-lock.json b/package-lock.json index c45997c2d..0757f9adb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,6 +69,7 @@ "knex": "3.1.0", "nodemailer": "6.9.14", "objection": "3.1.4", + "openai": "4.57.3", "pg": "8.12.0", "pino": "9.3.2", "pino-pretty": "11.2.2", @@ -3401,201 +3402,592 @@ "node": ">=16" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", "cpu": [ - "x64" + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@eslint/js": { - "version": "9.9.0", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@expo/config-plugins": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-8.0.8.tgz", - "integrity": "sha512-Fvu6IO13EUw0R9WeqxUO37FkM62YJBNcZb9DyJAOgMz7Ez/vaKQGEjKt9cwT+Q6uirtCATMgaq6VWAW7YW8xXw==", - "dependencies": { - "@expo/config-types": "^51.0.0-unreleased", - "@expo/json-file": "~8.3.0", - "@expo/plist": "^0.1.0", - "@expo/sdk-runtime-versions": "^1.0.0", - "chalk": "^4.1.2", - "debug": "^4.3.1", - "find-up": "~5.0.0", - "getenv": "^1.0.0", - "glob": "7.1.6", - "resolve-from": "^5.0.0", - "semver": "^7.5.4", - "slash": "^3.0.0", - "slugify": "^1.6.6", - "xcode": "^3.0.1", - "xml2js": "0.6.0" + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@expo/config-plugins/node_modules/brace-expansion": { + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.9.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@expo/config-plugins": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-8.0.8.tgz", + "integrity": "sha512-Fvu6IO13EUw0R9WeqxUO37FkM62YJBNcZb9DyJAOgMz7Ez/vaKQGEjKt9cwT+Q6uirtCATMgaq6VWAW7YW8xXw==", + "dependencies": { + "@expo/config-types": "^51.0.0-unreleased", + "@expo/json-file": "~8.3.0", + "@expo/plist": "^0.1.0", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.1", + "find-up": "~5.0.0", + "getenv": "^1.0.0", + "glob": "7.1.6", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slash": "^3.0.0", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/config-plugins/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", @@ -9862,496 +10254,870 @@ "version": "2.0.0", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.8" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/destroy": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "license": "MIT" + }, + "node_modules/easy-table": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "optionalDependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editorconfig-checker": { + "version": "5.1.8", + "dev": true, + "license": "MIT", + "bin": { + "ec": "dist/index.js", + "editorconfig-checker": "dist/index.js" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/mstruebing" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/deprecation": { - "version": "2.3.1", - "dev": true, - "license": "ISC" - }, - "node_modules/destroy": { - "version": "1.2.0", - "license": "MIT", + "node_modules/entities": { + "version": "4.5.0", + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/detect-libc": { - "version": "2.0.3", - "license": "Apache-2.0", + "node_modules/envinfo": { + "version": "7.13.0", + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/diff": { - "version": "4.0.2", + "node_modules/environment": { + "version": "1.1.0", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.3.1" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, + "node_modules/error-ex": { + "version": "1.3.2", "license": "MIT", "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" + "is-arrayish": "^0.2.1" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "license": "Apache-2.0", + "node_modules/error-stack-parser": { + "version": "2.1.4", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" + "stackframe": "^1.3.4" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "node_modules/errorhandler": { + "version": "1.5.1", + "license": "MIT", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" + "accepts": "~1.3.7", + "escape-html": "~1.0.3" }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "engines": { + "node": ">= 0.8" } }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "node_modules/es-abstract": { + "version": "1.23.3", + "dev": true, + "license": "MIT", "dependencies": { - "domelementtype": "^2.3.0" + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { - "node": ">= 4" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "node_modules/es-define-property": { + "version": "1.0.0", + "license": "MIT", "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" + "get-intrinsic": "^1.2.4" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "engines": { + "node": ">= 0.4" } }, - "node_modules/dot-case": { - "version": "3.0.4", + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", "dev": true, "license": "MIT", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dot-prop": { - "version": "5.3.0", + "node_modules/es-iterator-helpers": { + "version": "1.0.19", "dev": true, "license": "MIT", "dependencies": { - "is-obj": "^2.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/dotenv": { - "version": "16.4.5", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" + "node_modules/es-module-lexer": { + "version": "1.5.4", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" }, - "funding": { - "url": "https://dotenvx.com" + "engines": { + "node": ">= 0.4" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "license": "MIT" - }, - "node_modules/easy-table": { - "version": "1.2.0", + "node_modules/es-set-tostringtag": { + "version": "2.0.3", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, - "optionalDependencies": { - "wcwidth": "^1.0.1" + "engines": { + "node": ">= 0.4" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", + "node_modules/es-shim-unscopables": { + "version": "1.0.2", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "safe-buffer": "^5.0.1" + "hasown": "^2.0.0" } }, - "node_modules/editorconfig-checker": { - "version": "5.1.8", + "node_modules/es-to-primitive": { + "version": "1.2.1", "dev": true, "license": "MIT", - "bin": { - "ec": "dist/index.js", - "editorconfig-checker": "dist/index.js" + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" }, "engines": { - "node": ">=18.0.0" + "node": ">= 0.4" }, "funding": { - "type": "buymeacoffee", - "url": "https://www.buymeacoffee.com/mstruebing" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", - "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "1.0.2", + "node_modules/esbuild": { + "version": "0.21.5", + "dev": true, + "hasInstallScript": true, "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", + "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=10.13.0" + "node": ">=12" } }, - "node_modules/entities": { - "version": "4.5.0", - "license": "BSD-2-Clause", + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "node": ">=12" } }, - "node_modules/env-paths": { - "version": "2.2.1", + "node_modules/esbuild/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/envinfo": { - "version": "7.13.0", + "node_modules/esbuild/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/environment": { - "version": "1.1.0", + "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/error-ex": { - "version": "1.3.2", + "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "node_modules/error-stack-parser": { - "version": "2.1.4", + "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "stackframe": "^1.3.4" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/errorhandler": { - "version": "1.5.1", + "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "accepts": "~1.3.7", - "escape-html": "~1.0.3" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/es-abstract": { - "version": "1.23.3", + "node_modules/esbuild/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/es-define-property": { - "version": "1.0.0", + "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">=12" } }, - "node_modules/es-errors": { - "version": "1.3.0", + "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">=12" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", + "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/es-iterator-helpers": { - "version": "1.0.19", + "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">=12" } }, - "node_modules/es-module-lexer": { - "version": "1.5.4", + "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/es-object-atoms": { - "version": "1.0.0", + "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">=12" } }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", + "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">=12" } }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", + "node_modules/esbuild/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", + "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/esbuild": { + "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -11692,6 +12458,20 @@ "version": "1.0.0", "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "license": "MIT", @@ -19177,6 +19957,8 @@ }, "node_modules/tsx": { "version": "4.17.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.17.0.tgz", + "integrity": "sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==", "dev": true, "license": "MIT", "dependencies": { @@ -19195,6 +19977,8 @@ }, "node_modules/tsx/node_modules/@esbuild/win32-x64": { "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", "cpu": [ "x64" ], @@ -19210,6 +19994,8 @@ }, "node_modules/tsx/node_modules/esbuild": { "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", "dev": true, "hasInstallScript": true, "license": "MIT", From 24ee13fa4994e53c450105e2f1e13b6e7e262fcc Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 15:35:50 +0100 Subject: [PATCH 124/244] refactor(backend): update handleRequiresAction for more clear code bb-203 --- .../libs/modules/open-ai/open-ai.module.ts | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts index 21a0b0e44..a0720b7e4 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts @@ -77,30 +77,38 @@ class OpenAi { run: OpenAI.Beta.Threads.Runs.Run, functionName: string, ): Promise { - if (run.required_action) { - await Promise.all( - run.required_action.submit_tool_outputs.tool_calls.map( - async (toolCall) => { - const { function: toolFunction } = toolCall; - - if (toolFunction.name === functionName) { - await this.openAi.beta.threads.runs.submitToolOutputsAndPoll( - run.thread_id, - run.id, + if (!run.required_action) { + return; + } + + const { tool_calls } = run.required_action.submit_tool_outputs; + + await Promise.all( + tool_calls.map( + async ({ + function: toolFunction, + function: { arguments: arguments_ }, + id, + }) => { + if (toolFunction.name !== functionName) { + return; + } + + await this.openAi.beta.threads.runs.submitToolOutputsAndPoll( + run.thread_id, + run.id, + { + tool_outputs: [ { - tool_outputs: [ - { - output: toolCall.function.arguments, - tool_call_id: toolCall.id, - }, - ], + output: arguments_, + tool_call_id: id, }, - ); - } - }, - ), - ); - } + ], + }, + ); + }, + ), + ); } private async handleRunStatus( From e99f6b0a66eb1157427391aa5c67da130be10d0b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 16:05:36 +0100 Subject: [PATCH 125/244] refactor(backend): refactor methods to create prompts to reduce nestling bb-203 --- .../change-task/geregate-change-task-prompt.ts | 13 ++++++------- .../helpers/initial-chat/generate-scores-prompt.ts | 8 ++------ .../generate-suggest-task-prompt.ts | 8 ++------ 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts index 3ddd5b214..338689100 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts @@ -6,14 +6,13 @@ import { import { type TaskCreateDto } from "../../types/types.js"; import { ChangeTaskPromptTemplates } from "./change-task-message.enum.js"; -function generaChangeTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { - const promptContent = { - context: ChangeTaskPromptTemplates.CHANGE_TASKS_CONTEXT, - task, - }; - +function generaChangeTaskPrompt( + task: TaskCreateDto, + context: string = ChangeTaskPromptTemplates.CHANGE_TASKS_CONTEXT, +): OpenAiRequestMessage { + /* eslint-disable perfectionist/sort-objects */ return { - content: JSON.stringify(promptContent), + content: JSON.stringify({ context, task }), role: OpenAiRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts index ce0372963..7a9fa35e1 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -8,6 +8,7 @@ import { OpenAiInitialPromptTemplates } from "./generate-init-promt-message.enum function generateUserScoresPrompt( userScores: QuizScoresGetAllResponseDto, + context: string = OpenAiInitialPromptTemplates.WHEEL_OF_BALANCE_CONTEXT, ): OpenAiRequestMessage { const { items } = userScores; @@ -17,13 +18,8 @@ function generateUserScoresPrompt( })); /* eslint-disable perfectionist/sort-objects */ - const promptContent = { - context: OpenAiInitialPromptTemplates.WHEEL_OF_BALANCE_CONTEXT, - categories, - }; - return { - content: JSON.stringify(promptContent), + content: JSON.stringify({ context, categories }), role: OpenAiRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts index 56a2f0409..b71e7c9e1 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts @@ -8,15 +8,11 @@ import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-messages.enum. function generateSuggestTaskPrompt( categories: SelectedCategories[], + context: string = SuggestTaskPromptTemplates.SUGGEST_TASKS_CONTEXT, ): OpenAiRequestMessage { /* eslint-disable perfectionist/sort-objects */ - const promptContent = { - context: SuggestTaskPromptTemplates.SUGGEST_TASKS_CONTEXT, - categories, - }; - return { - content: JSON.stringify(promptContent), + content: JSON.stringify({ context, categories }), role: OpenAiRoleKey.USER, }; } From 668c312b981375d1cdf3637d5f4f8e8964ab7c0e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 16:08:15 +0100 Subject: [PATCH 126/244] refactor(backend): refactor names in init-chat files bb-203 --- ...omt-message.enum.ts => generate-init-prompt-message.enum.ts} | 0 .../helpers/initial-chat/generate-questions-answers-prompt.ts | 2 +- .../libs/helpers/initial-chat/generate-scores-prompt.ts | 2 +- .../ai-assistant/libs/helpers/initial-chat/initial-chat.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/{generate-init-promt-message.enum.ts => generate-init-prompt-message.enum.ts} (100%) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-prompt-message.enum.ts similarity index 100% rename from apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-promt-message.enum.ts rename to apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-prompt-message.enum.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts index 71c4c15da..4c15516db 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts @@ -5,7 +5,7 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type OnboardingQuestionEntity } from "~/modules/onboarding/onboarding.js"; -import { OpenAiInitialPromptTemplates } from "./generate-init-promt-message.enum.js"; +import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enum.js"; function generateQuestionsAnswersPrompt( userQuestionsWithAnswers: OnboardingQuestionEntity[], diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts index 7a9fa35e1..5f0dae12b 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -4,7 +4,7 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; -import { OpenAiInitialPromptTemplates } from "./generate-init-promt-message.enum.js"; +import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enum.js"; function generateUserScoresPrompt( userScores: QuizScoresGetAllResponseDto, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts index 0977c2487..ecfcbeb8f 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts @@ -5,7 +5,7 @@ import { import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; import { BalanceAnalysis as BalanceAnalysisResponseValidationSchema } from "./balance-analysis.validation-schema.js"; -import { OpenAiInitialPromptTemplates } from "./generate-init-promt-message.enum.js"; +import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enum.js"; import { generateUserScoresPrompt } from "./generate-scores-prompt.js"; const runInitialThreadOptions = ( From f73f5c13c6b0b53299464a0a5c5be98f76396476 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 16:14:36 +0100 Subject: [PATCH 127/244] refactor(backend): refactor generate AI response files to reduce nesting bb-203 --- .../change-task/change-task-response.ts | 39 +++++++++---------- .../initial-chat/generate-scores-response.ts | 39 +++++++++---------- .../generate-suggest-task-response.ts | 35 ++++++++--------- 3 files changed, 55 insertions(+), 58 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts index 2bc997a16..ff5652ac5 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts @@ -22,28 +22,27 @@ const generateChangeTaskSuggestionsResponse = ( const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); - if (parsedResult.success) { - const contentText: string = - parsedResult.data.content[ZERO_INDEX].text.value; - const resultData: TaskByCategoryData = JSON.parse( - contentText, - ) as TaskByCategoryData; - - return { - message: resultData.message, - tasks: [ - { - categoryId: Number(resultData.tasks.categoryId), - categoryName: resultData.tasks.categoryName, - description: resultData.tasks.description, - dueDate: resultData.tasks.dueDate, - label: resultData.tasks.label, - }, - ], - }; + if (!parsedResult.success) { + return null; } - return null; + const contentText: string = parsedResult.data.content[ZERO_INDEX].text.value; + const resultData: TaskByCategoryData = JSON.parse( + contentText, + ) as TaskByCategoryData; + + return { + message: resultData.message, + tasks: [ + { + categoryId: Number(resultData.tasks.categoryId), + categoryName: resultData.tasks.categoryName, + description: resultData.tasks.description, + dueDate: resultData.tasks.dueDate, + label: resultData.tasks.label, + }, + ], + }; }; export { generateChangeTaskSuggestionsResponse }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index 2669758e6..00a28cfff 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -22,28 +22,27 @@ const generateScoresResponse = ( const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); - if (parsedResult.success) { - const contentText: string = - parsedResult.data.content[ZERO_INDEX].text.value; - const resultData: BalanceAnalysisData = JSON.parse( - contentText, - ) as BalanceAnalysisData; - - return { - lowestCategories: resultData.lowestCategories.map((category) => ({ - categoryId: category.categoryId, - categoryName: category.categoryName, - })), - messages: { - comments: resultData.messages.comments, - greeting: resultData.messages.greeting, - question: resultData.messages.question, - }, - threadId: message.thread_id, - }; + if (!parsedResult.success) { + return null; } - return null; + const contentText: string = parsedResult.data.content[ZERO_INDEX].text.value; + const resultData: BalanceAnalysisData = JSON.parse( + contentText, + ) as BalanceAnalysisData; + + return { + lowestCategories: resultData.lowestCategories.map((category) => ({ + categoryId: category.categoryId, + categoryName: category.categoryName, + })), + messages: { + comments: resultData.messages.comments, + greeting: resultData.messages.greeting, + question: resultData.messages.question, + }, + threadId: message.thread_id, + }; }; export { generateScoresResponse }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index 2af867004..fada60729 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -22,26 +22,25 @@ const generateTaskSuggestionsResponse = ( const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); - if (parsedResult.success) { - const contentText: string = - parsedResult.data.content[ZERO_INDEX].text.value; - const resultData: TaskByCategoryData = JSON.parse( - contentText, - ) as TaskByCategoryData; - - return { - message: resultData.message, - tasks: resultData.tasks.map((task) => ({ - categoryId: task.categoryId, - categoryName: task.categoryName, - description: task.description, - dueDate: task.dueDate, - label: task.label, - })), - }; + if (!parsedResult.success) { + return null; } - return null; + const contentText: string = parsedResult.data.content[ZERO_INDEX].text.value; + const resultData: TaskByCategoryData = JSON.parse( + contentText, + ) as TaskByCategoryData; + + return { + message: resultData.message, + tasks: resultData.tasks.map((task) => ({ + categoryId: task.categoryId, + categoryName: task.categoryName, + description: task.description, + dueDate: task.dueDate, + label: task.label, + })), + }; }; export { generateTaskSuggestionsResponse }; From 3e49cd2716a70838f2cdfa0756376e53d3f44d60 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 16:38:42 +0100 Subject: [PATCH 128/244] refactor(main): delete duplicated Task table from readme bb-203 --- readme.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/readme.md b/readme.md index de31881ef..d3915d70c 100644 --- a/readme.md +++ b/readme.md @@ -46,21 +46,6 @@ erDiagram int avatar_file_id FK } - tasks { - int id PK - varchar label - varchar description - varchar status - int user_id FK - int category_id FK - dateTime due_date - dateTime created_at - dateTime updated_at - } - - users }|--o| tasks: user_id - categories }|--o| tasks: category_id - files { int id PK varchar file_key UK From 798216be1b67dd6c02540efd3e7df0d37dbc9c65 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 17:12:36 +0100 Subject: [PATCH 129/244] refactor(backend): rename validation schemas in AI Module bb-203 --- .../libs/helpers/change-task/change-task-response.ts | 4 ++-- .../ai-assistant/libs/helpers/change-task/change-task.ts | 2 +- .../helpers/change-task/change-task.validation-schema.ts | 4 ++-- .../initial-chat/balance-analysis.validation-schema.ts | 4 ++-- .../libs/helpers/initial-chat/generate-scores-response.ts | 4 ++-- .../libs/helpers/initial-chat/initial-chat.ts | 2 +- .../generate-suggest-task-response.ts | 4 ++-- .../suggest-task-by-category/suggest-task-by-category.ts | 2 +- .../suggest-task-by-category.validation-schema.ts | 8 ++++---- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts index ff5652ac5..3b380721b 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts @@ -7,9 +7,9 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type TaskSuggestionsResponseDto } from "../../types/types.js"; -import { type ChangeTaskByCategory } from "./change-task.validation-schema.js"; +import { type changeTaskByCategory } from "./change-task.validation-schema.js"; -type TaskByCategoryData = z.infer; +type TaskByCategoryData = z.infer; const generateChangeTaskSuggestionsResponse = ( aiResponse: OpenAiResponseMessage, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts index d40c4a568..b52d79a59 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts @@ -4,7 +4,7 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type TaskCreateDto } from "../../types/types.js"; -import { ChangeTaskByCategory as ChangeTaskByCategoryValidationSchema } from "./change-task.validation-schema.js"; +import { changeTaskByCategory as ChangeTaskByCategoryValidationSchema } from "./change-task.validation-schema.js"; import { ChangeTaskPromptTemplates } from "./change-task-message.enum.js"; import { generaChangeTaskPrompt } from "./geregate-change-task-prompt.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts index 69412d12a..7c21b3587 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -const ChangeTaskByCategory = z.object({ +const changeTaskByCategory = z.object({ message: z.string(), tasks: z.object({ categoryId: z.number(), @@ -11,4 +11,4 @@ const ChangeTaskByCategory = z.object({ }), }); -export { ChangeTaskByCategory }; +export { changeTaskByCategory }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index 29852d759..bb42afcea 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -11,9 +11,9 @@ const Messages = z.object({ question: z.string(), }); -const BalanceAnalysis = z.object({ +const balanceAnalysis = z.object({ lowestCategories: z.array(Category), messages: Messages, }); -export { BalanceAnalysis }; +export { balanceAnalysis }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index 00a28cfff..87d12e905 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -7,9 +7,9 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type BalanceWheelAnalysisResponseDto } from "../../types/types.js"; -import { type BalanceAnalysis } from "./balance-analysis.validation-schema.js"; +import { type balanceAnalysis } from "./balance-analysis.validation-schema.js"; -type BalanceAnalysisData = z.infer; +type BalanceAnalysisData = z.infer; const generateScoresResponse = ( aiResponse: OpenAiResponseMessage, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts index ecfcbeb8f..a17a26349 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts @@ -4,7 +4,7 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; -import { BalanceAnalysis as BalanceAnalysisResponseValidationSchema } from "./balance-analysis.validation-schema.js"; +import { balanceAnalysis as BalanceAnalysisResponseValidationSchema } from "./balance-analysis.validation-schema.js"; import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enum.js"; import { generateUserScoresPrompt } from "./generate-scores-prompt.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index fada60729..95bc3acac 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -7,9 +7,9 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type TaskSuggestionsResponseDto } from "../../types/types.js"; -import { type TaskByCategory } from "./suggest-task-by-category.validation-schema.js"; +import { type taskByCategory } from "./suggest-task-by-category.validation-schema.js"; -type TaskByCategoryData = z.infer; +type TaskByCategoryData = z.infer; const generateTaskSuggestionsResponse = ( aiResponse: OpenAiResponseMessage, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts index 11ab3f544..a870473ae 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts @@ -5,7 +5,7 @@ import { import { type SelectedCategories } from "../../types/types.js"; import { generateSuggestTaskPrompt } from "./generate-suggest-task-prompt.js"; -import { TaskByCategory as TaskByCategoryValidationSchema } from "./suggest-task-by-category.validation-schema.js"; +import { taskByCategory as TaskByCategoryValidationSchema } from "./suggest-task-by-category.validation-schema.js"; import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-messages.enum.js"; const runTaskByCategoryOptions = ( diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts index 32e461940..33e82c251 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -const Task = z.object({ +const task = z.object({ categoryId: z.number(), categoryName: z.string(), description: z.string(), @@ -8,9 +8,9 @@ const Task = z.object({ label: z.string(), }); -const TaskByCategory = z.object({ +const taskByCategory = z.object({ message: z.string(), - tasks: z.array(Task), + tasks: z.array(task), }); -export { TaskByCategory }; +export { taskByCategory }; From b1e7afcf394be80af78eee658afef2ad33788a11 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Mon, 16 Sep 2024 17:36:04 +0100 Subject: [PATCH 130/244] fix(backend): caught errors if OpenAi severs not responding bb-203 --- .../libs/modules/open-ai/open-ai.module.ts | 158 ++++++++++++------ 1 file changed, 103 insertions(+), 55 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts index a0720b7e4..09d07ab70 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts @@ -40,12 +40,12 @@ class OpenAi { } private async getOrInitializeAssistant(): Promise { - const existingAssistants = await this.openAi.beta.assistants.list(); - const assistant = existingAssistants.data.find( - (assistant) => assistant.name === OpenAiAssistantConfig.NAME, - ); - try { + const existingAssistants = await this.openAi.beta.assistants.list(); + const assistant = existingAssistants.data.find( + (assistant) => assistant.name === OpenAiAssistantConfig.NAME, + ); + const initializedAssistant = assistant ?? (await this.openAi.beta.assistants.create({ @@ -94,18 +94,29 @@ class OpenAi { return; } - await this.openAi.beta.threads.runs.submitToolOutputsAndPoll( - run.thread_id, - run.id, - { - tool_outputs: [ - { - output: arguments_, - tool_call_id: id, - }, - ], - }, - ); + try { + await this.openAi.beta.threads.runs.submitToolOutputsAndPoll( + run.thread_id, + run.id, + { + tool_outputs: [ + { + output: arguments_, + tool_call_id: id, + }, + ], + }, + ); + } catch (error) { + this.logger.error( + `Error submitting tool outputs: ${String(error)}`, + ); + + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } }, ), ); @@ -136,53 +147,77 @@ class OpenAi { threadId: string, message: OpenAiRequestMessage, ): Promise { - const newMessage = await this.openAi.beta.threads.messages.create( - threadId, - message, - ); + try { + const newMessage = await this.openAi.beta.threads.messages.create( + threadId, + message, + ); + + return !("error" in newMessage); + } catch (error) { + this.logger.error(`Error adding message to thread: ${String(error)}`); - if ("error" in newMessage) { throw new OpenAIError({ message: OpenAIErrorMessage.WRONG_RESPONSE, status: HTTPCode.INTERNAL_SERVER_ERROR, }); } - - return true; } public async createThread( message: OpenAiRequestMessage[] = [], ): Promise { - const thread = await this.openAi.beta.threads.create({ messages: message }); + try { + const thread = await this.openAi.beta.threads.create({ + messages: message, + }); + + if ("error" in thread) { + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } + + return thread.id; + } catch (error) { + this.logger.error(`Error creating thread: ${String(error)}`); - if ("error" in thread) { throw new OpenAIError({ message: OpenAIErrorMessage.WRONG_RESPONSE, status: HTTPCode.INTERNAL_SERVER_ERROR, }); } - - return thread.id; } public async deleteThread(threadId: string): Promise { - const result = await this.openAi.beta.threads.del(threadId); + try { + const result = await this.openAi.beta.threads.del(threadId); + + return result.deleted; + } catch (error) { + this.logger.error(`Error deleting thread: ${String(error)}`); - if (!result.deleted) { throw new OpenAIError({ message: OpenAIErrorMessage.WRONG_RESPONSE, status: HTTPCode.INTERNAL_SERVER_ERROR, }); } - - return result.deleted; } public async getAllMessages( threadId: string, ): Promise { - return await this.openAi.beta.threads.messages.list(threadId); + try { + return await this.openAi.beta.threads.messages.list(threadId); + } catch (error) { + this.logger.error(`Error getting messages: ${String(error)}`); + + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } } async initializeAssistant(): Promise { @@ -193,32 +228,45 @@ class OpenAi { threadId: string, runOptions: OpenAiRunThreadRequestDto, ): Promise { - const runs = await this.openAi.beta.threads.runs.list(threadId); + try { + const runs = await this.openAi.beta.threads.runs.list(threadId); - const pendingRuns = runs.data.filter( - (run) => run.status === "in_progress" || run.status === "queued", - ); + const pendingRuns = runs.data.filter( + (run) => run.status === "in_progress" || run.status === "queued", + ); - for (const run of pendingRuns) { - await this.openAi.beta.threads.runs.poll(threadId, run.id); - } + for (const run of pendingRuns) { + await this.openAi.beta.threads.runs.poll(threadId, run.id); + } + + const run = await this.openAi.beta.threads.runs.createAndPoll(threadId, { + additional_instructions: runOptions.additional_instructions, + additional_messages: runOptions.messages, + assistant_id: this.assistantId as string, + instructions: runOptions.instructions, + response_format: zodResponseFormat( + runOptions.validationSchema, + "use_response_validation", + ), + tool_choice: { + function: { name: runOptions.function_name }, + type: "function", + }, + }); - const run = await this.openAi.beta.threads.runs.createAndPoll(threadId, { - additional_instructions: runOptions.additional_instructions, - additional_messages: runOptions.messages, - assistant_id: this.assistantId as string, - instructions: runOptions.instructions, - response_format: zodResponseFormat( - runOptions.validationSchema, - "use_response_validation", - ), - tool_choice: { - function: { name: runOptions.function_name }, - type: "function", - }, - }); + return await this.handleRunStatus( + threadId, + run, + runOptions.function_name, + ); + } catch (error) { + this.logger.error(`Error running thread: ${String(error)}`); - return await this.handleRunStatus(threadId, run, runOptions.function_name); + throw new OpenAIError({ + message: OpenAIErrorMessage.WRONG_RESPONSE, + status: HTTPCode.INTERNAL_SERVER_ERROR, + }); + } } } From d4b4ec592526fc7108e0b04e1664eca10a32c359 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 13:04:51 +0100 Subject: [PATCH 131/244] feat(backend): add task deadline according to app logic bb-203 --- .../open-ai/libs/tools/change-task-tool.ts | 12 +----- .../open-ai/libs/tools/suggest-task.tool.ts | 5 --- .../ai-assistant/ai-assistant.controller.ts | 11 +++-- .../ai-assistant/ai-assistant.service.ts | 41 +++++++++++-------- .../src/modules/ai-assistant/ai-assistant.ts | 4 +- .../change-task/change-task-message.enum.ts | 1 - .../change-task/change-task-response.ts | 3 +- .../change-task.validation-schema.ts | 1 - .../generate-suggest-task-response.ts | 3 +- ...gest-task-by-category.validation-schema.ts | 1 - .../suggest-task-prompt-messages.enum.ts | 1 - .../backend/src/modules/tasks/task.service.ts | 6 +-- apps/backend/src/modules/tasks/tasks.ts | 4 +- .../ai-assistant-validatuon-rule.enum.ts | 1 - ...hange-task-suggestion.validation-schema.ts | 2 +- 15 files changed, 43 insertions(+), 53 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts index ca4b38192..bbf4190eb 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts @@ -51,22 +51,12 @@ const ChangeTaskTool = { description: "Detailed description of the new task", type: "string", }, - dueDate: { - description: "Suggested due date for the new task", - type: "string", - }, label: { description: "Label or name of the task", type: "string", }, }, - required: [ - "categoryId", - "categoryName", - "description", - "dueDate", - "label", - ], + required: ["categoryId", "categoryName", "description", "label"], type: "object", }, }, diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts index 7c2cc80b6..363de8d87 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts @@ -72,10 +72,6 @@ const SuggestTaskTool = { description: "Detailed description of the task", type: "string", }, - dueDate: { - description: "Suggested due date for the task", - type: "string", - }, label: { description: "Label or name of the task", type: "string", @@ -85,7 +81,6 @@ const SuggestTaskTool = { "categoryId", "categoryName", "description", - "dueDate", "label", ], type: "object", diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 47e40f18b..27d1e9bee 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -161,6 +161,7 @@ class AiAssistantController extends BaseController { this.changeTaskSuggestion( options as APIHandlerOptions<{ body: ChangeTaskSuggestionRequestDto; + user: UserDto; }>, ), method: "POST", @@ -333,12 +334,13 @@ class AiAssistantController extends BaseController { private async changeTaskSuggestion( options: APIHandlerOptions<{ body: ChangeTaskSuggestionRequestDto; + user: UserDto; }>, ): Promise { - const { body } = options; + const { body, user } = options; return { - payload: await this.openAiService.changeTaskSuggestion(body), + payload: await this.openAiService.changeTaskSuggestion(user, body), status: HTTPCode.OK, }; } @@ -537,12 +539,13 @@ class AiAssistantController extends BaseController { private async suggestTasksForCategories( options: APIHandlerOptions<{ body: TaskSuggestionRequestDto; + user: UserDto; }>, ): Promise { - const { body } = options; + const { body, user } = options; return { - payload: await this.openAiService.suggestTasksForCategories(body), + payload: await this.openAiService.suggestTasksForCategories(user, body), status: HTTPCode.OK, }; } diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index 46a57e728..ccb71ec2a 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -2,7 +2,7 @@ import { type OpenAi, OpenAiRoleKey } from "~/libs/modules/open-ai/open-ai.js"; import { type UserDto } from "~/libs/types/types.js"; import { type CategoryService } from "~/modules/categories/categories.js"; import { type OnboardingRepository } from "~/modules/onboarding/onboarding.js"; -import { TaskEntity, type TaskRepository } from "~/modules/tasks/tasks.js"; +import { type TaskService } from "~/modules/tasks/tasks.js"; import { generateChangeTaskSuggestionsResponse, @@ -26,25 +26,25 @@ type Constructor = { categoryService: CategoryService; onboardingRepository: OnboardingRepository; openAi: OpenAi; - taskRepository: TaskRepository; + taskService: TaskService; }; class AiAssistantService { private categoryService: CategoryService; private onboardingRepository: OnboardingRepository; private openAi: OpenAi; - private taskRepository: TaskRepository; + private taskService: TaskService; public constructor({ categoryService, onboardingRepository, openAi, - taskRepository, + taskService, }: Constructor) { this.openAi = openAi; this.categoryService = categoryService; this.onboardingRepository = onboardingRepository; - this.taskRepository = taskRepository; + this.taskService = taskService; } public async acceptTask( @@ -53,15 +53,12 @@ class AiAssistantService { ): Promise { const { task, threadId } = body; - const newTask = await this.taskRepository.create( - TaskEntity.initializeNew({ - categoryId: task.categoryId, - description: task.description, - dueDate: task.dueDate, - label: task.label, - userId: user.id, - }), - ); + const newTask = await this.taskService.create({ + categoryId: task.categoryId, + description: task.description, + label: task.label, + user, + }); const chatMessage = { content: `User has accepted this task: ${JSON.stringify(newTask)}`, role: OpenAiRoleKey.USER, @@ -69,7 +66,7 @@ class AiAssistantService { await this.openAi.addMessageToThread(threadId, chatMessage); - return newTask.toObject(); + return newTask; } public async addMessageToThread( @@ -86,15 +83,18 @@ class AiAssistantService { } public async changeTaskSuggestion( + user: UserDto, body: ChangeTaskSuggestionRequestDto, ): Promise { const { task, threadId } = body; const runThreadOptions = runChangeTaskByCategoryOptions(task); - + const taskDeadLine = this.taskService.calculateDeadline( + user.userTaskDays as number[], + ); const result = await this.openAi.runThread(threadId, runThreadOptions); - return generateChangeTaskSuggestionsResponse(result); + return generateChangeTaskSuggestionsResponse(result, taskDeadLine); } public async initNewChat( @@ -121,15 +121,20 @@ class AiAssistantService { } public async suggestTasksForCategories( + user: UserDto, body: TaskSuggestionRequestDto, ): Promise { const { categories, threadId } = body; const runThreadOptions = runTaskByCategoryOptions(categories); + const taskDeadLine = this.taskService.calculateDeadline( + user.userTaskDays as number[], + ); + const result = await this.openAi.runThread(threadId, runThreadOptions); - return generateTaskSuggestionsResponse(result); + return generateTaskSuggestionsResponse(result, taskDeadLine); } } diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.ts index 6299e5b4f..dd4df3980 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.ts @@ -2,7 +2,7 @@ import { logger } from "~/libs/modules/logger/logger.js"; import { openAi } from "~/libs/modules/open-ai/open-ai.js"; import { categoryService } from "~/modules/categories/categories.js"; import { onboardingRepository } from "~/modules/onboarding/onboarding.js"; -import { taskRepository } from "~/modules/tasks/tasks.js"; +import { taskService } from "~/modules/tasks/tasks.js"; import { AiAssistantController } from "./ai-assistant.controller.js"; import { AiAssistantService } from "./ai-assistant.service.js"; @@ -11,7 +11,7 @@ const aiAssistantService = new AiAssistantService({ categoryService, onboardingRepository, openAi, - taskRepository, + taskService, }); const aiAssistantController = new AiAssistantController( diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts index 89d54b526..5c10700f8 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts @@ -21,7 +21,6 @@ response_structure: categoryId: number, // Unique identifier for the category. categoryName: string, // Name of the category. description: string, // Detailed description of the new task. - dueDate: string, // Suggested due date for the new task. label: string // Label or name of the new task. } } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts index 3b380721b..ad15663e8 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts @@ -13,6 +13,7 @@ type TaskByCategoryData = z.infer; const generateChangeTaskSuggestionsResponse = ( aiResponse: OpenAiResponseMessage, + taskDeadLine: string, ): null | TaskSuggestionsResponseDto => { const message = aiResponse.getPaginatedItems().shift(); @@ -38,7 +39,7 @@ const generateChangeTaskSuggestionsResponse = ( categoryId: Number(resultData.tasks.categoryId), categoryName: resultData.tasks.categoryName, description: resultData.tasks.description, - dueDate: resultData.tasks.dueDate, + dueDate: taskDeadLine, label: resultData.tasks.label, }, ], diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts index 7c21b3587..e7c27aaea 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.validation-schema.ts @@ -6,7 +6,6 @@ const changeTaskByCategory = z.object({ categoryId: z.number(), categoryName: z.string(), description: z.string(), - dueDate: z.string(), label: z.string(), }), }); diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index 95bc3acac..e19759d3c 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -13,6 +13,7 @@ type TaskByCategoryData = z.infer; const generateTaskSuggestionsResponse = ( aiResponse: OpenAiResponseMessage, + taskDeadLine: string, ): null | TaskSuggestionsResponseDto => { const message = aiResponse.getPaginatedItems().shift(); @@ -37,7 +38,7 @@ const generateTaskSuggestionsResponse = ( categoryId: task.categoryId, categoryName: task.categoryName, description: task.description, - dueDate: task.dueDate, + dueDate: taskDeadLine, label: task.label, })), }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts index 33e82c251..e5d26c99b 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.validation-schema.ts @@ -4,7 +4,6 @@ const task = z.object({ categoryId: z.number(), categoryName: z.string(), description: z.string(), - dueDate: z.string(), label: z.string(), }); diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts index 1b1f4d971..8382f152b 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts @@ -19,7 +19,6 @@ response_structure: categoryId: number, // Unique identifier for the category. categoryName: string, // Name of the category. description: string, // Detailed description of the task. - dueDate: string, // Suggested due date for the task. label: string // Label or name of the task. } ] diff --git a/apps/backend/src/modules/tasks/task.service.ts b/apps/backend/src/modules/tasks/task.service.ts index 956bdfc9d..22a3990f5 100644 --- a/apps/backend/src/modules/tasks/task.service.ts +++ b/apps/backend/src/modules/tasks/task.service.ts @@ -18,7 +18,9 @@ import { type TaskModel } from "./task.model.js"; import { type TaskRepository } from "./task.repository.js"; class TaskService implements Service { - private calculateDeadline = (userTaskDays: number[]): string => { + private taskRepository: TaskRepository; + + public calculateDeadline = (userTaskDays: number[]): string => { const createdAt = new Date(); const createdAtDayOfWeek = createdAt.getDay(); @@ -45,8 +47,6 @@ class TaskService implements Service { return deadline.toISOString(); }; - private taskRepository: TaskRepository; - public constructor(taskRepository: TaskRepository) { this.taskRepository = taskRepository; } diff --git a/apps/backend/src/modules/tasks/tasks.ts b/apps/backend/src/modules/tasks/tasks.ts index d09b87826..565ebe413 100644 --- a/apps/backend/src/modules/tasks/tasks.ts +++ b/apps/backend/src/modules/tasks/tasks.ts @@ -9,7 +9,7 @@ const taskRepository = new TaskRepository(TaskModel); const taskService = new TaskService(taskRepository); const taskController = new TaskController(logger, taskService); -export { taskController, taskRepository }; +export { taskController, taskService }; export { TaskEntity } from "./task.entity.js"; export { TaskModel } from "./task.model.js"; -export { type TaskRepository } from "./task.repository.js"; +export { type TaskService } from "./task.service.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts index 63680fb69..bc52cc8ba 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -1,5 +1,4 @@ const AiAssistantValidationRule = { - DATE_FORMAT: /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}Z)?$/, NON_EMPTY_NUMBER_MIN_LENGTH: 1, NON_EMPTY_STRING_MIN_LENGTH: 1, THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts index 9c69111ab..2043e5a67 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts @@ -20,7 +20,7 @@ const ChangeTaskSuggestionRequest = z.object({ .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { message: AiAssistantValidationMessage.DESCRIPTION_REQUIRED, }), - dueDate: z.string().regex(AiAssistantValidationRule.DATE_FORMAT, { + dueDate: z.string().datetime({ message: AiAssistantValidationMessage.DUE_DATE_INVALID_FORMAT, }), label: z From f074911d6410abf96a133bcd6b9c8bb8ac97b9e6 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 13:17:44 +0100 Subject: [PATCH 132/244] refactor(backend): refactor files and names in OpenAI module (Ai => AI) bb-203 --- .../src/libs/modules/open-ai/libs/enums/enums.ts | 10 +++++----- .../libs/enums/open-ai-assistant-config.enum.ts | 11 +++++------ ...sage.enum.ts => open-ai-error-template.enum.ts} | 0 .../libs/enums/open-ai-function-name.enum.ts | 4 ++-- .../libs/enums/open-ai-prompt-messages.enum.ts | 4 ++-- .../open-ai/libs/enums/open-ai-role-key.enum.ts | 4 ++-- ...yze-balance-tool.ts => analyze-balance.tool.ts} | 0 .../{change-task-tool.ts => change-task.tool.ts} | 0 .../src/libs/modules/open-ai/libs/tools/tools.ts | 4 ++-- .../types/open-ai-run-thread-request-dto.type.ts | 4 ++-- .../src/libs/modules/open-ai/open-ai.module.ts | 14 +++++++------- apps/backend/src/libs/modules/open-ai/open-ai.ts | 12 ++++++------ .../modules/ai-assistant/ai-assistant.service.ts | 6 +++--- .../src/modules/ai-assistant/ai-assistant.ts | 4 ++-- ...essage.enum.ts => change-task-template.enum.ts} | 0 .../libs/helpers/change-task/change-task.ts | 6 +++--- .../change-task/geregate-change-task-prompt.ts | 6 +++--- .../generate-questions-answers-prompt.ts | 4 ++-- .../helpers/initial-chat/generate-scores-prompt.ts | 4 ++-- .../libs/helpers/initial-chat/initial-chat.ts | 4 ++-- .../generate-suggest-task-prompt.ts | 6 +++--- .../suggest-task-by-category.ts | 6 +++--- ...num.ts => suggest-task-prompt-template.enum.ts} | 0 23 files changed, 56 insertions(+), 57 deletions(-) rename apps/backend/src/libs/modules/open-ai/libs/enums/{open-ai-error-message.enum.ts => open-ai-error-template.enum.ts} (100%) rename apps/backend/src/libs/modules/open-ai/libs/tools/{analyze-balance-tool.ts => analyze-balance.tool.ts} (100%) rename apps/backend/src/libs/modules/open-ai/libs/tools/{change-task-tool.ts => change-task.tool.ts} (100%) rename apps/backend/src/modules/ai-assistant/libs/helpers/change-task/{change-task-message.enum.ts => change-task-template.enum.ts} (100%) rename apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/{suggest-task-prompt-messages.enum.ts => suggest-task-prompt-template.enum.ts} (100%) diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts index 6d90d83c0..2cda14787 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts @@ -1,5 +1,5 @@ -export { OpenAiAssistantConfig } from "./open-ai-assistant-config.enum.js"; -export { OpenAIErrorMessage } from "./open-ai-error-message.enum.js"; -export { OpenAiFunctionName } from "./open-ai-function-name.enum.js"; -export { OpenAiPromptTemplates } from "./open-ai-prompt-messages.enum.js"; -export { OpenAiRoleKey } from "./open-ai-role-key.enum.js"; +export { OpenAIAssistantConfig } from "./open-ai-assistant-config.enum.js"; +export { OpenAIErrorMessage } from "./open-ai-error-template.enum.js"; +export { OpenAIFunctionName } from "./open-ai-function-name.enum.js"; +export { OpenAIPromptTemplate } from "./open-ai-prompt-messages.enum.js"; +export { OpenAIRoleKey } from "./open-ai-role-key.enum.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts index 38251f31c..8a3f05739 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts @@ -2,16 +2,15 @@ import { AnalyzeBalanceTool, ChangeTaskTool, SuggestTaskTool, -} from "~/libs/modules/open-ai/libs/tools/tools.js"; +} from "../../libs/tools/tools.js"; +import { OpenAIPromptTemplate } from "./open-ai-prompt-messages.enum.js"; -import { OpenAiPromptTemplates } from "./open-ai-prompt-messages.enum.js"; - -const OpenAiAssistantConfig = { - INSTRUCTION: OpenAiPromptTemplates.ASSISTANT_INSTRUCTION, +const OpenAIAssistantConfig = { + INSTRUCTION: OpenAIPromptTemplate.ASSISTANT_INSTRUCTION, NAME: "Wheel of Balance Assistant", TEMPERATURE: 1, TOOLS: [AnalyzeBalanceTool, SuggestTaskTool, ChangeTaskTool], TOP_P: 1, } as const; -export { OpenAiAssistantConfig }; +export { OpenAIAssistantConfig }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-message.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-template.enum.ts similarity index 100% rename from apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-message.enum.ts rename to apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-template.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts index 09094e57b..b46e1ab3f 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts @@ -1,6 +1,6 @@ -const OpenAiFunctionName = { +const OpenAIFunctionName = { ANALYZE_BALANCE_SCORES: "analyze_balance_scores", CHANGE_TASK: "change_task", GENERATE_TASK_BY_CATEGORY: "generate_task_by_category", } as const; -export { OpenAiFunctionName }; +export { OpenAIFunctionName }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts index 60b73fae8..069146a34 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts @@ -1,4 +1,4 @@ -const OpenAiPromptTemplates = { +const OpenAIPromptTemplate = { ASSISTANT_INSTRUCTION: ` You are an instructor responsible for analyzing the user's preferences and scores based on the Wheel of Balance. The Wheel of Balance helps the user prioritize various areas of their life, such as health, career, relationships, @@ -19,4 +19,4 @@ After this stage, you will generate appropriate tasks for improvement later. `, } as const; -export { OpenAiPromptTemplates }; +export { OpenAIPromptTemplate }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts index c4892c5d7..e35f1a27c 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-role-key.enum.ts @@ -1,7 +1,7 @@ -const OpenAiRoleKey = { +const OpenAIRoleKey = { ASSISTANT: "assistant", SYSTEM: "system", USER: "user", } as const; -export { OpenAiRoleKey }; +export { OpenAIRoleKey }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts similarity index 100% rename from apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance-tool.ts rename to apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/change-task.tool.ts similarity index 100% rename from apps/backend/src/libs/modules/open-ai/libs/tools/change-task-tool.ts rename to apps/backend/src/libs/modules/open-ai/libs/tools/change-task.tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts index a79c25db5..dd2d76576 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts @@ -1,3 +1,3 @@ -export { AnalyzeBalanceTool } from "./analyze-balance-tool.js"; -export { ChangeTaskTool } from "./change-task-tool.js"; +export { AnalyzeBalanceTool } from "./analyze-balance.tool.js"; +export { ChangeTaskTool } from "./change-task.tool.js"; export { SuggestTaskTool } from "./suggest-task.tool.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts b/apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts index 210c85746..71cb5ebaa 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/types/open-ai-run-thread-request-dto.type.ts @@ -1,12 +1,12 @@ import { type MessageCreateParams } from "openai/resources/beta/threads/index"; import { type ZodSchema } from "zod"; -import { type OpenAiFunctionName } from "~/libs/modules/open-ai/open-ai.js"; +import { type OpenAIFunctionName } from "~/libs/modules/open-ai/open-ai.js"; import { type ValueOf } from "~/libs/types/types.js"; type OpenAiRunThreadRequestDto = { additional_instructions: null | string; - function_name: ValueOf; + function_name: ValueOf; instructions: null | string; messages: MessageCreateParams[]; validationSchema: ZodSchema; diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts index 09d07ab70..5587da5b7 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts @@ -6,7 +6,7 @@ import { HTTPCode } from "~/libs/modules/http/http.js"; import { type Logger } from "~/libs/modules/logger/logger.js"; import { - OpenAiAssistantConfig, + OpenAIAssistantConfig, OpenAIErrorMessage, } from "./libs/enums/enums.js"; import { OpenAIError } from "./libs/exceptions/exceptions.js"; @@ -43,18 +43,18 @@ class OpenAi { try { const existingAssistants = await this.openAi.beta.assistants.list(); const assistant = existingAssistants.data.find( - (assistant) => assistant.name === OpenAiAssistantConfig.NAME, + (assistant) => assistant.name === OpenAIAssistantConfig.NAME, ); const initializedAssistant = assistant ?? (await this.openAi.beta.assistants.create({ - instructions: OpenAiAssistantConfig.INSTRUCTION, + instructions: OpenAIAssistantConfig.INSTRUCTION, model: this.config.ENV.OPEN_AI.MODEL, - name: OpenAiAssistantConfig.NAME, - temperature: OpenAiAssistantConfig.TEMPERATURE, - tools: [...OpenAiAssistantConfig.TOOLS], - top_p: OpenAiAssistantConfig.TOP_P, + name: OpenAIAssistantConfig.NAME, + temperature: OpenAIAssistantConfig.TEMPERATURE, + tools: [...OpenAIAssistantConfig.TOOLS], + top_p: OpenAIAssistantConfig.TOP_P, })); this.logger.info( diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.ts b/apps/backend/src/libs/modules/open-ai/open-ai.ts index 402bf4915..c48800099 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.ts @@ -3,18 +3,18 @@ import { logger } from "~/libs/modules/logger/logger.js"; import { OpenAi } from "./open-ai.module.js"; -const openAi = new OpenAi({ +const openAI = new OpenAi({ config, logger, }); -await openAi.initializeAssistant(); +await openAI.initializeAssistant(); -export { openAi }; +export { openAI }; export { - OpenAiFunctionName, - OpenAiPromptTemplates, - OpenAiRoleKey, + OpenAIFunctionName, + OpenAIPromptTemplate, + OpenAIRoleKey, } from "./libs/enums/enums.js"; export { type OpenAiRequestMessage, diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index ccb71ec2a..d43b3f31d 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -1,4 +1,4 @@ -import { type OpenAi, OpenAiRoleKey } from "~/libs/modules/open-ai/open-ai.js"; +import { type OpenAi, OpenAIRoleKey } from "~/libs/modules/open-ai/open-ai.js"; import { type UserDto } from "~/libs/types/types.js"; import { type CategoryService } from "~/modules/categories/categories.js"; import { type OnboardingRepository } from "~/modules/onboarding/onboarding.js"; @@ -61,7 +61,7 @@ class AiAssistantService { }); const chatMessage = { content: `User has accepted this task: ${JSON.stringify(newTask)}`, - role: OpenAiRoleKey.USER, + role: OpenAIRoleKey.USER, }; await this.openAi.addMessageToThread(threadId, chatMessage); @@ -76,7 +76,7 @@ class AiAssistantService { const prompt = { content: text, - role: OpenAiRoleKey.USER, + role: OpenAIRoleKey.USER, }; return await this.openAi.addMessageToThread(threadId, prompt); diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.ts index dd4df3980..2dd7243de 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.ts @@ -1,5 +1,5 @@ import { logger } from "~/libs/modules/logger/logger.js"; -import { openAi } from "~/libs/modules/open-ai/open-ai.js"; +import { openAI } from "~/libs/modules/open-ai/open-ai.js"; import { categoryService } from "~/modules/categories/categories.js"; import { onboardingRepository } from "~/modules/onboarding/onboarding.js"; import { taskService } from "~/modules/tasks/tasks.js"; @@ -10,7 +10,7 @@ import { AiAssistantService } from "./ai-assistant.service.js"; const aiAssistantService = new AiAssistantService({ categoryService, onboardingRepository, - openAi, + openAi: openAI, taskService, }); diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-template.enum.ts similarity index 100% rename from apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-message.enum.ts rename to apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-template.enum.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts index b52d79a59..a00da403b 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts @@ -1,11 +1,11 @@ import { - OpenAiFunctionName, + OpenAIFunctionName, type OpenAiRunThreadRequestDto, } from "~/libs/modules/open-ai/open-ai.js"; import { type TaskCreateDto } from "../../types/types.js"; import { changeTaskByCategory as ChangeTaskByCategoryValidationSchema } from "./change-task.validation-schema.js"; -import { ChangeTaskPromptTemplates } from "./change-task-message.enum.js"; +import { ChangeTaskPromptTemplates } from "./change-task-template.enum.js"; import { generaChangeTaskPrompt } from "./geregate-change-task-prompt.js"; const runChangeTaskByCategoryOptions = ( @@ -15,7 +15,7 @@ const runChangeTaskByCategoryOptions = ( return { additional_instructions: null, - function_name: OpenAiFunctionName.CHANGE_TASK, + function_name: OpenAIFunctionName.CHANGE_TASK, instructions: ChangeTaskPromptTemplates.CHANGE_TASKS_INSTRUCTIONS, messages: [changeTaskPrompt], validationSchema: ChangeTaskByCategoryValidationSchema, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts index 338689100..bd7b62ee3 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts @@ -1,10 +1,10 @@ import { type OpenAiRequestMessage, - OpenAiRoleKey, + OpenAIRoleKey, } from "~/libs/modules/open-ai/open-ai.js"; import { type TaskCreateDto } from "../../types/types.js"; -import { ChangeTaskPromptTemplates } from "./change-task-message.enum.js"; +import { ChangeTaskPromptTemplates } from "./change-task-template.enum.js"; function generaChangeTaskPrompt( task: TaskCreateDto, @@ -13,7 +13,7 @@ function generaChangeTaskPrompt( /* eslint-disable perfectionist/sort-objects */ return { content: JSON.stringify({ context, task }), - role: OpenAiRoleKey.USER, + role: OpenAIRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts index 4c15516db..8719f24cf 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts @@ -1,7 +1,7 @@ import { ZERO_INDEX } from "~/libs/constants/constants.js"; import { type OpenAiRequestMessage, - OpenAiRoleKey, + OpenAIRoleKey, } from "~/libs/modules/open-ai/open-ai.js"; import { type OnboardingQuestionEntity } from "~/modules/onboarding/onboarding.js"; @@ -33,7 +33,7 @@ function generateQuestionsAnswersPrompt( return { content: JSON.stringify(promptContent), - role: OpenAiRoleKey.USER, + role: OpenAIRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts index 5f0dae12b..d072e0caa 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -1,6 +1,6 @@ import { type OpenAiRequestMessage, - OpenAiRoleKey, + OpenAIRoleKey, } from "~/libs/modules/open-ai/open-ai.js"; import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; @@ -20,7 +20,7 @@ function generateUserScoresPrompt( /* eslint-disable perfectionist/sort-objects */ return { content: JSON.stringify({ context, categories }), - role: OpenAiRoleKey.USER, + role: OpenAIRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts index a17a26349..4b57eb728 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts @@ -1,5 +1,5 @@ import { - OpenAiFunctionName, + OpenAIFunctionName, type OpenAiRunThreadRequestDto, } from "~/libs/modules/open-ai/open-ai.js"; import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; @@ -16,7 +16,7 @@ const runInitialThreadOptions = ( return { additional_instructions: null, - function_name: OpenAiFunctionName.ANALYZE_BALANCE_SCORES, + function_name: OpenAIFunctionName.ANALYZE_BALANCE_SCORES, instructions: OpenAiInitialPromptTemplates.WHEEL_OF_BALANCE_INSTRUCTIONS.replace( "{{userName}}", diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts index b71e7c9e1..a07c59bc1 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts @@ -1,10 +1,10 @@ import { type OpenAiRequestMessage, - OpenAiRoleKey, + OpenAIRoleKey, } from "~/libs/modules/open-ai/open-ai.js"; import { type SelectedCategories } from "../../types/types.js"; -import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-messages.enum.js"; +import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-template.enum.js"; function generateSuggestTaskPrompt( categories: SelectedCategories[], @@ -13,7 +13,7 @@ function generateSuggestTaskPrompt( /* eslint-disable perfectionist/sort-objects */ return { content: JSON.stringify({ context, categories }), - role: OpenAiRoleKey.USER, + role: OpenAIRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts index a870473ae..c8ba9b327 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts @@ -1,12 +1,12 @@ import { - OpenAiFunctionName, + OpenAIFunctionName, type OpenAiRunThreadRequestDto, } from "~/libs/modules/open-ai/open-ai.js"; import { type SelectedCategories } from "../../types/types.js"; import { generateSuggestTaskPrompt } from "./generate-suggest-task-prompt.js"; import { taskByCategory as TaskByCategoryValidationSchema } from "./suggest-task-by-category.validation-schema.js"; -import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-messages.enum.js"; +import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-template.enum.js"; const runTaskByCategoryOptions = ( categories: SelectedCategories[], @@ -15,7 +15,7 @@ const runTaskByCategoryOptions = ( return { additional_instructions: null, - function_name: OpenAiFunctionName.GENERATE_TASK_BY_CATEGORY, + function_name: OpenAIFunctionName.GENERATE_TASK_BY_CATEGORY, instructions: SuggestTaskPromptTemplates.SUGGEST_TASKS_INSTRUCTIONS, messages: [suggestTaskPrompt], validationSchema: TaskByCategoryValidationSchema, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-template.enum.ts similarity index 100% rename from apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-messages.enum.ts rename to apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-prompt-template.enum.ts From 0914e93eaa0ae65f4b04b6551eec3cda5118b181 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 13:34:07 +0100 Subject: [PATCH 133/244] refactor(shared): change api path names bb-203 --- .../modules/ai-assistant/ai-assistant.controller.ts | 10 +++++----- .../libs/enums/ai-assistant-api-path.enum.ts | 13 ++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 27d1e9bee..3d8fe90ec 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -139,7 +139,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.INIT_NEW_CHAT, + path: AiAssistantApiPath.CHAT_INITIATE, }); this.addRoute({ @@ -150,7 +150,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.ADD_MESSAGE, + path: AiAssistantApiPath.CHAT_ADD_MESSAGE, validation: { body: addMessageToThreadValidationSchema, }, @@ -165,7 +165,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.CHANGE_TASK, + path: AiAssistantApiPath.CHAT_CHANGE_TASK, validation: { body: ChangeTaskSuggestionRequestValidationSchema, }, @@ -180,7 +180,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.SUGGEST_TASKS, + path: AiAssistantApiPath.CHAT_SUGGEST_TASKS, validation: { body: TaskSuggestionRequestValidationSchema, }, @@ -195,7 +195,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.ACCEPT_TASK, + path: AiAssistantApiPath.CHAT_ACCEPT_TASK, validation: { body: ChangeTaskSuggestionRequestValidationSchema, }, diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts index 4fc97c8c5..4df8b7f80 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -1,11 +1,10 @@ const AiAssistantApiPath = { - ACCEPT_TASK: "/chat/accept-task", - ADD_MESSAGE: "/chat/add-message", - CHANGE_TASK: "/chat/change-task", - CONTINUE_CHAT: "/chat/continue", - DELETE_CHAT: "/chat/remove", - INIT_NEW_CHAT: "/chat/initiate", - SUGGEST_TASKS: "/chat/suggest-tasks", + CHAT_ACCEPT_TASK: "/chat/accept-task", + CHAT_ADD_MESSAGE: "/chat/add-message", + CHAT_CHANGE_TASK: "/chat/change-task", + CHAT_CONTINUE: "/chat/continue", + CHAT_INITIATE: "/chat/initiate", + CHAT_SUGGEST_TASKS: "/chat/suggest-tasks", } as const; export { AiAssistantApiPath }; From 7e60b198ea161ac6690f5eabb769408d3164f98f Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 13:44:51 +0100 Subject: [PATCH 134/244] refactor(shared): change BalanceWheelAnalysisResponseDto for more readable type bb-203 --- .../types/balance-wheel-analysis-response.dto.type.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts index 3d3d3c289..95035b783 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/balance-wheel-analysis-response.dto.type.ts @@ -1,9 +1,7 @@ -import { type QuizScoresGetAllItemResponseDto } from "../../../quiz/quiz.js"; - -type SimplifiedQuizScoreDto = Omit< - QuizScoresGetAllItemResponseDto, - "createdAt" | "id" | "score" | "updatedAt" | "userId" ->; +type SimplifiedQuizScoreDto = { + categoryId: number; + categoryName: string; +}; type BalanceWheelAnalysisResponseDto = { lowestCategories: SimplifiedQuizScoreDto[]; From 2638bfc56183c6a569b371039b71bb7d4373d7a7 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 13:48:18 +0100 Subject: [PATCH 135/244] refactor(shared): change AiAssistantValidationRule and schemas bb-203 --- .../enums/ai-assistant-validatuon-rule.enum.ts | 3 +-- .../add-message-to-thread.validation-schema.ts | 4 ++-- .../change-task-suggestion.validation-schema.ts | 14 ++++++-------- .../task-suggestion-request.validation-schema.ts | 6 +++--- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts index bc52cc8ba..807898815 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -1,6 +1,5 @@ const AiAssistantValidationRule = { - NON_EMPTY_NUMBER_MIN_LENGTH: 1, - NON_EMPTY_STRING_MIN_LENGTH: 1, + NON_EMPTY_ITEM_MIN_LENGTH: 1, THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, } as const; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts index 9b2b96e65..c5ee9f9a8 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts @@ -15,13 +15,13 @@ const addMessageToThread = z text: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.TEXT_REQUIRED, }), threadId: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, }) .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts index 2043e5a67..92ff08947 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts @@ -12,27 +12,25 @@ const ChangeTaskSuggestionRequest = z.object({ }), categoryName: z .string() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, }), description: z .string() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.DESCRIPTION_REQUIRED, }), dueDate: z.string().datetime({ message: AiAssistantValidationMessage.DUE_DATE_INVALID_FORMAT, }), - label: z - .string() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { - message: AiAssistantValidationMessage.LABEL_REQUIRED, - }), + label: z.string().min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AiAssistantValidationMessage.LABEL_REQUIRED, + }), }), threadId: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, }) .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 4cb0affdd..4d4c45631 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -11,12 +11,12 @@ const TaskSuggestionRequest = z.object({ z.object({ categoryId: z .number() - .min(AiAssistantValidationRule.NON_EMPTY_NUMBER_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, }), categoryName: z .string() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, }), }), @@ -27,7 +27,7 @@ const TaskSuggestionRequest = z.object({ threadId: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_STRING_MIN_LENGTH, { + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, }) .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { From ca18ae709d9c6c9f1dbfd1da79ebff14cea512b4 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 13:53:24 +0100 Subject: [PATCH 136/244] refactor(shared): change code to follow B27 bb-203 --- apps/backend/src/modules/tasks/task.repository.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/modules/tasks/task.repository.ts b/apps/backend/src/modules/tasks/task.repository.ts index 3e065f719..534978041 100644 --- a/apps/backend/src/modules/tasks/task.repository.ts +++ b/apps/backend/src/modules/tasks/task.repository.ts @@ -96,8 +96,8 @@ class TaskRepository implements Repository { async findAllByUserId(userId: number): Promise { const tasks = await TaskModel.query().where({ userId }); - return tasks.map((task) => - TaskEntity.initialize({ + return tasks.map((task) => { + return TaskEntity.initialize({ category: task.category.name, categoryId: task.categoryId, createdAt: task.createdAt, @@ -108,8 +108,8 @@ class TaskRepository implements Repository { status: task.status, updatedAt: task.updatedAt, userId: task.userId, - }), - ); + }); + }); } public async findCurrentByUserId(userId: number): Promise { From 6948c1d1825212a0bc707a1bfd0699b7f9d48766 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 13:58:52 +0100 Subject: [PATCH 137/244] refactor(shared): change code to follow B27 bb-203 --- .../src/modules/onboarding/onboarding.repository.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/modules/onboarding/onboarding.repository.ts b/apps/backend/src/modules/onboarding/onboarding.repository.ts index 11d7971ed..4ea27969c 100644 --- a/apps/backend/src/modules/onboarding/onboarding.repository.ts +++ b/apps/backend/src/modules/onboarding/onboarding.repository.ts @@ -264,16 +264,16 @@ class OnboardingRepository implements Repository { ); return OnboardingQuestionEntity.initialize({ - answers: answersForQuestion.map((answer) => - OnboardingAnswerEntity.initialize({ + answers: answersForQuestion.map((answer) => { + return OnboardingAnswerEntity.initialize({ createdAt: answer.createdAt, id: answer.id, label: answer.label, questionId: answer.questionId, updatedAt: answer.updatedAt, userId, - }), - ), + }); + }), createdAt: question.createdAt, id: question.id, label: question.label, From fd25e70de8f41240347e7c1e18985ca9fe71cdd6 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 14:02:56 +0100 Subject: [PATCH 138/244] refactor(shared): change code to follow B27 bb-203 --- .../initial-chat/generate-scores-response.ts | 10 ++++++---- .../generate-suggest-task-response.ts | 16 +++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index 87d12e905..fb6712b1f 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -32,10 +32,12 @@ const generateScoresResponse = ( ) as BalanceAnalysisData; return { - lowestCategories: resultData.lowestCategories.map((category) => ({ - categoryId: category.categoryId, - categoryName: category.categoryName, - })), + lowestCategories: resultData.lowestCategories.map((category) => { + return { + categoryId: category.categoryId, + categoryName: category.categoryName, + }; + }), messages: { comments: resultData.messages.comments, greeting: resultData.messages.greeting, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index e19759d3c..30b02aabc 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -34,13 +34,15 @@ const generateTaskSuggestionsResponse = ( return { message: resultData.message, - tasks: resultData.tasks.map((task) => ({ - categoryId: task.categoryId, - categoryName: task.categoryName, - description: task.description, - dueDate: taskDeadLine, - label: task.label, - })), + tasks: resultData.tasks.map((task) => { + return { + categoryId: task.categoryId, + categoryName: task.categoryName, + description: task.description, + dueDate: taskDeadLine, + label: task.label, + }; + }), }; }; From 340631bf36b7f8aabab94821d4f3db7b0543851e Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 14:05:02 +0100 Subject: [PATCH 139/244] refactor(backend): change name in validation schema bb-203 --- .../initial-chat/balance-analysis.validation-schema.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index bb42afcea..1627434c5 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -const Category = z.object({ +const category = z.object({ categoryId: z.number(), categoryName: z.string(), }); @@ -12,7 +12,7 @@ const Messages = z.object({ }); const balanceAnalysis = z.object({ - lowestCategories: z.array(Category), + lowestCategories: z.array(category), messages: Messages, }); From b1983d0e0ea74a92615d04e538de215a0b3b208b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 14:18:16 +0100 Subject: [PATCH 140/244] refactor(backend): add run status enum bb-203 --- .../src/libs/modules/open-ai/libs/enums/enums.ts | 1 + .../open-ai/libs/enums/open-ai-run-status.enum.ts | 8 ++++++++ .../src/libs/modules/open-ai/open-ai.module.ts | 13 ++++++++----- 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-run-status.enum.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts index 2cda14787..1f355b837 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts @@ -3,3 +3,4 @@ export { OpenAIErrorMessage } from "./open-ai-error-template.enum.js"; export { OpenAIFunctionName } from "./open-ai-function-name.enum.js"; export { OpenAIPromptTemplate } from "./open-ai-prompt-messages.enum.js"; export { OpenAIRoleKey } from "./open-ai-role-key.enum.js"; +export { OpenAIRunStatus } from "./open-ai-run-status.enum.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-run-status.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-run-status.enum.ts new file mode 100644 index 000000000..a022bc9de --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-run-status.enum.ts @@ -0,0 +1,8 @@ +const OpenAIRunStatus = { + COMPLETED: "completed", + IN_PROGRESS: "in_progress", + QUEUED: "queued", + REQUIRE_ACTIONS: "requires_action", +} as const; + +export { OpenAIRunStatus }; diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts index 5587da5b7..36793c8b1 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.module.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.module.ts @@ -8,6 +8,7 @@ import { type Logger } from "~/libs/modules/logger/logger.js"; import { OpenAIAssistantConfig, OpenAIErrorMessage, + OpenAIRunStatus, } from "./libs/enums/enums.js"; import { OpenAIError } from "./libs/exceptions/exceptions.js"; import { @@ -87,7 +88,7 @@ class OpenAi { tool_calls.map( async ({ function: toolFunction, - function: { arguments: arguments_ }, + function: { arguments: toolArguments }, id, }) => { if (toolFunction.name !== functionName) { @@ -101,7 +102,7 @@ class OpenAi { { tool_outputs: [ { - output: arguments_, + output: toolArguments, tool_call_id: id, }, ], @@ -127,9 +128,9 @@ class OpenAi { run: OpenAI.Beta.Threads.Runs.Run, functionName: string, ): Promise { - if (run.status === "completed") { + if (run.status === OpenAIRunStatus.COMPLETED) { return await this.getAllMessages(threadId); - } else if (run.status === "requires_action") { + } else if (run.status === OpenAIRunStatus.REQUIRE_ACTIONS) { await this.handleRequiresAction(run, functionName); return await this.getAllMessages(threadId); @@ -232,7 +233,9 @@ class OpenAi { const runs = await this.openAi.beta.threads.runs.list(threadId); const pendingRuns = runs.data.filter( - (run) => run.status === "in_progress" || run.status === "queued", + (run) => + run.status === OpenAIRunStatus.IN_PROGRESS || + run.status === OpenAIRunStatus.QUEUED, ); for (const run of pendingRuns) { From 310f641446012249166b4b5f5a40bb6ac35fc8f2 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 14:21:01 +0100 Subject: [PATCH 141/244] refactor(backend): rename Assistant validation schema bb-203 --- .../ai-assistant-message.validation-schema.ts | 4 ++-- .../open-ai/libs/validation-schemas/validation-schemas.ts | 2 +- apps/backend/src/libs/modules/open-ai/open-ai.ts | 2 +- .../libs/helpers/change-task/change-task-response.ts | 4 ++-- .../libs/helpers/initial-chat/generate-scores-response.ts | 4 ++-- .../generate-suggest-task-response.ts | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts index 86f45ed8d..0f87a32c7 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/ai-assistant-message.validation-schema.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -const AiAssistantMessage = z.object({ +const openAIAssistantMessage = z.object({ content: z .array( z.object({ @@ -14,4 +14,4 @@ const AiAssistantMessage = z.object({ id: z.string(), }); -export { AiAssistantMessage }; +export { openAIAssistantMessage }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts index a51134a11..7b91309b0 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/validation-schemas/validation-schemas.ts @@ -1 +1 @@ -export { AiAssistantMessage as AiAssistantMessageValidationSchema } from "./ai-assistant-message.validation-schema.js"; +export { openAIAssistantMessage as AIAssistantMessageValidationSchema } from "./ai-assistant-message.validation-schema.js"; diff --git a/apps/backend/src/libs/modules/open-ai/open-ai.ts b/apps/backend/src/libs/modules/open-ai/open-ai.ts index c48800099..1ee671dca 100644 --- a/apps/backend/src/libs/modules/open-ai/open-ai.ts +++ b/apps/backend/src/libs/modules/open-ai/open-ai.ts @@ -21,5 +21,5 @@ export { type OpenAiResponseMessage, type OpenAiRunThreadRequestDto, } from "./libs/types/types.js"; -export { AiAssistantMessageValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; +export { AIAssistantMessageValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { type OpenAi } from "./open-ai.module.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts index ad15663e8..500cfe474 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts @@ -2,7 +2,7 @@ import { type z } from "zod"; import { ZERO_INDEX } from "~/libs/constants/constants.js"; import { - AiAssistantMessageValidationSchema, + AIAssistantMessageValidationSchema, type OpenAiResponseMessage, } from "~/libs/modules/open-ai/open-ai.js"; @@ -21,7 +21,7 @@ const generateChangeTaskSuggestionsResponse = ( return null; } - const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); + const parsedResult = AIAssistantMessageValidationSchema.safeParse(message); if (!parsedResult.success) { return null; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index fb6712b1f..c8688b2da 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -2,7 +2,7 @@ import { type z } from "zod"; import { ZERO_INDEX } from "~/libs/constants/constants.js"; import { - AiAssistantMessageValidationSchema, + AIAssistantMessageValidationSchema, type OpenAiResponseMessage, } from "~/libs/modules/open-ai/open-ai.js"; @@ -20,7 +20,7 @@ const generateScoresResponse = ( return null; } - const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); + const parsedResult = AIAssistantMessageValidationSchema.safeParse(message); if (!parsedResult.success) { return null; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index 30b02aabc..98e034575 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -2,7 +2,7 @@ import { type z } from "zod"; import { ZERO_INDEX } from "~/libs/constants/constants.js"; import { - AiAssistantMessageValidationSchema, + AIAssistantMessageValidationSchema, type OpenAiResponseMessage, } from "~/libs/modules/open-ai/open-ai.js"; @@ -21,7 +21,7 @@ const generateTaskSuggestionsResponse = ( return null; } - const parsedResult = AiAssistantMessageValidationSchema.safeParse(message); + const parsedResult = AIAssistantMessageValidationSchema.safeParse(message); if (!parsedResult.success) { return null; From 10438f2534fa44f32a614ba72a4a71d3be3b75d7 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 15:13:56 +0100 Subject: [PATCH 142/244] refactor(backend): refactor helpers not to disable linter rules bb-203 --- .../geregate-change-task-prompt.ts | 14 ++++++++------ .../generate-questions-answers-prompt.ts | 19 +++++++------------ .../initial-chat/generate-scores-prompt.ts | 10 +++++++--- .../generate-suggest-task-prompt.ts | 10 +++++++--- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts index bd7b62ee3..10602685d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts @@ -6,13 +6,15 @@ import { import { type TaskCreateDto } from "../../types/types.js"; import { ChangeTaskPromptTemplates } from "./change-task-template.enum.js"; -function generaChangeTaskPrompt( - task: TaskCreateDto, - context: string = ChangeTaskPromptTemplates.CHANGE_TASKS_CONTEXT, -): OpenAiRequestMessage { - /* eslint-disable perfectionist/sort-objects */ +function generaChangeTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { + const content = ` + { + "context": "${ChangeTaskPromptTemplates.CHANGE_TASKS_CONTEXT}", + "task": ${JSON.stringify(task)}, + }`; + return { - content: JSON.stringify({ context, task }), + content, role: OpenAIRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts index 8719f24cf..7b94e8c7a 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts @@ -19,20 +19,15 @@ function generateQuestionsAnswersPrompt( }, ); - /* eslint-disable perfectionist/sort-objects */ - const promptContent = { - context: OpenAiInitialPromptTemplates.INIT_CHAT_CONTENT, - user_answers: questionsWithAnswers - .map( - ({ answer, question }) => - `- Question: ${question}\nAnswer: ${answer as string}`, - ) - .join("\n"), - instructions: OpenAiInitialPromptTemplates.INIT_CHAT_INSTRUCTION, - }; + const content = ` + { + "context": "${OpenAiInitialPromptTemplates.INIT_CHAT_CONTENT}", + "user_answers": ${JSON.stringify(questionsWithAnswers)}, + "instructions": "${OpenAiInitialPromptTemplates.INIT_CHAT_INSTRUCTION}", + }`; return { - content: JSON.stringify(promptContent), + content, role: OpenAIRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts index d072e0caa..289a9058a 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -8,7 +8,6 @@ import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enu function generateUserScoresPrompt( userScores: QuizScoresGetAllResponseDto, - context: string = OpenAiInitialPromptTemplates.WHEEL_OF_BALANCE_CONTEXT, ): OpenAiRequestMessage { const { items } = userScores; @@ -17,9 +16,14 @@ function generateUserScoresPrompt( categoryName, })); - /* eslint-disable perfectionist/sort-objects */ + const content = ` + { + "context": "${OpenAiInitialPromptTemplates.WHEEL_OF_BALANCE_CONTEXT}" + "categories": ${JSON.stringify(categories)}, + }`; + return { - content: JSON.stringify({ context, categories }), + content, role: OpenAIRoleKey.USER, }; } diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts index a07c59bc1..69c155fb6 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts @@ -8,11 +8,15 @@ import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-template.enum. function generateSuggestTaskPrompt( categories: SelectedCategories[], - context: string = SuggestTaskPromptTemplates.SUGGEST_TASKS_CONTEXT, ): OpenAiRequestMessage { - /* eslint-disable perfectionist/sort-objects */ + const content = ` + { + "context": "${SuggestTaskPromptTemplates.SUGGEST_TASKS_CONTEXT}", + "categories": ${JSON.stringify(categories)}, + }`; + return { - content: JSON.stringify({ context, categories }), + content, role: OpenAIRoleKey.USER, }; } From 364538067875dd3d99249100f04789261e81f2ee Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Tue, 17 Sep 2024 15:16:20 +0100 Subject: [PATCH 143/244] refactor(backend/shared): change validation names bb-203 --- .../modules/ai-assistant/ai-assistant.controller.ts | 10 +++++----- .../libs/validation-schemas/validation-schemas.ts | 4 ++-- packages/shared/src/index.ts | 4 ++-- .../shared/src/modules/ai-assistant/ai-assistant.ts | 4 ++-- .../change-task-suggestion.validation-schema.ts | 4 ++-- .../task-suggestion-request.validation-schema.ts | 4 ++-- .../libs/validation-schemas/validation-schemas.ts | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 3d8fe90ec..ff1bfa2a6 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -17,8 +17,8 @@ import { } from "./libs/types/types.js"; import { addMessageToThreadValidationSchema, - ChangeTaskSuggestionRequestValidationSchema, - TaskSuggestionRequestValidationSchema, + changeTaskSuggestionRequestValidationSchema, + taskSuggestionRequestValidationSchema, } from "./libs/validation-schemas/validation-schemas.js"; /** @@ -167,7 +167,7 @@ class AiAssistantController extends BaseController { method: "POST", path: AiAssistantApiPath.CHAT_CHANGE_TASK, validation: { - body: ChangeTaskSuggestionRequestValidationSchema, + body: changeTaskSuggestionRequestValidationSchema, }, }); @@ -182,7 +182,7 @@ class AiAssistantController extends BaseController { method: "POST", path: AiAssistantApiPath.CHAT_SUGGEST_TASKS, validation: { - body: TaskSuggestionRequestValidationSchema, + body: taskSuggestionRequestValidationSchema, }, }); @@ -197,7 +197,7 @@ class AiAssistantController extends BaseController { method: "POST", path: AiAssistantApiPath.CHAT_ACCEPT_TASK, validation: { - body: ChangeTaskSuggestionRequestValidationSchema, + body: changeTaskSuggestionRequestValidationSchema, }, }); } diff --git a/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts index ba41d0c31..d647fc46d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts +++ b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -1,5 +1,5 @@ export { addMessageToThreadValidationSchema, - ChangeTaskSuggestionRequestValidationSchema, - TaskSuggestionRequestValidationSchema, + changeTaskSuggestionRequestValidationSchema, + taskSuggestionRequestValidationSchema, } from "shared"; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 1d196b234..7694bcdd7 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -47,10 +47,10 @@ export { AiAssistantApiPath, type BalanceWheelAnalysisResponseDto, type ChangeTaskSuggestionRequestDto, - ChangeTaskSuggestionRequestValidationSchema, + changeTaskSuggestionRequestValidationSchema, type SelectedCategories, type TaskSuggestionRequestDto, - TaskSuggestionRequestValidationSchema, + taskSuggestionRequestValidationSchema, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "./modules/ai-assistant/ai-assistant.js"; diff --git a/packages/shared/src/modules/ai-assistant/ai-assistant.ts b/packages/shared/src/modules/ai-assistant/ai-assistant.ts index 095037ff6..fbb2ccf8f 100644 --- a/packages/shared/src/modules/ai-assistant/ai-assistant.ts +++ b/packages/shared/src/modules/ai-assistant/ai-assistant.ts @@ -8,5 +8,5 @@ export { type ThreadMessageCreateDto, } from "./libs/types/types.js"; export { addMessageToThread as addMessageToThreadValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; -export { TaskSuggestionRequest as TaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; -export { ChangeTaskSuggestionRequest as ChangeTaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; +export { taskSuggestionRequest as taskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; +export { changeTaskSuggestionRequest as changeTaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts index 92ff08947..a8f796e3b 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts @@ -5,7 +5,7 @@ import { AiAssistantValidationRule, } from "../enums/enums.js"; -const ChangeTaskSuggestionRequest = z.object({ +const changeTaskSuggestionRequest = z.object({ task: z.object({ categoryId: z.number({ invalid_type_error: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, @@ -38,4 +38,4 @@ const ChangeTaskSuggestionRequest = z.object({ }), }); -export { ChangeTaskSuggestionRequest }; +export { changeTaskSuggestionRequest }; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 4d4c45631..36c6989b9 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -5,7 +5,7 @@ import { AiAssistantValidationRule, } from "../enums/enums.js"; -const TaskSuggestionRequest = z.object({ +const taskSuggestionRequest = z.object({ categories: z .array( z.object({ @@ -35,4 +35,4 @@ const TaskSuggestionRequest = z.object({ }), }); -export { TaskSuggestionRequest }; +export { taskSuggestionRequest }; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts index e8672b9e8..d98c7934c 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -1,3 +1,3 @@ export { addMessageToThread } from "./add-message-to-thread.validation-schema.js"; -export { ChangeTaskSuggestionRequest } from "./change-task-suggestion.validation-schema.js"; -export { TaskSuggestionRequest } from "./task-suggestion-request.validation-schema.js"; +export { changeTaskSuggestionRequest } from "./change-task-suggestion.validation-schema.js"; +export { taskSuggestionRequest } from "./task-suggestion-request.validation-schema.js"; From 536dd0c273ccb7d3f339126c31b49cfcd289092a Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Tue, 17 Sep 2024 19:08:08 +0300 Subject: [PATCH 144/244] feat(frontend): add types, enum bb-340 --- apps/frontend/src/libs/hooks/hooks.ts | 2 +- apps/frontend/src/modules/chat/chat.ts | 1 + .../libs/enums/chat-button-labels.enum.ts | 7 ++++++ .../chat/libs/enums/chat-message-type.enum.ts | 9 ++++++++ .../src/modules/chat/libs/enums/enums.ts | 2 ++ .../modules/chat/libs/types/message.type.ts | 23 +++++++------------ .../src/modules/chat/libs/types/types.ts | 2 ++ .../src/modules/tasks/libs/types/types.ts | 2 +- apps/frontend/src/modules/tasks/tasks.ts | 2 +- .../libs/enums/chat-button-action.enum.ts | 6 +++++ .../src/pages/chat/libs/enums/enums.ts | 1 + .../pages/chat/libs/types/chart-data.type.ts | 6 +++++ .../src/pages/chat/libs/types/types.ts | 1 + 13 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 apps/frontend/src/modules/chat/libs/enums/chat-button-labels.enum.ts create mode 100644 apps/frontend/src/modules/chat/libs/enums/chat-message-type.enum.ts create mode 100644 apps/frontend/src/pages/chat/libs/enums/chat-button-action.enum.ts create mode 100644 apps/frontend/src/pages/chat/libs/enums/enums.ts create mode 100644 apps/frontend/src/pages/chat/libs/types/chart-data.type.ts create mode 100644 apps/frontend/src/pages/chat/libs/types/types.ts diff --git a/apps/frontend/src/libs/hooks/hooks.ts b/apps/frontend/src/libs/hooks/hooks.ts index de2cb3f5f..0749ca239 100644 --- a/apps/frontend/src/libs/hooks/hooks.ts +++ b/apps/frontend/src/libs/hooks/hooks.ts @@ -5,6 +5,6 @@ export { export { useAppForm } from "./use-app-form/use-app-form.hook.js"; export { useAppSelector } from "./use-app-selector/use-app-selector.hook.js"; export { useQuery } from "./use-query/use-query-hook.js"; -export { useCallback, useEffect, useRef, useState } from "react"; +export { useCallback, useEffect, useMemo, useRef, useState } from "react"; export { useController as useFormController } from "react-hook-form"; export { useLocation, useNavigate, useParams } from "react-router-dom"; diff --git a/apps/frontend/src/modules/chat/chat.ts b/apps/frontend/src/modules/chat/chat.ts index ce21da06d..77ae3b749 100644 --- a/apps/frontend/src/modules/chat/chat.ts +++ b/apps/frontend/src/modules/chat/chat.ts @@ -11,6 +11,7 @@ const chatApi = new ChatApi({ }); export { chatApi }; +export { ChatMessageType } from "./libs/enums/enums.js"; export { type SimplifiedQuizScoreDto, type TaskSuggestionRequestDto, diff --git a/apps/frontend/src/modules/chat/libs/enums/chat-button-labels.enum.ts b/apps/frontend/src/modules/chat/libs/enums/chat-button-labels.enum.ts new file mode 100644 index 000000000..fe9e453e2 --- /dev/null +++ b/apps/frontend/src/modules/chat/libs/enums/chat-button-labels.enum.ts @@ -0,0 +1,7 @@ +const ChatButtonLabels = { + ACCEPT_CATEGORIES: "Accept categories", + NO_DIFFERENT: "No something else", + YES_LOWEST: "Yes, 3 lowest", +} as const; + +export { ChatButtonLabels }; diff --git a/apps/frontend/src/modules/chat/libs/enums/chat-message-type.enum.ts b/apps/frontend/src/modules/chat/libs/enums/chat-message-type.enum.ts new file mode 100644 index 000000000..2cef56154 --- /dev/null +++ b/apps/frontend/src/modules/chat/libs/enums/chat-message-type.enum.ts @@ -0,0 +1,9 @@ +const ChatMessageType = { + CATEGORY_FORM: "categoryForm", + CONFIRMATION_BUTTONS: "confirmationButtons", + TASK_LIST: "taskList", + TEXT: "text", + WHEEL_ANALYSIS: "wheelAnalysis", +} as const; + +export { ChatMessageType }; diff --git a/apps/frontend/src/modules/chat/libs/enums/enums.ts b/apps/frontend/src/modules/chat/libs/enums/enums.ts index c79d89039..092d14678 100644 --- a/apps/frontend/src/modules/chat/libs/enums/enums.ts +++ b/apps/frontend/src/modules/chat/libs/enums/enums.ts @@ -1 +1,3 @@ +export { ChatButtonLabels } from "./chat-button-labels.enum.js"; +export { ChatMessageType } from "./chat-message-type.enum.js"; export { AiAssistantApiPath } from "shared"; diff --git a/apps/frontend/src/modules/chat/libs/types/message.type.ts b/apps/frontend/src/modules/chat/libs/types/message.type.ts index 751a143d4..6b26b10b5 100644 --- a/apps/frontend/src/modules/chat/libs/types/message.type.ts +++ b/apps/frontend/src/modules/chat/libs/types/message.type.ts @@ -1,22 +1,15 @@ -import { type TaskCreateDto } from "./types.js"; +import { type ValueOf } from "~/libs/types/types.js"; -type ButtonLabels = string[]; +import { type ChatMessageType } from "../enums/enums.js"; +import { type SelectedCategories, type TaskCreateDto } from "./types.js"; type Message = { - buttonLabels?: ButtonLabels; - lowestCategories?: Array<{ - categoryId: number; - categoryName: string; - }>; - taskList?: TaskCreateDto[]; - text: string; + buttonLabels?: string[]; + lowestCategories?: SelectedCategories[]; + message: string; + tasks?: TaskCreateDto[]; threadId?: string; - type: - | "categoryForm" - | "confirmationButtons" - | "taskList" - | "text" - | "wheelAnalysis"; + type: ValueOf; }; export { type Message }; diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts index 66757480b..d3a794408 100644 --- a/apps/frontend/src/modules/chat/libs/types/types.ts +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -1,5 +1,7 @@ +export { type Message } from "./message.type.js"; export { type BalanceWheelAnalysisResponseDto, + type SelectedCategories, type SimplifiedQuizScoreDto, type TaskCreateDto, type TaskDto, diff --git a/apps/frontend/src/modules/tasks/libs/types/types.ts b/apps/frontend/src/modules/tasks/libs/types/types.ts index 3b7390aeb..123b4adb5 100644 --- a/apps/frontend/src/modules/tasks/libs/types/types.ts +++ b/apps/frontend/src/modules/tasks/libs/types/types.ts @@ -1 +1 @@ -export { type TaskDto } from "shared"; +export { type TaskCreateDto, type TaskDto } from "shared"; diff --git a/apps/frontend/src/modules/tasks/tasks.ts b/apps/frontend/src/modules/tasks/tasks.ts index 15dc14e53..967cc1de6 100644 --- a/apps/frontend/src/modules/tasks/tasks.ts +++ b/apps/frontend/src/modules/tasks/tasks.ts @@ -11,5 +11,5 @@ const tasksApi = new TasksApi({ }); export { tasksApi }; -export { type TaskDto } from "./libs/types/types.js"; +export { type TaskCreateDto, type TaskDto } from "./libs/types/types.js"; export { actions, reducer } from "./slices/tasks.js"; diff --git a/apps/frontend/src/pages/chat/libs/enums/chat-button-action.enum.ts b/apps/frontend/src/pages/chat/libs/enums/chat-button-action.enum.ts new file mode 100644 index 000000000..f67a16d42 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/enums/chat-button-action.enum.ts @@ -0,0 +1,6 @@ +const ChatButtonAction = { + GET_CATEGORY_FORM: "getCategoryForm", + GET_TASKS: "getTasks", +} as const; + +export { ChatButtonAction }; diff --git a/apps/frontend/src/pages/chat/libs/enums/enums.ts b/apps/frontend/src/pages/chat/libs/enums/enums.ts new file mode 100644 index 000000000..d319a81a8 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/enums/enums.ts @@ -0,0 +1 @@ +export { ChatButtonAction } from "../enums/chat-button-action.enum.js"; diff --git a/apps/frontend/src/pages/chat/libs/types/chart-data.type.ts b/apps/frontend/src/pages/chat/libs/types/chart-data.type.ts new file mode 100644 index 000000000..90f6e9657 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/types/chart-data.type.ts @@ -0,0 +1,6 @@ +type ChartDataType = { + data: number; + label: string; +}; + +export { type ChartDataType }; diff --git a/apps/frontend/src/pages/chat/libs/types/types.ts b/apps/frontend/src/pages/chat/libs/types/types.ts new file mode 100644 index 000000000..695b97c36 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/types/types.ts @@ -0,0 +1 @@ +export { type ChartDataType } from "./chart-data.type.js"; From 4db4aec0e473ea255eb7230c05a31dd81859d5a1 Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Tue, 17 Sep 2024 19:09:27 +0300 Subject: [PATCH 145/244] refactor(frontend): use types, enum bb-340 --- .../src/modules/chat/slices/chat.slice.ts | 37 ++++++------ apps/frontend/src/pages/chat/chat.tsx | 56 ++++++++++--------- .../components/chat-message/chat-message.tsx | 38 +++++++------ .../helpers/handle-button-action.helper.ts | 15 +++-- 4 files changed, 79 insertions(+), 67 deletions(-) diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 60f5712f5..ee3df577c 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -3,8 +3,11 @@ import { createSlice } from "@reduxjs/toolkit"; import { DataStatus } from "~/libs/enums/enums.js"; import { type ValueOf } from "~/libs/types/types.js"; -import { type Message } from "../libs/types/message.type.js"; -import { type SimplifiedQuizScoreDto } from "../libs/types/types.js"; +import { ChatButtonLabels, ChatMessageType } from "../libs/enums/enums.js"; +import { + type Message, + type SimplifiedQuizScoreDto, +} from "../libs/types/types.js"; import { getTasksForCategories, initConversation } from "./actions.js"; type State = { @@ -32,17 +35,21 @@ const { actions, name, reducer } = createSlice({ state.threadId = action.payload.threadId; state.messages.push( { - text: action.payload.messages.greeting, - type: "text", + message: action.payload.messages.greeting, + type: ChatMessageType.TEXT, }, + { - text: action.payload.messages.comments, - type: "wheelAnalysis", + message: action.payload.messages.comments, + type: ChatMessageType.WHEEL_ANALYSIS, }, { - buttonLabels: ["✅ Yes, 3 lowest", "🚫 No smth else"], - text: action.payload.messages.question, - type: "confirmationButtons", + buttonLabels: [ + ChatButtonLabels.YES_LOWEST, + ChatButtonLabels.NO_DIFFERENT, + ], + message: action.payload.messages.question, + type: ChatMessageType.CONFIRMATION_BUTTONS, }, ); state.dataStatus = DataStatus.FULFILLED; @@ -55,11 +62,9 @@ const { actions, name, reducer } = createSlice({ }) .addCase(getTasksForCategories.fulfilled, (state, action) => { state.dataStatus = DataStatus.FULFILLED; - const { message, tasks } = action.payload; state.messages.push({ - taskList: tasks, - text: message, - type: "taskList", + ...action.payload, + type: ChatMessageType.TASK_LIST, }); }) .addCase(getTasksForCategories.rejected, (state) => { @@ -71,9 +76,9 @@ const { actions, name, reducer } = createSlice({ reducers: { addCategoryCheckboxMessage(state) { state.messages.push({ - buttonLabels: ["Accept categories"], - text: "What categories do you want to work on?", - type: "categoryForm", + buttonLabels: [ChatButtonLabels.ACCEPT_CATEGORIES], + message: "What categories do you want to work on?", + type: ChatMessageType.CATEGORY_FORM, }); }, updateSelectedCategories( diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 56b49be40..913eda92b 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -3,6 +3,7 @@ import { useAppSelector, useCallback, useEffect, + useMemo, } from "~/libs/hooks/hooks.js"; import { actions as chatActions, @@ -16,10 +17,15 @@ import styles from "./styles.module.css"; const ChatComponent: React.FC = () => { const dispatch = useAppDispatch(); - const { scores } = useAppSelector((state) => state.quiz); - const { quizCategories } = useAppSelector(({ categories }) => ({ - quizCategories: categories.items, - })); + const { messages, quizCategories, scores, selectedCategories, threadId } = + useAppSelector((state) => ({ + messages: state.chat.messages, + quizCategories: state.categories.items, + scores: state.quiz.scores, + selectedCategories: state.chat.selectedCategories, + threadId: state.chat.threadId, + })); + const chartData = scores.map((score) => { return { data: score.score, @@ -27,32 +33,26 @@ const ChatComponent: React.FC = () => { }; }); - useEffect(() => { - void dispatch(quizActions.getScores()); - }, [dispatch]); + const formattedCategories = selectedCategories.map((category) => { + return { + categoryId: category.categoryId, + categoryName: category.categoryName, + }; + }); - const { messages, selectedCategories, threadId } = useAppSelector( - ({ chat }) => ({ - messages: chat.messages, - selectedCategories: chat.selectedCategories, - threadId: chat.threadId, + const contentData = useMemo( + () => ({ + chartData, + selectedCategories: { + categories: formattedCategories, + threadId: threadId ?? "", + }, }), + [chartData, formattedCategories, threadId], ); - const formattedCategories = selectedCategories.map((category) => ({ - categoryId: category.categoryId, - categoryName: category.categoryName, - })); - - const contentData = { - chartData, - selectedCategories: { - categories: formattedCategories, - threadId: threadId ?? "", - }, - }; - useEffect(() => { + void dispatch(quizActions.getScores()); void dispatch(chatActions.initConversation()); }, [dispatch]); @@ -64,6 +64,7 @@ const ChatComponent: React.FC = () => { categoryId: category.id, categoryName: category.name, })); + dispatch(chatActions.updateSelectedCategories(newSelectedCategories)); const taskPayload: TaskSuggestionRequestDto = { @@ -92,9 +93,10 @@ const ChatComponent: React.FC = () => { ); diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index b2d690d73..5b75f4ef9 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -4,34 +4,36 @@ import { } from "~/libs/components/components.js"; import { INDEX_ONE, ZERO_INDEX } from "~/libs/enums/enums.js"; import { useAppDispatch, useCallback } from "~/libs/hooks/hooks.js"; +import { type ValueOf } from "~/libs/types/types.js"; +import { + ChatMessageType, + type TaskSuggestionRequestDto, +} from "~/modules/chat/chat.js"; +// import { type TaskCreateDto } from "~/modules/tasks/tasks.js"; import { handleButtonAction } from "../../helpers/helpers.js"; +import { type ChartDataType } from "../../types/types.js"; import { ConfirmationButtons } from "../confirmation-buttons/confirmation-buttons.js"; +import { TaskListContainer } from "../task-list-container/task-list-container.js"; import styles from "./styles.module.css"; type Properties = { buttonLabels?: string[]; contentData: { - chartData: { data: number; label: string }[]; - selectedCategories: { - categories: { categoryId: number; categoryName: string }[]; - threadId: string; - }; + chartData: ChartDataType[]; + selectedCategories: TaskSuggestionRequestDto; }; onFormSubmit?: (payload: { categoryIds: number[] }) => void; + // taskList: TaskCreateDto[]; text: string; - type: - | "categoryForm" - | "confirmationButtons" - | "taskList" - | "text" - | "wheelAnalysis"; + type: ValueOf; }; const ChatMessage: React.FC = ({ buttonLabels = [], contentData, onFormSubmit, + // taskList, text, type, }: Properties) => { @@ -51,7 +53,7 @@ const ChatMessage: React.FC = ({ const renderContent = (): JSX.Element | null => { switch (type) { - case "categoryForm": { + case ChatMessageType.CATEGORY_FORM: { return onFormSubmit ? ( = ({ ) : null; } - case "confirmationButtons": { + case ChatMessageType.CONFIRMATION_BUTTONS: { return ( = ({ ); } - case "wheelAnalysis": { + case ChatMessageType.WHEEL_ANALYSIS: { return ; } - case "taskList": { - return
    Task list
    ; + case ChatMessageType.TASK_LIST: { + return ; } default: { @@ -89,8 +91,8 @@ const ChatMessage: React.FC = ({ return (
  • - {text} - {content} +

    {text}

    + {content &&
    {content}
    }
  • ); }; diff --git a/apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts b/apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts index d16b72747..986c5bd2d 100644 --- a/apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts +++ b/apps/frontend/src/pages/chat/libs/helpers/handle-button-action.helper.ts @@ -1,21 +1,24 @@ import { type AppDispatch } from "~/libs/hooks/hooks.js"; -import { type TaskSuggestionRequestDto } from "~/modules/chat/chat.js"; -import { actions as chatActions } from "~/modules/chat/chat.js"; +import { type ValueOf } from "~/libs/types/types.js"; +import { + actions as chatActions, + type TaskSuggestionRequestDto, +} from "~/modules/chat/chat.js"; -type ActionType = "getCategoryForm" | "getTasks"; +import { ChatButtonAction } from "../enums/enums.js"; const handleButtonAction = async ( dispatch: AppDispatch, - actionType: ActionType, + actionType: ValueOf, payload?: TaskSuggestionRequestDto, ): Promise => { switch (actionType) { - case "getCategoryForm": { + case ChatButtonAction.GET_CATEGORY_FORM: { dispatch(chatActions.addCategoryCheckboxMessage()); break; } - case "getTasks": { + case ChatButtonAction.GET_TASKS: { await dispatch( chatActions.getTasksForCategories(payload as TaskSuggestionRequestDto), ); From f89b384f81538714635d3e139b762405a7e130be Mon Sep 17 00:00:00 2001 From: Julia Olshanska <63751946+yulyaolshanska@users.noreply.github.com> Date: Tue, 17 Sep 2024 19:10:19 +0300 Subject: [PATCH 146/244] feat(frontend): add styles bb-340 --- apps/frontend/src/assets/css/scaffolding.css | 4 +++ .../components/chat-message/styles.module.css | 32 ++++++------------- .../pages/chat/libs/components/components.ts | 1 + .../confirmation-buttons.tsx | 10 ++++-- .../confirmation-buttons/styles.module.css | 8 +++++ .../task-list-container/styles.module.css | 7 ++++ .../task-list-container.tsx | 20 ++++++++++++ .../frontend/src/pages/chat/styles.module.css | 19 ----------- .../components/task-card/styles.module.css | 2 +- 9 files changed, 58 insertions(+), 45 deletions(-) create mode 100644 apps/frontend/src/pages/chat/libs/components/confirmation-buttons/styles.module.css create mode 100644 apps/frontend/src/pages/chat/libs/components/task-list-container/styles.module.css create mode 100644 apps/frontend/src/pages/chat/libs/components/task-list-container/task-list-container.tsx diff --git a/apps/frontend/src/assets/css/scaffolding.css b/apps/frontend/src/assets/css/scaffolding.css index dc2db551f..2bbe8736f 100644 --- a/apps/frontend/src/assets/css/scaffolding.css +++ b/apps/frontend/src/assets/css/scaffolding.css @@ -49,3 +49,7 @@ select { margin: 0; font-family: inherit; } + +li { + list-style: none; +} diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css index e36277139..3da1377a0 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css @@ -1,28 +1,16 @@ -.container { - display: flex; - flex-direction: column; - gap: 10px; -} - .message-container { - max-width: 620px; - padding: 13px; - background-color: #f6f5fa; - - /* border-radius: 0px 10px 10px; */ -} - -.button-container { display: flex; flex-direction: column; - gap: 10px; - align-items: center; + justify-content: center; + max-width: 730px; + padding: 15px; + background-color: var(--background-gray); + border-radius: 0 10px 10px; } -.button { - width: 200px; - padding: 10px; - margin-bottom: 10px; - border: 1px solid var(--blue-accent); - border-radius: 30px; +.content { + display: flex; + justify-content: center; + padding: 15px; + border-radius: 0 10px 10px; } diff --git a/apps/frontend/src/pages/chat/libs/components/components.ts b/apps/frontend/src/pages/chat/libs/components/components.ts index 4c351a3e5..821bc9b28 100644 --- a/apps/frontend/src/pages/chat/libs/components/components.ts +++ b/apps/frontend/src/pages/chat/libs/components/components.ts @@ -1,2 +1,3 @@ export { ChatMessage } from "./chat-message/chat-message.js"; export { ConfirmationButtons } from "./confirmation-buttons/confirmation-buttons.js"; +export { TaskListContainer } from "./task-list-container/task-list-container.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx b/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx index f01ceb2f9..285062ead 100644 --- a/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx +++ b/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/confirmation-buttons.tsx @@ -1,3 +1,7 @@ +import { Button } from "~/libs/components/components.js"; + +import styles from "./styles.module.css"; + type Properties = { handleNo: () => void; handleYes: () => void; @@ -12,9 +16,9 @@ const ConfirmationButtons: React.FC = ({ yesButtonLabel, }: Properties) => { return ( -
    - - +
    +
    ); }; diff --git a/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/styles.module.css b/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/styles.module.css new file mode 100644 index 000000000..470a75774 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/confirmation-buttons/styles.module.css @@ -0,0 +1,8 @@ +.button-container { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + justify-content: center; + max-width: 280px; +} diff --git a/apps/frontend/src/pages/chat/libs/components/task-list-container/styles.module.css b/apps/frontend/src/pages/chat/libs/components/task-list-container/styles.module.css new file mode 100644 index 000000000..c178a5af1 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/task-list-container/styles.module.css @@ -0,0 +1,7 @@ +.task-list { + display: flex; + flex-wrap: wrap; + gap: 20px; + height: fit-content; + padding: 20px; +} diff --git a/apps/frontend/src/pages/chat/libs/components/task-list-container/task-list-container.tsx b/apps/frontend/src/pages/chat/libs/components/task-list-container/task-list-container.tsx new file mode 100644 index 000000000..2324b5227 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/task-list-container/task-list-container.tsx @@ -0,0 +1,20 @@ +// import { type TaskCreateDto } from "~/modules/tasks/tasks.js"; +// import { TaskCard } from "~/pages/tasks/libs/components/components.js"; + +import styles from "./styles.module.css"; + +// type Properties = { +// taskList: TaskCreateDto[]; +// }; + +const TaskListContainer: React.FC = () => { + return ( +
      + {/* {taskList.map((task) => ( + + ))} */} +
    + ); +}; + +export { TaskListContainer }; diff --git a/apps/frontend/src/pages/chat/styles.module.css b/apps/frontend/src/pages/chat/styles.module.css index 3d4ef3afd..4eb8f1665 100644 --- a/apps/frontend/src/pages/chat/styles.module.css +++ b/apps/frontend/src/pages/chat/styles.module.css @@ -4,27 +4,8 @@ gap: 10px; } -.message-container { - max-width: 620px; - padding: 13px; - background-color: #f6f5fa; - - /* border-radius: 0px 10px 10px; */ -} - .page-container { display: flex; justify-content: space-between; padding: 24px; } - -.quiz-form-container { - display: flex; - flex-direction: column; - min-width: 400px; - padding: 24px 32px; - text-align: center; - border: 2px solid var(--light-gray); - border-radius: 24px; - box-shadow: 0 0 4px var(--light-blue); -} diff --git a/apps/frontend/src/pages/tasks/libs/components/task-card/styles.module.css b/apps/frontend/src/pages/tasks/libs/components/task-card/styles.module.css index cce4bdf4f..a0561bc3f 100644 --- a/apps/frontend/src/pages/tasks/libs/components/task-card/styles.module.css +++ b/apps/frontend/src/pages/tasks/libs/components/task-card/styles.module.css @@ -1,5 +1,5 @@ .card { - width: 356px; + max-width: 356px; height: 251px; padding: 20px; padding-right: 12px; From cf76c179432bdf9d52ff84748ddad6a7b913ddb6 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 10:32:49 +0100 Subject: [PATCH 147/244] refactor(backend): change files names bb-203 --- apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts | 2 +- .../modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts | 2 +- ...-prompt-messages.enum.ts => open-ai-prompt-template.enum.ts} | 0 ...ask-template.enum.ts => change-task-prompt-template.enum.ts} | 0 .../ai-assistant/libs/helpers/change-task/change-task.ts | 2 +- .../libs/helpers/change-task/geregate-change-task-prompt.ts | 2 +- ...pt-message.enum.ts => generate-init-prompt-template.enum.ts} | 0 .../helpers/initial-chat/generate-questions-answers-prompt.ts | 2 +- .../libs/helpers/initial-chat/generate-scores-prompt.ts | 2 +- .../ai-assistant/libs/helpers/initial-chat/initial-chat.ts | 2 +- 10 files changed, 7 insertions(+), 7 deletions(-) rename apps/backend/src/libs/modules/open-ai/libs/enums/{open-ai-prompt-messages.enum.ts => open-ai-prompt-template.enum.ts} (100%) rename apps/backend/src/modules/ai-assistant/libs/helpers/change-task/{change-task-template.enum.ts => change-task-prompt-template.enum.ts} (100%) rename apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/{generate-init-prompt-message.enum.ts => generate-init-prompt-template.enum.ts} (100%) diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts index 1f355b837..67dd5cedb 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/enums.ts @@ -1,6 +1,6 @@ export { OpenAIAssistantConfig } from "./open-ai-assistant-config.enum.js"; export { OpenAIErrorMessage } from "./open-ai-error-template.enum.js"; export { OpenAIFunctionName } from "./open-ai-function-name.enum.js"; -export { OpenAIPromptTemplate } from "./open-ai-prompt-messages.enum.js"; +export { OpenAIPromptTemplate } from "./open-ai-prompt-template.enum.js"; export { OpenAIRoleKey } from "./open-ai-role-key.enum.js"; export { OpenAIRunStatus } from "./open-ai-run-status.enum.js"; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts index 8a3f05739..f9335ccb7 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts @@ -3,7 +3,7 @@ import { ChangeTaskTool, SuggestTaskTool, } from "../../libs/tools/tools.js"; -import { OpenAIPromptTemplate } from "./open-ai-prompt-messages.enum.js"; +import { OpenAIPromptTemplate } from "./open-ai-prompt-template.enum.js"; const OpenAIAssistantConfig = { INSTRUCTION: OpenAIPromptTemplate.ASSISTANT_INSTRUCTION, diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-template.enum.ts similarity index 100% rename from apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-messages.enum.ts rename to apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-prompt-template.enum.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-template.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-prompt-template.enum.ts similarity index 100% rename from apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-template.enum.ts rename to apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-prompt-template.enum.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts index a00da403b..c54d63a2d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts @@ -5,7 +5,7 @@ import { import { type TaskCreateDto } from "../../types/types.js"; import { changeTaskByCategory as ChangeTaskByCategoryValidationSchema } from "./change-task.validation-schema.js"; -import { ChangeTaskPromptTemplates } from "./change-task-template.enum.js"; +import { ChangeTaskPromptTemplates } from "./change-task-prompt-template.enum.js"; import { generaChangeTaskPrompt } from "./geregate-change-task-prompt.js"; const runChangeTaskByCategoryOptions = ( diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts index 10602685d..babf77ea0 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts @@ -4,7 +4,7 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type TaskCreateDto } from "../../types/types.js"; -import { ChangeTaskPromptTemplates } from "./change-task-template.enum.js"; +import { ChangeTaskPromptTemplates } from "./change-task-prompt-template.enum.js"; function generaChangeTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { const content = ` diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-prompt-message.enum.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-prompt-template.enum.ts similarity index 100% rename from apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-prompt-message.enum.ts rename to apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-init-prompt-template.enum.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts index 7b94e8c7a..5433f15f7 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-questions-answers-prompt.ts @@ -5,7 +5,7 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type OnboardingQuestionEntity } from "~/modules/onboarding/onboarding.js"; -import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enum.js"; +import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-template.enum.js"; function generateQuestionsAnswersPrompt( userQuestionsWithAnswers: OnboardingQuestionEntity[], diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts index 289a9058a..8cdf7a88e 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -4,7 +4,7 @@ import { } from "~/libs/modules/open-ai/open-ai.js"; import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; -import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enum.js"; +import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-template.enum.js"; function generateUserScoresPrompt( userScores: QuizScoresGetAllResponseDto, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts index 4b57eb728..8c3c7a874 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/initial-chat.ts @@ -5,7 +5,7 @@ import { import { type QuizScoresGetAllResponseDto } from "~/modules/categories/categories.js"; import { balanceAnalysis as BalanceAnalysisResponseValidationSchema } from "./balance-analysis.validation-schema.js"; -import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-message.enum.js"; +import { OpenAiInitialPromptTemplates } from "./generate-init-prompt-template.enum.js"; import { generateUserScoresPrompt } from "./generate-scores-prompt.js"; const runInitialThreadOptions = ( From c92c9fcb2ee7409cb06b7b261bde6460e6a06efd Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 10:36:18 +0100 Subject: [PATCH 148/244] refactor(backend): change const names bb-203 --- .../ai-assistant/libs/helpers/change-task/change-task.ts | 4 ++-- .../libs/helpers/change-task/geregate-change-task-prompt.ts | 4 ++-- .../initial-chat/balance-analysis.validation-schema.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts index c54d63a2d..00305f4f2 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts @@ -6,12 +6,12 @@ import { import { type TaskCreateDto } from "../../types/types.js"; import { changeTaskByCategory as ChangeTaskByCategoryValidationSchema } from "./change-task.validation-schema.js"; import { ChangeTaskPromptTemplates } from "./change-task-prompt-template.enum.js"; -import { generaChangeTaskPrompt } from "./geregate-change-task-prompt.js"; +import { generateChangeTaskPrompt } from "./geregate-change-task-prompt.js"; const runChangeTaskByCategoryOptions = ( task: TaskCreateDto, ): OpenAiRunThreadRequestDto => { - const changeTaskPrompt = generaChangeTaskPrompt(task); + const changeTaskPrompt = generateChangeTaskPrompt(task); return { additional_instructions: null, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts index babf77ea0..c80939354 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts @@ -6,7 +6,7 @@ import { import { type TaskCreateDto } from "../../types/types.js"; import { ChangeTaskPromptTemplates } from "./change-task-prompt-template.enum.js"; -function generaChangeTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { +function generateChangeTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { const content = ` { "context": "${ChangeTaskPromptTemplates.CHANGE_TASKS_CONTEXT}", @@ -19,4 +19,4 @@ function generaChangeTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { }; } -export { generaChangeTaskPrompt }; +export { generateChangeTaskPrompt }; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts index 1627434c5..495539750 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/balance-analysis.validation-schema.ts @@ -5,7 +5,7 @@ const category = z.object({ categoryName: z.string(), }); -const Messages = z.object({ +const messages = z.object({ comments: z.string(), greeting: z.string(), question: z.string(), @@ -13,7 +13,7 @@ const Messages = z.object({ const balanceAnalysis = z.object({ lowestCategories: z.array(category), - messages: Messages, + messages, }); export { balanceAnalysis }; From 9deb0c22b35caa334eaf1c5c95e4f6fc23ef03a0 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 11:01:01 +0100 Subject: [PATCH 149/244] refactor(shared): fix imports in TaskDto bb-203 --- packages/shared/src/modules/tasks/libs/types/task-dto.type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts index 74451a037..4e271f8f9 100644 --- a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts +++ b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts @@ -1,4 +1,4 @@ -import { type ValueOf } from "../../../../libs/types/value-of.type.js"; +import { type ValueOf } from "../../../../libs/types/types.js"; import { type TaskStatus } from "../enums/enums.js"; type TaskDto = { From 177cd6dd301b23a485eed275308232e3d1155b90 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 14:09:21 +0100 Subject: [PATCH 150/244] refactor(shared): fix text in AiAssistantValidationMessage bb-203 --- .../libs/enums/ai-assistant-validation-message.enum.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts index 6301f40e4..9302db7a7 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts @@ -5,7 +5,7 @@ const AiAssistantValidationMessage = { DESCRIPTION_REQUIRED: "Description is required", DUE_DATE_INVALID_FORMAT: "Due date has an invalid format", LABEL_REQUIRED: "Label is required", - TEXT_REQUIRED: "text required", + TEXT_REQUIRED: "Text is required", THREAD_ID_INVALID_FORMAT: "Thread ID has an invalid format", THREAD_ID_REQUIRED: "Thread ID is required", } as const; From bb349cb3754cc14dfe7e62398fda7d47dd402cbe Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 14:35:47 +0100 Subject: [PATCH 151/244] refactor(backend): change error message bb-203 --- .../modules/open-ai/libs/enums/open-ai-error-template.enum.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-template.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-template.enum.ts index 6d4de0999..24fb9b93d 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-template.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-error-template.enum.ts @@ -1,5 +1,5 @@ const OpenAIErrorMessage = { - WRONG_RESPONSE: "Wrong response from OpenAI.", + WRONG_RESPONSE: "Wrong response from AI Assistant.", } as const; export { OpenAIErrorMessage }; From ac04c0593d50ba6ff41686fc8120e41fecf8a219 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Wed, 18 Sep 2024 16:39:58 +0300 Subject: [PATCH 152/244] fix: changed env variable name in env.example bb-340 --- apps/backend/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/.env.example b/apps/backend/.env.example index f3ba9e897..d371b4474 100644 --- a/apps/backend/.env.example +++ b/apps/backend/.env.example @@ -50,5 +50,5 @@ MAILER_SERVICE=Gmail # # OPEN AI # -OPEN_AI_API_KEY= +OPENAI_API_KEY= OPENAI_MODEL=gpt-4o-mini From 68b0c2d1c094260dba581413b1c7c58ca82d4eb5 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 14:41:43 +0100 Subject: [PATCH 153/244] refactor(backend): add enum for function name bb-203 --- .../libs/modules/open-ai/libs/tools/analyze-balance.tool.ts | 4 +++- .../src/libs/modules/open-ai/libs/tools/change-task.tool.ts | 4 +++- .../src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts index e3b46f6f3..952d632db 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts @@ -1,8 +1,10 @@ +import { OpenAIFunctionName } from "../enums/open-ai-function-name.enum.js"; + const AnalyzeBalanceTool = { function: { description: "Analyzes user's life balance scores and identifies the three lowest categories with suggestions for improvement.", - name: "analyze_balance_scores", + name: OpenAIFunctionName.ANALYZE_BALANCE_SCORES, parameters: { additionalProperties: false, properties: { diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/change-task.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/change-task.tool.ts index bbf4190eb..573fcea7b 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/change-task.tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/change-task.tool.ts @@ -1,8 +1,10 @@ +import { OpenAIFunctionName } from "../enums/open-ai-function-name.enum.js"; + const ChangeTaskTool = { function: { description: "Generates a new task for the category based on the user's request, ensuring it doesn't repeat previously suggested tasks and takes into account the user's onboarding quiz priorities.", - name: "change_task", + name: OpenAIFunctionName.CHANGE_TASK, parameters: { additionalProperties: false, properties: { diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts index 363de8d87..fcbce0832 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/suggest-task.tool.ts @@ -1,8 +1,10 @@ +import { OpenAIFunctionName } from "../enums/open-ai-function-name.enum.js"; + const SuggestTaskTool = { function: { description: "Generates specific and actionable tasks for each user-selected category based on their onboarding responses.", - name: "generate_task_by_category", + name: OpenAIFunctionName.GENERATE_TASK_BY_CATEGORY, parameters: { additionalProperties: false, properties: { From e45ef66470e29a943bc0283006e4648e256b0021 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 14:47:45 +0100 Subject: [PATCH 154/244] refactor(backend): fix file names spelling bb-203 --- .../ai-assistant/libs/helpers/change-task/change-task.ts | 2 +- ...ate-change-task-prompt.ts => generate-change-task-prompt.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename apps/backend/src/modules/ai-assistant/libs/helpers/change-task/{geregate-change-task-prompt.ts => generate-change-task-prompt.ts} (100%) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts index 00305f4f2..521d3a73b 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task.ts @@ -6,7 +6,7 @@ import { import { type TaskCreateDto } from "../../types/types.js"; import { changeTaskByCategory as ChangeTaskByCategoryValidationSchema } from "./change-task.validation-schema.js"; import { ChangeTaskPromptTemplates } from "./change-task-prompt-template.enum.js"; -import { generateChangeTaskPrompt } from "./geregate-change-task-prompt.js"; +import { generateChangeTaskPrompt } from "./generate-change-task-prompt.js"; const runChangeTaskByCategoryOptions = ( task: TaskCreateDto, diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/generate-change-task-prompt.ts similarity index 100% rename from apps/backend/src/modules/ai-assistant/libs/helpers/change-task/geregate-change-task-prompt.ts rename to apps/backend/src/modules/ai-assistant/libs/helpers/change-task/generate-change-task-prompt.ts From fdd36756e2a4859b13737470caa85dfe89bd5c92 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Wed, 18 Sep 2024 14:51:54 +0100 Subject: [PATCH 155/244] refactor(backend): fix env name bb-203 --- apps/backend/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/.env.example b/apps/backend/.env.example index f3ba9e897..d371b4474 100644 --- a/apps/backend/.env.example +++ b/apps/backend/.env.example @@ -50,5 +50,5 @@ MAILER_SERVICE=Gmail # # OPEN AI # -OPEN_AI_API_KEY= +OPENAI_API_KEY= OPENAI_MODEL=gpt-4o-mini From df9c6ba0469c612f5cca7d346ffb4caefb7488ac Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Thu, 19 Sep 2024 19:40:22 +0300 Subject: [PATCH 156/244] feat: fixed balance wheel chart display, added message loader to chat bb-340 --- .../balance-wheel-chart/styles.module.css | 2 +- apps/frontend/src/pages/chat/chat.tsx | 27 ++++++++----- .../pages/chat/libs/components/components.ts | 1 + .../message-loader/message-loader.tsx | 14 +++++++ .../message-loader/styles.module.css | 40 +++++++++++++++++++ .../src/libs/constants/index-one.constant.ts | 3 -- 6 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 apps/frontend/src/pages/chat/libs/components/message-loader/message-loader.tsx create mode 100644 apps/frontend/src/pages/chat/libs/components/message-loader/styles.module.css delete mode 100644 packages/shared/src/libs/constants/index-one.constant.ts diff --git a/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css b/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css index dc774a179..a3d234122 100644 --- a/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css +++ b/apps/frontend/src/libs/components/balance-wheel-chart/styles.module.css @@ -4,5 +4,5 @@ } .root-wheel-container { - max-width: 649px; + width: 649px; } diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index eda862c75..32cacc2fe 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -1,3 +1,4 @@ +import { DataStatus } from "~/libs/enums/enums.js"; import { useAppDispatch, useAppSelector, @@ -11,20 +12,27 @@ import { } from "~/modules/chat/chat.js"; import { actions as quizActions } from "~/modules/quiz/quiz.js"; -import { ChatMessage } from "./libs/components/components.js"; +import { ChatMessage, MessageLoader } from "./libs/components/components.js"; import styles from "./styles.module.css"; const Chat: React.FC = () => { const dispatch = useAppDispatch(); - const { messages, quizCategories, scores, selectedCategories, threadId } = - useAppSelector((state) => ({ - messages: state.chat.messages, - quizCategories: state.categories.items, - scores: state.quiz.scores, - selectedCategories: state.chat.selectedCategories, - threadId: state.chat.threadId, - })); + const { + messages, + messageStatus, + quizCategories, + scores, + selectedCategories, + threadId, + } = useAppSelector((state) => ({ + messages: state.chat.messages, + messageStatus: state.chat.dataStatus, + quizCategories: state.categories.items, + scores: state.quiz.scores, + selectedCategories: state.chat.selectedCategories, + threadId: state.chat.threadId, + })); const chartData = scores.map((score) => { return { @@ -101,6 +109,7 @@ const Chat: React.FC = () => { /> ); })} + {messageStatus === DataStatus.PENDING && }
    diff --git a/apps/frontend/src/pages/chat/libs/components/components.ts b/apps/frontend/src/pages/chat/libs/components/components.ts index 821bc9b28..471e16893 100644 --- a/apps/frontend/src/pages/chat/libs/components/components.ts +++ b/apps/frontend/src/pages/chat/libs/components/components.ts @@ -1,3 +1,4 @@ export { ChatMessage } from "./chat-message/chat-message.js"; export { ConfirmationButtons } from "./confirmation-buttons/confirmation-buttons.js"; +export { MessageLoader } from "./message-loader/message-loader.js"; export { TaskListContainer } from "./task-list-container/task-list-container.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/message-loader/message-loader.tsx b/apps/frontend/src/pages/chat/libs/components/message-loader/message-loader.tsx new file mode 100644 index 000000000..06ee2afed --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/message-loader/message-loader.tsx @@ -0,0 +1,14 @@ +import styles from "./styles.module.css"; + +const MessageLoader: React.FC = () => { + return ( + + Assistant typing + . + . + . + + ); +}; + +export { MessageLoader }; diff --git a/apps/frontend/src/pages/chat/libs/components/message-loader/styles.module.css b/apps/frontend/src/pages/chat/libs/components/message-loader/styles.module.css new file mode 100644 index 000000000..796b69cd1 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/message-loader/styles.module.css @@ -0,0 +1,40 @@ +.loader-text { + font-size: 16px; + font-weight: 700; + color: var(--medium-gray); + opacity: 0.5; +} + +.dot { + width: 8px; + height: 8px; + margin: 0 2px; + opacity: 0; + animation: loading-fade 1s infinite; +} + +.dot:nth-child(1) { + animation-delay: 0s; +} + +.dot:nth-child(2) { + animation-delay: 0.2s; +} + +.dot:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes loading-fade { + 0% { + opacity: 0; + } + + 50% { + opacity: 0.8; + } + + 100% { + opacity: 0; + } +} diff --git a/packages/shared/src/libs/constants/index-one.constant.ts b/packages/shared/src/libs/constants/index-one.constant.ts deleted file mode 100644 index ef152edb4..000000000 --- a/packages/shared/src/libs/constants/index-one.constant.ts +++ /dev/null @@ -1,3 +0,0 @@ -const INDEX_ONE = 1; - -export { INDEX_ONE }; From 84cd4b6e1d48161325563050c857de3736ef2a6c Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:03:20 +0100 Subject: [PATCH 157/244] feat(shared): add ChatMessageAuthor enum bb-203 --- .../modules/chats/libs/enums/chat-message-author.enum.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/shared/src/modules/chats/libs/enums/chat-message-author.enum.ts diff --git a/packages/shared/src/modules/chats/libs/enums/chat-message-author.enum.ts b/packages/shared/src/modules/chats/libs/enums/chat-message-author.enum.ts new file mode 100644 index 000000000..d89236e2c --- /dev/null +++ b/packages/shared/src/modules/chats/libs/enums/chat-message-author.enum.ts @@ -0,0 +1,6 @@ +const ChatMessageAuthor = { + ASSISTANT: "assistant", + USER: "user", +} as const; + +export { ChatMessageAuthor }; From 8974fce389db81b8c0e798a3f1c7999a99b74923 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:07:53 +0100 Subject: [PATCH 158/244] feat(shared): add ChatMessageType enum bb-203 --- .../modules/chats/libs/enums/chat-message-type.enum.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/shared/src/modules/chats/libs/enums/chat-message-type.enum.ts diff --git a/packages/shared/src/modules/chats/libs/enums/chat-message-type.enum.ts b/packages/shared/src/modules/chats/libs/enums/chat-message-type.enum.ts new file mode 100644 index 000000000..9e2afc9c7 --- /dev/null +++ b/packages/shared/src/modules/chats/libs/enums/chat-message-type.enum.ts @@ -0,0 +1,8 @@ +const ChatMessageType = { + BALANCE_WHEEL: "balance wheel", + QUESTION_WITH_BUTTONS: "question with buttons", + TASK: "task", + TEXT: "text", +} as const; + +export { ChatMessageType }; From 4b38f0878f6bad68354257863c8beb03b4adfd14 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:09:49 +0100 Subject: [PATCH 159/244] feat(shared): add TextMessage type bb-203 --- .../shared/src/modules/chats/libs/types/text.message.type.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/shared/src/modules/chats/libs/types/text.message.type.ts diff --git a/packages/shared/src/modules/chats/libs/types/text.message.type.ts b/packages/shared/src/modules/chats/libs/types/text.message.type.ts new file mode 100644 index 000000000..7c0b5b647 --- /dev/null +++ b/packages/shared/src/modules/chats/libs/types/text.message.type.ts @@ -0,0 +1,5 @@ +type TextMessage = { + text: string; +}; + +export { type TextMessage }; From 1a47cebea7ddfb0e7969ede99d3ce3798c54dbd2 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:10:50 +0100 Subject: [PATCH 160/244] feat(shared): add TaskMessage type bb-203 --- .../src/modules/chats/libs/types/task-message.type.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/shared/src/modules/chats/libs/types/task-message.type.ts diff --git a/packages/shared/src/modules/chats/libs/types/task-message.type.ts b/packages/shared/src/modules/chats/libs/types/task-message.type.ts new file mode 100644 index 000000000..93c4b5863 --- /dev/null +++ b/packages/shared/src/modules/chats/libs/types/task-message.type.ts @@ -0,0 +1,8 @@ +import { type TaskCreateDto, type TaskDto } from "../../../tasks/tasks.js"; + +type TaskMessage = { + task: TaskCreateDto | TaskDto; + text?: string; +}; + +export { type TaskMessage }; From 749993941523e8737eeb857c5eca92d69c87383f Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:13:41 +0100 Subject: [PATCH 161/244] feat(shared): add QuestionMessage type bb-203 --- .../modules/chats/libs/types/question-message.type.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 packages/shared/src/modules/chats/libs/types/question-message.type.ts diff --git a/packages/shared/src/modules/chats/libs/types/question-message.type.ts b/packages/shared/src/modules/chats/libs/types/question-message.type.ts new file mode 100644 index 000000000..df980787d --- /dev/null +++ b/packages/shared/src/modules/chats/libs/types/question-message.type.ts @@ -0,0 +1,9 @@ +type QuestionMessage = { + buttons: { + label: string; + value: string; + }[]; + text: string; +}; + +export { type QuestionMessage }; From 1beb661390bc3b423342af5768a1f885aa9cb269 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:32:36 +0100 Subject: [PATCH 162/244] feat(shared): add SelectedCategory type bb-203 --- packages/shared/src/modules/categories/categories.ts | 1 + .../modules/categories/libs/types/category-selected.type.ts | 6 ++++++ packages/shared/src/modules/categories/libs/types/types.ts | 1 + 3 files changed, 8 insertions(+) create mode 100644 packages/shared/src/modules/categories/libs/types/category-selected.type.ts diff --git a/packages/shared/src/modules/categories/categories.ts b/packages/shared/src/modules/categories/categories.ts index dbd70de56..26ba1c332 100644 --- a/packages/shared/src/modules/categories/categories.ts +++ b/packages/shared/src/modules/categories/categories.ts @@ -7,6 +7,7 @@ export { type CategoryDto, type CategoryUpdateRequestDto, type CategoryWithScoresDto, + type SelectedCategory, } from "./libs/types/types.js"; export { categoryIds as categoryIdsValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { categoriesSelected as categoriesSelectedValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/categories/libs/types/category-selected.type.ts b/packages/shared/src/modules/categories/libs/types/category-selected.type.ts new file mode 100644 index 000000000..edb26589a --- /dev/null +++ b/packages/shared/src/modules/categories/libs/types/category-selected.type.ts @@ -0,0 +1,6 @@ +type SelectedCategory = { + categoryId: number; + categoryName: string; +}; + +export { type SelectedCategory }; diff --git a/packages/shared/src/modules/categories/libs/types/types.ts b/packages/shared/src/modules/categories/libs/types/types.ts index 725176a85..1f88bdca7 100644 --- a/packages/shared/src/modules/categories/libs/types/types.ts +++ b/packages/shared/src/modules/categories/libs/types/types.ts @@ -3,5 +3,6 @@ export { type CategoriesGetRequestQueryDto } from "./categories-get-request-quer export { type CategoriesSelectedRequestDto } from "./categories-selected-request-dto.type.js"; export { type CategoryCreateRequestDto } from "./category-create-request-dto.type.js"; export { type CategoryDto } from "./category-dto.type.js"; +export { type SelectedCategory } from "./category-selected.type.js"; export { type CategoryUpdateRequestDto } from "./category-update-request-dto.type.js"; export { type CategoryWithScoresDto } from "./category-with-scores-dto.type.js"; From 50a09231a437191a915b34fa327f677ca91bbbe0 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:33:57 +0100 Subject: [PATCH 163/244] feat(shared): add BalanceWheelMessage type bb-203 --- .../chats/libs/types/balance-wheel-message.type.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts diff --git a/packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts b/packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts new file mode 100644 index 000000000..c168d5273 --- /dev/null +++ b/packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts @@ -0,0 +1,8 @@ +import { type SelectedCategory } from "../../../categories/categories.js"; + +type BalanceWheelMessage = { + lowestCategories: SelectedCategory[]; + text: string; +}; + +export { type BalanceWheelMessage }; From 29d42a6916dba78e75f4df27411dabca12c82f27 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:36:04 +0100 Subject: [PATCH 164/244] feat(shared): add ChatMessageDto type bb-203 --- .../chats/libs/types/chat-message-dto.type.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts diff --git a/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts new file mode 100644 index 000000000..3f3240af5 --- /dev/null +++ b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts @@ -0,0 +1,26 @@ +import { type ValueOf } from "../../../../libs/types/types.js"; +import { + type ChatMessageAuthor, + type ChatMessageType, +} from "../enums/enums.js"; +import { type BalanceWheelMessage } from "./balance-wheel-message.type.js"; +import { type QuestionMessage } from "./question-message.type.js"; +import { type TaskMessage } from "./task-message.type.js"; +import { type TextMessage } from "./text.message.type.js"; + +type ChatMessagePayload = + | BalanceWheelMessage + | QuestionMessage + | TaskMessage + | TextMessage; + +type ChatMessageDto = { + author: ValueOf; + createdAt: string; + id: number; + isRead: boolean; + payload: ChatMessagePayload; + type: ValueOf; +}; + +export { type ChatMessageDto }; From b653f9918618968387de4ecc8bbc6b6885bfbdc5 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:42:16 +0100 Subject: [PATCH 165/244] feat(shared): add chat module and export chain bb-203 --- packages/shared/src/index.ts | 12 ++++++++++++ packages/shared/src/modules/chats/chats.ts | 8 ++++++++ .../shared/src/modules/chats/libs/enums/enums.ts | 2 ++ .../shared/src/modules/chats/libs/types/types.ts | 5 +++++ 4 files changed, 27 insertions(+) create mode 100644 packages/shared/src/modules/chats/chats.ts create mode 100644 packages/shared/src/modules/chats/libs/enums/enums.ts create mode 100644 packages/shared/src/modules/chats/libs/types/types.ts diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index ff6021f0b..05f5f0007 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -46,6 +46,8 @@ export { export { addMessageToThreadValidationSchema, AiAssistantApiPath, + type AIAssistantRequestDto, + type AIAssistantResponseDto, type BalanceWheelAnalysisResponseDto, type ChangeTaskSuggestionRequestDto, changeTaskSuggestionRequestValidationSchema, @@ -70,7 +72,17 @@ export { categoryIdsValidationSchema, type CategoryUpdateRequestDto, type CategoryWithScoresDto, + type SelectedCategory, } from "./modules/categories/categories.js"; +export { + type BalanceWheelMessage, + ChatMessageAuthor, + type ChatMessageDto, + ChatMessageType, + type QuestionMessage, + type TaskMessage, + type TextMessage, +} from "./modules/chats/chats.js"; export { type OnboardingAnswerDto, type OnboardingAnswerRequestBodyDto, diff --git a/packages/shared/src/modules/chats/chats.ts b/packages/shared/src/modules/chats/chats.ts new file mode 100644 index 000000000..4bbaf958d --- /dev/null +++ b/packages/shared/src/modules/chats/chats.ts @@ -0,0 +1,8 @@ +export { ChatMessageAuthor, ChatMessageType } from "./libs/enums/enums.js"; +export { + type BalanceWheelMessage, + type ChatMessageDto, + type QuestionMessage, + type TaskMessage, + type TextMessage, +} from "./libs/types/types.js"; diff --git a/packages/shared/src/modules/chats/libs/enums/enums.ts b/packages/shared/src/modules/chats/libs/enums/enums.ts new file mode 100644 index 000000000..009b83984 --- /dev/null +++ b/packages/shared/src/modules/chats/libs/enums/enums.ts @@ -0,0 +1,2 @@ +export { ChatMessageAuthor } from "./chat-message-author.enum.js"; +export { ChatMessageType } from "./chat-message-type.enum.js"; diff --git a/packages/shared/src/modules/chats/libs/types/types.ts b/packages/shared/src/modules/chats/libs/types/types.ts new file mode 100644 index 000000000..40c1b6a77 --- /dev/null +++ b/packages/shared/src/modules/chats/libs/types/types.ts @@ -0,0 +1,5 @@ +export { type BalanceWheelMessage } from "./balance-wheel-message.type.js"; +export { type ChatMessageDto } from "./chat-message-dto.type.js"; +export { type QuestionMessage } from "./question-message.type.js"; +export { type TaskMessage } from "./task-message.type.js"; +export { type TextMessage } from "./text.message.type.js"; From cf1cd9bea82270c672608cce73baa3fb5d5ac9df Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:46:12 +0100 Subject: [PATCH 166/244] feat(shared): add explain task path to AIAssistantApiPath bb-203 --- .../ai-assistant/libs/enums/ai-assistant-api-path.enum.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts index 4df8b7f80..9eaa34b50 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -1,10 +1,11 @@ -const AiAssistantApiPath = { +const AIAssistantApiPath = { CHAT_ACCEPT_TASK: "/chat/accept-task", CHAT_ADD_MESSAGE: "/chat/add-message", CHAT_CHANGE_TASK: "/chat/change-task", CHAT_CONTINUE: "/chat/continue", + CHAT_EXPLAIN_TASK: "/chat/explain-task", CHAT_INITIATE: "/chat/initiate", CHAT_SUGGEST_TASKS: "/chat/suggest-tasks", } as const; -export { AiAssistantApiPath }; +export { AIAssistantApiPath }; From 3c0ab41cae530739294fed76ff13d20d8f9fb2cb Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:48:11 +0100 Subject: [PATCH 167/244] feat(shared): add validation message to AIAssistantValidationMessage bb-203 --- .../libs/enums/ai-assistant-validation-message.enum.ts | 5 +++-- packages/shared/src/modules/ai-assistant/libs/enums/enums.ts | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts index 9302db7a7..08003c38f 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validation-message.enum.ts @@ -1,13 +1,14 @@ -const AiAssistantValidationMessage = { +const AIAssistantValidationMessage = { CATEGORIES_REQUIRED: "Categories are required", CATEGORY_ID_REQUIRED: "Category ID is required", CATEGORY_NAME_REQUIRED: "Category name is required", DESCRIPTION_REQUIRED: "Description is required", DUE_DATE_INVALID_FORMAT: "Due date has an invalid format", LABEL_REQUIRED: "Label is required", + LAST_MESSAGE_ID_REQUIRED: "Last message ID is required", TEXT_REQUIRED: "Text is required", THREAD_ID_INVALID_FORMAT: "Thread ID has an invalid format", THREAD_ID_REQUIRED: "Thread ID is required", } as const; -export { AiAssistantValidationMessage }; +export { AIAssistantValidationMessage }; diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts b/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts index a7003a6f4..80fb3c73d 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts @@ -1,3 +1,3 @@ -export { AiAssistantApiPath } from "./ai-assistant-api-path.enum.js"; -export { AiAssistantValidationMessage } from "./ai-assistant-validation-message.enum.js"; +export { AIAssistantApiPath } from "./ai-assistant-api-path.enum.js"; +export { AIAssistantValidationMessage } from "./ai-assistant-validation-message.enum.js"; export { AiAssistantValidationRule } from "./ai-assistant-validatuon-rule.enum.js"; From f6ab751c9d63eb1ba06cbe5efd5d2353d31720e0 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:50:39 +0100 Subject: [PATCH 168/244] feat(shared): add AIAssistantResponseDto type bb-203 --- .../libs/types/ai-assistant-response-dto.type.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts new file mode 100644 index 000000000..2222a88e9 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts @@ -0,0 +1,8 @@ +import { type ChatMessageDto } from "../../../chats/chats.js"; + +type AIAssistantResponseDto = { + messages: ChatMessageDto[]; + threadId: string; +}; + +export { type AIAssistantResponseDto }; From e869f5f3d7157a5fa0b2e370485a813b10eac635 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 20:56:22 +0100 Subject: [PATCH 169/244] feat(shared): add AIAssistantRequestDto type bb-203 --- .../libs/types/ai-assistant-request-dto.type.ts | 11 +++++++++++ .../src/modules/ai-assistant/libs/types/types.ts | 2 ++ 2 files changed, 13 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-request-dto.type.ts diff --git a/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-request-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-request-dto.type.ts new file mode 100644 index 000000000..a3b9efe68 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-request-dto.type.ts @@ -0,0 +1,11 @@ +import { type SelectedCategory } from "../../../categories/categories.js"; +import { type TextMessage } from "../../../chats/chats.js"; +import { type TaskCreateDto } from "../../../tasks/tasks.js"; + +type AIAssistantRequestDto = { + lastMessageId: number; + payload: SelectedCategory[] | TaskCreateDto | TextMessage; + threadId: string; +}; + +export { type AIAssistantRequestDto }; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/types.ts b/packages/shared/src/modules/ai-assistant/libs/types/types.ts index 97a7fb090..2ca0d34cb 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/types.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/types.ts @@ -1,3 +1,5 @@ +export { type AIAssistantRequestDto } from "./ai-assistant-request-dto.type.js"; +export { type AIAssistantResponseDto } from "./ai-assistant-response-dto.type.js"; export { type BalanceWheelAnalysisResponseDto } from "./balance-wheel-analysis-response.dto.type.js"; export { type ChangeTaskSuggestionRequestDto } from "./change-task-suggestion-request-dto.type.js"; export { From 8dfbf2c0e5a0ea7b9d4b943aec68bedab9db520b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 21:00:13 +0100 Subject: [PATCH 170/244] refactor(shared): change taskSuggestionRequest validation to have payload and lastMessageId bb-203 --- ...sk-suggestion-request.validation-schema.ts | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 36c6989b9..9cc612e38 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -1,37 +1,40 @@ import { z } from "zod"; import { - AiAssistantValidationMessage, + AIAssistantValidationMessage, AiAssistantValidationRule, } from "../enums/enums.js"; +const selectedCategory = z.object({ + categoryId: z + .number() + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.CATEGORY_ID_REQUIRED, + }), + categoryName: z + .string() + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.CATEGORY_NAME_REQUIRED, + }), +}); + const taskSuggestionRequest = z.object({ - categories: z - .array( - z.object({ - categoryId: z - .number() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, - }), - categoryName: z - .string() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, - }), - }), - ) - .nonempty({ - message: AiAssistantValidationMessage.CATEGORIES_REQUIRED, + lastMessageId: z + .number() + .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.LAST_MESSAGE_ID_REQUIRED, }), + payload: z + .array(selectedCategory) + .nonempty({ message: AIAssistantValidationMessage.CATEGORIES_REQUIRED }), threadId: z .string() .trim() .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, + message: AIAssistantValidationMessage.THREAD_ID_REQUIRED, }) .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { - message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + message: AIAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, }), }); From 3df3e42110a8a41adc40e1420ce427c5eb0eef2b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 21:02:38 +0100 Subject: [PATCH 171/244] refactor(shared): rename AIAssistantValidationRule and uses in code bb-203 --- .../ai-assistant-validatuon-rule.enum.ts | 4 +-- .../modules/ai-assistant/libs/enums/enums.ts | 2 +- ...add-message-to-thread.validation-schema.ts | 16 +++++------ ...hange-task-suggestion.validation-schema.ts | 28 +++++++++---------- ...sk-suggestion-request.validation-schema.ts | 12 ++++---- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts index 807898815..a514c1c7a 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-validatuon-rule.enum.ts @@ -1,6 +1,6 @@ -const AiAssistantValidationRule = { +const AIAssistantValidationRule = { NON_EMPTY_ITEM_MIN_LENGTH: 1, THREAD_ID_VALID_CHARS: /^thread_[\da-z]+$/i, } as const; -export { AiAssistantValidationRule }; +export { AIAssistantValidationRule }; diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts b/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts index 80fb3c73d..d3dd02a8d 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/enums.ts @@ -1,3 +1,3 @@ export { AIAssistantApiPath } from "./ai-assistant-api-path.enum.js"; export { AIAssistantValidationMessage } from "./ai-assistant-validation-message.enum.js"; -export { AiAssistantValidationRule } from "./ai-assistant-validatuon-rule.enum.js"; +export { AIAssistantValidationRule } from "./ai-assistant-validatuon-rule.enum.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts index c5ee9f9a8..bc9934360 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/add-message-to-thread.validation-schema.ts @@ -1,8 +1,8 @@ import { z } from "zod"; import { - AiAssistantValidationMessage, - AiAssistantValidationRule, + AIAssistantValidationMessage, + AIAssistantValidationRule, } from "../enums/enums.js"; type AiAssistantMessageCreateDto = { @@ -15,17 +15,17 @@ const addMessageToThread = z text: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.TEXT_REQUIRED, + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.TEXT_REQUIRED, }), threadId: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.THREAD_ID_REQUIRED, }) - .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { - message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + .regex(AIAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AIAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, }), }) .required(); diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts index a8f796e3b..a786df93a 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/change-task-suggestion.validation-schema.ts @@ -1,40 +1,40 @@ import { z } from "zod"; import { - AiAssistantValidationMessage, - AiAssistantValidationRule, + AIAssistantValidationMessage, + AIAssistantValidationRule, } from "../enums/enums.js"; const changeTaskSuggestionRequest = z.object({ task: z.object({ categoryId: z.number({ - invalid_type_error: AiAssistantValidationMessage.CATEGORY_ID_REQUIRED, + invalid_type_error: AIAssistantValidationMessage.CATEGORY_ID_REQUIRED, }), categoryName: z .string() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.CATEGORY_NAME_REQUIRED, + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.CATEGORY_NAME_REQUIRED, }), description: z .string() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.DESCRIPTION_REQUIRED, + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.DESCRIPTION_REQUIRED, }), dueDate: z.string().datetime({ - message: AiAssistantValidationMessage.DUE_DATE_INVALID_FORMAT, + message: AIAssistantValidationMessage.DUE_DATE_INVALID_FORMAT, }), - label: z.string().min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.LABEL_REQUIRED, + label: z.string().min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.LABEL_REQUIRED, }), }), threadId: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { - message: AiAssistantValidationMessage.THREAD_ID_REQUIRED, + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.THREAD_ID_REQUIRED, }) - .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { - message: AiAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + .regex(AIAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AIAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, }), }); diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts index 9cc612e38..cbb85890d 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-suggestion-request.validation-schema.ts @@ -2,18 +2,18 @@ import { z } from "zod"; import { AIAssistantValidationMessage, - AiAssistantValidationRule, + AIAssistantValidationRule, } from "../enums/enums.js"; const selectedCategory = z.object({ categoryId: z .number() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AIAssistantValidationMessage.CATEGORY_ID_REQUIRED, }), categoryName: z .string() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AIAssistantValidationMessage.CATEGORY_NAME_REQUIRED, }), }); @@ -21,7 +21,7 @@ const selectedCategory = z.object({ const taskSuggestionRequest = z.object({ lastMessageId: z .number() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AIAssistantValidationMessage.LAST_MESSAGE_ID_REQUIRED, }), payload: z @@ -30,10 +30,10 @@ const taskSuggestionRequest = z.object({ threadId: z .string() .trim() - .min(AiAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { message: AIAssistantValidationMessage.THREAD_ID_REQUIRED, }) - .regex(AiAssistantValidationRule.THREAD_ID_VALID_CHARS, { + .regex(AIAssistantValidationRule.THREAD_ID_VALID_CHARS, { message: AIAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, }), }); From d721dee0eb8c927447a5e1fb463fd8e48398153a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 21:04:09 +0100 Subject: [PATCH 172/244] refactor(shared): chane export chain in Assistant module bb-203 --- packages/shared/src/modules/ai-assistant/ai-assistant.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/ai-assistant.ts b/packages/shared/src/modules/ai-assistant/ai-assistant.ts index fbb2ccf8f..bce6e17d5 100644 --- a/packages/shared/src/modules/ai-assistant/ai-assistant.ts +++ b/packages/shared/src/modules/ai-assistant/ai-assistant.ts @@ -1,5 +1,7 @@ -export { AiAssistantApiPath } from "./libs/enums/enums.js"; +export { AIAssistantApiPath } from "./libs/enums/enums.js"; export { + type AIAssistantRequestDto, + type AIAssistantResponseDto, type BalanceWheelAnalysisResponseDto, type ChangeTaskSuggestionRequestDto, type SelectedCategories, From af67e9bbf87cfa7d4123aeb625477ccc8a66ee54 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 21:09:19 +0100 Subject: [PATCH 173/244] fix(backend): fix to pass score to Assistant bb-203 --- .../libs/helpers/initial-chat/generate-scores-prompt.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts index 8cdf7a88e..5221c2219 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-prompt.ts @@ -11,9 +11,10 @@ function generateUserScoresPrompt( ): OpenAiRequestMessage { const { items } = userScores; - const categories = items.map(({ categoryId, categoryName }) => ({ + const categories = items.map(({ categoryId, categoryName, score }) => ({ categoryId, categoryName, + score, })); const content = ` From f9951dc4f903c01d8421309f88bc2c98bea15ffb Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 21:59:44 +0100 Subject: [PATCH 174/244] refactor(backend): change scores response to be ChatMessageDto bb-203 --- .../initial-chat/generate-scores-response.ts | 71 +++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts index c8688b2da..9ccc1c82d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/initial-chat/generate-scores-response.ts @@ -6,14 +6,18 @@ import { type OpenAiResponseMessage, } from "~/libs/modules/open-ai/open-ai.js"; -import { type BalanceWheelAnalysisResponseDto } from "../../types/types.js"; +import { ChatMessageAuthor, ChatMessageType } from "../../enums/enums.js"; +import { + type AIAssistantResponseDto, + type ChatMessageDto, +} from "../../types/types.js"; import { type balanceAnalysis } from "./balance-analysis.validation-schema.js"; type BalanceAnalysisData = z.infer; const generateScoresResponse = ( aiResponse: OpenAiResponseMessage, -): BalanceWheelAnalysisResponseDto | null => { +): AIAssistantResponseDto | null => { const message = aiResponse.getPaginatedItems().shift(); if (!message) { @@ -31,18 +35,59 @@ const generateScoresResponse = ( contentText, ) as BalanceAnalysisData; - return { - lowestCategories: resultData.lowestCategories.map((category) => { - return { - categoryId: category.categoryId, - categoryName: category.categoryName, - }; - }), - messages: { - comments: resultData.messages.comments, - greeting: resultData.messages.greeting, - question: resultData.messages.question, + let messageIdCounter = ZERO_INDEX; + + const greetingMessage: ChatMessageDto = { + author: ChatMessageAuthor.ASSISTANT, + createdAt: new Date().toISOString(), + id: messageIdCounter++, + isRead: false, + payload: { + text: resultData.messages.greeting, + }, + type: "text", + }; + + const balanceWheelMessage: ChatMessageDto = { + author: ChatMessageAuthor.ASSISTANT, + createdAt: new Date().toISOString(), + id: messageIdCounter++, + isRead: false, + payload: { + lowestCategories: resultData.lowestCategories.map((category) => { + return { + categoryId: category.categoryId, + categoryName: category.categoryName, + }; + }), + text: resultData.messages.comments, }, + type: "balance wheel", + }; + + const categoryQuestion = { + author: ChatMessageAuthor.ASSISTANT, + createdAt: new Date().toISOString(), + id: messageIdCounter++, + isRead: false, + payload: { + buttons: [ + { + label: "Yes, 3 lowest", + value: "Yes, 3 lowest", + }, + { + label: "No, something else", + value: "No, something else", + }, + ], + text: resultData.messages.question, + }, + type: ChatMessageType.QUESTION_WITH_BUTTONS, + }; + + return { + messages: [greetingMessage, balanceWheelMessage, categoryQuestion], threadId: message.thread_id, }; }; From daed7e65fe535534fc13754a12df0446dff19aba Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:01:41 +0100 Subject: [PATCH 175/244] refactor(backend): change response_structure in analyze balance tool bb-203 --- .../libs/tools/analyze-balance.tool.ts | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts index 952d632db..e8eb85a02 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/analyze-balance.tool.ts @@ -55,16 +55,6 @@ const AnalyzeBalanceTool = { response_structure: { additionalProperties: false, properties: { - comments: { - description: - "A summary of the balance analysis and the identified areas for improvement.", - type: "string", - }, - greeting: { - description: - "A personalized greeting for the user based on their name, e.g., 'Hello, John!'", - type: "string", - }, lowestCategories: { description: "An array of the three categories where the user scored the lowest, including category ID, name, and score.", @@ -85,13 +75,30 @@ const AnalyzeBalanceTool = { }, type: "array", }, - question: { - description: - "A follow-up question that guides the user to either focus on improving the three areas with the lowest scores or allows them to choose the areas for further improvement. The question should be crafted to encourage thoughtful reflection and engagement, and it must include the user's name.", - type: "string", + messages: { + additionalProperties: false, + description: "An array of messages summarizing the analysis.", + properties: { + comments: { + description: + "Summary of the balance analysis with identified areas for improvement.", + type: "string", + }, + greeting: { + description: "A personalized greeting for the user.", + type: "string", + }, + question: { + description: + "A follow-up question that prompts the user to engage further with the suggested improvements.", + type: "string", + }, + }, + required: ["greeting", "comments", "question"], + type: "object", }, }, - required: ["greeting", "comments", "lowestCategories", "question"], + required: ["messages", "lowestCategories"], type: "object", }, }, From 5ee49cac0f6f190fa6ff0f0c29634dadfd8548d5 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:07:19 +0100 Subject: [PATCH 176/244] refactor(backend): change dto name in generateSuggestTaskPrompt/runTaskByCategoryOptions bb-203 --- .../suggest-task-by-category/generate-suggest-task-prompt.ts | 4 ++-- .../suggest-task-by-category/suggest-task-by-category.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts index 69c155fb6..c7d246401 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-prompt.ts @@ -3,11 +3,11 @@ import { OpenAIRoleKey, } from "~/libs/modules/open-ai/open-ai.js"; -import { type SelectedCategories } from "../../types/types.js"; +import { type SelectedCategory } from "../../types/types.js"; import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-template.enum.js"; function generateSuggestTaskPrompt( - categories: SelectedCategories[], + categories: SelectedCategory[], ): OpenAiRequestMessage { const content = ` { diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts index c8ba9b327..78f90c562 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/suggest-task-by-category.ts @@ -3,13 +3,13 @@ import { type OpenAiRunThreadRequestDto, } from "~/libs/modules/open-ai/open-ai.js"; -import { type SelectedCategories } from "../../types/types.js"; +import { type SelectedCategory } from "../../types/types.js"; import { generateSuggestTaskPrompt } from "./generate-suggest-task-prompt.js"; import { taskByCategory as TaskByCategoryValidationSchema } from "./suggest-task-by-category.validation-schema.js"; import { SuggestTaskPromptTemplates } from "./suggest-task-prompt-template.enum.js"; const runTaskByCategoryOptions = ( - categories: SelectedCategories[], + categories: SelectedCategory[], ): OpenAiRunThreadRequestDto => { const suggestTaskPrompt = generateSuggestTaskPrompt(categories); From 64b037c5cd05f2a2546a598826485fc043cb221a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:09:01 +0100 Subject: [PATCH 177/244] refactor(backend): change response type to chat Messages in TaskSuggestionsResponseDto bb-203 --- .../generate-suggest-task-response.ts | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts index 98e034575..fa702beab 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/suggest-task-by-category/generate-suggest-task-response.ts @@ -4,9 +4,14 @@ import { ZERO_INDEX } from "~/libs/constants/constants.js"; import { AIAssistantMessageValidationSchema, type OpenAiResponseMessage, + OpenAIRoleKey, } from "~/libs/modules/open-ai/open-ai.js"; -import { type TaskSuggestionsResponseDto } from "../../types/types.js"; +import { ChatMessageAuthor } from "../../enums/enums.js"; +import { + type AIAssistantResponseDto, + type ChatMessageDto, +} from "../../types/types.js"; import { type taskByCategory } from "./suggest-task-by-category.validation-schema.js"; type TaskByCategoryData = z.infer; @@ -14,7 +19,8 @@ type TaskByCategoryData = z.infer; const generateTaskSuggestionsResponse = ( aiResponse: OpenAiResponseMessage, taskDeadLine: string, -): null | TaskSuggestionsResponseDto => { + lastMessageId: number, +): AIAssistantResponseDto | null => { const message = aiResponse.getPaginatedItems().shift(); if (!message) { @@ -32,17 +38,39 @@ const generateTaskSuggestionsResponse = ( contentText, ) as TaskByCategoryData; + const textMessage: ChatMessageDto = { + author: OpenAIRoleKey.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + text: resultData.message, + }, + type: "text", + }; + + const taskMessages: ChatMessageDto[] = resultData.tasks.map((task) => { + return { + author: ChatMessageAuthor.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + task: { + categoryId: task.categoryId, + categoryName: task.categoryName, + description: task.description, + dueDate: taskDeadLine, + label: task.label, + }, + }, + type: "task", + }; + }); + return { - message: resultData.message, - tasks: resultData.tasks.map((task) => { - return { - categoryId: task.categoryId, - categoryName: task.categoryName, - description: task.description, - dueDate: taskDeadLine, - label: task.label, - }; - }), + messages: [textMessage, ...taskMessages], + threadId: message.thread_id, }; }; From a413add94d4811b1de204f45691f0f4f4d16d308 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:11:07 +0100 Subject: [PATCH 178/244] refactor(backend/shared): change import export for Assistant module bb-203 --- apps/backend/src/modules/ai-assistant/libs/enums/enums.ts | 2 +- apps/backend/src/modules/ai-assistant/libs/types/types.ts | 7 +++++-- packages/shared/src/index.ts | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/enums/enums.ts b/apps/backend/src/modules/ai-assistant/libs/enums/enums.ts index c79d89039..d4ade7adb 100644 --- a/apps/backend/src/modules/ai-assistant/libs/enums/enums.ts +++ b/apps/backend/src/modules/ai-assistant/libs/enums/enums.ts @@ -1 +1 @@ -export { AiAssistantApiPath } from "shared"; +export { AIAssistantApiPath, ChatMessageAuthor, ChatMessageType } from "shared"; diff --git a/apps/backend/src/modules/ai-assistant/libs/types/types.ts b/apps/backend/src/modules/ai-assistant/libs/types/types.ts index e334ef91d..1a27d6986 100644 --- a/apps/backend/src/modules/ai-assistant/libs/types/types.ts +++ b/apps/backend/src/modules/ai-assistant/libs/types/types.ts @@ -1,10 +1,13 @@ export { - type BalanceWheelAnalysisResponseDto, + type AIAssistantRequestDto, + type AIAssistantResponseDto, type ChangeTaskSuggestionRequestDto, - type SelectedCategories, + type ChatMessageDto, + type SelectedCategory, type TaskCreateDto, type TaskDto, type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, + type TextMessage, type ThreadMessageCreateDto, } from "shared"; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 05f5f0007..c2aa57144 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -45,7 +45,7 @@ export { } from "./libs/types/types.js"; export { addMessageToThreadValidationSchema, - AiAssistantApiPath, + AIAssistantApiPath, type AIAssistantRequestDto, type AIAssistantResponseDto, type BalanceWheelAnalysisResponseDto, From 320afaa99d4188e6e0a4d78cddbb70a1595a1c56 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:14:21 +0100 Subject: [PATCH 179/244] chore(main): update package-lock.json bb-203 --- package-lock.json | 176 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 159 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb2e7a7fe..95b70fe47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ } }, "apps/backend": { - "version": "1.20.0", + "version": "1.22.0", "dependencies": { "@aws-sdk/client-s3": "3.637.0", "@fastify/multipart": "8.3.0", @@ -69,6 +69,7 @@ "knex": "3.1.0", "nodemailer": "6.9.14", "objection": "3.1.4", + "openai": "4.57.3", "pg": "8.12.0", "pino": "9.3.2", "pino-pretty": "11.2.2", @@ -82,7 +83,8 @@ "@types/swagger-jsdoc": "6.0.4", "ts-node": "10.9.2", "ts-paths-esm-loader": "1.4.3", - "tsx": "4.17.0" + "tsx": "4.17.0", + "zod": "3.23.8" }, "engines": { "node": "20.x.x", @@ -90,7 +92,7 @@ } }, "apps/frontend": { - "version": "1.37.0", + "version": "1.39.0", "dependencies": { "@hookform/resolvers": "3.9.0", "@reduxjs/toolkit": "2.2.7", @@ -7326,6 +7328,15 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/node-forge": { "version": "1.3.11", "license": "MIT", @@ -7352,6 +7363,11 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@types/qs": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==" + }, "node_modules/@types/react": { "version": "18.3.3", "devOptional": true, @@ -7840,6 +7856,17 @@ "node": ">= 6.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "dev": true, @@ -8256,6 +8283,11 @@ "retry": "0.12.0" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/atomic-sleep": { "version": "1.0.0", "license": "MIT", @@ -8655,7 +8687,6 @@ }, "node_modules/call-bind": { "version": "1.0.7", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -9052,6 +9083,17 @@ "node": ">=0.1.90" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/command-exists": { "version": "1.2.9", "license": "MIT" @@ -9773,7 +9815,6 @@ }, "node_modules/define-data-property": { "version": "1.1.4", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -9803,6 +9844,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "license": "MIT" @@ -10159,7 +10208,6 @@ }, "node_modules/es-define-property": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" @@ -10170,7 +10218,6 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -11546,6 +11593,36 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/forwarded": { "version": "0.2.0", "license": "MIT", @@ -11721,7 +11798,6 @@ }, "node_modules/get-intrinsic": { "version": "1.2.4", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -11989,7 +12065,6 @@ }, "node_modules/gopd": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -12025,7 +12100,6 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -12036,7 +12110,6 @@ }, "node_modules/has-proto": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12047,7 +12120,6 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12211,6 +12283,14 @@ "node": ">=16.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/hyperlinker": { "version": "1.0.0", "dev": true, @@ -14716,6 +14796,24 @@ "node": "*" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "license": "MIT", @@ -14885,7 +14983,6 @@ }, "node_modules/object-inspect": { "version": "1.13.2", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -15070,6 +15167,46 @@ "node": ">=4" } }, + "node_modules/openai": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.57.3.tgz", + "integrity": "sha512-mTz5/SmulkkeSpqbSr6WNLRU6krkyhnbfRUC8XfaXbj1T6xUorKEELjZvbRSzI714JLOk1MeFkqYS9H4WHhqDQ==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "@types/qs": "^6.9.15", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "qs": "^6.10.3" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", + "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/openapi-types": { "version": "12.1.3", "license": "MIT" @@ -16121,7 +16258,6 @@ }, "node_modules/qs": { "version": "6.13.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.6" @@ -17444,7 +17580,6 @@ }, "node_modules/set-function-length": { "version": "1.2.2", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -17543,7 +17678,6 @@ }, "node_modules/side-channel": { "version": "1.0.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -19514,6 +19648,14 @@ "defaults": "^1.0.3" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "license": "BSD-2-Clause" @@ -19998,7 +20140,7 @@ } }, "packages/shared": { - "version": "1.20.0", + "version": "1.22.0", "dependencies": { "date-fns": "3.6.0", "zod": "3.23.8" From c84dd507455f426bbe3e58ed3ca122c296148b0b Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:16:00 +0100 Subject: [PATCH 180/244] feat(main): add explain task prompt template bb-203 --- .../explain-task-prompt-template.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-prompt-template.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-prompt-template.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-prompt-template.ts new file mode 100644 index 000000000..92a305ed8 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-prompt-template.ts @@ -0,0 +1,36 @@ +const ExplainTaskPromptTemplates = { + EXPLAIN_TASK_CONTEXT: ` +The user is asking for an explanation of the task that was previously suggested to them. Your role as the assistant is to +provide a clear and concise summary of the task, emphasizing its purpose and how it aligns with the user's goals. +Make sure to explain how the task contributes to the user's progress. + +Task details: +`, + + EXPLAIN_TASK_INSTRUCTIONS: ` +task: +Your role is to explain the task to the user. The user has requested a breakdown of the previously suggested task. +Your task is to explain its purpose and show how it helps the user achieve their personal goals. Ensure that the explanation is clear and actionable. + +response_structure: { + message: { // Object containing information about the task explanation. + summary: string, // A short summary of the task's purpose. + details: string, // More detailed information about the task and why it's important. + explanation: string, // A clear explanation of how the task aligns with the user's goals. + steps: string, // A string that lists the actionable steps the user should take to complete the task. + // Use numbered format like "1. Do this. 2. Do that." + motivation_tips: string // Tips to help the user stay motivated while completing the task. + } +}, +} + +action: +1. Provide a **summary** of the task that briefly explains its purpose and importance to the user's goals. Start with: "This task is..." +2. Offer **details** that give more context and explanation about why the task is important. +3. Explain how the task **aligns with the user's goals** and priorities, taking into account their onboarding quiz results. +4. List specific, **actionable steps** that the user should take to successfully complete the task. +5. Include **motivation tips** that encourage consistency and help the user stay focused and make gradual progress toward their goals. +`, +} as const; + +export { ExplainTaskPromptTemplates }; From cdb538a071582d44253f21e27df3938ae4772264 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:16:51 +0100 Subject: [PATCH 181/244] feat(main): add explain task validation bb-203 --- .../explain-task/explain-task.validation-schema.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.validation-schema.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.validation-schema.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.validation-schema.ts new file mode 100644 index 000000000..6769a5b54 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.validation-schema.ts @@ -0,0 +1,13 @@ +import { z } from "zod"; + +const explainTask = z.object({ + message: z.object({ + explanation: z.string(), + motivation_tips: z.string(), + question: z.string(), + steps: z.string(), + suggestions: z.string(), + }), +}); + +export { explainTask }; From 7f12ff2fc31fb4b2eec690f201742317f3dc4c60 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:19:05 +0100 Subject: [PATCH 182/244] feat(main): add explain task prompt generation bb-203 --- .../generate-explain-task-prompt.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/generate-explain-task-prompt.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/generate-explain-task-prompt.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/generate-explain-task-prompt.ts new file mode 100644 index 000000000..2efdd02ed --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/generate-explain-task-prompt.ts @@ -0,0 +1,22 @@ +import { + type OpenAiRequestMessage, + OpenAIRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type TaskCreateDto } from "../../types/types.js"; +import { ExplainTaskPromptTemplates } from "./explain-task-prompt-template.js"; + +function generateExplainTaskPrompt(task: TaskCreateDto): OpenAiRequestMessage { + const content = ` + { + "context": "${ExplainTaskPromptTemplates.EXPLAIN_TASK_CONTEXT}", + "task": ${JSON.stringify(task)}, + }`; + + return { + content, + role: OpenAIRoleKey.USER, + }; +} + +export { generateExplainTaskPrompt }; From eafd1ba1db1bda30b242a6a1f6ca7cf9cbd26854 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 22:21:19 +0100 Subject: [PATCH 183/244] feat(main): add explain task helper bb-203 --- .../libs/helpers/explain-task/explain-task.ts | 26 +++++++++++++++++++ .../ai-assistant/libs/helpers/helpers.ts | 4 +++ 2 files changed, 30 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts new file mode 100644 index 000000000..1f8211c4f --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts @@ -0,0 +1,26 @@ +import { + OpenAIFunctionName, + type OpenAiRunThreadRequestDto, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { type TaskCreateDto } from "../../types/types.js"; +import { explainTask as explainTaskValidationSchema } from "./explain-task.validation-schema.js"; +import { ExplainTaskPromptTemplates } from "./explain-task-prompt-template.js"; +import { generateExplainTaskPrompt } from "./generate-explain-task-prompt.js"; + +const runExplainTaskOptions = ( + task: TaskCreateDto, +): OpenAiRunThreadRequestDto => { + const explainTaskPrompt = generateExplainTaskPrompt(task); + + return { + additional_instructions: null, + function_name: OpenAIFunctionName.CHANGE_TASK, + instructions: ExplainTaskPromptTemplates.EXPLAIN_TASK_INSTRUCTIONS, + messages: [explainTaskPrompt], + validationSchema: explainTaskValidationSchema, + }; +}; + +export { runExplainTaskOptions }; +export { generateExplainTaskSuggestionsResponse } from "./explain-task-response.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts index a2abf58f3..e04ac2c8a 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/helpers.ts @@ -2,6 +2,10 @@ export { generateChangeTaskSuggestionsResponse, runChangeTaskByCategoryOptions, } from "./change-task/change-task.js"; +export { + generateExplainTaskSuggestionsResponse, + runExplainTaskOptions, +} from "./explain-task/explain-task.js"; export { generateQuestionsAnswersPrompt, generateScoresResponse, From 4d2b73534996a327848fd5668e4d06561743428d Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:04:36 +0100 Subject: [PATCH 184/244] feat(shared/backend): add taskActionRequestSchema validation bb-203 --- .../validation-schemas/validation-schemas.ts | 1 + packages/shared/src/index.ts | 1 + .../src/modules/ai-assistant/ai-assistant.ts | 1 + .../task-action-request.validation-schema.ts | 48 +++++++++++++++++++ .../validation-schemas/validation-schemas.ts | 1 + 5 files changed, 52 insertions(+) create mode 100644 packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-action-request.validation-schema.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts index d647fc46d..5834c56a6 100644 --- a/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts +++ b/apps/backend/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -1,5 +1,6 @@ export { addMessageToThreadValidationSchema, changeTaskSuggestionRequestValidationSchema, + taskActionRequestSchemaValidationSchema, taskSuggestionRequestValidationSchema, } from "shared"; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index c2aa57144..68b1badd4 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -52,6 +52,7 @@ export { type ChangeTaskSuggestionRequestDto, changeTaskSuggestionRequestValidationSchema, type SelectedCategories, + taskActionRequestSchemaValidationSchema, type TaskSuggestionRequestDto, taskSuggestionRequestValidationSchema, type TaskSuggestionsResponseDto, diff --git a/packages/shared/src/modules/ai-assistant/ai-assistant.ts b/packages/shared/src/modules/ai-assistant/ai-assistant.ts index bce6e17d5..d8709cd1b 100644 --- a/packages/shared/src/modules/ai-assistant/ai-assistant.ts +++ b/packages/shared/src/modules/ai-assistant/ai-assistant.ts @@ -12,3 +12,4 @@ export { export { addMessageToThread as addMessageToThreadValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { taskSuggestionRequest as taskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { changeTaskSuggestionRequest as changeTaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; +export { taskActionRequestSchema as taskActionRequestSchemaValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-action-request.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-action-request.validation-schema.ts new file mode 100644 index 000000000..683a28551 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/task-action-request.validation-schema.ts @@ -0,0 +1,48 @@ +import { z } from "zod"; + +import { + AIAssistantValidationMessage, + AIAssistantValidationRule, +} from "../enums/enums.js"; + +const taskCreateDto = z.object({ + categoryId: z.number({ + invalid_type_error: AIAssistantValidationMessage.CATEGORY_ID_REQUIRED, + }), + categoryName: z + .string() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.CATEGORY_NAME_REQUIRED, + }), + description: z + .string() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.DESCRIPTION_REQUIRED, + }), + dueDate: z.string().datetime({ + message: AIAssistantValidationMessage.DUE_DATE_INVALID_FORMAT, + }), + label: z.string().min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.LABEL_REQUIRED, + }), +}); + +const taskActionRequestSchema = z.object({ + lastMessageId: z + .number() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.LAST_MESSAGE_ID_REQUIRED, + }), + payload: taskCreateDto, + threadId: z + .string() + .trim() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.THREAD_ID_REQUIRED, + }) + .regex(AIAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AIAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + }), +}); + +export { taskActionRequestSchema }; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts index d98c7934c..f342438ce 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -1,3 +1,4 @@ export { addMessageToThread } from "./add-message-to-thread.validation-schema.js"; export { changeTaskSuggestionRequest } from "./change-task-suggestion.validation-schema.js"; +export { taskActionRequestSchema } from "./task-action-request.validation-schema.js"; export { taskSuggestionRequest } from "./task-suggestion-request.validation-schema.js"; From bbd0567c30f0b72d463378a18a4cfc631636d96a Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:06:29 +0100 Subject: [PATCH 185/244] feat(backend): add generate Explain TaskSuggestions Response bb-203 --- .../explain-task/explain-task-response.ts | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts new file mode 100644 index 000000000..a8c05da70 --- /dev/null +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts @@ -0,0 +1,102 @@ +import { ChatMessageAuthor, ChatMessageType } from "shared"; +import { type z } from "zod"; + +import { ZERO_INDEX } from "~/libs/constants/constants.js"; +import { + AIAssistantMessageValidationSchema, + type OpenAiResponseMessage, + OpenAIRoleKey, +} from "~/libs/modules/open-ai/open-ai.js"; + +import { + type AIAssistantResponseDto, + type ChatMessageDto, + type TaskCreateDto, +} from "../../types/types.js"; +import { type explainTask } from "./explain-task.validation-schema.js"; + +type TaskByCategoryData = z.infer; + +const generateExplainTaskSuggestionsResponse = ( + aiResponse: OpenAiResponseMessage, + task: TaskCreateDto, + lastMessageId: number, +): AIAssistantResponseDto | null => { + const message = aiResponse.getPaginatedItems().shift(); + + if (!message) { + return null; + } + + const parsedResult = AIAssistantMessageValidationSchema.safeParse(message); + + if (!parsedResult.success) { + return null; + } + + const contentText: string = parsedResult.data.content[ZERO_INDEX].text.value; + const resultData: TaskByCategoryData = JSON.parse( + contentText, + ) as TaskByCategoryData; + + const textMessage: ChatMessageDto = { + author: OpenAIRoleKey.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + text: + resultData.message.explanation + + "\n\n" + + resultData.message.suggestions + + "\n\n" + + resultData.message.steps, + }, + type: "text", + }; + + const taskMessage: ChatMessageDto = { + author: OpenAIRoleKey.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + task: { + categoryId: task.categoryId, + categoryName: task.categoryName, + description: task.description, + dueDate: task.dueDate, + label: task.label, + }, + }, + type: "task", + }; + + const acceptTaskQuestion = { + author: ChatMessageAuthor.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + buttons: [ + { + label: "Yes, accepts the task", + value: "Yes, accepts the task", + }, + { + label: "No, I would like to try something else", + value: "No, I would like to try something else", + }, + ], + text: resultData.message.question, + }, + type: ChatMessageType.QUESTION_WITH_BUTTONS, + }; + + return { + messages: [textMessage, taskMessage, acceptTaskQuestion], + threadId: message.thread_id, + }; +}; + +export { generateExplainTaskSuggestionsResponse }; From 2c7a8482ba5bb70535d81140bddccc7f8b740fcc Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:07:50 +0100 Subject: [PATCH 186/244] feat(backend): add Explain Task in AiAssistantService bb-203 --- .../ai-assistant/ai-assistant.service.ts | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index d43b3f31d..523f967cc 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -6,18 +6,22 @@ import { type TaskService } from "~/modules/tasks/tasks.js"; import { generateChangeTaskSuggestionsResponse, + generateExplainTaskSuggestionsResponse, generateQuestionsAnswersPrompt, generateScoresResponse, generateTaskSuggestionsResponse, runChangeTaskByCategoryOptions, + runExplainTaskOptions, runInitialThreadOptions, runTaskByCategoryOptions, } from "./libs/helpers/helpers.js"; import { - type BalanceWheelAnalysisResponseDto, + type AIAssistantRequestDto, + type AIAssistantResponseDto, type ChangeTaskSuggestionRequestDto, + type SelectedCategory, + type TaskCreateDto, type TaskDto, - type TaskSuggestionRequestDto, type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; @@ -97,9 +101,23 @@ class AiAssistantService { return generateChangeTaskSuggestionsResponse(result, taskDeadLine); } + public async explainTaskSuggestion( + body: AIAssistantRequestDto, + ): Promise { + const { lastMessageId, payload, threadId } = body; + + const task = payload as TaskCreateDto; + + const runThreadOptions = runExplainTaskOptions(task); + + const result = await this.openAi.runThread(threadId, runThreadOptions); + + return generateExplainTaskSuggestionsResponse(result, task, lastMessageId); + } + public async initNewChat( user: UserDto, - ): Promise { + ): Promise { const userQuestionsWithAnswers = await this.onboardingRepository.findUserAnswersWithQuestions(user.id); @@ -122,10 +140,10 @@ class AiAssistantService { public async suggestTasksForCategories( user: UserDto, - body: TaskSuggestionRequestDto, - ): Promise { - const { categories, threadId } = body; - + body: AIAssistantRequestDto, + ): Promise { + const { lastMessageId, payload, threadId } = body; + const categories = payload as SelectedCategory[]; const runThreadOptions = runTaskByCategoryOptions(categories); const taskDeadLine = this.taskService.calculateDeadline( @@ -134,7 +152,7 @@ class AiAssistantService { const result = await this.openAi.runThread(threadId, runThreadOptions); - return generateTaskSuggestionsResponse(result, taskDeadLine); + return generateTaskSuggestionsResponse(result, taskDeadLine, lastMessageId); } } From b636a68af6f6405f64c07d5d206e4b4ce202dd59 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:08:45 +0100 Subject: [PATCH 187/244] feat(backend): add Explain Task in AiAssistantController bb-203 --- .../ai-assistant/ai-assistant.controller.ts | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index ff1bfa2a6..ea7a2f743 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -9,15 +9,15 @@ import { type Logger } from "~/libs/modules/logger/logger.js"; import { type UserDto } from "~/modules/users/users.js"; import { type AiAssistantService } from "./ai-assistant.service.js"; -import { AiAssistantApiPath } from "./libs/enums/enums.js"; +import { AIAssistantApiPath } from "./libs/enums/enums.js"; import { + type AIAssistantRequestDto, type ChangeTaskSuggestionRequestDto, - type TaskSuggestionRequestDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; import { addMessageToThreadValidationSchema, - changeTaskSuggestionRequestValidationSchema, + taskActionRequestSchemaValidationSchema, taskSuggestionRequestValidationSchema, } from "./libs/validation-schemas/validation-schemas.js"; @@ -139,7 +139,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.CHAT_INITIATE, + path: AIAssistantApiPath.CHAT_INITIATE, }); this.addRoute({ @@ -150,7 +150,7 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.CHAT_ADD_MESSAGE, + path: AIAssistantApiPath.CHAT_ADD_MESSAGE, validation: { body: addMessageToThreadValidationSchema, }, @@ -165,9 +165,24 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.CHAT_CHANGE_TASK, + path: AIAssistantApiPath.CHAT_CHANGE_TASK, validation: { - body: changeTaskSuggestionRequestValidationSchema, + body: taskActionRequestSchemaValidationSchema, + }, + }); + + this.addRoute({ + handler: (options) => + this.explainTaskSuggestion( + options as APIHandlerOptions<{ + body: AIAssistantRequestDto; + user: UserDto; + }>, + ), + method: "POST", + path: AIAssistantApiPath.CHAT_EXPLAIN_TASK, + validation: { + body: taskActionRequestSchemaValidationSchema, }, }); @@ -175,12 +190,12 @@ class AiAssistantController extends BaseController { handler: (options) => this.suggestTasksForCategories( options as APIHandlerOptions<{ - body: TaskSuggestionRequestDto; + body: AIAssistantRequestDto; user: UserDto; }>, ), method: "POST", - path: AiAssistantApiPath.CHAT_SUGGEST_TASKS, + path: AIAssistantApiPath.CHAT_SUGGEST_TASKS, validation: { body: taskSuggestionRequestValidationSchema, }, @@ -195,9 +210,9 @@ class AiAssistantController extends BaseController { }>, ), method: "POST", - path: AiAssistantApiPath.CHAT_ACCEPT_TASK, + path: AIAssistantApiPath.CHAT_ACCEPT_TASK, validation: { - body: changeTaskSuggestionRequestValidationSchema, + body: taskActionRequestSchemaValidationSchema, }, }); } @@ -345,6 +360,19 @@ class AiAssistantController extends BaseController { }; } + private async explainTaskSuggestion( + options: APIHandlerOptions<{ + body: AIAssistantRequestDto; + }>, + ): Promise { + const { body } = options; + + return { + payload: await this.openAiService.explainTaskSuggestion(body), + status: HTTPCode.OK, + }; + } + /** * @swagger * /assistant/chat/initiate: @@ -538,7 +566,7 @@ class AiAssistantController extends BaseController { */ private async suggestTasksForCategories( options: APIHandlerOptions<{ - body: TaskSuggestionRequestDto; + body: AIAssistantRequestDto; user: UserDto; }>, ): Promise { From 0d51ab52830639544e68b072568c74537c1f44e5 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:23:40 +0100 Subject: [PATCH 188/244] refactor(backend): add TaskSuggestionsResponseDto to generateChangeTask/service/controller bb-203 --- .../ai-assistant/ai-assistant.controller.ts | 4 +- .../ai-assistant/ai-assistant.service.ts | 14 ++++--- .../change-task/change-task-response.ts | 41 +++++++++++++++---- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index ea7a2f743..c42eca715 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -160,7 +160,7 @@ class AiAssistantController extends BaseController { handler: (options) => this.changeTaskSuggestion( options as APIHandlerOptions<{ - body: ChangeTaskSuggestionRequestDto; + body: AIAssistantRequestDto; user: UserDto; }>, ), @@ -348,7 +348,7 @@ class AiAssistantController extends BaseController { */ private async changeTaskSuggestion( options: APIHandlerOptions<{ - body: ChangeTaskSuggestionRequestDto; + body: AIAssistantRequestDto; user: UserDto; }>, ): Promise { diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index 523f967cc..5d9038f1e 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -22,7 +22,6 @@ import { type SelectedCategory, type TaskCreateDto, type TaskDto, - type TaskSuggestionsResponseDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; @@ -88,9 +87,10 @@ class AiAssistantService { public async changeTaskSuggestion( user: UserDto, - body: ChangeTaskSuggestionRequestDto, - ): Promise { - const { task, threadId } = body; + body: AIAssistantRequestDto, + ): Promise { + const { lastMessageId, payload, threadId } = body; + const task = payload as TaskCreateDto; const runThreadOptions = runChangeTaskByCategoryOptions(task); const taskDeadLine = this.taskService.calculateDeadline( @@ -98,7 +98,11 @@ class AiAssistantService { ); const result = await this.openAi.runThread(threadId, runThreadOptions); - return generateChangeTaskSuggestionsResponse(result, taskDeadLine); + return generateChangeTaskSuggestionsResponse( + result, + taskDeadLine, + lastMessageId, + ); } public async explainTaskSuggestion( diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts index 500cfe474..eeb70f162 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/change-task/change-task-response.ts @@ -4,9 +4,13 @@ import { ZERO_INDEX } from "~/libs/constants/constants.js"; import { AIAssistantMessageValidationSchema, type OpenAiResponseMessage, + OpenAIRoleKey, } from "~/libs/modules/open-ai/open-ai.js"; -import { type TaskSuggestionsResponseDto } from "../../types/types.js"; +import { + type AIAssistantResponseDto, + type ChatMessageDto, +} from "../../types/types.js"; import { type changeTaskByCategory } from "./change-task.validation-schema.js"; type TaskByCategoryData = z.infer; @@ -14,7 +18,8 @@ type TaskByCategoryData = z.infer; const generateChangeTaskSuggestionsResponse = ( aiResponse: OpenAiResponseMessage, taskDeadLine: string, -): null | TaskSuggestionsResponseDto => { + lastMessageId: number, +): AIAssistantResponseDto | null => { const message = aiResponse.getPaginatedItems().shift(); if (!message) { @@ -32,17 +37,37 @@ const generateChangeTaskSuggestionsResponse = ( contentText, ) as TaskByCategoryData; - return { - message: resultData.message, - tasks: [ - { - categoryId: Number(resultData.tasks.categoryId), + const textMessage: ChatMessageDto = { + author: OpenAIRoleKey.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + text: resultData.message, + }, + type: "text", + }; + + const taskMessage: ChatMessageDto = { + author: OpenAIRoleKey.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + task: { + categoryId: resultData.tasks.categoryId, categoryName: resultData.tasks.categoryName, description: resultData.tasks.description, dueDate: taskDeadLine, label: resultData.tasks.label, }, - ], + }, + type: "task", + }; + + return { + messages: [textMessage, taskMessage], + threadId: message.thread_id, }; }; From 4d72f92429606aa1e5d545141952685c118dce86 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:28:37 +0100 Subject: [PATCH 189/244] refactor(backend): change types to accept task methods bb-203 --- .../src/modules/ai-assistant/ai-assistant.controller.ts | 5 ++--- .../src/modules/ai-assistant/ai-assistant.service.ts | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index c42eca715..8fc9a4f8a 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -12,7 +12,6 @@ import { type AiAssistantService } from "./ai-assistant.service.js"; import { AIAssistantApiPath } from "./libs/enums/enums.js"; import { type AIAssistantRequestDto, - type ChangeTaskSuggestionRequestDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; import { @@ -205,7 +204,7 @@ class AiAssistantController extends BaseController { handler: (options) => this.acceptTask( options as APIHandlerOptions<{ - body: ChangeTaskSuggestionRequestDto; + body: AIAssistantRequestDto; user: UserDto; }>, ), @@ -249,7 +248,7 @@ class AiAssistantController extends BaseController { */ private async acceptTask( options: APIHandlerOptions<{ - body: ChangeTaskSuggestionRequestDto; + body: AIAssistantRequestDto; user: UserDto; }>, ): Promise { diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index 5d9038f1e..8a9d0f921 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -18,7 +18,6 @@ import { import { type AIAssistantRequestDto, type AIAssistantResponseDto, - type ChangeTaskSuggestionRequestDto, type SelectedCategory, type TaskCreateDto, type TaskDto, @@ -52,9 +51,10 @@ class AiAssistantService { public async acceptTask( user: UserDto, - body: ChangeTaskSuggestionRequestDto, + body: AIAssistantRequestDto, ): Promise { - const { task, threadId } = body; + const { payload, threadId } = body; + const task = payload as TaskCreateDto; const newTask = await this.taskService.create({ categoryId: task.categoryId, From 49c60860fa4a46e98a404ace9fa3d05ae26abf87 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:47:44 +0100 Subject: [PATCH 190/244] feat(backend): add explain task OpenAI tool bb-203 --- .../enums/open-ai-assistant-config.enum.ts | 3 +- .../libs/enums/open-ai-function-name.enum.ts | 1 + .../open-ai/libs/tools/explain-task.tool.ts | 104 ++++++++++++++++++ .../libs/modules/open-ai/libs/tools/tools.ts | 1 + .../libs/helpers/explain-task/explain-task.ts | 2 +- 5 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 apps/backend/src/libs/modules/open-ai/libs/tools/explain-task.tool.ts diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts index f9335ccb7..21bb950cb 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-assistant-config.enum.ts @@ -1,6 +1,7 @@ import { AnalyzeBalanceTool, ChangeTaskTool, + ExplainTaskTool, SuggestTaskTool, } from "../../libs/tools/tools.js"; import { OpenAIPromptTemplate } from "./open-ai-prompt-template.enum.js"; @@ -9,7 +10,7 @@ const OpenAIAssistantConfig = { INSTRUCTION: OpenAIPromptTemplate.ASSISTANT_INSTRUCTION, NAME: "Wheel of Balance Assistant", TEMPERATURE: 1, - TOOLS: [AnalyzeBalanceTool, SuggestTaskTool, ChangeTaskTool], + TOOLS: [AnalyzeBalanceTool, SuggestTaskTool, ChangeTaskTool, ExplainTaskTool], TOP_P: 1, } as const; diff --git a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts index b46e1ab3f..64491409a 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/enums/open-ai-function-name.enum.ts @@ -1,6 +1,7 @@ const OpenAIFunctionName = { ANALYZE_BALANCE_SCORES: "analyze_balance_scores", CHANGE_TASK: "change_task", + EXPLAIN_TASK: "explain_task", GENERATE_TASK_BY_CATEGORY: "generate_task_by_category", } as const; export { OpenAIFunctionName }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/explain-task.tool.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/explain-task.tool.ts new file mode 100644 index 000000000..e088cd551 --- /dev/null +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/explain-task.tool.ts @@ -0,0 +1,104 @@ +import { OpenAIFunctionName } from "../enums/open-ai-function-name.enum.js"; + +const ExplainTaskTool = { + function: { + description: + "Provides a detailed explanation of the task, including its purpose, steps for completion, and how it aligns with the user's goals.", + name: OpenAIFunctionName.EXPLAIN_TASK, + parameters: { + additionalProperties: false, + properties: { + context: { + description: + "Context explaining the user's need for a detailed explanation of the task.", + type: "string", + }, + instructions: { + additionalProperties: false, + properties: { + action: { + description: + "Steps the assistant should take (e.g., explain the task, provide motivation, describe the steps for completion)", + type: "string", + }, + task: { + description: + "The main task for the assistant (e.g., provide an explanation and detailed breakdown of the task)", + type: "string", + }, + }, + required: ["task", "action"], + type: "object", + }, + response_structure: { + additionalProperties: false, + description: "Structure of the expected response", + properties: { + explanation: { + description: + "A detailed explanation of the task and how it aligns with the user's goals", + type: "string", + }, + message: { + description: "A message summarizing the explanation of the task", + type: "string", + }, + motivation_tips: { + description: + "Tips to help the user stay motivated while completing the task", + type: "string", + }, + steps: { + description: + "An array of actionable steps the user should take to complete the task", + type: "string", + }, + }, + required: ["message", "explanation", "steps", "motivation_tips"], + type: "object", + }, + task: { + additionalProperties: false, + description: + "Details about the task the user is asking for an explanation for.", + properties: { + categoryId: { + description: "Unique identifier for the category", + type: "number", + }, + categoryName: { + description: "The name of the category (e.g., Health, Work)", + type: "string", + }, + description: { + description: "Description of the task that needs to be explained", + type: "string", + }, + dueDate: { + description: "Due date of the task", + type: "string", + }, + label: { + description: "Label or name of the task", + type: "string", + }, + }, + required: [ + "categoryId", + "categoryName", + "description", + "dueDate", + "label", + ], + type: "object", + }, + }, + required: ["context", "response_structure", "instructions", "task"], + type: "object", + }, + strict: true, + }, + type: "function", +} as const; + +export { ExplainTaskTool }; diff --git a/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts b/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts index dd2d76576..32078f8a5 100644 --- a/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts +++ b/apps/backend/src/libs/modules/open-ai/libs/tools/tools.ts @@ -1,3 +1,4 @@ export { AnalyzeBalanceTool } from "./analyze-balance.tool.js"; export { ChangeTaskTool } from "./change-task.tool.js"; +export { ExplainTaskTool } from "./explain-task.tool.js"; export { SuggestTaskTool } from "./suggest-task.tool.js"; diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts index 1f8211c4f..5cfd1674d 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task.ts @@ -15,7 +15,7 @@ const runExplainTaskOptions = ( return { additional_instructions: null, - function_name: OpenAIFunctionName.CHANGE_TASK, + function_name: OpenAIFunctionName.EXPLAIN_TASK, instructions: ExplainTaskPromptTemplates.EXPLAIN_TASK_INSTRUCTIONS, messages: [explainTaskPrompt], validationSchema: explainTaskValidationSchema, From 5dfdab0a333533304a0d7714cbd305c8a4344a42 Mon Sep 17 00:00:00 2001 From: Andrii Levin Date: Thu, 19 Sep 2024 23:49:01 +0100 Subject: [PATCH 191/244] feat(backend): add motivation message to explain task bb-203 --- .../helpers/explain-task/explain-task-response.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts index a8c05da70..f0f17ce78 100644 --- a/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts +++ b/apps/backend/src/modules/ai-assistant/libs/helpers/explain-task/explain-task-response.ts @@ -93,8 +93,19 @@ const generateExplainTaskSuggestionsResponse = ( type: ChatMessageType.QUESTION_WITH_BUTTONS, }; + const motivationMessage = { + author: ChatMessageAuthor.ASSISTANT, + createdAt: new Date().toISOString(), + id: lastMessageId++, + isRead: false, + payload: { + text: resultData.message.motivation_tips, + }, + type: ChatMessageType.TEXT, + }; + return { - messages: [textMessage, taskMessage, acceptTaskQuestion], + messages: [textMessage, taskMessage, acceptTaskQuestion, motivationMessage], threadId: message.thread_id, }; }; From b6f0e4a71131725eb6ca28cc4b7969daaa1b388c Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Fri, 20 Sep 2024 17:55:15 +0300 Subject: [PATCH 192/244] refactor: rewritten initial messages to be stored on frontend bb-340 --- .../src/modules/chat/slices/chat.slice.ts | 19 ------ apps/frontend/src/pages/chat/chat.tsx | 7 +- .../components/chat-message/chat-message.tsx | 4 +- .../pages/chat/libs/components/components.ts | 3 +- .../confirmation-buttons.tsx | 4 +- .../initial-messages/initial-messages.tsx | 66 +++++++++++++++++++ .../initial-messages/styles.module.css | 16 +++++ 7 files changed, 94 insertions(+), 25 deletions(-) create mode 100644 apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx create mode 100644 apps/frontend/src/pages/chat/libs/components/initial-messages/styles.module.css diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index ee3df577c..2acfda96b 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -31,27 +31,8 @@ const { actions, name, reducer } = createSlice({ state.dataStatus = DataStatus.PENDING; }) .addCase(initConversation.fulfilled, (state, action) => { - state.selectedCategories = action.payload.lowestCategories; state.threadId = action.payload.threadId; - state.messages.push( - { - message: action.payload.messages.greeting, - type: ChatMessageType.TEXT, - }, - { - message: action.payload.messages.comments, - type: ChatMessageType.WHEEL_ANALYSIS, - }, - { - buttonLabels: [ - ChatButtonLabels.YES_LOWEST, - ChatButtonLabels.NO_DIFFERENT, - ], - message: action.payload.messages.question, - type: ChatMessageType.CONFIRMATION_BUTTONS, - }, - ); state.dataStatus = DataStatus.FULFILLED; }) .addCase(initConversation.rejected, (state) => { diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 6d3c2bbe8..ed3c77c07 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -12,7 +12,11 @@ import { } from "~/modules/chat/chat.js"; import { actions as quizActions } from "~/modules/quiz/quiz.js"; -import { ChatMessage, MessageLoader } from "./libs/components/components.js"; +import { + ChatMessage, + InitialMessages, + MessageLoader, +} from "./libs/components/components.js"; import { type ChartDataType } from "./libs/types/types.js"; import styles from "./styles.module.css"; @@ -94,6 +98,7 @@ const Chat: React.FC = () => {
      + {threadId && } {messages.map((message) => { return ( = ({ case ChatMessageType.CONFIRMATION_BUTTONS: { return ( - = ({ +const ChatButtons: React.FC = ({ handleNo, handleYes, noButtonLabel, @@ -23,4 +23,4 @@ const ConfirmationButtons: React.FC = ({ ); }; -export { ConfirmationButtons }; +export { ChatButtons }; diff --git a/apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx b/apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx new file mode 100644 index 000000000..624e7cf20 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx @@ -0,0 +1,66 @@ +import { BalanceWheelChart } from "~/libs/components/components.js"; +import { + useAppDispatch, + useAppSelector, + useCallback, +} from "~/libs/hooks/hooks.js"; + +import { handleButtonAction } from "../../helpers/handle-button-action.helper.js"; +import { ChatButtons } from "../components.js"; +import styles from "./styles.module.css"; + +const InitialMessages: React.FC = () => { + const dispatch = useAppDispatch(); + const { scores, user } = useAppSelector((state) => ({ + scores: state.quiz.scores, + user: state.auth.user, + })); + + const chartData = scores.map((score) => { + return { + data: score.score, + label: score.categoryName, + }; + }); + + const handleNo = useCallback(() => { + void handleButtonAction(dispatch, "getCategoryForm"); + }, [dispatch]); + + const handleYes = useCallback(() => { + void handleButtonAction(dispatch, "getTasks"); + }, [dispatch]); + + return ( + <> +
      +

      + Hello {user?.name}! I'm so glad you're here and taking steps + towards a more balanced life. You've got this! +

      +
      +
      +

      here's how your wheel looks like right now:

      +
      + +
      +
      +
      +

      + Do you want to work on 3 fields, with the lowest score, or you want to + choose the fields to work on by yourself? +

      +
      + +
      +
      + + ); +}; + +export { InitialMessages }; diff --git a/apps/frontend/src/pages/chat/libs/components/initial-messages/styles.module.css b/apps/frontend/src/pages/chat/libs/components/initial-messages/styles.module.css new file mode 100644 index 000000000..3da1377a0 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/initial-messages/styles.module.css @@ -0,0 +1,16 @@ +.message-container { + display: flex; + flex-direction: column; + justify-content: center; + max-width: 730px; + padding: 15px; + background-color: var(--background-gray); + border-radius: 0 10px 10px; +} + +.content { + display: flex; + justify-content: center; + padding: 15px; + border-radius: 0 10px 10px; +} From fc1f2c1407a9aac6d09c7155d02bc0732a97ac97 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Sat, 21 Sep 2024 10:30:25 +0300 Subject: [PATCH 193/244] refactor: three lowest categories are now selected on frontend bb-340 --- .../src/modules/categories/categories.ts | 5 ++++- .../modules/categories/libs/types/types.ts | 1 + .../initial-messages/initial-messages.tsx | 19 ++++++++++++++++--- .../helpers/get-three-lowest-scores.helper.ts | 12 ++++++++++++ .../initial-messages/libs/helpers/helpers.ts | 1 + .../src/libs/enums/numerical-value.enum.ts | 1 + 6 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/get-three-lowest-scores.helper.ts create mode 100644 apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/helpers.ts diff --git a/apps/frontend/src/modules/categories/categories.ts b/apps/frontend/src/modules/categories/categories.ts index 8edcb2734..f35f131ef 100644 --- a/apps/frontend/src/modules/categories/categories.ts +++ b/apps/frontend/src/modules/categories/categories.ts @@ -10,6 +10,9 @@ const categoriesApi = new CategoriesApi({ storage, }); -export { type CategoriesGetRequestQueryDto } from "./libs/types/types.js"; +export { + type CategoriesGetRequestQueryDto, + type SelectedCategory, +} from "./libs/types/types.js"; export { actions, reducer } from "./slices/categories.js"; export { categoriesApi }; diff --git a/apps/frontend/src/modules/categories/libs/types/types.ts b/apps/frontend/src/modules/categories/libs/types/types.ts index 181d5040c..34897339e 100644 --- a/apps/frontend/src/modules/categories/libs/types/types.ts +++ b/apps/frontend/src/modules/categories/libs/types/types.ts @@ -2,4 +2,5 @@ export { type CategoriesGetAllResponseDto, type CategoriesGetRequestQueryDto, type CategoryDto, + type SelectedCategory, } from "shared"; diff --git a/apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx b/apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx index 624e7cf20..537cc2666 100644 --- a/apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx +++ b/apps/frontend/src/pages/chat/libs/components/initial-messages/initial-messages.tsx @@ -7,12 +7,14 @@ import { import { handleButtonAction } from "../../helpers/handle-button-action.helper.js"; import { ChatButtons } from "../components.js"; +import { getThreeLowestScores } from "./libs/helpers/helpers.js"; import styles from "./styles.module.css"; const InitialMessages: React.FC = () => { const dispatch = useAppDispatch(); - const { scores, user } = useAppSelector((state) => ({ + const { scores, threadId, user } = useAppSelector((state) => ({ scores: state.quiz.scores, + threadId: state.chat.threadId, user: state.auth.user, })); @@ -28,8 +30,19 @@ const InitialMessages: React.FC = () => { }, [dispatch]); const handleYes = useCallback(() => { - void handleButtonAction(dispatch, "getTasks"); - }, [dispatch]); + const threeLowestScores = getThreeLowestScores(scores); + const selectedCategories = threeLowestScores.map((score) => { + return { + categoryId: score.categoryId, + categoryName: score.categoryName, + }; + }); + + void handleButtonAction(dispatch, "getTasks", { + categories: selectedCategories, + threadId: threadId as string, + }); + }, [dispatch, scores, threadId]); return ( <> diff --git a/apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/get-three-lowest-scores.helper.ts b/apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/get-three-lowest-scores.helper.ts new file mode 100644 index 000000000..8eada86cd --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/get-three-lowest-scores.helper.ts @@ -0,0 +1,12 @@ +import { NumericalValue } from "~/libs/enums/enums.js"; +import { type QuizScoresGetAllItemResponseDto } from "~/modules/quiz/quiz.js"; + +function getThreeLowestScores( + categories: QuizScoresGetAllItemResponseDto[], +): QuizScoresGetAllItemResponseDto[] { + const categoriesSorted = categories.toSorted((a, b) => a.score - b.score); + + return categoriesSorted.slice(NumericalValue.ZERO, NumericalValue.THREE); +} + +export { getThreeLowestScores }; diff --git a/apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/helpers.ts b/apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/helpers.ts new file mode 100644 index 000000000..2ea47e9bc --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/initial-messages/libs/helpers/helpers.ts @@ -0,0 +1 @@ +export { getThreeLowestScores } from "./get-three-lowest-scores.helper.js"; diff --git a/packages/shared/src/libs/enums/numerical-value.enum.ts b/packages/shared/src/libs/enums/numerical-value.enum.ts index b0a6ae9b0..2c2e6dc82 100644 --- a/packages/shared/src/libs/enums/numerical-value.enum.ts +++ b/packages/shared/src/libs/enums/numerical-value.enum.ts @@ -1,5 +1,6 @@ const NumericalValue = { ONE: 1, + THREE: 3, ZERO: 0, } as const; From 21a7f7236fbed425c066b001a5115507e1180a0f Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Sun, 22 Sep 2024 13:36:38 +0300 Subject: [PATCH 194/244] refactor: changed position of message loader bb-340 --- apps/frontend/src/pages/chat/chat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 5e1ca703d..4c87fedb6 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -48,8 +48,8 @@ const Chat: React.FC = () => { ); })} - {messageStatus === DataStatus.PENDING && } {threadId && } + {messageStatus === DataStatus.PENDING && }
    From e153d5968fe8a1766494133fa45a0296edd289d8 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Sun, 22 Sep 2024 14:32:44 +0300 Subject: [PATCH 195/244] refactor: remade buttonMode to be based of enum bb-340 --- apps/frontend/src/modules/chat/chat.ts | 5 +--- .../chat/libs/types/buttons-mode.type.ts | 3 --- .../src/modules/chat/libs/types/types.ts | 1 - .../src/modules/chat/slices/chat.slice.ts | 16 ++++++------ .../buttons-controller/buttons-controller.tsx | 19 +++++++++----- .../task-creation-options.tsx | 5 ++-- .../components/chat-message/chat-message.tsx | 26 +++++++++++++------ .../libs/enums/buttons-mode-option.enum.ts | 7 +++++ .../src/pages/chat/libs/enums/enums.ts | 1 + 9 files changed, 50 insertions(+), 33 deletions(-) delete mode 100644 apps/frontend/src/modules/chat/libs/types/buttons-mode.type.ts create mode 100644 apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts create mode 100644 apps/frontend/src/pages/chat/libs/enums/enums.ts diff --git a/apps/frontend/src/modules/chat/chat.ts b/apps/frontend/src/modules/chat/chat.ts index 8005ac101..2e9ade38a 100644 --- a/apps/frontend/src/modules/chat/chat.ts +++ b/apps/frontend/src/modules/chat/chat.ts @@ -12,8 +12,5 @@ const chatApi = new ChatApi({ export { chatApi }; export { ChatMessageAuthor, ChatMessageType } from "./libs/enums/enums.js"; -export { - type ButtonsMode, - type ChatMessagePayload, -} from "./libs/types/types.js"; +export { type ChatMessagePayload } from "./libs/types/types.js"; export { actions, reducer } from "./slices/chat.js"; diff --git a/apps/frontend/src/modules/chat/libs/types/buttons-mode.type.ts b/apps/frontend/src/modules/chat/libs/types/buttons-mode.type.ts deleted file mode 100644 index 523f91374..000000000 --- a/apps/frontend/src/modules/chat/libs/types/buttons-mode.type.ts +++ /dev/null @@ -1,3 +0,0 @@ -type ButtonsMode = "CategoriesCheckbox" | "none" | "taskGenerationOptions"; - -export { type ButtonsMode }; diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts index 9f2534c83..7234b9e2e 100644 --- a/apps/frontend/src/modules/chat/libs/types/types.ts +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -1,4 +1,3 @@ -export { type ButtonsMode } from "./buttons-mode.type.js"; export { type AIAssistantRequestDto, type AIAssistantResponseDto, diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 7822246bb..838af0758 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -3,17 +3,14 @@ import { createSlice, type PayloadAction } from "@reduxjs/toolkit"; import { DataStatus } from "~/libs/enums/enums.js"; import { type ValueOf } from "~/libs/types/types.js"; import { type SelectedCategory } from "~/modules/categories/categories.js"; -import { - type ButtonsMode, - ChatMessageAuthor, - ChatMessageType, -} from "~/modules/chat/chat.js"; +import { ChatMessageAuthor, ChatMessageType } from "~/modules/chat/chat.js"; +import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { type ChatMessageDto } from "../libs/types/types.js"; import { getTasksForCategories, initConversation } from "./actions.js"; type State = { - buttonsMode: ButtonsMode; + buttonsMode: ValueOf; dataStatus: ValueOf; messages: Omit[]; selectedCategories: SelectedCategory[]; @@ -21,7 +18,7 @@ type State = { }; const initialState: State = { - buttonsMode: "taskGenerationOptions", + buttonsMode: buttonsModeOption.TASK_CREATION, dataStatus: DataStatus.IDLE, messages: [], selectedCategories: [], @@ -80,7 +77,10 @@ const { actions, name, reducer } = createSlice({ state.messages.push(userMessage); }, - setButtonsMode(state, action: PayloadAction) { + setButtonsMode( + state, + action: PayloadAction>, + ) { state.buttonsMode = action.payload; }, updateSelectedCategories(state, action: { payload: SelectedCategory[] }) { diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx index 78ccd91fa..ad361a376 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx @@ -1,5 +1,6 @@ import { useAppSelector } from "~/libs/hooks/hooks.js"; +import { buttonsModeOption } from "../../enums/enums.js"; import { CategoriesSelector, TaskCreationOptions, @@ -8,15 +9,19 @@ import { const ButtonsController: React.FC = () => { const buttonsMode = useAppSelector((state) => state.chat.buttonsMode); - if (buttonsMode === "taskGenerationOptions") { - return ; - } + switch (buttonsMode) { + case buttonsModeOption.TASK_CREATION: { + return ; + } - if (buttonsMode === "CategoriesCheckbox") { - return ; - } + case buttonsModeOption.CATEGORIES_CHECKBOX: { + return ; + } - return null; + default: { + return null; + } + } }; export { ButtonsController }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/task-creation-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/task-creation-options.tsx index 7a5a34366..55ba885fa 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/task-creation-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/task-creation-options.tsx @@ -5,6 +5,7 @@ import { useCallback, } from "~/libs/hooks/hooks.js"; import { actions as chatActions } from "~/modules/chat/chat.js"; +import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { CONFIRMATION_BUTTONS_TEXT } from "./libs/constants/constants.js"; import { selectCategoriesButtonLabel } from "./libs/enums/enums.js"; @@ -21,7 +22,7 @@ const TaskCreationOptions: React.FC = () => { const handleNo = useCallback(() => { dispatch(chatActions.addAssistantTextMessage(CONFIRMATION_BUTTONS_TEXT)); dispatch(chatActions.addUserTextMessage(selectCategoriesButtonLabel.NO)); - dispatch(chatActions.setButtonsMode("CategoriesCheckbox")); + dispatch(chatActions.setButtonsMode(buttonsModeOption.CATEGORIES_CHECKBOX)); }, [dispatch]); const handleYes = useCallback(() => { @@ -33,7 +34,7 @@ const TaskCreationOptions: React.FC = () => { }; }); - dispatch(chatActions.setButtonsMode("none")); + dispatch(chatActions.setButtonsMode(buttonsModeOption.NONE)); dispatch(chatActions.addAssistantTextMessage(CONFIRMATION_BUTTONS_TEXT)); dispatch(chatActions.addUserTextMessage(selectCategoriesButtonLabel.YES)); void dispatch( diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index bbb2ff1a5..90a044f29 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -4,7 +4,7 @@ import { type ValueOf } from "~/libs/types/types.js"; import { type ChatMessageAuthor, type ChatMessagePayload, - type ChatMessageType, + ChatMessageType, } from "~/modules/chat/chat.js"; import styles from "./styles.module.css"; @@ -34,13 +34,23 @@ const ChatMessage: React.FC = ({ : styles["content-container-user"], ); - if (type === "text") { - return ( -
  • - -
    {payload.text}
    -
  • - ); + switch (type) { + case ChatMessageType.TEXT: { + return ( +
  • + +
    {payload.text}
    +
  • + ); + } + + case ChatMessageType.TASK: { + return "hello"; + } + + default: { + return null; + } } }; diff --git a/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts new file mode 100644 index 000000000..3850c93d9 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts @@ -0,0 +1,7 @@ +const buttonsModeOption = { + CATEGORIES_CHECKBOX: "categoriesCheckbox", + NONE: "none", + TASK_CREATION: "taskGeneration", +} as const; + +export { buttonsModeOption }; diff --git a/apps/frontend/src/pages/chat/libs/enums/enums.ts b/apps/frontend/src/pages/chat/libs/enums/enums.ts new file mode 100644 index 000000000..278040a9d --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/enums/enums.ts @@ -0,0 +1 @@ +export { buttonsModeOption } from "./buttons-mode-option.enum.js"; From 1c6a1ac30cc55e8db0937306229a8938c7f09279 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Sun, 22 Sep 2024 16:59:07 +0300 Subject: [PATCH 196/244] feat: intermediate commit bb-340 --- .../src/libs/components/components.ts | 1 + .../libs/components/category/category.tsx | 2 +- ...vert-category-name-to-kebab-case.helper.ts | 0 .../category/libs/helpers/helpers.ts | 1 + .../components/category/styles.module.css | 0 .../task-card}/libs/components/components.ts | 1 - .../libs/components/deadline/deadline.tsx | 0 .../deadline/libs/constants/constants.ts | 0 .../constants/countdown-expired.constant.ts | 0 .../components/deadline/libs/enums/enums.ts | 0 .../libs/enums/milliseconds-per-unit.enum.ts | 0 .../deadline/libs/enums/time-pad.enum.ts | 0 .../deadline/libs/types/countdown.type.ts | 0 .../components/deadline/libs/types/types.ts | 0 .../components/deadline/styles.module.css | 0 .../past-task-status/past-task-status.tsx | 0 .../past-task-status/styles.module.css | 0 .../components/task-card/libs/enums/enums.ts | 1 + .../components/task-card/styles.module.css | 0 .../libs/components/task-card/task-card.tsx | 60 +++++++++++-------- .../components/chat-message/chat-message.tsx | 12 +++- .../src/pages/tasks/libs/helpers/helpers.ts | 1 - apps/frontend/src/pages/tasks/tasks.tsx | 3 +- .../libs/types/chat-message-payload.type.ts | 4 +- 24 files changed, 54 insertions(+), 32 deletions(-) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/category/category.tsx (89%) rename apps/frontend/src/{pages/tasks/libs/helpers/convert-category-name-to-kebab-case => libs/components/task-card/libs/components/category/libs/helpers}/convert-category-name-to-kebab-case.helper.ts (100%) create mode 100644 apps/frontend/src/libs/components/task-card/libs/components/category/libs/helpers/helpers.ts rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/category/styles.module.css (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/components.ts (76%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/deadline.tsx (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/libs/constants/constants.ts (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/libs/constants/countdown-expired.constant.ts (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/libs/enums/enums.ts (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/libs/enums/milliseconds-per-unit.enum.ts (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/libs/enums/time-pad.enum.ts (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/libs/types/countdown.type.ts (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/libs/types/types.ts (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/deadline/styles.module.css (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/past-task-status/past-task-status.tsx (100%) rename apps/frontend/src/{pages/tasks => libs/components/task-card}/libs/components/past-task-status/styles.module.css (100%) create mode 100644 apps/frontend/src/libs/components/task-card/libs/enums/enums.ts rename apps/frontend/src/{pages/tasks => }/libs/components/task-card/styles.module.css (100%) rename apps/frontend/src/{pages/tasks => }/libs/components/task-card/task-card.tsx (58%) delete mode 100644 apps/frontend/src/pages/tasks/libs/helpers/helpers.ts diff --git a/apps/frontend/src/libs/components/components.ts b/apps/frontend/src/libs/components/components.ts index dd81cd466..7366007fd 100644 --- a/apps/frontend/src/libs/components/components.ts +++ b/apps/frontend/src/libs/components/components.ts @@ -17,5 +17,6 @@ export { RouterProvider } from "./router-provider/router-provider.js"; export { Sidebar } from "./sidebar/sidebar.js"; export { Slider } from "./slider/slider.js"; export { Switch } from "./switch/switch.js"; +export { TaskCard } from "./task-card/task-card.js"; export { Provider as StoreProvider } from "react-redux"; export { Navigate, Outlet as RouterOutlet } from "react-router-dom"; diff --git a/apps/frontend/src/pages/tasks/libs/components/category/category.tsx b/apps/frontend/src/libs/components/task-card/libs/components/category/category.tsx similarity index 89% rename from apps/frontend/src/pages/tasks/libs/components/category/category.tsx rename to apps/frontend/src/libs/components/task-card/libs/components/category/category.tsx index f2a600318..e5286392b 100644 --- a/apps/frontend/src/pages/tasks/libs/components/category/category.tsx +++ b/apps/frontend/src/libs/components/task-card/libs/components/category/category.tsx @@ -1,6 +1,6 @@ import { getValidClassNames } from "~/libs/helpers/helpers.js"; -import { convertCategoryNameToKebabCase } from "../../helpers/helpers.js"; +import { convertCategoryNameToKebabCase } from "./libs/helpers/helpers.js"; import styles from "./styles.module.css"; type Properties = { diff --git a/apps/frontend/src/pages/tasks/libs/helpers/convert-category-name-to-kebab-case/convert-category-name-to-kebab-case.helper.ts b/apps/frontend/src/libs/components/task-card/libs/components/category/libs/helpers/convert-category-name-to-kebab-case.helper.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/helpers/convert-category-name-to-kebab-case/convert-category-name-to-kebab-case.helper.ts rename to apps/frontend/src/libs/components/task-card/libs/components/category/libs/helpers/convert-category-name-to-kebab-case.helper.ts diff --git a/apps/frontend/src/libs/components/task-card/libs/components/category/libs/helpers/helpers.ts b/apps/frontend/src/libs/components/task-card/libs/components/category/libs/helpers/helpers.ts new file mode 100644 index 000000000..5ff56931c --- /dev/null +++ b/apps/frontend/src/libs/components/task-card/libs/components/category/libs/helpers/helpers.ts @@ -0,0 +1 @@ +export { convertCategoryNameToKebabCase } from "./convert-category-name-to-kebab-case.helper.js"; diff --git a/apps/frontend/src/pages/tasks/libs/components/category/styles.module.css b/apps/frontend/src/libs/components/task-card/libs/components/category/styles.module.css similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/category/styles.module.css rename to apps/frontend/src/libs/components/task-card/libs/components/category/styles.module.css diff --git a/apps/frontend/src/pages/tasks/libs/components/components.ts b/apps/frontend/src/libs/components/task-card/libs/components/components.ts similarity index 76% rename from apps/frontend/src/pages/tasks/libs/components/components.ts rename to apps/frontend/src/libs/components/task-card/libs/components/components.ts index 033ef01e4..c1fdb5c34 100644 --- a/apps/frontend/src/pages/tasks/libs/components/components.ts +++ b/apps/frontend/src/libs/components/task-card/libs/components/components.ts @@ -1,4 +1,3 @@ export { Category } from "./category/category.js"; export { Deadline } from "./deadline/deadline.js"; export { PastTaskStatus } from "./past-task-status/past-task-status.js"; -export { TaskCard } from "./task-card/task-card.js"; diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/deadline.tsx b/apps/frontend/src/libs/components/task-card/libs/components/deadline/deadline.tsx similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/deadline.tsx rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/deadline.tsx diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/libs/constants/constants.ts b/apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/constants/constants.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/libs/constants/constants.ts rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/constants/constants.ts diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/libs/constants/countdown-expired.constant.ts b/apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/constants/countdown-expired.constant.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/libs/constants/countdown-expired.constant.ts rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/constants/countdown-expired.constant.ts diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/libs/enums/enums.ts b/apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/enums/enums.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/libs/enums/enums.ts rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/enums/enums.ts diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/libs/enums/milliseconds-per-unit.enum.ts b/apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/enums/milliseconds-per-unit.enum.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/libs/enums/milliseconds-per-unit.enum.ts rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/enums/milliseconds-per-unit.enum.ts diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/libs/enums/time-pad.enum.ts b/apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/enums/time-pad.enum.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/libs/enums/time-pad.enum.ts rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/enums/time-pad.enum.ts diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/libs/types/countdown.type.ts b/apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/types/countdown.type.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/libs/types/countdown.type.ts rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/types/countdown.type.ts diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/libs/types/types.ts b/apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/types/types.ts similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/libs/types/types.ts rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/libs/types/types.ts diff --git a/apps/frontend/src/pages/tasks/libs/components/deadline/styles.module.css b/apps/frontend/src/libs/components/task-card/libs/components/deadline/styles.module.css similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/deadline/styles.module.css rename to apps/frontend/src/libs/components/task-card/libs/components/deadline/styles.module.css diff --git a/apps/frontend/src/pages/tasks/libs/components/past-task-status/past-task-status.tsx b/apps/frontend/src/libs/components/task-card/libs/components/past-task-status/past-task-status.tsx similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/past-task-status/past-task-status.tsx rename to apps/frontend/src/libs/components/task-card/libs/components/past-task-status/past-task-status.tsx diff --git a/apps/frontend/src/pages/tasks/libs/components/past-task-status/styles.module.css b/apps/frontend/src/libs/components/task-card/libs/components/past-task-status/styles.module.css similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/past-task-status/styles.module.css rename to apps/frontend/src/libs/components/task-card/libs/components/past-task-status/styles.module.css diff --git a/apps/frontend/src/libs/components/task-card/libs/enums/enums.ts b/apps/frontend/src/libs/components/task-card/libs/enums/enums.ts new file mode 100644 index 000000000..0287ea101 --- /dev/null +++ b/apps/frontend/src/libs/components/task-card/libs/enums/enums.ts @@ -0,0 +1 @@ +export { TaskStatus } from "shared"; diff --git a/apps/frontend/src/pages/tasks/libs/components/task-card/styles.module.css b/apps/frontend/src/libs/components/task-card/styles.module.css similarity index 100% rename from apps/frontend/src/pages/tasks/libs/components/task-card/styles.module.css rename to apps/frontend/src/libs/components/task-card/styles.module.css diff --git a/apps/frontend/src/pages/tasks/libs/components/task-card/task-card.tsx b/apps/frontend/src/libs/components/task-card/task-card.tsx similarity index 58% rename from apps/frontend/src/pages/tasks/libs/components/task-card/task-card.tsx rename to apps/frontend/src/libs/components/task-card/task-card.tsx index ede121837..251194b73 100644 --- a/apps/frontend/src/pages/tasks/libs/components/task-card/task-card.tsx +++ b/apps/frontend/src/libs/components/task-card/task-card.tsx @@ -2,13 +2,17 @@ import { Button } from "~/libs/components/components.js"; import { useCallback } from "~/libs/hooks/hooks.js"; import { type TaskDto } from "~/modules/tasks/tasks.js"; -import { TaskStatus } from "../../enums/enums.js"; -import { Category, Deadline, PastTaskStatus } from "../components.js"; +import { + Category, + Deadline, + PastTaskStatus, +} from "./libs/components/components.js"; +import { TaskStatus } from "./libs/enums/enums.js"; import styles from "./styles.module.css"; type Properties = { - onComplete: (id: number) => void; - onSkip: (id: number) => void; + onComplete?: (id: number) => void; + onSkip?: (id: number) => void; task: TaskDto; }; @@ -18,11 +22,15 @@ const TaskCard: React.FC = ({ task, }: Properties) => { const handleSkip = useCallback(() => { - onSkip(task.id); + if (onSkip) { + onSkip(task.id); + } }, [task, onSkip]); const handleComplete = useCallback(() => { - onComplete(task.id); + if (onComplete) { + onComplete(task.id); + } }, [task, onComplete]); const isActive = task.status === TaskStatus.CURRENT; @@ -42,24 +50,28 @@ const TaskCard: React.FC = ({
    {isActive ? ( <> -
    -
    -
    -
    + {Boolean(onSkip) && ( +
    +
    + )} + {Boolean(onComplete) && ( +
    +
    + )} ) : (
    diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index 90a044f29..0b28091a5 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -1,4 +1,4 @@ -import { Icon } from "~/libs/components/components.js"; +import { Icon, TaskCard } from "~/libs/components/components.js"; import { getValidClassNames } from "~/libs/helpers/helpers.js"; import { type ValueOf } from "~/libs/types/types.js"; import { @@ -6,6 +6,7 @@ import { type ChatMessagePayload, ChatMessageType, } from "~/modules/chat/chat.js"; +import { type TaskDto } from "~/modules/tasks/tasks.js"; import styles from "./styles.module.css"; @@ -45,7 +46,14 @@ const ChatMessage: React.FC = ({ } case ChatMessageType.TASK: { - return "hello"; + return ( +
  • + +
    + +
    +
  • + ); } default: { diff --git a/apps/frontend/src/pages/tasks/libs/helpers/helpers.ts b/apps/frontend/src/pages/tasks/libs/helpers/helpers.ts deleted file mode 100644 index 574b2cef3..000000000 --- a/apps/frontend/src/pages/tasks/libs/helpers/helpers.ts +++ /dev/null @@ -1 +0,0 @@ -export { convertCategoryNameToKebabCase } from "./convert-category-name-to-kebab-case/convert-category-name-to-kebab-case.helper.js"; diff --git a/apps/frontend/src/pages/tasks/tasks.tsx b/apps/frontend/src/pages/tasks/tasks.tsx index 6fd3011f6..c2727e5b5 100644 --- a/apps/frontend/src/pages/tasks/tasks.tsx +++ b/apps/frontend/src/pages/tasks/tasks.tsx @@ -1,4 +1,4 @@ -import { Loader, Switch } from "~/libs/components/components.js"; +import { Loader, Switch, TaskCard } from "~/libs/components/components.js"; import { DataStatus } from "~/libs/enums/enums.js"; import { useAppDispatch, @@ -10,7 +10,6 @@ import { import { type ValueOf } from "~/libs/types/types.js"; import { actions as taskActions } from "~/modules/tasks/tasks.js"; -import { TaskCard } from "./libs/components/components.js"; import { TasksMode, TaskStatus } from "./libs/enums/enums.js"; import styles from "./styles.module.css"; diff --git a/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts b/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts index 4d9deffbb..745b706bb 100644 --- a/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts +++ b/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts @@ -2,6 +2,8 @@ import { type BalanceWheelMessage } from "./balance-wheel-message.type.js"; import { type TaskMessage } from "./task-message.type.js"; import { type TextMessage } from "./text.message.type.js"; -type ChatMessagePayload = BalanceWheelMessage | TaskMessage | TextMessage; +type ChatMessagePayload = Partial< + BalanceWheelMessage & TaskMessage & TextMessage +>; export { type ChatMessagePayload }; From 8d1303985df5d54b6327c87979a5fc4402d47257 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Sun, 22 Sep 2024 18:58:25 +0300 Subject: [PATCH 197/244] refactor: rewritten types for ai assistant outputs bb-340 --- .../libs/components/task-card/task-card.tsx | 64 ++++++++++--------- apps/frontend/src/modules/chat/chat.ts | 2 +- .../src/modules/chat/libs/types/types.ts | 1 + .../src/modules/chat/slices/chat.slice.ts | 16 ++++- .../src/modules/tasks/libs/types/types.ts | 6 +- apps/frontend/src/modules/tasks/tasks.ts | 6 +- .../components/chat-message/chat-message.tsx | 31 ++++++--- .../components/chat-message/styles.module.css | 11 +++- packages/shared/src/index.ts | 1 - .../types/ai-assistant-response-dto.type.ts | 5 +- packages/shared/src/modules/chats/chats.ts | 1 - .../libs/types/balance-wheel-message.type.ts | 8 --- .../chats/libs/types/chat-message-dto.type.ts | 5 +- .../libs/types/chat-message-payload.type.ts | 5 +- .../chats/libs/types/task-message.type.ts | 2 +- .../src/modules/chats/libs/types/types.ts | 1 - .../modules/tasks/libs/types/task-dto.type.ts | 1 - 17 files changed, 99 insertions(+), 67 deletions(-) delete mode 100644 packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts diff --git a/apps/frontend/src/libs/components/task-card/task-card.tsx b/apps/frontend/src/libs/components/task-card/task-card.tsx index 251194b73..db9fe8390 100644 --- a/apps/frontend/src/libs/components/task-card/task-card.tsx +++ b/apps/frontend/src/libs/components/task-card/task-card.tsx @@ -1,6 +1,6 @@ import { Button } from "~/libs/components/components.js"; import { useCallback } from "~/libs/hooks/hooks.js"; -import { type TaskDto } from "~/modules/tasks/tasks.js"; +import { type TaskCreateDto, type TaskDto } from "~/modules/tasks/tasks.js"; import { Category, @@ -13,7 +13,7 @@ import styles from "./styles.module.css"; type Properties = { onComplete?: (id: number) => void; onSkip?: (id: number) => void; - task: TaskDto; + task: TaskCreateDto | TaskDto; }; const TaskCard: React.FC = ({ @@ -23,22 +23,27 @@ const TaskCard: React.FC = ({ }: Properties) => { const handleSkip = useCallback(() => { if (onSkip) { - onSkip(task.id); + onSkip((task as TaskDto).id); } }, [task, onSkip]); const handleComplete = useCallback(() => { if (onComplete) { - onComplete(task.id); + onComplete((task as TaskDto).id); } }, [task, onComplete]); - const isActive = task.status === TaskStatus.CURRENT; + const isActive = (task as TaskDto).status === TaskStatus.CURRENT; + const isChatTask = Boolean(onComplete) && Boolean(onSkip); return (
    - + {isActive && }
    @@ -48,34 +53,33 @@ const TaskCard: React.FC = ({
    - {isActive ? ( + {isActive && isChatTask ? ( <> - {Boolean(onSkip) && ( -
    -
    - )} - {Boolean(onComplete) && ( -
    -
    - )} +
    +
    + +
    +
    ) : (
    - + {isChatTask && ( + + )}
    )}
    diff --git a/apps/frontend/src/modules/chat/chat.ts b/apps/frontend/src/modules/chat/chat.ts index 2e9ade38a..bb18a4aa2 100644 --- a/apps/frontend/src/modules/chat/chat.ts +++ b/apps/frontend/src/modules/chat/chat.ts @@ -12,5 +12,5 @@ const chatApi = new ChatApi({ export { chatApi }; export { ChatMessageAuthor, ChatMessageType } from "./libs/enums/enums.js"; -export { type ChatMessagePayload } from "./libs/types/types.js"; +export { type TaskCreateDto, type TextMessage } from "./libs/types/types.js"; export { actions, reducer } from "./slices/chat.js"; diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts index 7234b9e2e..67afe698a 100644 --- a/apps/frontend/src/modules/chat/libs/types/types.ts +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -5,5 +5,6 @@ export { type ChatMessagePayload, type TaskCreateDto, type TaskDto, + type TextMessage, type ThreadMessageCreateDto, } from "shared"; diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 838af0758..8e7df547e 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -6,14 +6,19 @@ import { type SelectedCategory } from "~/modules/categories/categories.js"; import { ChatMessageAuthor, ChatMessageType } from "~/modules/chat/chat.js"; import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; -import { type ChatMessageDto } from "../libs/types/types.js"; +import { + type ChatMessageDto, + type TaskCreateDto, + type TextMessage, +} from "../libs/types/types.js"; import { getTasksForCategories, initConversation } from "./actions.js"; type State = { buttonsMode: ValueOf; dataStatus: ValueOf; - messages: Omit[]; + messages: Omit, "createdAt" | "id">[]; selectedCategories: SelectedCategory[]; + taskSuggestions: Omit[]; threadId: null | string; }; @@ -22,6 +27,7 @@ const initialState: State = { dataStatus: DataStatus.IDLE, messages: [], selectedCategories: [], + taskSuggestions: [], threadId: null, }; @@ -48,6 +54,12 @@ const { actions, name, reducer } = createSlice({ for (const message of newMessages) { state.messages.push(message); + state.taskSuggestions.push({ + categoryId: message.payload.categoryId, + categoryName: message.payload.categoryName, + description: message.payload.description, + label: message.payload.label, + }); } }) .addCase(getTasksForCategories.rejected, (state) => { diff --git a/apps/frontend/src/modules/tasks/libs/types/types.ts b/apps/frontend/src/modules/tasks/libs/types/types.ts index ed4ebfb38..16d744aea 100644 --- a/apps/frontend/src/modules/tasks/libs/types/types.ts +++ b/apps/frontend/src/modules/tasks/libs/types/types.ts @@ -1,2 +1,6 @@ export { type TaskUpdatePayload } from "./task-update-payload.type.js"; -export { type TaskDto, type TaskUpdateRequestDto } from "shared"; +export { + type TaskCreateDto, + type TaskDto, + type TaskUpdateRequestDto, +} from "shared"; diff --git a/apps/frontend/src/modules/tasks/tasks.ts b/apps/frontend/src/modules/tasks/tasks.ts index e3d35c648..3acdabc19 100644 --- a/apps/frontend/src/modules/tasks/tasks.ts +++ b/apps/frontend/src/modules/tasks/tasks.ts @@ -11,5 +11,9 @@ const tasksApi = new TasksApi({ }); export { tasksApi }; -export { type TaskDto, type TaskUpdateRequestDto } from "./libs/types/types.js"; +export { + type TaskCreateDto, + type TaskDto, + type TaskUpdateRequestDto, +} from "./libs/types/types.js"; export { actions, reducer } from "./slices/tasks.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index 0b28091a5..28dd6451c 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -1,18 +1,20 @@ +import defaultAvatar from "~/assets/img/default-avatar.png"; import { Icon, TaskCard } from "~/libs/components/components.js"; import { getValidClassNames } from "~/libs/helpers/helpers.js"; -import { type ValueOf } from "~/libs/types/types.js"; +import { useAppSelector } from "~/libs/hooks/hooks.js"; +import { type UserDto, type ValueOf } from "~/libs/types/types.js"; import { - type ChatMessageAuthor, - type ChatMessagePayload, + ChatMessageAuthor, ChatMessageType, + type TextMessage, } from "~/modules/chat/chat.js"; -import { type TaskDto } from "~/modules/tasks/tasks.js"; +import { type TaskCreateDto } from "~/modules/tasks/tasks.js"; import styles from "./styles.module.css"; type Properties = { author: ValueOf; - payload: ChatMessagePayload; + payload: TaskCreateDto | TextMessage; type: ValueOf; }; @@ -21,6 +23,7 @@ const ChatMessage: React.FC = ({ payload, type, }: Properties) => { + const user = useAppSelector((state) => state.auth.user as UserDto); const messageContainerStyle = getValidClassNames( styles["message-container"], author === "assistant" @@ -39,18 +42,28 @@ const ChatMessage: React.FC = ({ case ChatMessageType.TEXT: { return (
  • - -
    {payload.text}
    + {author === ChatMessageAuthor.ASSISTANT ? ( + + ) : ( + {`${user.name}'s + )} +
    + {(payload as TextMessage).text} +
  • ); } case ChatMessageType.TASK: { return ( -
  • +
  • - +
  • ); diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css index 42143377a..840d9a9f8 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css @@ -17,13 +17,22 @@ justify-content: center; max-width: 730px; padding: 15px; - border-radius: 0 10px 10px; } .content-container-assistant { background-color: var(--background-gray); + border-radius: 0 10px 10px; } .content-container-user { background-color: var(--user-chat-bubble); + border-radius: 10px 0 10px 10px; +} + +.avatar { + width: 30px; + height: 30px; + margin-right: 9px; + object-fit: cover; + border-radius: 50%; } diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index d3a98c385..9628a7d20 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -71,7 +71,6 @@ export { type SelectedCategory, } from "./modules/categories/categories.js"; export { - type BalanceWheelMessage, ChatMessageAuthor, type ChatMessageDto, type ChatMessagePayload, diff --git a/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts index 2222a88e9..d7167f29e 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-response-dto.type.ts @@ -1,7 +1,8 @@ -import { type ChatMessageDto } from "../../../chats/chats.js"; +import { type ChatMessageDto, type TextMessage } from "../../../chats/chats.js"; +import { type TaskCreateDto, type TaskDto } from "../../../tasks/tasks.js"; type AIAssistantResponseDto = { - messages: ChatMessageDto[]; + messages: ChatMessageDto[]; threadId: string; }; diff --git a/packages/shared/src/modules/chats/chats.ts b/packages/shared/src/modules/chats/chats.ts index afc4d4d67..3f5ac7b5a 100644 --- a/packages/shared/src/modules/chats/chats.ts +++ b/packages/shared/src/modules/chats/chats.ts @@ -1,6 +1,5 @@ export { ChatMessageAuthor, ChatMessageType } from "./libs/enums/enums.js"; export { - type BalanceWheelMessage, type ChatMessageDto, type ChatMessagePayload, type TaskMessage, diff --git a/packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts b/packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts deleted file mode 100644 index c168d5273..000000000 --- a/packages/shared/src/modules/chats/libs/types/balance-wheel-message.type.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { type SelectedCategory } from "../../../categories/categories.js"; - -type BalanceWheelMessage = { - lowestCategories: SelectedCategory[]; - text: string; -}; - -export { type BalanceWheelMessage }; diff --git a/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts index 287967ed8..eb816b9ba 100644 --- a/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts +++ b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts @@ -3,14 +3,13 @@ import { type ChatMessageAuthor, type ChatMessageType, } from "../enums/enums.js"; -import { type ChatMessagePayload } from "./chat-message-payload.type.js"; -type ChatMessageDto = { +type ChatMessageDto = { author: ValueOf; createdAt: string; id: number; isRead: boolean; - payload: ChatMessagePayload; + payload: PayloadType; type: ValueOf; }; diff --git a/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts b/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts index 745b706bb..13a635e2a 100644 --- a/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts +++ b/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts @@ -1,9 +1,6 @@ -import { type BalanceWheelMessage } from "./balance-wheel-message.type.js"; import { type TaskMessage } from "./task-message.type.js"; import { type TextMessage } from "./text.message.type.js"; -type ChatMessagePayload = Partial< - BalanceWheelMessage & TaskMessage & TextMessage ->; +type ChatMessagePayload = TaskMessage | TextMessage; export { type ChatMessagePayload }; diff --git a/packages/shared/src/modules/chats/libs/types/task-message.type.ts b/packages/shared/src/modules/chats/libs/types/task-message.type.ts index 93c4b5863..f207a20d8 100644 --- a/packages/shared/src/modules/chats/libs/types/task-message.type.ts +++ b/packages/shared/src/modules/chats/libs/types/task-message.type.ts @@ -1,7 +1,7 @@ import { type TaskCreateDto, type TaskDto } from "../../../tasks/tasks.js"; type TaskMessage = { - task: TaskCreateDto | TaskDto; + task: TaskCreateDto & TaskDto; text?: string; }; diff --git a/packages/shared/src/modules/chats/libs/types/types.ts b/packages/shared/src/modules/chats/libs/types/types.ts index 1c97d513e..d1a7a01cb 100644 --- a/packages/shared/src/modules/chats/libs/types/types.ts +++ b/packages/shared/src/modules/chats/libs/types/types.ts @@ -1,4 +1,3 @@ -export { type BalanceWheelMessage } from "./balance-wheel-message.type.js"; export { type ChatMessageDto } from "./chat-message-dto.type.js"; export { type ChatMessagePayload } from "./chat-message-payload.type.js"; export { type TaskMessage } from "./task-message.type.js"; diff --git a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts index b696a6ecf..4e271f8f9 100644 --- a/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts +++ b/packages/shared/src/modules/tasks/libs/types/task-dto.type.ts @@ -4,7 +4,6 @@ import { type TaskStatus } from "../enums/enums.js"; type TaskDto = { category: string; categoryId: number; - categoryName?: string; createdAt: string; description: string; dueDate: string; From e4f8858e5ee13628392cc1d216c733973658dc85 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Sun, 22 Sep 2024 19:39:31 +0300 Subject: [PATCH 198/244] refactor: rewritten types for ai assistant outputs bb-340 --- .../libs/components/task-card/task-card.tsx | 6 +++--- apps/frontend/src/modules/chat/chat.ts | 6 +++++- .../src/modules/chat/libs/types/types.ts | 1 + .../src/modules/chat/slices/chat.slice.ts | 21 ++++++++++++------- .../components/chat-message/chat-message.tsx | 6 +++--- packages/shared/src/index.ts | 1 + .../types/ai-assistant-response-dto.type.ts | 4 ++-- .../tasks/libs/types/task-payload.type.ts | 8 +++++++ .../src/modules/tasks/libs/types/types.ts | 1 + packages/shared/src/modules/tasks/tasks.ts | 1 + 10 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 packages/shared/src/modules/tasks/libs/types/task-payload.type.ts diff --git a/apps/frontend/src/libs/components/task-card/task-card.tsx b/apps/frontend/src/libs/components/task-card/task-card.tsx index db9fe8390..31f927d10 100644 --- a/apps/frontend/src/libs/components/task-card/task-card.tsx +++ b/apps/frontend/src/libs/components/task-card/task-card.tsx @@ -34,7 +34,7 @@ const TaskCard: React.FC = ({ }, [task, onComplete]); const isActive = (task as TaskDto).status === TaskStatus.CURRENT; - const isChatTask = Boolean(onComplete) && Boolean(onSkip); + const isAcceptedTask = Boolean(onComplete) && Boolean(onSkip); return (
    @@ -53,7 +53,7 @@ const TaskCard: React.FC = ({
    - {isActive && isChatTask ? ( + {isActive && isAcceptedTask ? ( <>
    ); diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx index ad361a376..f967af4db 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx @@ -3,15 +3,20 @@ import { useAppSelector } from "~/libs/hooks/hooks.js"; import { buttonsModeOption } from "../../enums/enums.js"; import { CategoriesSelector, - TaskCreationOptions, + SuggestionsCreationOptions, + SuggestionsManipulationOptions, } from "./libs/components/components.js"; const ButtonsController: React.FC = () => { const buttonsMode = useAppSelector((state) => state.chat.buttonsMode); switch (buttonsMode) { - case buttonsModeOption.TASK_CREATION: { - return ; + case buttonsModeOption.SUGGESTIONS_CREATION: { + return ; + } + + case buttonsModeOption.SUGGESTIONS_MANIPULATION: { + return ; } case buttonsModeOption.CATEGORIES_CHECKBOX: { diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/components.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/components.ts index 3cd4f5427..08fa190e1 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/components.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/components.ts @@ -1,2 +1,3 @@ export { CategoriesSelector } from "./categories-selector/categories-selector.js"; -export { TaskCreationOptions } from "./task-creation-options/task-creation-options.js"; +export { SuggestionsCreationOptions } from "./suggestions-creation-options/suggestions-creation-options.js"; +export { SuggestionsManipulationOptions } from "./suggestions-manipulation-options/suggestions-manipulation-options.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/constants/confirmation-buttons-text.constant.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/confirmation-buttons-text.constant.ts similarity index 62% rename from apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/constants/confirmation-buttons-text.constant.ts rename to apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/confirmation-buttons-text.constant.ts index 74b4de3d2..2af0e179d 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/constants/confirmation-buttons-text.constant.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/confirmation-buttons-text.constant.ts @@ -1,4 +1,4 @@ -const CONFIRMATION_BUTTONS_TEXT = +const SUGGESTIONS_CREATION_TEXT = "Do you want to work on 3 fields, with the lowest score, or you want to choose the fields to work on by yourself?"; -export { CONFIRMATION_BUTTONS_TEXT }; +export { SUGGESTIONS_CREATION_TEXT }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/constants.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/constants.ts new file mode 100644 index 000000000..85449ede5 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/constants.ts @@ -0,0 +1 @@ +export { SUGGESTIONS_CREATION_TEXT } from "./confirmation-buttons-text.constant.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/enums.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/enums.ts new file mode 100644 index 000000000..455ad5782 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/enums.ts @@ -0,0 +1 @@ +export { suggestionsCreationButtonLabel } from "./suggestions-creation-button-label.enum.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/suggestions-creation-button-label.enum.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/suggestions-creation-button-label.enum.ts new file mode 100644 index 000000000..eeb84bc2b --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/suggestions-creation-button-label.enum.ts @@ -0,0 +1,6 @@ +const suggestionsCreationButtonLabel = { + NO: "no, smth else", + YES: "yes, 3 lowest", +} as const; + +export { suggestionsCreationButtonLabel }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/helpers/get-three-lowest-scores.helper.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/helpers/get-three-lowest-scores.helper.ts similarity index 100% rename from apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/helpers/get-three-lowest-scores.helper.ts rename to apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/helpers/get-three-lowest-scores.helper.ts diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/helpers/helpers.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/helpers/helpers.ts similarity index 100% rename from apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/helpers/helpers.ts rename to apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/helpers/helpers.ts diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/styles.module.css b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/styles.module.css similarity index 100% rename from apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/styles.module.css rename to apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/styles.module.css diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/task-creation-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx similarity index 70% rename from apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/task-creation-options.tsx rename to apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx index ee6524fa7..fc3822ce0 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/task-creation-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx @@ -7,12 +7,12 @@ import { import { actions as chatActions } from "~/modules/chat/chat.js"; import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; -import { CONFIRMATION_BUTTONS_TEXT } from "./libs/constants/constants.js"; -import { selectCategoriesButtonLabel } from "./libs/enums/enums.js"; +import { SUGGESTIONS_CREATION_TEXT } from "./libs/constants/constants.js"; +import { suggestionsCreationButtonLabel } from "./libs/enums/enums.js"; import { getThreeLowestScores } from "./libs/helpers/helpers.js"; import styles from "./styles.module.css"; -const TaskCreationOptions: React.FC = () => { +const SuggestionsCreationOptions: React.FC = () => { const { scores, threadId } = useAppSelector((state) => ({ scores: state.quiz.scores, threadId: state.chat.threadId, @@ -20,8 +20,8 @@ const TaskCreationOptions: React.FC = () => { const dispatch = useAppDispatch(); const handleNo = useCallback(() => { - dispatch(chatActions.addAssistantTextMessage(CONFIRMATION_BUTTONS_TEXT)); - dispatch(chatActions.addUserTextMessage(selectCategoriesButtonLabel.NO)); + dispatch(chatActions.addAssistantTextMessage(SUGGESTIONS_CREATION_TEXT)); + dispatch(chatActions.addUserTextMessage(suggestionsCreationButtonLabel.NO)); dispatch(chatActions.setButtonsMode(buttonsModeOption.CATEGORIES_CHECKBOX)); }, [dispatch]); @@ -35,8 +35,10 @@ const TaskCreationOptions: React.FC = () => { }); dispatch(chatActions.setButtonsMode(buttonsModeOption.NONE)); - dispatch(chatActions.addAssistantTextMessage(CONFIRMATION_BUTTONS_TEXT)); - dispatch(chatActions.addUserTextMessage(selectCategoriesButtonLabel.YES)); + dispatch(chatActions.addAssistantTextMessage(SUGGESTIONS_CREATION_TEXT)); + dispatch( + chatActions.addUserTextMessage(suggestionsCreationButtonLabel.YES), + ); void dispatch( chatActions.getTasksForCategories({ @@ -51,15 +53,15 @@ const TaskCreationOptions: React.FC = () => {
    -

    {CONFIRMATION_BUTTONS_TEXT}

    +

    {SUGGESTIONS_CREATION_TEXT}

    +
    +
    + + ); +}; + +export { SuggestionsManipulationOptions }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/constants/constants.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/constants/constants.ts deleted file mode 100644 index 95c71a325..000000000 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/constants/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export { CONFIRMATION_BUTTONS_TEXT } from "./confirmation-buttons-text.constant.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/enums/enums.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/enums/enums.ts deleted file mode 100644 index e77e01408..000000000 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/enums/enums.ts +++ /dev/null @@ -1 +0,0 @@ -export { selectCategoriesButtonLabel } from "./select-categories-button-label.enum.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/enums/select-categories-button-label.enum.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/enums/select-categories-button-label.enum.ts deleted file mode 100644 index bd273a6bb..000000000 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/task-creation-options/libs/enums/select-categories-button-label.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -const selectCategoriesButtonLabel = { - NO: "no, smth else", - YES: "yes, 3 lowest", -} as const; - -export { selectCategoriesButtonLabel }; diff --git a/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts index 3850c93d9..a56fa88db 100644 --- a/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts +++ b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts @@ -1,7 +1,8 @@ const buttonsModeOption = { CATEGORIES_CHECKBOX: "categoriesCheckbox", NONE: "none", - TASK_CREATION: "taskGeneration", + SUGGESTIONS_CREATION: "suggestionsGeneration", + SUGGESTIONS_MANIPULATION: "suggestionsManipulation", } as const; export { buttonsModeOption }; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index b1cd45dc9..707876aee 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -44,8 +44,10 @@ export { type ValueOf, } from "./libs/types/types.js"; export { + acceptMultipleTasksValidationSchema, addMessageToThreadValidationSchema, AIAssistantApiPath, + type AIAssistantCreateMultipleTasksDto, type AIAssistantRequestDto, type AIAssistantResponseDto, type AIAssistantSuggestTaskRequestDto, diff --git a/packages/shared/src/modules/ai-assistant/ai-assistant.ts b/packages/shared/src/modules/ai-assistant/ai-assistant.ts index ac8200c14..4e73bf54a 100644 --- a/packages/shared/src/modules/ai-assistant/ai-assistant.ts +++ b/packages/shared/src/modules/ai-assistant/ai-assistant.ts @@ -1,10 +1,12 @@ export { AIAssistantApiPath } from "./libs/enums/enums.js"; export { + type AIAssistantCreateMultipleTasksDto, type AIAssistantRequestDto, type AIAssistantResponseDto, type AIAssistantSuggestTaskRequestDto, type ThreadMessageCreateDto, } from "./libs/types/types.js"; +export { acceptMultipleTasks as acceptMultipleTasksValidationSchema } from "./libs/validation-schemas/accept-multiple-tasks.validation-schema.js"; export { addMessageToThread as addMessageToThreadValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { taskSuggestionRequest as taskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; export { changeTaskSuggestionRequest as changeTaskSuggestionRequestValidationSchema } from "./libs/validation-schemas/validation-schemas.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts index 9eaa34b50..55f2a1622 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -1,4 +1,5 @@ const AIAssistantApiPath = { + CHAT_ACCEPT_MULTIPLE_TASKS: "/chat/accept-mutiple-tasks", CHAT_ACCEPT_TASK: "/chat/accept-task", CHAT_ADD_MESSAGE: "/chat/add-message", CHAT_CHANGE_TASK: "/chat/change-task", diff --git a/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-create-multiple-tasks-dto.type.ts b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-create-multiple-tasks-dto.type.ts new file mode 100644 index 000000000..160776a29 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/types/ai-assistant-create-multiple-tasks-dto.type.ts @@ -0,0 +1,8 @@ +import { type TaskCreateDto } from "../../../tasks/tasks.js"; + +type AIAssistantCreateMultipleTasksDto = { + payload: TaskCreateDto[]; + threadId: string; +}; + +export { type AIAssistantCreateMultipleTasksDto }; diff --git a/packages/shared/src/modules/ai-assistant/libs/types/types.ts b/packages/shared/src/modules/ai-assistant/libs/types/types.ts index 3f474c7c4..e0732d70e 100644 --- a/packages/shared/src/modules/ai-assistant/libs/types/types.ts +++ b/packages/shared/src/modules/ai-assistant/libs/types/types.ts @@ -1,3 +1,4 @@ +export { type AIAssistantCreateMultipleTasksDto } from "./ai-assistant-create-multiple-tasks-dto.type.js"; export { type AIAssistantRequestDto } from "./ai-assistant-request-dto.type.js"; export { type AIAssistantResponseDto } from "./ai-assistant-response-dto.type.js"; export { type AIAssistantSuggestTaskRequestDto } from "./ai-assistant-suggest-task-request-dto.js"; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/accept-multiple-tasks.validation-schema.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/accept-multiple-tasks.validation-schema.ts new file mode 100644 index 000000000..b69a5b0f5 --- /dev/null +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/accept-multiple-tasks.validation-schema.ts @@ -0,0 +1,42 @@ +import { z } from "zod"; + +import { + AIAssistantValidationMessage, + AIAssistantValidationRule, +} from "../enums/enums.js"; + +const acceptMultipleTasks = z.object({ + payload: z.array( + z.object({ + categoryId: z.number({ + invalid_type_error: AIAssistantValidationMessage.CATEGORY_ID_REQUIRED, + }), + categoryName: z + .string() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.CATEGORY_NAME_REQUIRED, + }), + description: z + .string() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.DESCRIPTION_REQUIRED, + }), + label: z + .string() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.LABEL_REQUIRED, + }), + }), + ), + threadId: z + .string() + .trim() + .min(AIAssistantValidationRule.NON_EMPTY_ITEM_MIN_LENGTH, { + message: AIAssistantValidationMessage.THREAD_ID_REQUIRED, + }) + .regex(AIAssistantValidationRule.THREAD_ID_VALID_CHARS, { + message: AIAssistantValidationMessage.THREAD_ID_INVALID_FORMAT, + }), +}); + +export { acceptMultipleTasks }; diff --git a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts index f342438ce..c85dfa29b 100644 --- a/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts +++ b/packages/shared/src/modules/ai-assistant/libs/validation-schemas/validation-schemas.ts @@ -1,3 +1,4 @@ +export { acceptMultipleTasks } from "./accept-multiple-tasks.validation-schema.js"; export { addMessageToThread } from "./add-message-to-thread.validation-schema.js"; export { changeTaskSuggestionRequest } from "./change-task-suggestion.validation-schema.js"; export { taskActionRequestSchema } from "./task-action-request.validation-schema.js"; diff --git a/packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts b/packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts index da2317eab..ee0288955 100644 --- a/packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts +++ b/packages/shared/src/modules/tasks/libs/types/task-create-dto.type.ts @@ -2,7 +2,6 @@ type TaskCreateDto = { categoryId: number; categoryName: string; description: string; - dueDate: string; label: string; }; export { type TaskCreateDto }; From 5f196b732749dc47122f3bf1cfd5dd85099d9c85 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Mon, 23 Sep 2024 21:25:02 +0300 Subject: [PATCH 201/244] feat: task suggestions are now in a single message bb-340 --- .../src/modules/chat/slices/chat.slice.ts | 32 +++++++++++++++++-- .../components/chat-message/chat-message.tsx | 9 ++++-- .../libs/components/components.ts | 1 + .../styles.module.css | 5 +++ .../task-suggestions-display.tsx | 24 ++++++++++++++ .../components/chat-message/styles.module.css | 2 +- .../frontend/src/pages/chat/styles.module.css | 4 +-- .../chats/libs/types/chat-message-dto.type.ts | 2 +- 8 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/components.ts create mode 100644 apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/styles.module.css create mode 100644 apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index fc463ec5c..3c6bceea1 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -9,8 +9,13 @@ import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { type ChatMessageDto, type TaskCreateDto, + type TaskMessage, } from "../libs/types/types.js"; -import { getTasksForCategories, initConversation } from "./actions.js"; +import { + createTasksFromSuggestions, + getTasksForCategories, + initConversation, +} from "./actions.js"; type State = { buttonsMode: ValueOf; @@ -33,6 +38,17 @@ const initialState: State = { const { actions, name, reducer } = createSlice({ extraReducers(builder) { builder + .addCase(createTasksFromSuggestions.pending, (state) => { + state.taskSuggestions = []; + state.dataStatus = DataStatus.PENDING; + }) + .addCase(createTasksFromSuggestions.fulfilled, (state) => { + state.dataStatus = DataStatus.FULFILLED; + }) + .addCase(createTasksFromSuggestions.rejected, (state) => { + state.dataStatus = DataStatus.FULFILLED; + }) + .addCase(initConversation.pending, (state) => { state.dataStatus = DataStatus.PENDING; }) @@ -44,17 +60,22 @@ const { actions, name, reducer } = createSlice({ .addCase(initConversation.rejected, (state) => { state.dataStatus = DataStatus.REJECTED; }) + .addCase(getTasksForCategories.pending, (state) => { state.dataStatus = DataStatus.PENDING; }) .addCase(getTasksForCategories.fulfilled, (state, action) => { state.dataStatus = DataStatus.FULFILLED; const newMessages = action.payload.messages; + const taskSuggestionsMessagePayload: TaskMessage[] = []; for (const message of newMessages) { - state.messages.push(message); + if ("text" in message.payload) { + state.messages.push(message); + } if ("task" in message.payload) { + taskSuggestionsMessagePayload.push(message.payload); state.taskSuggestions.push({ categoryId: message.payload.task.categoryId, categoryName: message.payload.task.categoryName, @@ -64,6 +85,13 @@ const { actions, name, reducer } = createSlice({ } } + state.messages.push({ + author: ChatMessageAuthor.ASSISTANT, + isRead: true, + payload: taskSuggestionsMessagePayload, + type: ChatMessageType.TASK, + }); + state.buttonsMode = buttonsModeOption.SUGGESTIONS_MANIPULATION; }) .addCase(getTasksForCategories.rejected, (state) => { diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx index 493e81392..5ca029f34 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/chat-message.tsx @@ -1,5 +1,5 @@ import defaultAvatar from "~/assets/img/default-avatar.png"; -import { Icon, TaskCard } from "~/libs/components/components.js"; +import { Icon } from "~/libs/components/components.js"; import { getValidClassNames } from "~/libs/helpers/helpers.js"; import { useAppSelector } from "~/libs/hooks/hooks.js"; import { type UserDto, type ValueOf } from "~/libs/types/types.js"; @@ -10,11 +10,12 @@ import { type TextMessage, } from "~/modules/chat/chat.js"; +import { TaskSuggestionsDisplay } from "./libs/components/components.js"; import styles from "./styles.module.css"; type Properties = { author: ValueOf; - payload: TaskMessage | TextMessage; + payload: TaskMessage | TaskMessage[] | TextMessage; type: ValueOf; }; @@ -63,7 +64,9 @@ const ChatMessage: React.FC = ({
  • - +
  • ); diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/components.ts b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/components.ts new file mode 100644 index 000000000..f8250c41d --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/components.ts @@ -0,0 +1 @@ +export { TaskSuggestionsDisplay } from "./task-suggestions-display/task-suggestions-display.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/styles.module.css b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/styles.module.css new file mode 100644 index 000000000..627f47b61 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/styles.module.css @@ -0,0 +1,5 @@ +.tasks-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; +} diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx new file mode 100644 index 000000000..13896d65d --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx @@ -0,0 +1,24 @@ +import { TaskCard } from "~/libs/components/components.js"; +import { type TaskMessage } from "~/modules/chat/chat.js"; + +import styles from "./styles.module.css"; + +type Properties = { + taskSuggestions: TaskMessage[]; +}; + +const TaskSuggestionsDisplay: React.FC = ({ + taskSuggestions, +}: Properties) => { + return ( +
    + {taskSuggestions.map((suggestion) => { + return ( + + ); + })} +
    + ); +}; + +export { TaskSuggestionsDisplay }; diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css index 840d9a9f8..b5433341d 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css @@ -15,7 +15,7 @@ display: flex; flex-direction: column; justify-content: center; - max-width: 730px; + max-width: 800px; padding: 15px; } diff --git a/apps/frontend/src/pages/chat/styles.module.css b/apps/frontend/src/pages/chat/styles.module.css index 4eb8f1665..07d60fae3 100644 --- a/apps/frontend/src/pages/chat/styles.module.css +++ b/apps/frontend/src/pages/chat/styles.module.css @@ -5,7 +5,5 @@ } .page-container { - display: flex; - justify-content: space-between; - padding: 24px; + padding: 24px 48px 24px 24px; } diff --git a/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts index a4fdda71a..0bbf2ed00 100644 --- a/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts +++ b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts @@ -13,7 +13,7 @@ type ChatMessageDto = { createdAt: string; id: number; isRead: boolean; - payload: TaskMessage | TextMessage; + payload: TaskMessage | TaskMessage[] | TextMessage; type: ValueOf; }; From 339e19aafb3c2851523def849e8a1bbdeeae487c Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Mon, 23 Sep 2024 21:26:46 +0300 Subject: [PATCH 202/244] refactor: merged main bb-340 --- apps/frontend/src/pages/chat/styles.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/pages/chat/styles.module.css b/apps/frontend/src/pages/chat/styles.module.css index 07d60fae3..daef2e9eb 100644 --- a/apps/frontend/src/pages/chat/styles.module.css +++ b/apps/frontend/src/pages/chat/styles.module.css @@ -5,5 +5,5 @@ } .page-container { - padding: 24px 48px 24px 24px; + padding: 24px 50px 24px 24px; } From 15bd65518a403a4603a151eb94ef5b0f6d11426c Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Mon, 23 Sep 2024 21:43:58 +0300 Subject: [PATCH 203/244] fix: changed task.category to task.categoryName in mobile task-card component bb-340 --- apps/mobile/src/libs/components/task-card/task-card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/libs/components/task-card/task-card.tsx b/apps/mobile/src/libs/components/task-card/task-card.tsx index 02c8d28da..c6d03a71f 100644 --- a/apps/mobile/src/libs/components/task-card/task-card.tsx +++ b/apps/mobile/src/libs/components/task-card/task-card.tsx @@ -52,7 +52,7 @@ const TaskCard: React.FC = ({ onComplete, onSkip, task }) => { globalStyles.pt16, ]} > - + {isActiveTask && } From 81b2006cb858da584e0a378e11774cb5fc57ecbb Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:08:51 +0300 Subject: [PATCH 204/244] refactor: removed comment and redundant type bb-340 --- apps/frontend/src/modules/chat/libs/types/types.ts | 1 - packages/shared/src/index.ts | 1 - packages/shared/src/modules/chats/chats.ts | 1 - .../src/modules/chats/libs/types/chat-message-dto.type.ts | 2 -- .../modules/chats/libs/types/chat-message-payload.type.ts | 6 ------ packages/shared/src/modules/chats/libs/types/types.ts | 1 - 6 files changed, 12 deletions(-) delete mode 100644 packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts index 7e5165ea0..a43c969c4 100644 --- a/apps/frontend/src/modules/chat/libs/types/types.ts +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -4,7 +4,6 @@ export { type AIAssistantResponseDto, type AIAssistantSuggestTaskRequestDto, type ChatMessageDto, - type ChatMessagePayload, type TaskCreateDto, type TaskDto, type TaskMessage, diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 707876aee..5591d00c0 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -76,7 +76,6 @@ export { export { ChatMessageAuthor, type ChatMessageDto, - type ChatMessagePayload, ChatMessageType, type TaskMessage, type TextMessage, diff --git a/packages/shared/src/modules/chats/chats.ts b/packages/shared/src/modules/chats/chats.ts index 3f5ac7b5a..88a02e1b6 100644 --- a/packages/shared/src/modules/chats/chats.ts +++ b/packages/shared/src/modules/chats/chats.ts @@ -1,7 +1,6 @@ export { ChatMessageAuthor, ChatMessageType } from "./libs/enums/enums.js"; export { type ChatMessageDto, - type ChatMessagePayload, type TaskMessage, type TextMessage, } from "./libs/types/types.js"; diff --git a/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts index 0bbf2ed00..611cf8983 100644 --- a/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts +++ b/packages/shared/src/modules/chats/libs/types/chat-message-dto.type.ts @@ -6,8 +6,6 @@ import { import { type TaskMessage } from "./task-message.type.js"; import { type TextMessage } from "./text.message.type.js"; -// type ChatMessagePayload = TaskMessage | TextMessage; - type ChatMessageDto = { author: ValueOf; createdAt: string; diff --git a/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts b/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts deleted file mode 100644 index 13a635e2a..000000000 --- a/packages/shared/src/modules/chats/libs/types/chat-message-payload.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type TaskMessage } from "./task-message.type.js"; -import { type TextMessage } from "./text.message.type.js"; - -type ChatMessagePayload = TaskMessage | TextMessage; - -export { type ChatMessagePayload }; diff --git a/packages/shared/src/modules/chats/libs/types/types.ts b/packages/shared/src/modules/chats/libs/types/types.ts index d1a7a01cb..cbfe08c12 100644 --- a/packages/shared/src/modules/chats/libs/types/types.ts +++ b/packages/shared/src/modules/chats/libs/types/types.ts @@ -1,4 +1,3 @@ export { type ChatMessageDto } from "./chat-message-dto.type.js"; -export { type ChatMessagePayload } from "./chat-message-payload.type.js"; export { type TaskMessage } from "./task-message.type.js"; export { type TextMessage } from "./text.message.type.js"; From ce483b32d8c2fda9ec24f35b227d00c789e1a7e9 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:12:32 +0300 Subject: [PATCH 205/244] refactor: removed unnecessary state variables extractions from chat component bb-340 --- apps/frontend/src/pages/chat/chat.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index c8c760b8b..39a8273fd 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -23,9 +23,6 @@ const Chat: React.FC = () => { const { messages, messageStatus, threadId } = useAppSelector((state) => ({ messages: state.chat.messages, messageStatus: state.chat.dataStatus, - quizCategories: state.categories.items, - scores: state.quiz.scores, - selectedCategories: state.chat.selectedCategories, threadId: state.chat.threadId, })); From 939b9353fa2d20d2948700a1d2b6b6f3cc3bf4d0 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:19:31 +0300 Subject: [PATCH 206/244] refactor: removed duplicate type imports bb-340 --- apps/frontend/src/modules/chat/libs/types/types.ts | 1 - apps/frontend/src/modules/chat/slices/chat.slice.ts | 3 ++- apps/frontend/src/pages/chat/chat.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts index a43c969c4..c30e80e69 100644 --- a/apps/frontend/src/modules/chat/libs/types/types.ts +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -5,7 +5,6 @@ export { type AIAssistantSuggestTaskRequestDto, type ChatMessageDto, type TaskCreateDto, - type TaskDto, type TaskMessage, type TaskPayload, type TextMessage, diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 3c6bceea1..609b4abb7 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -27,7 +27,7 @@ type State = { }; const initialState: State = { - buttonsMode: buttonsModeOption.SUGGESTIONS_CREATION, + buttonsMode: buttonsModeOption.NONE, dataStatus: DataStatus.IDLE, messages: [], selectedCategories: [], @@ -55,6 +55,7 @@ const { actions, name, reducer } = createSlice({ .addCase(initConversation.fulfilled, (state, action) => { state.threadId = action.payload.threadId; + state.buttonsMode = buttonsModeOption.SUGGESTIONS_CREATION; state.dataStatus = DataStatus.FULFILLED; }) .addCase(initConversation.rejected, (state) => { diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index 39a8273fd..acfabbcff 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -56,7 +56,7 @@ const Chat: React.FC = () => { /> ); })} - {threadId && } + {messageStatus === DataStatus.PENDING && }
    From 6c77a3ef38aec969ce55a9aa6b93843500909080 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:24:02 +0300 Subject: [PATCH 207/244] refactor: removed duplicate type imports bb-340 --- apps/frontend/src/modules/chat/chat.ts | 1 - apps/frontend/src/modules/chat/libs/types/types.ts | 1 - apps/frontend/src/modules/chat/slices/chat.slice.ts | 7 ++----- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/frontend/src/modules/chat/chat.ts b/apps/frontend/src/modules/chat/chat.ts index f7d6a006c..2f0a093c3 100644 --- a/apps/frontend/src/modules/chat/chat.ts +++ b/apps/frontend/src/modules/chat/chat.ts @@ -13,7 +13,6 @@ const chatApi = new ChatApi({ export { chatApi }; export { ChatMessageAuthor, ChatMessageType } from "./libs/enums/enums.js"; export { - type TaskCreateDto, type TaskMessage, type TaskPayload, type TextMessage, diff --git a/apps/frontend/src/modules/chat/libs/types/types.ts b/apps/frontend/src/modules/chat/libs/types/types.ts index c30e80e69..2ef57a8ca 100644 --- a/apps/frontend/src/modules/chat/libs/types/types.ts +++ b/apps/frontend/src/modules/chat/libs/types/types.ts @@ -4,7 +4,6 @@ export { type AIAssistantResponseDto, type AIAssistantSuggestTaskRequestDto, type ChatMessageDto, - type TaskCreateDto, type TaskMessage, type TaskPayload, type TextMessage, diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 609b4abb7..c49f83eab 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -4,13 +4,10 @@ import { DataStatus } from "~/libs/enums/enums.js"; import { type ValueOf } from "~/libs/types/types.js"; import { type SelectedCategory } from "~/modules/categories/categories.js"; import { ChatMessageAuthor, ChatMessageType } from "~/modules/chat/chat.js"; +import { type TaskCreateDto } from "~/modules/tasks/tasks.js"; import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; -import { - type ChatMessageDto, - type TaskCreateDto, - type TaskMessage, -} from "../libs/types/types.js"; +import { type ChatMessageDto, type TaskMessage } from "../libs/types/types.js"; import { createTasksFromSuggestions, getTasksForCategories, From 8111bd31387fe43602ae011d70e8ca88d4cccba2 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:26:47 +0300 Subject: [PATCH 208/244] refactor: changed AI assistant api pth enum bb-340 --- .../ai-assistant/libs/enums/ai-assistant-api-path.enum.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts index 55f2a1622..1abc97cb5 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -5,7 +5,7 @@ const AIAssistantApiPath = { CHAT_CHANGE_TASK: "/chat/change-task", CHAT_CONTINUE: "/chat/continue", CHAT_EXPLAIN_TASK: "/chat/explain-task", - CHAT_INITIATE: "/chat/initiate", + CHAT_INITIALIZE: "/chat/initialize", CHAT_SUGGEST_TASKS: "/chat/suggest-tasks", } as const; From c141df22f9cdff5b4c29e81902727b1641ce1d14 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:28:07 +0300 Subject: [PATCH 209/244] refactor: changed AI assistant api pth enum bb-340 --- .../backend/src/modules/ai-assistant/ai-assistant.controller.ts | 2 +- apps/frontend/src/modules/chat/chat-api.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index 2b5595aa5..f75f696fd 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -283,7 +283,7 @@ class AIAssistantController extends BaseController { }>, ), method: "POST", - path: AIAssistantApiPath.CHAT_INITIATE, + path: AIAssistantApiPath.CHAT_INITIALIZE, }); this.addRoute({ diff --git a/apps/frontend/src/modules/chat/chat-api.ts b/apps/frontend/src/modules/chat/chat-api.ts index eb7831d26..8d8f025e6 100644 --- a/apps/frontend/src/modules/chat/chat-api.ts +++ b/apps/frontend/src/modules/chat/chat-api.ts @@ -55,7 +55,7 @@ class ChatApi extends BaseHTTPApi { public async initiateConversation(): Promise { const response = await this.load( - this.getFullEndpoint(AIAssistantApiPath.CHAT_INITIATE, {}), + this.getFullEndpoint(AIAssistantApiPath.CHAT_INITIALIZE, {}), { contentType: ContentType.JSON, hasAuth: true, From 3317fefb4908bb41b937270141c55226b0613798 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:29:20 +0300 Subject: [PATCH 210/244] refactor: changed AI assistant api pth enum bb-340 --- .../backend/src/modules/ai-assistant/ai-assistant.controller.ts | 2 +- apps/frontend/src/modules/chat/chat-api.ts | 2 +- .../ai-assistant/libs/enums/ai-assistant-api-path.enum.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index f75f696fd..d5f52f272 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -354,7 +354,7 @@ class AIAssistantController extends BaseController { }>, ), method: "POST", - path: AIAssistantApiPath.CHAT_ACCEPT_MULTIPLE_TASKS, + path: AIAssistantApiPath.CHAT_ACCEPT_TASKS, validation: { body: acceptMultipleTasksValidationSchema, }, diff --git a/apps/frontend/src/modules/chat/chat-api.ts b/apps/frontend/src/modules/chat/chat-api.ts index 8d8f025e6..571f3b98b 100644 --- a/apps/frontend/src/modules/chat/chat-api.ts +++ b/apps/frontend/src/modules/chat/chat-api.ts @@ -25,7 +25,7 @@ class ChatApi extends BaseHTTPApi { payload: AIAssistantCreateMultipleTasksDto, ): Promise { const response = await this.load( - this.getFullEndpoint(AIAssistantApiPath.CHAT_ACCEPT_MULTIPLE_TASKS, {}), + this.getFullEndpoint(AIAssistantApiPath.CHAT_ACCEPT_TASKS, {}), { contentType: ContentType.JSON, hasAuth: true, diff --git a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts index 1abc97cb5..f6dd434f0 100644 --- a/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts +++ b/packages/shared/src/modules/ai-assistant/libs/enums/ai-assistant-api-path.enum.ts @@ -1,6 +1,6 @@ const AIAssistantApiPath = { - CHAT_ACCEPT_MULTIPLE_TASKS: "/chat/accept-mutiple-tasks", CHAT_ACCEPT_TASK: "/chat/accept-task", + CHAT_ACCEPT_TASKS: "/chat/accept-tasks", CHAT_ADD_MESSAGE: "/chat/add-message", CHAT_CHANGE_TASK: "/chat/change-task", CHAT_CONTINUE: "/chat/continue", From d90554f535fa37de7b265e84d3f483b429460ab8 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:46:18 +0300 Subject: [PATCH 211/244] refactor: renamed createMultipleTasks into create tasks bb-340 --- .../ai-assistant/ai-assistant.controller.ts | 52 +++++++++++++++---- .../ai-assistant/ai-assistant.service.ts | 48 ++++++++--------- 2 files changed, 66 insertions(+), 34 deletions(-) diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts index d5f52f272..f5bcc0c0b 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.controller.ts @@ -347,7 +347,7 @@ class AIAssistantController extends BaseController { this.addRoute({ handler: (options) => - this.acceptMultipleTasks( + this.acceptTasks( options as APIHandlerOptions<{ body: AIAssistantCreateMultipleTasksDto; user: UserDto; @@ -376,25 +376,56 @@ class AIAssistantController extends BaseController { }); } - private async acceptMultipleTasks( + /** + * @swagger + * /assistant/chat/accept-task: + * post: + * summary: Accept a task suggestion + * tags: + * - AI Assistant + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * threadId: + * type: string + * description: Identifier for the thread + * example: "thread_5kL0dVY9ADvmNz8U33P7qFX3" + * payload: + * $ref: '#/components/schemas/TaskPayload' + * responses: + * 200: + * description: Returns the accepted task + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Task' + */ + + private async acceptTask( options: APIHandlerOptions<{ - body: AIAssistantCreateMultipleTasksDto; + body: AIAssistantRequestDto; user: UserDto; }>, ): Promise { const { body, user } = options; return { - payload: await this.openAIService.acceptMultipleTasks(user, body), + payload: await this.openAIService.acceptTask(user, body), status: HTTPCode.OK, }; } /** * @swagger - * /assistant/chat/accept-task: + * /assistant/chat/accept-tasks: * post: - * summary: Accept a task suggestion + * summary: Accept task suggestions * tags: * - AI Assistant * security: @@ -404,7 +435,7 @@ class AIAssistantController extends BaseController { * content: * application/json: * schema: - * type: object + * type: array * properties: * threadId: * type: string @@ -421,16 +452,16 @@ class AIAssistantController extends BaseController { * $ref: '#/components/schemas/Task' */ - private async acceptTask( + private async acceptTasks( options: APIHandlerOptions<{ - body: AIAssistantRequestDto; + body: AIAssistantCreateMultipleTasksDto; user: UserDto; }>, ): Promise { const { body, user } = options; return { - payload: await this.openAIService.acceptTask(user, body), + payload: await this.openAIService.acceptTasks(user, body), status: HTTPCode.OK, }; } @@ -468,6 +499,7 @@ class AIAssistantController extends BaseController { * type: boolean * example: true */ + private async addMessageToConversation( options: APIHandlerOptions<{ body: ThreadMessageCreateDto; diff --git a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts index 14172e4da..27a1063cc 100644 --- a/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts +++ b/apps/backend/src/modules/ai-assistant/ai-assistant.service.ts @@ -49,7 +49,30 @@ class AIAssistantService { this.taskService = taskService; } - public async acceptMultipleTasks( + public async acceptTask( + user: UserDto, + body: AIAssistantRequestDto, + ): Promise { + const { payload, threadId } = body; + const task = payload as TaskCreateDto; + + const newTask = await this.taskService.create({ + categoryId: task.categoryId, + description: task.description, + label: task.label, + user, + }); + const chatMessage = { + content: `User has accepted this task: ${JSON.stringify(newTask)}`, + role: OpenAIRoleKey.USER, + }; + + await this.openAI.addMessageToThread(threadId, chatMessage); + + return newTask; + } + + public async acceptTasks( user: UserDto, body: AIAssistantCreateMultipleTasksDto, ): Promise { @@ -77,29 +100,6 @@ class AIAssistantService { ); } - public async acceptTask( - user: UserDto, - body: AIAssistantRequestDto, - ): Promise { - const { payload, threadId } = body; - const task = payload as TaskCreateDto; - - const newTask = await this.taskService.create({ - categoryId: task.categoryId, - description: task.description, - label: task.label, - user, - }); - const chatMessage = { - content: `User has accepted this task: ${JSON.stringify(newTask)}`, - role: OpenAIRoleKey.USER, - }; - - await this.openAI.addMessageToThread(threadId, chatMessage); - - return newTask; - } - public async addMessageToThread( body: ThreadMessageCreateDto, ): Promise { From 30d6d2d14cb77a081b41fa20d7a6b42d20514e2a Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 09:58:46 +0300 Subject: [PATCH 212/244] refactor: renamed ButtonsModeOption enum bb-340 --- apps/frontend/src/assets/css/scaffolding.css | 4 ---- .../src/libs/components/task-card/task-card.tsx | 12 +++--------- apps/frontend/src/modules/chat/slices/chat.slice.ts | 12 ++++++------ .../buttons-controller/buttons-controller.tsx | 8 ++++---- .../suggestions-creation-options.tsx | 6 +++--- .../suggestions-manipulation-options.tsx | 4 ++-- .../libs/components/chat-message/styles.module.css | 1 + .../chat/libs/enums/buttons-mode-option.enum.ts | 4 ++-- apps/frontend/src/pages/chat/libs/enums/enums.ts | 2 +- 9 files changed, 22 insertions(+), 31 deletions(-) diff --git a/apps/frontend/src/assets/css/scaffolding.css b/apps/frontend/src/assets/css/scaffolding.css index 2bbe8736f..dc2db551f 100644 --- a/apps/frontend/src/assets/css/scaffolding.css +++ b/apps/frontend/src/assets/css/scaffolding.css @@ -49,7 +49,3 @@ select { margin: 0; font-family: inherit; } - -li { - list-style: none; -} diff --git a/apps/frontend/src/libs/components/task-card/task-card.tsx b/apps/frontend/src/libs/components/task-card/task-card.tsx index 2edfa5da3..bd1c4cbe6 100644 --- a/apps/frontend/src/libs/components/task-card/task-card.tsx +++ b/apps/frontend/src/libs/components/task-card/task-card.tsx @@ -24,21 +24,15 @@ const TaskCard: React.FC = ({ variant = "active", }: Properties) => { const handleSkip = useCallback(() => { - if (onSkip) { - onSkip((task as TaskDto).id); - } + onSkip?.((task as TaskDto).id); }, [task, onSkip]); const handleComplete = useCallback(() => { - if (onComplete) { - onComplete((task as TaskDto).id); - } + onComplete?.((task as TaskDto).id); }, [task, onComplete]); const handleExpire = useCallback(() => { - if (onExpire) { - onExpire(task as TaskDto); - } + onExpire?.(task as TaskDto); }, [task, onExpire]); const isActive = (task as TaskDto).status === TaskStatus.CURRENT; diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index c49f83eab..879e04629 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -5,7 +5,7 @@ import { type ValueOf } from "~/libs/types/types.js"; import { type SelectedCategory } from "~/modules/categories/categories.js"; import { ChatMessageAuthor, ChatMessageType } from "~/modules/chat/chat.js"; import { type TaskCreateDto } from "~/modules/tasks/tasks.js"; -import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; +import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { type ChatMessageDto, type TaskMessage } from "../libs/types/types.js"; import { @@ -15,7 +15,7 @@ import { } from "./actions.js"; type State = { - buttonsMode: ValueOf; + buttonsMode: ValueOf; dataStatus: ValueOf; messages: Omit[]; selectedCategories: SelectedCategory[]; @@ -24,7 +24,7 @@ type State = { }; const initialState: State = { - buttonsMode: buttonsModeOption.NONE, + buttonsMode: ButtonsModeOption.NONE, dataStatus: DataStatus.IDLE, messages: [], selectedCategories: [], @@ -52,7 +52,7 @@ const { actions, name, reducer } = createSlice({ .addCase(initConversation.fulfilled, (state, action) => { state.threadId = action.payload.threadId; - state.buttonsMode = buttonsModeOption.SUGGESTIONS_CREATION; + state.buttonsMode = ButtonsModeOption.SUGGESTIONS_CREATION; state.dataStatus = DataStatus.FULFILLED; }) .addCase(initConversation.rejected, (state) => { @@ -90,7 +90,7 @@ const { actions, name, reducer } = createSlice({ type: ChatMessageType.TASK, }); - state.buttonsMode = buttonsModeOption.SUGGESTIONS_MANIPULATION; + state.buttonsMode = ButtonsModeOption.SUGGESTIONS_MANIPULATION; }) .addCase(getTasksForCategories.rejected, (state) => { state.dataStatus = DataStatus.REJECTED; @@ -121,7 +121,7 @@ const { actions, name, reducer } = createSlice({ }, setButtonsMode( state, - action: PayloadAction>, + action: PayloadAction>, ) { state.buttonsMode = action.payload; }, diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx index f967af4db..2f4e1002a 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/buttons-controller.tsx @@ -1,6 +1,6 @@ import { useAppSelector } from "~/libs/hooks/hooks.js"; -import { buttonsModeOption } from "../../enums/enums.js"; +import { ButtonsModeOption } from "../../enums/enums.js"; import { CategoriesSelector, SuggestionsCreationOptions, @@ -11,15 +11,15 @@ const ButtonsController: React.FC = () => { const buttonsMode = useAppSelector((state) => state.chat.buttonsMode); switch (buttonsMode) { - case buttonsModeOption.SUGGESTIONS_CREATION: { + case ButtonsModeOption.SUGGESTIONS_CREATION: { return ; } - case buttonsModeOption.SUGGESTIONS_MANIPULATION: { + case ButtonsModeOption.SUGGESTIONS_MANIPULATION: { return ; } - case buttonsModeOption.CATEGORIES_CHECKBOX: { + case ButtonsModeOption.CATEGORIES_CHECKBOX: { return ; } diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx index fc3822ce0..7516986b8 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx @@ -5,7 +5,7 @@ import { useCallback, } from "~/libs/hooks/hooks.js"; import { actions as chatActions } from "~/modules/chat/chat.js"; -import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; +import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { SUGGESTIONS_CREATION_TEXT } from "./libs/constants/constants.js"; import { suggestionsCreationButtonLabel } from "./libs/enums/enums.js"; @@ -22,7 +22,7 @@ const SuggestionsCreationOptions: React.FC = () => { const handleNo = useCallback(() => { dispatch(chatActions.addAssistantTextMessage(SUGGESTIONS_CREATION_TEXT)); dispatch(chatActions.addUserTextMessage(suggestionsCreationButtonLabel.NO)); - dispatch(chatActions.setButtonsMode(buttonsModeOption.CATEGORIES_CHECKBOX)); + dispatch(chatActions.setButtonsMode(ButtonsModeOption.CATEGORIES_CHECKBOX)); }, [dispatch]); const handleYes = useCallback(() => { @@ -34,7 +34,7 @@ const SuggestionsCreationOptions: React.FC = () => { }; }); - dispatch(chatActions.setButtonsMode(buttonsModeOption.NONE)); + dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); dispatch(chatActions.addAssistantTextMessage(SUGGESTIONS_CREATION_TEXT)); dispatch( chatActions.addUserTextMessage(suggestionsCreationButtonLabel.YES), diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx index 98fc57390..57e7f19b3 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx @@ -5,7 +5,7 @@ import { useCallback, } from "~/libs/hooks/hooks.js"; import { actions as chatActions } from "~/modules/chat/chat.js"; -import { buttonsModeOption } from "~/pages/chat/libs/enums/enums.js"; +import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { suggestionsManipulationButtonLabel, @@ -17,7 +17,7 @@ const SuggestionsManipulationOptions: React.FC = () => { const { taskSuggestions, threadId } = useAppSelector((state) => state.chat); const dispatch = useAppDispatch(); const handleAcceptAllSuggestions = useCallback(() => { - void dispatch(chatActions.setButtonsMode(buttonsModeOption.NONE)); + void dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); void dispatch( chatActions.addAssistantTextMessage( diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css index b5433341d..d91cf8017 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/styles.module.css @@ -1,6 +1,7 @@ .message-container { display: flex; gap: 10px; + list-style: none; } .message-container-assistant { diff --git a/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts index a56fa88db..625566567 100644 --- a/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts +++ b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts @@ -1,8 +1,8 @@ -const buttonsModeOption = { +const ButtonsModeOption = { CATEGORIES_CHECKBOX: "categoriesCheckbox", NONE: "none", SUGGESTIONS_CREATION: "suggestionsGeneration", SUGGESTIONS_MANIPULATION: "suggestionsManipulation", } as const; -export { buttonsModeOption }; +export { ButtonsModeOption }; diff --git a/apps/frontend/src/pages/chat/libs/enums/enums.ts b/apps/frontend/src/pages/chat/libs/enums/enums.ts index 278040a9d..6ed7961b1 100644 --- a/apps/frontend/src/pages/chat/libs/enums/enums.ts +++ b/apps/frontend/src/pages/chat/libs/enums/enums.ts @@ -1 +1 @@ -export { buttonsModeOption } from "./buttons-mode-option.enum.js"; +export { ButtonsModeOption } from "./buttons-mode-option.enum.js"; From 74adf2d3560ca945f45c8c14776a17548b0db15f Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 12:43:26 +0300 Subject: [PATCH 213/244] refactor: changed constant file name, changed enum name in suggestions-creation-options bb-340 --- .../src/modules/chat/slices/chat.slice.ts | 28 +++++++++++++++---- apps/frontend/src/pages/chat/chat.tsx | 4 +-- .../categories-selector.tsx | 4 +-- .../libs/constants/constants.ts | 2 +- ... => suggestions-creation-text.constant.ts} | 0 .../libs/enums/enums.ts | 2 +- .../suggestions-creation-button-label.enum.ts | 4 +-- .../suggestions-creation-options.tsx | 10 +++---- .../chats/libs/types/chat-message-dto.type.ts | 4 +-- 9 files changed, 38 insertions(+), 20 deletions(-) rename apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/{confirmation-buttons-text.constant.ts => suggestions-creation-text.constant.ts} (100%) diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 879e04629..6e5aac009 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -7,17 +7,30 @@ import { ChatMessageAuthor, ChatMessageType } from "~/modules/chat/chat.js"; import { type TaskCreateDto } from "~/modules/tasks/tasks.js"; import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; -import { type ChatMessageDto, type TaskMessage } from "../libs/types/types.js"; +import { + type ChatMessageDto, + type TaskMessage, + type TextMessage, +} from "../libs/types/types.js"; import { createTasksFromSuggestions, getTasksForCategories, initConversation, } from "./actions.js"; +const checkIsTask = ( + message: ChatMessageDto, +): message is ChatMessageDto => { + return message.type === "task"; +}; + type State = { buttonsMode: ValueOf; dataStatus: ValueOf; - messages: Omit[]; + messages: Omit< + ChatMessageDto, + "createdAt" | "id" + >[]; selectedCategories: SelectedCategory[]; taskSuggestions: TaskCreateDto[]; threadId: null | string; @@ -68,11 +81,16 @@ const { actions, name, reducer } = createSlice({ const taskSuggestionsMessagePayload: TaskMessage[] = []; for (const message of newMessages) { - if ("text" in message.payload) { - state.messages.push(message); + if (message.type === "text") { + state.messages.push({ + author: ChatMessageAuthor.ASSISTANT, + isRead: true, + payload: message.payload as TextMessage, + type: message.type, + }); } - if ("task" in message.payload) { + if (checkIsTask(message)) { taskSuggestionsMessagePayload.push(message.payload); state.taskSuggestions.push({ categoryId: message.payload.task.categoryId, diff --git a/apps/frontend/src/pages/chat/chat.tsx b/apps/frontend/src/pages/chat/chat.tsx index acfabbcff..226a129db 100644 --- a/apps/frontend/src/pages/chat/chat.tsx +++ b/apps/frontend/src/pages/chat/chat.tsx @@ -26,14 +26,14 @@ const Chat: React.FC = () => { threadId: state.chat.threadId, })); - const scrollToBottom = (): void => { + const handleScrollToBottom = (): void => { if (chatEnd.current) { chatEnd.current.scrollIntoView({ behavior: "smooth" }); } }; useEffect(() => { - scrollToBottom(); + handleScrollToBottom(); }, [messages]); useEffect(() => { diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/categories-selector/categories-selector.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/categories-selector/categories-selector.tsx index 24edd9781..f0ab1906b 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/categories-selector/categories-selector.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/categories-selector/categories-selector.tsx @@ -40,7 +40,7 @@ const CategoriesSelector: React.FC = () => { [dispatch, quizCategories, threadId], ); - const handleFormSubmitWrapper = useCallback( + const handleFormSubmit = useCallback( (categoryIds: number[]): void => { void handleCategoriesSubmit(categoryIds); }, @@ -55,7 +55,7 @@ const CategoriesSelector: React.FC = () => {
    diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/constants.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/constants.ts index 85449ede5..ca0c4270c 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/constants.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/constants.ts @@ -1 +1 @@ -export { SUGGESTIONS_CREATION_TEXT } from "./confirmation-buttons-text.constant.js"; +export { SUGGESTIONS_CREATION_TEXT } from "./suggestions-creation-text.constant.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/confirmation-buttons-text.constant.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/suggestions-creation-text.constant.ts similarity index 100% rename from apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/confirmation-buttons-text.constant.ts rename to apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/constants/suggestions-creation-text.constant.ts diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/enums.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/enums.ts index 455ad5782..7d6c6f80e 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/enums.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/enums.ts @@ -1 +1 @@ -export { suggestionsCreationButtonLabel } from "./suggestions-creation-button-label.enum.js"; +export { SuggestionsCreationButtonLabel } from "./suggestions-creation-button-label.enum.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/suggestions-creation-button-label.enum.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/suggestions-creation-button-label.enum.ts index eeb84bc2b..4b23b1680 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/suggestions-creation-button-label.enum.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/libs/enums/suggestions-creation-button-label.enum.ts @@ -1,6 +1,6 @@ -const suggestionsCreationButtonLabel = { +const SuggestionsCreationButtonLabel = { NO: "no, smth else", YES: "yes, 3 lowest", } as const; -export { suggestionsCreationButtonLabel }; +export { SuggestionsCreationButtonLabel }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx index 7516986b8..c6224a120 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-creation-options/suggestions-creation-options.tsx @@ -8,7 +8,7 @@ import { actions as chatActions } from "~/modules/chat/chat.js"; import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { SUGGESTIONS_CREATION_TEXT } from "./libs/constants/constants.js"; -import { suggestionsCreationButtonLabel } from "./libs/enums/enums.js"; +import { SuggestionsCreationButtonLabel } from "./libs/enums/enums.js"; import { getThreeLowestScores } from "./libs/helpers/helpers.js"; import styles from "./styles.module.css"; @@ -21,7 +21,7 @@ const SuggestionsCreationOptions: React.FC = () => { const handleNo = useCallback(() => { dispatch(chatActions.addAssistantTextMessage(SUGGESTIONS_CREATION_TEXT)); - dispatch(chatActions.addUserTextMessage(suggestionsCreationButtonLabel.NO)); + dispatch(chatActions.addUserTextMessage(SuggestionsCreationButtonLabel.NO)); dispatch(chatActions.setButtonsMode(ButtonsModeOption.CATEGORIES_CHECKBOX)); }, [dispatch]); @@ -37,7 +37,7 @@ const SuggestionsCreationOptions: React.FC = () => { dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); dispatch(chatActions.addAssistantTextMessage(SUGGESTIONS_CREATION_TEXT)); dispatch( - chatActions.addUserTextMessage(suggestionsCreationButtonLabel.YES), + chatActions.addUserTextMessage(SuggestionsCreationButtonLabel.YES), ); void dispatch( @@ -56,12 +56,12 @@ const SuggestionsCreationOptions: React.FC = () => {

    {SUGGESTIONS_CREATION_TEXT}

    From 203dfa63dd71f7bb69813a44e6ad3bd035fccb4b Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Tue, 24 Sep 2024 12:59:53 +0300 Subject: [PATCH 216/244] refactor: renamed enums inside of suggestions manipulation options component bb-340 --- .../libs/enums/enums.ts | 4 ++-- .../suggestions-manipulation-button-label.enum.ts | 4 ++-- .../suggestions-manipulation-messages.enum.ts | 4 ++-- .../suggestions-manipulation-options.tsx | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/enums.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/enums.ts index d180d200a..88af42674 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/enums.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/enums.ts @@ -1,2 +1,2 @@ -export { suggestionsManipulationButtonLabel } from "./suggestions-manipulation-button-label.enum.js"; -export { suggestionsManipulationMessages } from "./suggestions-manipulation-messages.enum.js"; +export { SuggestionsManipulationButtonLabel } from "./suggestions-manipulation-button-label.enum.js"; +export { SuggestionsManipulationMessages } from "./suggestions-manipulation-messages.enum.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts index 9f8c7ca79..4907a7d1a 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts @@ -1,5 +1,5 @@ -const suggestionsManipulationButtonLabel = { +const SuggestionsManipulationButtonLabel = { acceptTasks: "add these tasks", } as const; -export { suggestionsManipulationButtonLabel }; +export { SuggestionsManipulationButtonLabel }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-messages.enum.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-messages.enum.ts index 15d91a9cf..4ea4b46f3 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-messages.enum.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-messages.enum.ts @@ -1,6 +1,6 @@ -const suggestionsManipulationMessages = { +const SuggestionsManipulationMessages = { ACCEPT_TASKS_RESPONSE: "Way to go! I'll check up on you later.", MAIN_MESSAGE: "How do you like these tasks?", } as const; -export { suggestionsManipulationMessages }; +export { SuggestionsManipulationMessages }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx index 57e7f19b3..11b91feb7 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx @@ -8,8 +8,8 @@ import { actions as chatActions } from "~/modules/chat/chat.js"; import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { - suggestionsManipulationButtonLabel, - suggestionsManipulationMessages, + SuggestionsManipulationButtonLabel, + SuggestionsManipulationMessages, } from "./libs/enums/enums.js"; import styles from "./styles.module.css"; @@ -21,17 +21,17 @@ const SuggestionsManipulationOptions: React.FC = () => { void dispatch( chatActions.addAssistantTextMessage( - suggestionsManipulationMessages.MAIN_MESSAGE, + SuggestionsManipulationMessages.MAIN_MESSAGE, ), ); void dispatch( chatActions.addUserTextMessage( - suggestionsManipulationButtonLabel.acceptTasks, + SuggestionsManipulationButtonLabel.acceptTasks, ), ); void dispatch( chatActions.addAssistantTextMessage( - suggestionsManipulationMessages.ACCEPT_TASKS_RESPONSE, + SuggestionsManipulationMessages.ACCEPT_TASKS_RESPONSE, ), ); @@ -48,10 +48,10 @@ const SuggestionsManipulationOptions: React.FC = () => {
    -

    {suggestionsManipulationMessages.MAIN_MESSAGE}

    +

    {SuggestionsManipulationMessages.MAIN_MESSAGE}

    +
    +
    + + ); +}; + +export { DislikeSuggestionsOptions }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/constants.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/constants.ts new file mode 100644 index 000000000..80ea94caa --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/constants.ts @@ -0,0 +1,2 @@ +export { DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL } from "./dislike-all-suggestions-button-label.constant.js"; +export { DISLIKE_SUGGESTIONS_OPTIONS_TEXT } from "./dislike-suggestion-options-text.constant.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-all-suggestions-button-label.constant.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-all-suggestions-button-label.constant.ts new file mode 100644 index 000000000..435617471 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-all-suggestions-button-label.constant.ts @@ -0,0 +1,3 @@ +const DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL = "All of them"; + +export { DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts new file mode 100644 index 000000000..434a6e722 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts @@ -0,0 +1,3 @@ +const DISLIKE_SUGGESTIONS_OPTIONS_TEXT = "Which exact tasks do you dislike?"; + +export { DISLIKE_SUGGESTIONS_OPTIONS_TEXT }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/styles.module.css b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/styles.module.css new file mode 100644 index 000000000..2b5cf8a26 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/styles.module.css @@ -0,0 +1,32 @@ +.button-container { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + justify-content: center; + max-width: 280px; +} + +.message-container { + display: flex; + gap: 10px; +} + +.content-container { + display: flex; + flex-direction: column; + justify-content: center; + max-width: 730px; + padding: 15px; + background-color: var(--background-gray); + border-radius: 0 10px 10px; +} + +.content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 15px; + border-radius: 0 10px 10px; +} diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts index 1e752c5a6..f792b2067 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/libs/enums/suggestions-manipulation-button-label.enum.ts @@ -1,5 +1,6 @@ const SuggestionsManipulationButtonLabel = { - ACCEPT_TASKS: "add these tasks", + ACCEPT_TASKS: "Add these tasks", + DISLIKE_TASKS: "I don't like the tasks", } as const; export { SuggestionsManipulationButtonLabel }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx index 4a5f44573..b77d6791b 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/suggestions-manipulation-options.tsx @@ -19,6 +19,7 @@ const SuggestionsManipulationOptions: React.FC = () => { threadId: state.chat.threadId, })); const dispatch = useAppDispatch(); + const handleAcceptAllSuggestions = useCallback(() => { void dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); @@ -46,6 +47,24 @@ const SuggestionsManipulationOptions: React.FC = () => { ); }, [dispatch, taskSuggestions, threadId]); + const handleDislikeSuggestions = useCallback(() => { + void dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); + + void dispatch( + chatActions.addAssistantTextMessage( + SuggestionsManipulationMessage.MAIN_MESSAGE, + ), + ); + void dispatch( + chatActions.addUserTextMessage( + SuggestionsManipulationButtonLabel.DISLIKE_TASKS, + ), + ); + void dispatch( + chatActions.setButtonsMode(ButtonsModeOption.DISLIKE_SUGGESTIONS), + ); + }, [dispatch]); + return (
    @@ -58,6 +77,11 @@ const SuggestionsManipulationOptions: React.FC = () => { onClick={handleAcceptAllSuggestions} variant="secondary" /> +
    diff --git a/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts index 625566567..e9099a831 100644 --- a/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts +++ b/apps/frontend/src/pages/chat/libs/enums/buttons-mode-option.enum.ts @@ -1,5 +1,6 @@ const ButtonsModeOption = { CATEGORIES_CHECKBOX: "categoriesCheckbox", + DISLIKE_SUGGESTIONS: "dislikeSuggestions", NONE: "none", SUGGESTIONS_CREATION: "suggestionsGeneration", SUGGESTIONS_MANIPULATION: "suggestionsManipulation", diff --git a/apps/frontend/src/pages/root/components/user-wheel/user-wheel.tsx b/apps/frontend/src/pages/root/components/user-wheel/user-wheel.tsx index fa439ad83..70b45f895 100644 --- a/apps/frontend/src/pages/root/components/user-wheel/user-wheel.tsx +++ b/apps/frontend/src/pages/root/components/user-wheel/user-wheel.tsx @@ -20,7 +20,7 @@ import { } from "./libs/components/components.js"; import { getFormattedDate, - getLocalDatestring, + // getLocalDatestring, } from "./libs/helpers/helpers.js"; import { type WheelEditMode } from "./libs/types/types.js"; import styles from "./styles.module.css"; @@ -53,12 +53,16 @@ const UserWheel: React.FC = () => { : "My wheel results"; const lastWheelUpdateDate = scoresLastUpdatedAt - ? getFormattedDate( - new Date(getLocalDatestring(scoresLastUpdatedAt)), - "d MMM yyyy, EEEE", - ) + ? getFormattedDate(new Date(scoresLastUpdatedAt), "d MMM yyyy, EEEE") : null; + // const lastWheelUpdateDate = scoresLastUpdatedAt + // ? getFormattedDate( + // new Date(getLocalDatestring(scoresLastUpdatedAt)), + // "d MMM yyyy, EEEE", + // ) + // : null; + const handleEditing = useCallback(() => { setIsEditingModalOpen(true); }, []); diff --git a/package-lock.json b/package-lock.json index 83e9923f1..a4186b11d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ } }, "apps/backend": { - "version": "1.26.0", + "version": "1.27.0", "dependencies": { "@aws-sdk/client-s3": "3.637.0", "@fastify/multipart": "8.3.0", @@ -92,7 +92,7 @@ } }, "apps/frontend": { - "version": "1.44.0", + "version": "1.45.0", "dependencies": { "@hookform/resolvers": "3.9.0", "@reduxjs/toolkit": "2.2.7", @@ -19665,7 +19665,7 @@ } }, "packages/shared": { - "version": "1.27.0", + "version": "1.28.0", "dependencies": { "date-fns": "3.6.0", "zod": "3.23.8" From 8a2a4889652afe7d8223c0e32d49a69c14dacf63 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Wed, 25 Sep 2024 16:42:15 +0300 Subject: [PATCH 232/244] feat: added regeneration of all task suggestions, fixed tasks grid css bb-340 --- apps/frontend/src/modules/chat/chat-api.ts | 17 +++++++++ .../src/modules/chat/slices/actions.ts | 18 +++++++++- .../src/modules/chat/slices/chat.slice.ts | 35 +++++++++++++++++++ apps/frontend/src/modules/chat/slices/chat.ts | 2 ++ .../dislike-suggestions-options.tsx | 29 +++++++++++++++ ...islike-suggestion-options-text.constant.ts | 2 +- .../styles.module.css | 2 +- .../styles.module.css | 2 +- .../task-suggestions-display.tsx | 9 ++++- 9 files changed, 111 insertions(+), 5 deletions(-) diff --git a/apps/frontend/src/modules/chat/chat-api.ts b/apps/frontend/src/modules/chat/chat-api.ts index 2295cfc6e..4087f9d60 100644 --- a/apps/frontend/src/modules/chat/chat-api.ts +++ b/apps/frontend/src/modules/chat/chat-api.ts @@ -5,6 +5,7 @@ import { type APIConfiguration } from "~/libs/types/types.js"; import { AIAssistantApiPath } from "./libs/enums/enums.js"; import { type AIAssistantCreateMultipleTasksDto, + type AIAssistantRequestDto, type AIAssistantResponseDto, type AIAssistantSuggestTaskRequestDto, } from "./libs/types/types.js"; @@ -14,6 +15,22 @@ class ChatApi extends BaseHTTPApi { super({ baseUrl, http, path: APIPath.ASSISTANT, storage }); } + public async changeTasksSuggestion( + payload: AIAssistantRequestDto, + ): Promise { + const response = await this.load( + this.getFullEndpoint(AIAssistantApiPath.CHAT_CHANGE_TASKS, {}), + { + contentType: ContentType.JSON, + hasAuth: true, + method: "POST", + payload: JSON.stringify(payload), + }, + ); + + return await response.json(); + } + public async createTasksFromSuggestions( payload: AIAssistantCreateMultipleTasksDto, ): Promise { diff --git a/apps/frontend/src/modules/chat/slices/actions.ts b/apps/frontend/src/modules/chat/slices/actions.ts index e162f2493..8399a5c3c 100644 --- a/apps/frontend/src/modules/chat/slices/actions.ts +++ b/apps/frontend/src/modules/chat/slices/actions.ts @@ -4,6 +4,7 @@ import { type AsyncThunkConfig } from "~/libs/types/types.js"; import { type AIAssistantCreateMultipleTasksDto, + type AIAssistantRequestDto, type AIAssistantResponseDto, type AIAssistantSuggestTaskRequestDto, } from "../libs/types/types.js"; @@ -39,4 +40,19 @@ const createTasksFromSuggestions = createAsyncThunk< return await chatApi.createTasksFromSuggestions(payload); }); -export { createTasksFromSuggestions, getTasksForCategories, initConversation }; +const changeTasksSuggestion = createAsyncThunk< + AIAssistantResponseDto, + AIAssistantRequestDto, + AsyncThunkConfig +>(`${sliceName}/change-tasks-suggestion`, async (payload, { extra }) => { + const { chatApi } = extra; + + return await chatApi.changeTasksSuggestion(payload); +}); + +export { + changeTasksSuggestion, + createTasksFromSuggestions, + getTasksForCategories, + initConversation, +}; diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index dcb42687a..4b86c0d21 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -14,6 +14,7 @@ import { type TextMessage, } from "../libs/types/types.js"; import { + changeTasksSuggestion, createTasksFromSuggestions, getTasksForCategories, initConversation, @@ -107,6 +108,40 @@ const { actions, name, reducer } = createSlice({ }) .addCase(getTasksForCategories.rejected, (state) => { state.dataStatus = DataStatus.REJECTED; + }) + + .addCase(changeTasksSuggestion.pending, (state) => { + state.dataStatus = DataStatus.PENDING; + }) + .addCase(changeTasksSuggestion.fulfilled, (state, action) => { + state.dataStatus = DataStatus.FULFILLED; + const newMessages = action.payload.messages; + state.taskSuggestions = []; + const newTaskSuggestions: TaskMessage[] = []; + + for (const message of newMessages) { + if (checkIsTaskMessage(message)) { + newTaskSuggestions.push(message.payload); + state.taskSuggestions.push({ + categoryId: message.payload.task.categoryId, + categoryName: message.payload.task.categoryName, + description: message.payload.task.description, + label: message.payload.task.label, + }); + } + } + + state.messages.push({ + author: ChatMessageAuthor.ASSISTANT, + isRead: true, + payload: newTaskSuggestions, + type: ChatMessageType.TASK, + }); + + state.buttonsMode = ButtonsModeOption.SUGGESTIONS_MANIPULATION; + }) + .addCase(changeTasksSuggestion.rejected, (state) => { + state.dataStatus = DataStatus.REJECTED; }); }, initialState, diff --git a/apps/frontend/src/modules/chat/slices/chat.ts b/apps/frontend/src/modules/chat/slices/chat.ts index 7e0ae7055..4bf677fbb 100644 --- a/apps/frontend/src/modules/chat/slices/chat.ts +++ b/apps/frontend/src/modules/chat/slices/chat.ts @@ -1,4 +1,5 @@ import { + changeTasksSuggestion, createTasksFromSuggestions, getTasksForCategories, initConversation, @@ -7,6 +8,7 @@ import { actions } from "./chat.slice.js"; const allActions = { ...actions, + changeTasksSuggestion, createTasksFromSuggestions, getTasksForCategories, initConversation, diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx index 6b7d55287..b33cf1578 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx @@ -1,4 +1,11 @@ import { Button, Icon } from "~/libs/components/components.js"; +import { + useAppDispatch, + useAppSelector, + useCallback, +} from "~/libs/hooks/hooks.js"; +import { actions as chatActions } from "~/modules/chat/chat.js"; +import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; import { DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL, @@ -7,6 +14,27 @@ import { import styles from "./styles.module.css"; const DislikeSuggestionsOptions: React.FC = () => { + const { taskSuggestions, threadId } = useAppSelector((state) => ({ + taskSuggestions: state.chat.taskSuggestions, + threadId: state.chat.threadId, + })); + const dispatch = useAppDispatch(); + const handleRegenerateAllSuggestions = useCallback(() => { + dispatch( + chatActions.addAssistantTextMessage(DISLIKE_SUGGESTIONS_OPTIONS_TEXT), + ); + dispatch( + chatActions.addUserTextMessage(DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL), + ); + dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); + void dispatch( + chatActions.changeTasksSuggestion({ + payload: taskSuggestions, + threadId: threadId as string, + }), + ); + }, [dispatch, threadId, taskSuggestions]); + return (
    @@ -16,6 +44,7 @@ const DislikeSuggestionsOptions: React.FC = () => {
    diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts index 434a6e722..2cbf61c34 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts @@ -1,3 +1,3 @@ -const DISLIKE_SUGGESTIONS_OPTIONS_TEXT = "Which exact tasks do you dislike?"; +const DISLIKE_SUGGESTIONS_OPTIONS_TEXT = "Which tasks do you dislike?"; export { DISLIKE_SUGGESTIONS_OPTIONS_TEXT }; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/styles.module.css b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/styles.module.css index 2b5cf8a26..ab4217665 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/styles.module.css +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/styles.module.css @@ -25,8 +25,8 @@ .content { display: flex; flex-direction: column; + gap: 10px; align-items: center; justify-content: center; - padding: 15px; border-radius: 0 10px 10px; } diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/styles.module.css b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/styles.module.css index 2b5cf8a26..ab4217665 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/styles.module.css +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/suggestions-manipulation-options/styles.module.css @@ -25,8 +25,8 @@ .content { display: flex; flex-direction: column; + gap: 10px; align-items: center; justify-content: center; - padding: 15px; border-radius: 0 10px 10px; } diff --git a/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx index 13896d65d..09b420bc4 100644 --- a/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx +++ b/apps/frontend/src/pages/chat/libs/components/chat-message/libs/components/task-suggestions-display/task-suggestions-display.tsx @@ -1,4 +1,6 @@ import { TaskCard } from "~/libs/components/components.js"; +import { NumericalValue } from "~/libs/enums/enums.js"; +import { getValidClassNames } from "~/libs/helpers/helpers.js"; import { type TaskMessage } from "~/modules/chat/chat.js"; import styles from "./styles.module.css"; @@ -10,8 +12,13 @@ type Properties = { const TaskSuggestionsDisplay: React.FC = ({ taskSuggestions, }: Properties) => { + const hasMultipleSuggestions = taskSuggestions.length > NumericalValue.ONE; + const tasksGridStyle = getValidClassNames( + hasMultipleSuggestions ? styles["tasks-grid"] : "", + ); + return ( -
    +
    {taskSuggestions.map((suggestion) => { return ( From a110302d6e033a252c5df25d4b681297de0fc910 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Wed, 25 Sep 2024 16:45:21 +0300 Subject: [PATCH 233/244] refactor: renamed a variable in chat slice bb-340 --- apps/frontend/src/modules/chat/slices/chat.slice.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/modules/chat/slices/chat.slice.ts b/apps/frontend/src/modules/chat/slices/chat.slice.ts index 4b86c0d21..6803b519e 100644 --- a/apps/frontend/src/modules/chat/slices/chat.slice.ts +++ b/apps/frontend/src/modules/chat/slices/chat.slice.ts @@ -117,11 +117,11 @@ const { actions, name, reducer } = createSlice({ state.dataStatus = DataStatus.FULFILLED; const newMessages = action.payload.messages; state.taskSuggestions = []; - const newTaskSuggestions: TaskMessage[] = []; + const newTasks: TaskMessage[] = []; for (const message of newMessages) { if (checkIsTaskMessage(message)) { - newTaskSuggestions.push(message.payload); + newTasks.push(message.payload); state.taskSuggestions.push({ categoryId: message.payload.task.categoryId, categoryName: message.payload.task.categoryName, @@ -134,7 +134,7 @@ const { actions, name, reducer } = createSlice({ state.messages.push({ author: ChatMessageAuthor.ASSISTANT, isRead: true, - payload: newTaskSuggestions, + payload: newTasks, type: ChatMessageType.TASK, }); From 076ae71babf77dab195b71e3e8c8b77312ca6041 Mon Sep 17 00:00:00 2001 From: ihorLysak Date: Wed, 25 Sep 2024 16:54:04 +0300 Subject: [PATCH 234/244] feat: added messages dispatching to regenerate suggestions bb-340 --- .../dislike-suggestions-options.tsx | 13 +++++++------ .../libs/constants/constants.ts | 1 - .../dislike-suggestion-options-text.constant.ts | 3 --- .../libs/enums/dislike-suggestion-message.enum.ts | 5 +++++ .../dislike-suggetsions-options/libs/enums/enums.ts | 1 + 5 files changed, 13 insertions(+), 10 deletions(-) delete mode 100644 apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/constants/dislike-suggestion-options-text.constant.ts create mode 100644 apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/enums/dislike-suggestion-message.enum.ts create mode 100644 apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/enums/enums.ts diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx index b33cf1578..23cdfda76 100644 --- a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/dislike-suggestions-options.tsx @@ -7,10 +7,8 @@ import { import { actions as chatActions } from "~/modules/chat/chat.js"; import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; -import { - DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL, - DISLIKE_SUGGESTIONS_OPTIONS_TEXT, -} from "./libs/constants/constants.js"; +import { DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL } from "./libs/constants/constants.js"; +import { DislikeSuggestionMessage } from "./libs/enums/enums.js"; import styles from "./styles.module.css"; const DislikeSuggestionsOptions: React.FC = () => { @@ -21,11 +19,14 @@ const DislikeSuggestionsOptions: React.FC = () => { const dispatch = useAppDispatch(); const handleRegenerateAllSuggestions = useCallback(() => { dispatch( - chatActions.addAssistantTextMessage(DISLIKE_SUGGESTIONS_OPTIONS_TEXT), + chatActions.addAssistantTextMessage(DislikeSuggestionMessage.MAIN), ); dispatch( chatActions.addUserTextMessage(DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL), ); + dispatch( + chatActions.addAssistantTextMessage(DislikeSuggestionMessage.WAIT), + ); dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); void dispatch( chatActions.changeTasksSuggestion({ @@ -40,7 +41,7 @@ const DislikeSuggestionsOptions: React.FC = () => {
    -

    {DISLIKE_SUGGESTIONS_OPTIONS_TEXT}

    +

    {DislikeSuggestionMessage.MAIN}

    diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/components/components.ts b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/components/components.ts new file mode 100644 index 000000000..6f30c39a5 --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/components/components.ts @@ -0,0 +1 @@ +export { RegenerateSuggestionButton } from "./regenarate-suggestion-button/regenerate-suggestion-button.js"; diff --git a/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/components/regenarate-suggestion-button/regenerate-suggestion-button.tsx b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/components/regenarate-suggestion-button/regenerate-suggestion-button.tsx new file mode 100644 index 000000000..78cdde3dc --- /dev/null +++ b/apps/frontend/src/pages/chat/libs/components/buttons-controller/libs/components/dislike-suggetsions-options/libs/components/regenarate-suggestion-button/regenerate-suggestion-button.tsx @@ -0,0 +1,51 @@ +import { Button } from "~/libs/components/components.js"; +import { useAppDispatch, useCallback } from "~/libs/hooks/hooks.js"; +import { actions as chatActions } from "~/modules/chat/chat.js"; +import { type TaskCreateDto } from "~/modules/tasks/tasks.js"; +import { ButtonsModeOption } from "~/pages/chat/libs/enums/enums.js"; + +import { DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL } from "../../constants/constants.js"; +import { DislikeSuggestionMessage } from "../../enums/enums.js"; + +type Properties = { + label: string; + suggestion: TaskCreateDto; + threadId: string; +}; + +const RegenerateSuggestionButton: React.FC = ({ + label, + suggestion, + threadId, +}: Properties) => { + const dispatch = useAppDispatch(); + + const handleRegenerateSuggestion = useCallback(() => { + dispatch( + chatActions.addAssistantTextMessage(DislikeSuggestionMessage.MAIN), + ); + dispatch( + chatActions.addUserTextMessage(DISLIKE_ALL_SUGGESTIONS_BUTTON_LABEL), + ); + dispatch( + chatActions.addAssistantTextMessage(DislikeSuggestionMessage.WAIT), + ); + dispatch(chatActions.setButtonsMode(ButtonsModeOption.NONE)); + void dispatch( + chatActions.changeTasksSuggestion({ + payload: [suggestion], + threadId, + }), + ); + }, [dispatch, threadId, suggestion]); + + return ( +