@ozdao/martyrs 0.2.568 → 0.2.569
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/martyrs/src/components/Button/{Button.vue2.js → Button.vue.js} +3 -3
- package/dist/martyrs/src/components/Button/Button.vue.js.map +1 -0
- package/dist/martyrs/src/components/EditImages/{EditImages.vue.js → EditImages.vue2.js} +2 -2
- package/dist/martyrs/src/components/EditImages/EditImages.vue2.js.map +1 -0
- package/dist/martyrs/src/components/Feed/Carousel.vue.js +1 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.js +2 -2
- package/dist/martyrs/src/components/FieldBig/FieldBig.vue.js +1 -1
- package/dist/martyrs/src/components/Loader/{Loader.vue.js → Loader.vue2.js} +2 -2
- package/dist/martyrs/src/components/Loader/Loader.vue2.js.map +1 -0
- package/dist/martyrs/src/components/LocationMarker/LocationMarker.vue.js +1 -1
- package/dist/martyrs/src/components/Media/Media.vue.js +1 -1
- package/dist/martyrs/src/components/Select/{Select.vue.js → Select.vue2.js} +2 -2
- package/dist/martyrs/src/components/Select/Select.vue2.js.map +1 -0
- package/dist/martyrs/src/components/UploadImage/UploadImage.vue.js +1 -1
- package/dist/martyrs/src/components/UploadImageMultiple/UploadImageMultiple.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/EnterPassword.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditAccount.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditProfile.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ResetPassword.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignUp.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/sections/ProfileEditCredentials.vue.js +1 -1
- package/dist/martyrs/src/modules/community/components/layouts/Community.vue.js +1 -1
- package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js +2 -2
- package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +1 -1
- package/dist/martyrs/src/modules/core/views/components/blocks/CardHeader.vue.js +1 -1
- package/dist/martyrs/src/modules/core/views/components/blocks/PopupAuth.vue.js +1 -1
- package/dist/martyrs/src/modules/core/views/components/blocks/PopupDateSelector.vue.js +2 -2
- package/dist/martyrs/src/modules/core/views/components/layouts/Client.vue.js +2 -2
- package/dist/martyrs/src/modules/core/views/components/partials/Header.vue.js +2 -2
- package/dist/martyrs/src/modules/core/views/components/partials/NavigationBar.vue.js +1 -1
- package/dist/martyrs/src/modules/core/views/components/sections/{Filters.vue.js → Filters.vue2.js} +2 -2
- package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue2.js.map +1 -0
- package/dist/martyrs/src/modules/events/components/elements/ButtonCheck.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/elements/ButtonJoin.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +3 -3
- package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +2 -2
- package/dist/martyrs/src/modules/events/components/sections/EditTickets.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/sections/Feed.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/sections/List.vue.js +1 -1
- package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +3 -3
- package/dist/martyrs/src/modules/inventory/components/forms/AdjustmentForm.vue.js +2 -2
- package/dist/martyrs/src/modules/inventory/components/forms/ColumnSettingsMenu.vue.js +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/HistoryView.vue.js +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/StockAlertsForm.vue.js +2 -2
- package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/blocks/ActionButtons.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/cards/PlaylistCard.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/forms/AlbumForm.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/forms/ArtistForm.vue.js +3 -3
- package/dist/martyrs/src/modules/music/components/forms/PlaylistForm.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/pages/TrackCreate.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/player/PlayerControls.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/forms/FormApplicationDetails.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/forms/FormCustomerDetails.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/forms/FormSelectCustomer.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/ApplicationDetails.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/CustomerDetails.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/elements/ButtonToggleMembership.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/forms/AddExistingMembersForm.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/forms/DepartmentForm.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/forms/InviteForm.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/sections/Documents.vue.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/sections/MembersAdd.vue.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +2 -2
- package/dist/martyrs/src/modules/pages/views/components/blocks/CardPage.vue.js +1 -1
- package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/pages/views/components/partials/SidebarPages.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/elements/Image360.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +4 -4
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +3 -3
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditAttributes.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditDiscounts.vue.js +2 -2
- package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.js +3 -3
- package/dist/martyrs/src/modules/products/components/sections/ProductConfigurator.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/ProductsRecommended.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js +25 -38
- package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/products.client.js +15 -21
- package/dist/martyrs/src/modules/products/products.client.js.map +1 -1
- package/dist/martyrs/src/modules/products/router/products.router.js +0 -34
- package/dist/martyrs/src/modules/products/router/products.router.js.map +1 -1
- package/dist/martyrs/src/modules/products/store/products.js +0 -15
- package/dist/martyrs/src/modules/products/store/products.js.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/reports/components/sections/FormReport.vue.js +2 -2
- package/dist/martyrs/src/modules/spots/components/blocks/SpotMemberModify.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/Map.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/wallet/views/components/blocks/CryptoDeposit.vue.js +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/pages/Wallet.vue.js +2 -2
- package/dist/products.server.js +1 -130
- package/dist/style.css +0 -23
- package/package.json +1 -1
- package/src/modules/products/components/sections/SectionProduct.vue +2 -9
- package/src/modules/products/controllers/products.controller.js +0 -51
- package/src/modules/products/experiments/product-recommendation/README.md +156 -0
- package/src/modules/products/experiments/product-recommendation/controllers/recommendation.controller.js +59 -0
- package/src/modules/products/experiments/product-recommendation/router/recommendation.router.js +43 -0
- package/src/modules/products/experiments/product-recommendation/routes/recommendation.routes.js +10 -0
- package/src/modules/products/experiments/product-recommendation/store/recommendation.store.js +38 -0
- package/src/modules/products/products.client.js +0 -6
- package/src/modules/products/products.router.js +0 -29
- package/src/modules/products/router/products.router.js +0 -28
- package/src/modules/products/routes/products.routes.js +0 -2
- package/src/modules/products/store/products.js +0 -16
- package/dist/martyrs/src/components/Button/Button.vue2.js.map +0 -1
- package/dist/martyrs/src/components/EditImages/EditImages.vue.js.map +0 -1
- package/dist/martyrs/src/components/Loader/Loader.vue.js.map +0 -1
- package/dist/martyrs/src/components/Select/Select.vue.js.map +0 -1
- package/dist/martyrs/src/components/Shader/Shader.vue.js +0 -2
- package/dist/martyrs/src/components/Shader/Shader.vue.js.map +0 -1
- package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js.map +0 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductRecommmendation.vue.js +0 -106
- package/dist/martyrs/src/modules/products/components/pages/ProductRecommmendation.vue.js.map +0 -1
- package/dist/martyrs/src/modules/products/components/sections/HeroRecommendation.vue.js +0 -120
- package/dist/martyrs/src/modules/products/components/sections/HeroRecommendation.vue.js.map +0 -1
- /package/src/modules/products/{components/sections → experiments/product-recommendation/components}/HeroRecommendation.vue +0 -0
- /package/src/modules/products/{components/pages → experiments/product-recommendation/components}/ProductRecommmendation.vue +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { computed, ref, watch, createElementBlock, openBlock, createElementVNode, createVNode, withCtx, createTextVNode } from "vue";
|
|
2
2
|
import dayjs from "../../../../../../../../_virtual/dayjs.min.js";
|
|
3
3
|
import _sfc_main$2 from "../../../../../../components/Tab/Tab.vue2.js";
|
|
4
|
-
import _sfc_main$3 from "../../../../../../components/Button/Button.
|
|
4
|
+
import _sfc_main$3 from "../../../../../../components/Button/Button.vue.js";
|
|
5
5
|
import _sfc_main$4 from "../../../../../../components/Dropdown/Dropdown.vue.js";
|
|
6
6
|
import Calendar from "../../../../../../components/Calendar/Calendar.vue2.js";
|
|
7
7
|
import _sfc_main$1 from "./DateLabel.vue.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ref, computed, onMounted, createElementBlock, openBlock, createElementVNode, createVNode, toDisplayString, unref, withCtx, Fragment, renderList, createBlock, createCommentVNode, createTextVNode } from "vue";
|
|
2
2
|
import _sfc_main$4 from "../../../../../components/Block/Block.vue.js";
|
|
3
|
-
import _sfc_main$5 from "../../../../../components/Button/Button.
|
|
3
|
+
import _sfc_main$5 from "../../../../../components/Button/Button.vue.js";
|
|
4
4
|
import Field from "../../../../../components/Field/Field.vue.js";
|
|
5
5
|
import _sfc_main$2 from "../../../../../components/Feed/Feed.vue.js";
|
|
6
6
|
import _sfc_main$1 from "../../../../../components/Popup/Popup.vue.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { reactive, ref, createElementBlock, openBlock, renderSlot, createVNode, withCtx, createElementVNode, createTextVNode } from "vue";
|
|
2
2
|
import _sfc_main$1 from "../../../../components/Popup/Popup.vue.js";
|
|
3
|
-
import _sfc_main$2 from "../../../../components/Button/Button.
|
|
4
|
-
import Select from "../../../../components/Select/Select.
|
|
3
|
+
import _sfc_main$2 from "../../../../components/Button/Button.vue.js";
|
|
4
|
+
import Select from "../../../../components/Select/Select.vue2.js";
|
|
5
5
|
import { actions } from "../../store/reports.js";
|
|
6
6
|
const _sfc_main = {
|
|
7
7
|
__name: "FormReport",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ref, computed, resolveComponent, createElementBlock, openBlock, createElementVNode, createCommentVNode, createBlock, toDisplayString } from "vue";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../../../../../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
-
/* empty css
|
|
4
|
+
/* empty css */
|
|
5
5
|
/* empty css */
|
|
6
6
|
const _hoisted_1 = { class: "br-grey-transp-25 radius-small mn-b-small" };
|
|
7
7
|
const _hoisted_2 = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ref, onMounted, createElementBlock, openBlock, createElementVNode, createVNode, withCtx, createTextVNode } from "vue";
|
|
2
2
|
import { useRouter, useRoute } from "vue-router";
|
|
3
3
|
import { Loader } from "../../../../../../node_modules/.pnpm/@googlemaps_js-api-loader@1.16.8/node_modules/@googlemaps/js-api-loader/dist/index.js";
|
|
4
|
-
import _sfc_main$1 from "../../../../components/Button/Button.
|
|
4
|
+
import _sfc_main$1 from "../../../../components/Button/Button.vue.js";
|
|
5
5
|
import { actions, state as state$1 } from "../../../organizations/store/organizations.js";
|
|
6
6
|
import { useStore } from "../../../core/views/store/core.store.js";
|
|
7
7
|
import { state } from "../../../marketplace/views/store/marketplace.js";
|
|
@@ -4,11 +4,11 @@ import _sfc_main$1 from "../../../../components/Block/Block.vue.js";
|
|
|
4
4
|
import UploadImage from "../../../../components/UploadImage/UploadImage.vue.js";
|
|
5
5
|
/* empty css */
|
|
6
6
|
import Field from "../../../../components/Field/Field.vue.js";
|
|
7
|
-
import Select from "../../../../components/Select/Select.
|
|
7
|
+
import Select from "../../../../components/Select/Select.vue2.js";
|
|
8
8
|
import _sfc_main$3 from "../../../../components/Checkbox/Checkbox.vue.js";
|
|
9
9
|
import _sfc_main$4 from "../../../../components/Address/Address.vue.js";
|
|
10
10
|
import _sfc_main$5 from "../../../../components/LocationMarker/LocationMarker.vue.js";
|
|
11
|
-
import _sfc_main$2 from "../../../../components/Button/Button.
|
|
11
|
+
import _sfc_main$2 from "../../../../components/Button/Button.vue.js";
|
|
12
12
|
/* empty css */
|
|
13
13
|
import WorktimeEdit from "../sections/WorktimeEdit.vue.js";
|
|
14
14
|
import { actions, state } from "../../store/spots.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mergeModels, useModel, ref, computed, onMounted, createElementBlock, openBlock, createElementVNode, createVNode, toDisplayString, unref, withCtx, createTextVNode, Fragment, renderList, normalizeClass, createCommentVNode, createBlock } from "vue";
|
|
2
2
|
import { useI18n } from "vue-i18n";
|
|
3
|
-
import _sfc_main$1 from "../../../../components/Button/Button.
|
|
3
|
+
import _sfc_main$1 from "../../../../components/Button/Button.vue.js";
|
|
4
4
|
import Field from "../../../../components/Field/Field.vue.js";
|
|
5
|
-
import Select from "../../../../components/Select/Select.
|
|
5
|
+
import Select from "../../../../components/Select/Select.vue2.js";
|
|
6
6
|
import _sfc_main$3 from "../../../../components/Checkbox/Checkbox.vue.js";
|
|
7
7
|
import _sfc_main$2 from "../../../../components/Popup/Popup.vue.js";
|
|
8
8
|
/* empty css */
|
|
@@ -4,7 +4,7 @@ import { BigNumber } from "../../../../../../node_modules/.pnpm/bignumber.js@9.1
|
|
|
4
4
|
import { state, actions } from "../../store/wallet.store.js";
|
|
5
5
|
import text from "../../localization/wallet.json.js";
|
|
6
6
|
import Field from "../../../../../components/Field/Field.vue.js";
|
|
7
|
-
import Select from "../../../../../components/Select/Select.
|
|
7
|
+
import Select from "../../../../../components/Select/Select.vue2.js";
|
|
8
8
|
const _hoisted_1 = { class: "mn-b-small t-center t-bold" };
|
|
9
9
|
const _hoisted_2 = { class: "t-semi" };
|
|
10
10
|
const _hoisted_3 = ["disabled"];
|
|
@@ -4,11 +4,11 @@ import Web3 from "web3";
|
|
|
4
4
|
import { state, actions } from "../../store/wallet.store.js";
|
|
5
5
|
import text from "../../localization/wallet.json.js";
|
|
6
6
|
import _sfc_main$3 from "../../../../../components/Popup/Popup.vue.js";
|
|
7
|
-
import _sfc_main$1 from "../../../../../components/Button/Button.
|
|
7
|
+
import _sfc_main$1 from "../../../../../components/Button/Button.vue.js";
|
|
8
8
|
import "vue-router";
|
|
9
9
|
/* empty css */
|
|
10
10
|
/* empty css */
|
|
11
|
-
/* empty css
|
|
11
|
+
/* empty css */
|
|
12
12
|
import _sfc_main$2 from "../elements/ConnectMetamask.vue.js";
|
|
13
13
|
import _sfc_main$4 from "../blocks/CashDeposit.vue.js";
|
|
14
14
|
import _sfc_main$5 from "../blocks/CardDeposit.vue.js";
|
package/dist/products.server.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { C as CacheNamespaced } from "./core.cache-DALYFDdy.js";
|
|
2
2
|
import { L as LoggerNamespaced, c as coreabac } from "./abac-BPl9Bmf9.js";
|
|
3
3
|
import { q as queryProcessorCore } from "./queryProcessor-C_5Iipam.js";
|
|
4
|
-
import OpenAI from "openai";
|
|
5
4
|
import { Types } from "mongoose";
|
|
6
5
|
import { a as applyCommonSchema } from "./common.schema-DswiUXKB.js";
|
|
7
6
|
import { a as applyEngagementSchema } from "./engagement.schema-fh6W1fb_.js";
|
|
@@ -344,92 +343,6 @@ const controllerFactory$1 = (db) => {
|
|
|
344
343
|
}
|
|
345
344
|
};
|
|
346
345
|
};
|
|
347
|
-
class OpenAIGlobal {
|
|
348
|
-
constructor() {
|
|
349
|
-
if (OpenAIGlobal.instance) {
|
|
350
|
-
return OpenAIGlobal.instance;
|
|
351
|
-
}
|
|
352
|
-
this.client = new OpenAI({
|
|
353
|
-
organization: process.env.OPENAI_ORG_KEY,
|
|
354
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
355
|
-
});
|
|
356
|
-
this.models = {
|
|
357
|
-
chat: "gpt-3.5-turbo",
|
|
358
|
-
vision: "gpt-4-vision-preview",
|
|
359
|
-
embedding: "text-embedding-ada-002"
|
|
360
|
-
};
|
|
361
|
-
OpenAIGlobal.instance = this;
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* Generate completions with retry logic for handling JSON parsing errors
|
|
365
|
-
* @param {string} prompt - The prompt text
|
|
366
|
-
* @param {Object} options - Additional options
|
|
367
|
-
* @returns {Promise<Object|string>} - Parsed JSON response or raw content
|
|
368
|
-
*/
|
|
369
|
-
async createChatCompletion(prompt, options = {}) {
|
|
370
|
-
const {
|
|
371
|
-
model = this.models.chat,
|
|
372
|
-
maxRetries = 3,
|
|
373
|
-
temperature = 0.7,
|
|
374
|
-
parseJSON = true,
|
|
375
|
-
systemPrompt = ""
|
|
376
|
-
} = options;
|
|
377
|
-
let attempt = 0;
|
|
378
|
-
while (attempt < maxRetries) {
|
|
379
|
-
try {
|
|
380
|
-
const messages = [];
|
|
381
|
-
if (systemPrompt) {
|
|
382
|
-
messages.push({ role: "system", content: systemPrompt });
|
|
383
|
-
}
|
|
384
|
-
messages.push({ role: "user", content: prompt });
|
|
385
|
-
const response = await this.client.chat.completions.create({
|
|
386
|
-
model,
|
|
387
|
-
messages,
|
|
388
|
-
temperature,
|
|
389
|
-
response_format: parseJSON ? { type: "json_object" } : void 0
|
|
390
|
-
});
|
|
391
|
-
const content = response.choices[0].message.content;
|
|
392
|
-
if (parseJSON) {
|
|
393
|
-
return JSON.parse(content);
|
|
394
|
-
}
|
|
395
|
-
return content;
|
|
396
|
-
} catch (err) {
|
|
397
|
-
attempt++;
|
|
398
|
-
if (err instanceof SyntaxError && attempt < maxRetries) {
|
|
399
|
-
console.error(`Invalid JSON in OpenAI response (attempt ${attempt}/${maxRetries}): ${err.message}`);
|
|
400
|
-
} else if (attempt >= maxRetries) {
|
|
401
|
-
console.error(`Max retries (${maxRetries}) reached for OpenAI completion: ${err.message}`);
|
|
402
|
-
throw err;
|
|
403
|
-
} else {
|
|
404
|
-
console.error(`OpenAI API error (attempt ${attempt}/${maxRetries}): ${err.message}`);
|
|
405
|
-
if (err.status === 429) {
|
|
406
|
-
const waitTime = Math.pow(2, attempt) * 1e3;
|
|
407
|
-
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3 * attempt));
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Get direct access to OpenAI client instance
|
|
416
|
-
* @returns {OpenAI} - OpenAI client instance
|
|
417
|
-
*/
|
|
418
|
-
getClient() {
|
|
419
|
-
return this.client;
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Set default model for specific API
|
|
423
|
-
* @param {string} type - API type ('chat', 'vision', 'embedding')
|
|
424
|
-
* @param {string} modelId - Model identifier
|
|
425
|
-
*/
|
|
426
|
-
setDefaultModel(type, modelId) {
|
|
427
|
-
if (this.models[type]) {
|
|
428
|
-
this.models[type] = modelId;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
const openaiGlobal = new OpenAIGlobal();
|
|
433
346
|
const ObjectId = Types.ObjectId;
|
|
434
347
|
function getCategoriesFilterStage(categories) {
|
|
435
348
|
if (!categories) return [];
|
|
@@ -883,52 +796,11 @@ const controllerFactory = (db) => {
|
|
|
883
796
|
res.status(500).send({ message: err.message });
|
|
884
797
|
}
|
|
885
798
|
};
|
|
886
|
-
const getProductRecommendation = async (req, res) => {
|
|
887
|
-
const { mood } = req.body;
|
|
888
|
-
try {
|
|
889
|
-
const products = await Product.find({
|
|
890
|
-
status: "published"
|
|
891
|
-
}).limit(40);
|
|
892
|
-
if (!products) {
|
|
893
|
-
console.log("no products");
|
|
894
|
-
return res.status(404).send({ message: "Products not found." });
|
|
895
|
-
}
|
|
896
|
-
const productsList = products.map((p) => {
|
|
897
|
-
const info = p.attributes || [];
|
|
898
|
-
const value0 = info[0] ? info[0].value : "";
|
|
899
|
-
const value1 = info[1] ? `(${info[1].value}%)` : "";
|
|
900
|
-
const value2 = info[2] ? `(${info[2].value})` : "";
|
|
901
|
-
return `${p._id}: ${p.name} (${value0}) ${value1} ${value2}`;
|
|
902
|
-
}).join(", ");
|
|
903
|
-
const prompt = `
|
|
904
|
-
1. When asked how the client wants to feel, they responded "${mood}".
|
|
905
|
-
2. Here is a list of products in our store: ${productsList}.
|
|
906
|
-
3. Based on the attributes about the products (strain, THC content) and the user's desires, choose 1 product to recommend to the user.
|
|
907
|
-
4. The response should be in the language that the user used in mood (${mood}).
|
|
908
|
-
5. Please format your response as a JSON object '{"_id": "ID of the recommended product (it must correspond to one of the product IDs I sent)", "recommendationText": "Text explaining why this particular product"'. Write only the JSON object without any other text outside of it.
|
|
909
|
-
`;
|
|
910
|
-
const result = await openaiGlobal.createChatCompletion(prompt, {
|
|
911
|
-
model: "gpt-4",
|
|
912
|
-
temperature: 0.8,
|
|
913
|
-
systemPrompt: "You are a product recommendation specialist with expertise in matching customer needs to product attributes."
|
|
914
|
-
});
|
|
915
|
-
const recommendedProduct = await Product.findById(result._id);
|
|
916
|
-
if (!recommendedProduct) {
|
|
917
|
-
console.log(`No product found with _id: ${result._id}`);
|
|
918
|
-
return res.status(404).send({ message: "Recommended product not found." });
|
|
919
|
-
}
|
|
920
|
-
res.status(200).json({ product: recommendedProduct, recommendationText: result.recommendationText });
|
|
921
|
-
} catch (err) {
|
|
922
|
-
console.log(err);
|
|
923
|
-
res.status(500).send({ message: err });
|
|
924
|
-
}
|
|
925
|
-
};
|
|
926
799
|
return {
|
|
927
800
|
Create,
|
|
928
801
|
Read,
|
|
929
802
|
Update,
|
|
930
|
-
Delete
|
|
931
|
-
getProductRecommendation
|
|
803
|
+
Delete
|
|
932
804
|
};
|
|
933
805
|
};
|
|
934
806
|
const CategoryModel = (db) => {
|
|
@@ -1447,7 +1319,6 @@ const productsRoutes = (function(app, db, allowedOrigins) {
|
|
|
1447
1319
|
app.get("/api/products/read", controller.Read);
|
|
1448
1320
|
app.post("/api/products/:_id", controller.Update);
|
|
1449
1321
|
app.delete("/api/products/:_id", controller.Delete);
|
|
1450
|
-
app.post("/api/product/recommended", controller.getProductRecommendation);
|
|
1451
1322
|
});
|
|
1452
1323
|
const verifierFactory = (function(db) {
|
|
1453
1324
|
const createVerifier = new Verifier({
|
package/dist/style.css
CHANGED
|
@@ -2604,27 +2604,6 @@ to { opacity: 1; transform: translateY(0);
|
|
|
2604
2604
|
.thumbnail.active[data-v-eddb4b2b] {
|
|
2605
2605
|
border: 1px solid rgb(var(--second));
|
|
2606
2606
|
}
|
|
2607
|
-
|
|
2608
|
-
.spiral {
|
|
2609
|
-
object-fit: cover;
|
|
2610
|
-
width: 100rem;
|
|
2611
|
-
height: 100rem;
|
|
2612
|
-
position: absolute;
|
|
2613
|
-
top: 50%;
|
|
2614
|
-
left: 50%;
|
|
2615
|
-
opacity: 0.066;
|
|
2616
|
-
transform: translate(-50%, -50%) rotate(0deg);
|
|
2617
|
-
transform-origin: center center;
|
|
2618
|
-
animation: spin 5s linear infinite;
|
|
2619
|
-
}
|
|
2620
|
-
@keyframes spin {
|
|
2621
|
-
0% {
|
|
2622
|
-
transform: translate(-50%, -50%) rotate(0deg);
|
|
2623
|
-
}
|
|
2624
|
-
100% {
|
|
2625
|
-
transform: translate(-50%, -50%) rotate(360deg);
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
2607
|
.popupar_products .carousel__slide {
|
|
2629
2608
|
flex: 0 0 25%;
|
|
2630
2609
|
min-width: 0;
|
|
@@ -2651,8 +2630,6 @@ to { opacity: 1; transform: translateY(0);
|
|
|
2651
2630
|
.text-muted[data-v-a5eb77c9] {
|
|
2652
2631
|
color: #6c757d;
|
|
2653
2632
|
}
|
|
2654
|
-
|
|
2655
|
-
/* Add your styles here */
|
|
2656
2633
|
.custom-table[data-v-b85cde7e] {
|
|
2657
2634
|
border-collapse: collapse;
|
|
2658
2635
|
}
|
package/package.json
CHANGED
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
class="pos-absolute pos-t-regular pos-r-regular i-medium t-transp"
|
|
42
42
|
/>
|
|
43
43
|
|
|
44
|
-
<h2 v-if="recommendation" class="t-main t-semi p-medium">{{t('airecommend')}}</h2>
|
|
45
44
|
<!-- Name -->
|
|
46
45
|
<h1 class="w-100 h1-product mn-b-small">{{ product.name }}</h1>
|
|
47
46
|
<!-- Price -->
|
|
@@ -51,9 +50,6 @@
|
|
|
51
50
|
<SelectElement v-if="sizes2.length > 0" :elements="sizes2" :selected="product.selectedSize" class="mn-r-medium" />
|
|
52
51
|
</div> -->
|
|
53
52
|
<!-- Description -->
|
|
54
|
-
<h3 v-if="recommendation" class="mn-b-semi">
|
|
55
|
-
{{ recommendation }}
|
|
56
|
-
</h3>
|
|
57
53
|
|
|
58
54
|
<Tab
|
|
59
55
|
v-model:selected="tabProduct"
|
|
@@ -69,11 +65,11 @@
|
|
|
69
65
|
<transition name="slide-fade">
|
|
70
66
|
|
|
71
67
|
<div v-if="tabProduct === 'description'" class="pd-medium radius-medium bg-light ">
|
|
72
|
-
<p v-if="product.description && !product.translations < 1
|
|
68
|
+
<p v-if="product.description && !product.translations < 1" class="w-100 t-transp">
|
|
73
69
|
{{ product.description }}
|
|
74
70
|
</p>
|
|
75
71
|
|
|
76
|
-
<p v-if="product.translations && product.translations.length > 1
|
|
72
|
+
<p v-if="product.translations && product.translations.length > 1" class="w-100 t-transp">
|
|
77
73
|
{{ t('description') }}
|
|
78
74
|
</p>
|
|
79
75
|
</div>
|
|
@@ -161,9 +157,6 @@ const props = defineProps({
|
|
|
161
157
|
accesses: {
|
|
162
158
|
type: Object,
|
|
163
159
|
default: null
|
|
164
|
-
},
|
|
165
|
-
recommendation: {
|
|
166
|
-
type: String
|
|
167
160
|
}
|
|
168
161
|
})
|
|
169
162
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import ChatGPT from '@martyrs/src/modules/integrations/openai/openai.globals.js';
|
|
2
|
-
|
|
3
1
|
import queryProcessorCore from '@martyrs/src/modules/core/controllers/utils/queryProcessor.js';
|
|
4
2
|
import queryProcessorProducts from '@martyrs/src/modules/products/controllers/queries/products.queries.js';
|
|
5
3
|
|
|
@@ -158,61 +156,12 @@ const controllerFactory = db => {
|
|
|
158
156
|
res.status(500).send({ message: err.message });
|
|
159
157
|
}
|
|
160
158
|
};
|
|
161
|
-
|
|
162
|
-
const getProductRecommendation = async (req, res) => {
|
|
163
|
-
const { mood } = req.body;
|
|
164
|
-
try {
|
|
165
|
-
const products = await Product.find({
|
|
166
|
-
status: 'published',
|
|
167
|
-
}).limit(40);
|
|
168
|
-
if (!products) {
|
|
169
|
-
console.log('no products');
|
|
170
|
-
return res.status(404).send({ message: 'Products not found.' });
|
|
171
|
-
}
|
|
172
|
-
const productsList = products
|
|
173
|
-
.map(p => {
|
|
174
|
-
const info = p.attributes || [];
|
|
175
|
-
const value0 = info[0] ? info[0].value : '';
|
|
176
|
-
const value1 = info[1] ? `(${info[1].value}%)` : '';
|
|
177
|
-
const value2 = info[2] ? `(${info[2].value})` : '';
|
|
178
|
-
return `${p._id}: ${p.name} (${value0}) ${value1} ${value2}`;
|
|
179
|
-
})
|
|
180
|
-
.join(', ');
|
|
181
|
-
|
|
182
|
-
const prompt = `
|
|
183
|
-
1. When asked how the client wants to feel, they responded "${mood}".
|
|
184
|
-
2. Here is a list of products in our store: ${productsList}.
|
|
185
|
-
3. Based on the attributes about the products (strain, THC content) and the user's desires, choose 1 product to recommend to the user.
|
|
186
|
-
4. The response should be in the language that the user used in mood (${mood}).
|
|
187
|
-
5. Please format your response as a JSON object '{"_id": "ID of the recommended product (it must correspond to one of the product IDs I sent)", "recommendationText": "Text explaining why this particular product"'. Write only the JSON object without any other text outside of it.
|
|
188
|
-
`;
|
|
189
|
-
|
|
190
|
-
// Specify a model explicitly
|
|
191
|
-
const result = await ChatGPT.createChatCompletion(prompt, {
|
|
192
|
-
model: 'gpt-4',
|
|
193
|
-
temperature: 0.8,
|
|
194
|
-
systemPrompt: 'You are a product recommendation specialist with expertise in matching customer needs to product attributes.'
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const recommendedProduct = await Product.findById(result._id);
|
|
198
|
-
|
|
199
|
-
if (!recommendedProduct) {
|
|
200
|
-
console.log(`No product found with _id: ${result._id}`);
|
|
201
|
-
return res.status(404).send({ message: 'Recommended product not found.' });
|
|
202
|
-
}
|
|
203
|
-
res.status(200).json({ product: recommendedProduct, recommendationText: result.recommendationText });
|
|
204
|
-
} catch (err) {
|
|
205
|
-
console.log(err);
|
|
206
|
-
res.status(500).send({ message: err });
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
159
|
|
|
210
160
|
return {
|
|
211
161
|
Create,
|
|
212
162
|
Read,
|
|
213
163
|
Update,
|
|
214
164
|
Delete,
|
|
215
|
-
getProductRecommendation,
|
|
216
165
|
};
|
|
217
166
|
};
|
|
218
167
|
export default controllerFactory;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Product Recommendation (Experiment)
|
|
2
|
+
|
|
3
|
+
AI-powered product recommendation feature using OpenAI GPT-4.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This experiment provides personalized product recommendations based on user mood/preferences using ChatGPT.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- AI-powered product selection based on user mood
|
|
12
|
+
- Integration with OpenAI GPT-4
|
|
13
|
+
- Custom recommendation page with mood input
|
|
14
|
+
- Recommendation display in product details
|
|
15
|
+
|
|
16
|
+
## Structure
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
experiments/product-recommendation/
|
|
20
|
+
├── components/
|
|
21
|
+
│ ├── ProductRecommmendation.vue # Main recommendation page
|
|
22
|
+
│ └── HeroRecommendation.vue # Mood input component
|
|
23
|
+
├── store/
|
|
24
|
+
│ └── recommendation.store.js # Store for recommendation state
|
|
25
|
+
├── controllers/
|
|
26
|
+
│ └── recommendation.controller.js # Backend recommendation logic
|
|
27
|
+
├── routes/
|
|
28
|
+
│ └── recommendation.routes.js # API endpoint
|
|
29
|
+
├── router/
|
|
30
|
+
│ └── recommendation.router.js # Frontend routes
|
|
31
|
+
└── README.md
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
To use this experiment, you need:
|
|
37
|
+
|
|
38
|
+
1. **OpenAI API Key** in your `.env` file:
|
|
39
|
+
```
|
|
40
|
+
OPENAI_API_KEY=your-api-key-here
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
2. **OpenAI integration** at `/martyrs/src/modules/integrations/openai/openai.globals.js`
|
|
44
|
+
|
|
45
|
+
## How to Enable
|
|
46
|
+
|
|
47
|
+
### 1. Backend Setup
|
|
48
|
+
|
|
49
|
+
Add to your `products.server.js`:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
import recommendationRoutes from './experiments/product-recommendation/routes/recommendation.routes.js';
|
|
53
|
+
|
|
54
|
+
// In initialize function:
|
|
55
|
+
recommendationRoutes(app, db);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Frontend Store
|
|
59
|
+
|
|
60
|
+
Add to your `products.client.js`:
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
import * as storeRecommendation from './experiments/product-recommendation/store/recommendation.store.js';
|
|
64
|
+
|
|
65
|
+
// In initialize function:
|
|
66
|
+
store.addStore('recommendation', storeRecommendation);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. Frontend Routes
|
|
70
|
+
|
|
71
|
+
Import and add routes from `./experiments/product-recommendation/router/recommendation.router.js`:
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
import { recommendationRoutes } from './experiments/product-recommendation/router/recommendation.router.js';
|
|
75
|
+
|
|
76
|
+
// Add to your routes:
|
|
77
|
+
...recommendationRoutes.homeRoutes,
|
|
78
|
+
...recommendationRoutes.organizationRoutes,
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 4. Component Exports
|
|
82
|
+
|
|
83
|
+
Add to `products.client.js` exports:
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
import HeroRecommendation from './experiments/product-recommendation/components/HeroRecommendation.vue';
|
|
87
|
+
import ProductRecommendation from './experiments/product-recommendation/components/ProductRecommmendation.vue';
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
// ... other exports
|
|
91
|
+
HeroRecommendation,
|
|
92
|
+
ProductRecommendation,
|
|
93
|
+
};
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 5. SectionProduct Integration (Optional)
|
|
97
|
+
|
|
98
|
+
To show recommendations in product details, add to `SectionProduct.vue`:
|
|
99
|
+
|
|
100
|
+
```vue
|
|
101
|
+
<template>
|
|
102
|
+
<SectionProduct
|
|
103
|
+
:product="product"
|
|
104
|
+
:recommendation="recommendation.state.current.recommendation"
|
|
105
|
+
/>
|
|
106
|
+
</template>
|
|
107
|
+
|
|
108
|
+
<script>
|
|
109
|
+
import * as recommendation from '../experiments/product-recommendation/store/recommendation.store.js';
|
|
110
|
+
</script>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
And add prop to `SectionProduct.vue`:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
defineProps({
|
|
117
|
+
// ... other props
|
|
118
|
+
recommendation: {
|
|
119
|
+
type: String
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Usage
|
|
125
|
+
|
|
126
|
+
1. Navigate to `/products/recommendation`
|
|
127
|
+
2. Enter your mood/preference
|
|
128
|
+
3. Get AI-powered product recommendation
|
|
129
|
+
4. View recommended product details
|
|
130
|
+
|
|
131
|
+
## API Endpoint
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
POST /api/product/recommended
|
|
135
|
+
Body: { mood: "your mood here" }
|
|
136
|
+
Response: { product: {...}, recommendationText: "..." }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Notes
|
|
140
|
+
|
|
141
|
+
- Requires OpenAI API key and valid subscription
|
|
142
|
+
- Uses GPT-4 model for better recommendations
|
|
143
|
+
- Customize prompt in `recommendation.controller.js`
|
|
144
|
+
- Product attributes (strain, THC content) are used for matching
|
|
145
|
+
|
|
146
|
+
## Removed from Core
|
|
147
|
+
|
|
148
|
+
This feature was moved to experiments to:
|
|
149
|
+
- Remove OpenAI dependency from core products module
|
|
150
|
+
- Make it optional for projects that don't need AI recommendations
|
|
151
|
+
- Allow easier customization and experimentation
|
|
152
|
+
- Reduce bundle size for projects without AI features
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
Part of @ozdao/martyrs framework.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import ChatGPT from '@martyrs/src/modules/integrations/openai/openai.globals.js';
|
|
2
|
+
|
|
3
|
+
const controllerFactory = db => {
|
|
4
|
+
const Product = db.product;
|
|
5
|
+
|
|
6
|
+
const getProductRecommendation = async (req, res) => {
|
|
7
|
+
const { mood } = req.body;
|
|
8
|
+
try {
|
|
9
|
+
const products = await Product.find({
|
|
10
|
+
status: 'published',
|
|
11
|
+
}).limit(40);
|
|
12
|
+
if (!products) {
|
|
13
|
+
console.log('no products');
|
|
14
|
+
return res.status(404).send({ message: 'Products not found.' });
|
|
15
|
+
}
|
|
16
|
+
const productsList = products
|
|
17
|
+
.map(p => {
|
|
18
|
+
const info = p.attributes || [];
|
|
19
|
+
const value0 = info[0] ? info[0].value : '';
|
|
20
|
+
const value1 = info[1] ? `(${info[1].value}%)` : '';
|
|
21
|
+
const value2 = info[2] ? `(${info[2].value})` : '';
|
|
22
|
+
return `${p._id}: ${p.name} (${value0}) ${value1} ${value2}`;
|
|
23
|
+
})
|
|
24
|
+
.join(', ');
|
|
25
|
+
|
|
26
|
+
const prompt = `
|
|
27
|
+
1. When asked how the client wants to feel, they responded "${mood}".
|
|
28
|
+
2. Here is a list of products in our store: ${productsList}.
|
|
29
|
+
3. Based on the attributes about the products (strain, THC content) and the user's desires, choose 1 product to recommend to the user.
|
|
30
|
+
4. The response should be in the language that the user used in mood (${mood}).
|
|
31
|
+
5. Please format your response as a JSON object '{"_id": "ID of the recommended product (it must correspond to one of the product IDs I sent)", "recommendationText": "Text explaining why this particular product"'. Write only the JSON object without any other text outside of it.
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
// Specify a model explicitly
|
|
35
|
+
const result = await ChatGPT.createChatCompletion(prompt, {
|
|
36
|
+
model: 'gpt-4',
|
|
37
|
+
temperature: 0.8,
|
|
38
|
+
systemPrompt: 'You are a product recommendation specialist with expertise in matching customer needs to product attributes.'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const recommendedProduct = await Product.findById(result._id);
|
|
42
|
+
|
|
43
|
+
if (!recommendedProduct) {
|
|
44
|
+
console.log(`No product found with _id: ${result._id}`);
|
|
45
|
+
return res.status(404).send({ message: 'Recommended product not found.' });
|
|
46
|
+
}
|
|
47
|
+
res.status(200).json({ product: recommendedProduct, recommendationText: result.recommendationText });
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.log(err);
|
|
50
|
+
res.status(500).send({ message: err });
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
getProductRecommendation,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default controllerFactory;
|