@ozdao/martyrs 0.2.568 → 0.2.570

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.
Files changed (167) hide show
  1. package/dist/martyrs/src/components/Button/{Button.vue2.js → Button.vue.js} +3 -3
  2. package/dist/martyrs/src/components/Button/Button.vue.js.map +1 -0
  3. package/dist/martyrs/src/components/EditImages/{EditImages.vue.js → EditImages.vue2.js} +2 -2
  4. package/dist/martyrs/src/components/EditImages/EditImages.vue2.js.map +1 -0
  5. package/dist/martyrs/src/components/Feed/Carousel.vue.js +1 -1
  6. package/dist/martyrs/src/components/Feed/Feed.vue.js +2 -2
  7. package/dist/martyrs/src/components/Field/{Field.vue.js → Field.vue2.js} +2 -2
  8. package/dist/martyrs/src/components/Field/Field.vue2.js.map +1 -0
  9. package/dist/martyrs/src/components/FieldBig/FieldBig.vue.js +2 -2
  10. package/dist/martyrs/src/components/Loader/{Loader.vue.js → Loader.vue2.js} +2 -2
  11. package/dist/martyrs/src/components/Loader/Loader.vue2.js.map +1 -0
  12. package/dist/martyrs/src/components/LocationMarker/LocationMarker.vue.js +1 -1
  13. package/dist/martyrs/src/components/Media/Media.vue.js +1 -1
  14. package/dist/martyrs/src/components/Menu/{Menu.vue2.js → Menu.vue.js} +2 -2
  15. package/dist/martyrs/src/components/Menu/Menu.vue.js.map +1 -0
  16. package/dist/martyrs/src/components/Select/{Select.vue.js → Select.vue2.js} +2 -2
  17. package/dist/martyrs/src/components/Select/Select.vue2.js.map +1 -0
  18. package/dist/martyrs/src/components/UploadImage/UploadImage.vue.js +1 -1
  19. package/dist/martyrs/src/components/UploadImageMultiple/UploadImageMultiple.vue.js +1 -1
  20. package/dist/martyrs/src/modules/auth/views/components/pages/EnterCode.vue.js +1 -1
  21. package/dist/martyrs/src/modules/auth/views/components/pages/EnterPassword.vue.js +2 -2
  22. package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js +2 -2
  23. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +3 -3
  24. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.vue.js +1 -1
  25. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditAccount.vue.js +1 -1
  26. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditProfile.vue.js +2 -2
  27. package/dist/martyrs/src/modules/auth/views/components/pages/ResetPassword.vue.js +2 -2
  28. package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js +2 -2
  29. package/dist/martyrs/src/modules/auth/views/components/pages/SignUp.vue.js +2 -2
  30. package/dist/martyrs/src/modules/auth/views/components/sections/ProfileEditCredentials.vue.js +2 -2
  31. package/dist/martyrs/src/modules/community/components/layouts/Community.vue.js +1 -1
  32. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js +2 -2
  33. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +2 -2
  34. package/dist/martyrs/src/modules/constructor/components/elements/Card.vue.js +1 -1
  35. package/dist/martyrs/src/modules/constructor/components/elements/Embed.vue.js +1 -1
  36. package/dist/martyrs/src/modules/core/views/components/blocks/BlockSearch.vue.js +1 -1
  37. package/dist/martyrs/src/modules/core/views/components/blocks/CardHeader.vue.js +1 -1
  38. package/dist/martyrs/src/modules/core/views/components/blocks/PopupAuth.vue.js +1 -1
  39. package/dist/martyrs/src/modules/core/views/components/blocks/PopupDateSelector.vue.js +2 -2
  40. package/dist/martyrs/src/modules/core/views/components/layouts/Client.vue.js +2 -2
  41. package/dist/martyrs/src/modules/core/views/components/partials/Header.vue.js +2 -2
  42. package/dist/martyrs/src/modules/core/views/components/partials/NavigationBar.vue.js +1 -1
  43. package/dist/martyrs/src/modules/core/views/components/sections/{Filters.vue.js → Filters.vue2.js} +2 -2
  44. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue2.js.map +1 -0
  45. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterRange.vue.js +1 -1
  46. package/dist/martyrs/src/modules/core/views/router/scrollBehavior.js +27 -25
  47. package/dist/martyrs/src/modules/core/views/router/scrollBehavior.js.map +1 -1
  48. package/dist/martyrs/src/modules/events/components/elements/ButtonCheck.vue.js +1 -1
  49. package/dist/martyrs/src/modules/events/components/elements/ButtonJoin.vue.js +1 -1
  50. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +4 -4
  51. package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.js +2 -2
  52. package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +3 -3
  53. package/dist/martyrs/src/modules/events/components/sections/EditTickets.vue.js +2 -2
  54. package/dist/martyrs/src/modules/events/components/sections/Feed.vue.js +1 -1
  55. package/dist/martyrs/src/modules/events/components/sections/List.vue.js +1 -1
  56. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +4 -4
  57. package/dist/martyrs/src/modules/inventory/components/forms/AdjustmentForm.vue.js +3 -3
  58. package/dist/martyrs/src/modules/inventory/components/forms/ColumnSettingsMenu.vue.js +1 -1
  59. package/dist/martyrs/src/modules/inventory/components/forms/HistoryView.vue.js +1 -1
  60. package/dist/martyrs/src/modules/inventory/components/forms/StockAlertsForm.vue.js +3 -3
  61. package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +3 -3
  62. package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js +2 -2
  63. package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.js +1 -1
  64. package/dist/martyrs/src/modules/music/components/blocks/ActionButtons.vue.js +1 -1
  65. package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.js +1 -1
  66. package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.js +1 -1
  67. package/dist/martyrs/src/modules/music/components/cards/PlaylistCard.vue.js +1 -1
  68. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js +1 -1
  69. package/dist/martyrs/src/modules/music/components/forms/AlbumForm.vue.js +3 -3
  70. package/dist/martyrs/src/modules/music/components/forms/ArtistForm.vue.js +4 -4
  71. package/dist/martyrs/src/modules/music/components/forms/PlaylistForm.vue.js +2 -2
  72. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js +1 -1
  73. package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.js +3 -3
  74. package/dist/martyrs/src/modules/music/components/pages/Album.vue.js +2 -2
  75. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js +2 -2
  76. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js +1 -1
  77. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js +2 -2
  78. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js +2 -2
  79. package/dist/martyrs/src/modules/music/components/pages/Track.vue.js +2 -2
  80. package/dist/martyrs/src/modules/music/components/pages/TrackCreate.vue.js +1 -1
  81. package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.js +1 -1
  82. package/dist/martyrs/src/modules/music/components/player/PlayerControls.vue.js +1 -1
  83. package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.js +1 -1
  84. package/dist/martyrs/src/modules/orders/components/forms/FormApplicationDetails.vue.js +3 -3
  85. package/dist/martyrs/src/modules/orders/components/forms/FormCustomerDetails.vue.js +3 -3
  86. package/dist/martyrs/src/modules/orders/components/forms/FormSelectCustomer.vue.js +2 -2
  87. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +2 -2
  88. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +1 -1
  89. package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.js +2 -2
  90. package/dist/martyrs/src/modules/orders/components/sections/ApplicationDetails.vue.js +1 -1
  91. package/dist/martyrs/src/modules/orders/components/sections/CustomerDetails.vue.js +1 -1
  92. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +3 -3
  93. package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js +1 -1
  94. package/dist/martyrs/src/modules/organizations/components/elements/ButtonToggleMembership.vue.js +1 -1
  95. package/dist/martyrs/src/modules/organizations/components/forms/AddExistingMembersForm.vue.js +1 -1
  96. package/dist/martyrs/src/modules/organizations/components/forms/DepartmentForm.vue.js +2 -2
  97. package/dist/martyrs/src/modules/organizations/components/forms/InviteForm.vue.js +2 -2
  98. package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +1 -1
  99. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
  100. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +3 -3
  101. package/dist/martyrs/src/modules/organizations/components/sections/Documents.vue.js +3 -3
  102. package/dist/martyrs/src/modules/organizations/components/sections/MembersAdd.vue.js +3 -3
  103. package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +3 -3
  104. package/dist/martyrs/src/modules/pages/views/components/blocks/CardPage.vue.js +2 -2
  105. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +2 -2
  106. package/dist/martyrs/src/modules/pages/views/components/partials/SidebarPages.vue.js +1 -1
  107. package/dist/martyrs/src/modules/products/components/elements/Image360.vue.js +1 -1
  108. package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js +1 -1
  109. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +5 -5
  110. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +1 -1
  111. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +4 -4
  112. package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +2 -2
  113. package/dist/martyrs/src/modules/products/components/sections/EditAttributes.vue.js +2 -2
  114. package/dist/martyrs/src/modules/products/components/sections/EditDiscounts.vue.js +3 -3
  115. package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.js +4 -4
  116. package/dist/martyrs/src/modules/products/components/sections/ProductConfigurator.vue.js +1 -1
  117. package/dist/martyrs/src/modules/products/components/sections/ProductsRecommended.vue.js +1 -1
  118. package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js +25 -38
  119. package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js.map +1 -1
  120. package/dist/martyrs/src/modules/products/products.client.js +15 -21
  121. package/dist/martyrs/src/modules/products/products.client.js.map +1 -1
  122. package/dist/martyrs/src/modules/products/router/products.router.js +0 -34
  123. package/dist/martyrs/src/modules/products/router/products.router.js.map +1 -1
  124. package/dist/martyrs/src/modules/products/store/products.js +0 -15
  125. package/dist/martyrs/src/modules/products/store/products.js.map +1 -1
  126. package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js +1 -1
  127. package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js +2 -2
  128. package/dist/martyrs/src/modules/reports/components/sections/FormReport.vue.js +2 -2
  129. package/dist/martyrs/src/modules/spots/components/blocks/SpotMemberModify.vue.js +2 -2
  130. package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.js +1 -1
  131. package/dist/martyrs/src/modules/spots/components/pages/Map.vue.js +1 -1
  132. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +3 -3
  133. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +3 -3
  134. package/dist/martyrs/src/modules/wallet/views/components/blocks/CardDeposit.vue.js +1 -1
  135. package/dist/martyrs/src/modules/wallet/views/components/blocks/CryptoDeposit.vue.js +2 -2
  136. package/dist/martyrs/src/modules/wallet/views/components/pages/Wallet.vue.js +2 -2
  137. package/dist/products.server.js +1 -130
  138. package/dist/style.css +0 -23
  139. package/package.json +1 -1
  140. package/src/modules/core/views/router/scrollBehavior.js +30 -28
  141. package/src/modules/products/components/sections/SectionProduct.vue +2 -9
  142. package/src/modules/products/controllers/products.controller.js +0 -51
  143. package/src/modules/products/experiments/product-recommendation/README.md +156 -0
  144. package/src/modules/products/experiments/product-recommendation/controllers/recommendation.controller.js +59 -0
  145. package/src/modules/products/experiments/product-recommendation/router/recommendation.router.js +43 -0
  146. package/src/modules/products/experiments/product-recommendation/routes/recommendation.routes.js +10 -0
  147. package/src/modules/products/experiments/product-recommendation/store/recommendation.store.js +38 -0
  148. package/src/modules/products/products.client.js +0 -6
  149. package/src/modules/products/products.router.js +0 -29
  150. package/src/modules/products/router/products.router.js +0 -28
  151. package/src/modules/products/routes/products.routes.js +0 -2
  152. package/src/modules/products/store/products.js +0 -16
  153. package/dist/martyrs/src/components/Button/Button.vue2.js.map +0 -1
  154. package/dist/martyrs/src/components/EditImages/EditImages.vue.js.map +0 -1
  155. package/dist/martyrs/src/components/Field/Field.vue.js.map +0 -1
  156. package/dist/martyrs/src/components/Loader/Loader.vue.js.map +0 -1
  157. package/dist/martyrs/src/components/Menu/Menu.vue2.js.map +0 -1
  158. package/dist/martyrs/src/components/Select/Select.vue.js.map +0 -1
  159. package/dist/martyrs/src/components/Shader/Shader.vue.js +0 -2
  160. package/dist/martyrs/src/components/Shader/Shader.vue.js.map +0 -1
  161. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js.map +0 -1
  162. package/dist/martyrs/src/modules/products/components/pages/ProductRecommmendation.vue.js +0 -106
  163. package/dist/martyrs/src/modules/products/components/pages/ProductRecommmendation.vue.js.map +0 -1
  164. package/dist/martyrs/src/modules/products/components/sections/HeroRecommendation.vue.js +0 -120
  165. package/dist/martyrs/src/modules/products/components/sections/HeroRecommendation.vue.js.map +0 -1
  166. /package/src/modules/products/{components/sections → experiments/product-recommendation/components}/HeroRecommendation.vue +0 -0
  167. /package/src/modules/products/{components/pages → experiments/product-recommendation/components}/ProductRecommmendation.vue +0 -0
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ozdao/martyrs",
3
- "version": "0.2.568",
3
+ "version": "0.2.570",
4
4
  "description": "Fullstack framework focused on user experience and ease of development.",
5
5
  "author": "OZ DAO <hello@ozdao.dev>",
6
6
  "license": "GPL-3.0-or-later",
@@ -1,34 +1,36 @@
1
- export default async function scrollBehavior(to, from, savedPosition) {
2
- if (to.hash) {
3
- const findEl = async (hash, x) => {
4
- return (
5
- document.querySelector(hash) ||
6
- new Promise((resolve, reject) => {
7
- if (x > 50) {
8
- return resolve();
9
- }
10
- setTimeout(() => {
11
- resolve(findEl(hash, ++x || 1));
12
- }, 1000);
13
- })
14
- );
15
- };
16
-
1
+ export default function scrollBehavior(selector = '#scrollview') {
2
+ return async function(to, from, savedPosition) {
17
3
  if (to.hash) {
18
- let el = await findEl(to.hash);
19
- let screen = await findEl('#scrollview');
4
+ const findEl = async (hash, x) => {
5
+ return (
6
+ document.querySelector(hash) ||
7
+ new Promise((resolve, reject) => {
8
+ if (x > 50) {
9
+ return resolve();
10
+ }
11
+ setTimeout(() => {
12
+ resolve(findEl(hash, ++x || 1));
13
+ }, 1000);
14
+ })
15
+ );
16
+ };
17
+
18
+ if (to.hash) {
19
+ let el = await findEl(to.hash);
20
+ let screen = await findEl(selector);
20
21
 
21
- if ('scrollBehavior' in document.documentElement.style) {
22
- return screen.scrollTo({ top: el.offsetTop, behavior: 'smooth' });
23
- } else {
24
- return screen.scrollTo(0, el.offsetTop);
22
+ if ('scrollBehavior' in document.documentElement.style) {
23
+ return screen.scrollTo({ top: el.offsetTop, behavior: 'smooth' });
24
+ } else {
25
+ return screen.scrollTo(0, el.offsetTop);
26
+ }
25
27
  }
28
+ } else if (to.matched.some(m => m.meta.scrollTo)) {
29
+ return { top: m.meta.scrollTo.top, left: m.meta.scrollTo.left };
30
+ } else if (savedPosition) {
31
+ return { savedPosition };
32
+ } else {
33
+ return { top: 0 };
26
34
  }
27
- } else if (to.matched.some(m => m.meta.scrollTo)) {
28
- return { top: m.meta.scrollTo.top, left: m.meta.scrollTo.left };
29
- } else if (savedPosition) {
30
- return { savedPosition };
31
- } else {
32
- return { top: 0 };
33
35
  }
34
36
  }
@@ -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 && !recommendation" class="w-100 t-transp">
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 && !recommendation" class="w-100 t-transp">
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;
@@ -0,0 +1,43 @@
1
+ // Product Recommendation Routes
2
+ // These routes can be added to products router if needed
3
+
4
+ export const recommendationRoutes = {
5
+ // Home context routes
6
+ homeRoutes: [
7
+ {
8
+ path: 'recommendation',
9
+ name: 'ProductRecommmendation',
10
+ meta: {
11
+ title: {
12
+ en: 'Product Recommmendation',
13
+ ru: 'Рекомендации продукта',
14
+ },
15
+ header_theme: 'dark',
16
+ footer_theme: 'dark',
17
+ },
18
+ component: () => import(/* webpackChunkName: 'products-recommendation' */ '../components/ProductRecommmendation.vue'),
19
+ props: route => ({ mood: route.query.mood }),
20
+ },
21
+ ],
22
+
23
+ // Organization context routes
24
+ organizationRoutes: [
25
+ {
26
+ path: 'recommendation',
27
+ name: 'Organization_ProductRecommmendation',
28
+ meta: {
29
+ title: {
30
+ en: 'Product Recommmendation',
31
+ ru: 'Рекомендации продукта',
32
+ },
33
+ header_theme: 'dark',
34
+ footer_theme: 'dark',
35
+ context: 'organization',
36
+ },
37
+ component: () => import(/* webpackChunkName: 'products-recommendation' */ '../components/ProductRecommmendation.vue'),
38
+ props: route => ({ mood: route.query.mood }),
39
+ },
40
+ ],
41
+ };
42
+
43
+ export default recommendationRoutes;
@@ -0,0 +1,10 @@
1
+ import controllerFactory from '../controllers/recommendation.controller.js';
2
+
3
+ const routesFactory = (app, db) => {
4
+ const controller = controllerFactory(db);
5
+
6
+ // Product recommendation endpoint
7
+ app.post('/api/product/recommended', controller.getProductRecommendation);
8
+ };
9
+
10
+ export default routesFactory;
@@ -0,0 +1,38 @@
1
+ import { reactive } from 'vue';
2
+ import $axios from '@martyrs/src/modules/core/plugins/axios.js';
3
+
4
+ const state = reactive({
5
+ current: {
6
+ recommendation: false,
7
+ },
8
+ });
9
+
10
+ const actions = {
11
+ async submitMood(presetMood = null) {
12
+ return $axios.post('/api/product/recommended', { mood: presetMood }).then(
13
+ response => {
14
+ state.current = response.data.product;
15
+ state.current.recommendation = response.data.recommendationText;
16
+ return Promise.resolve(response.data);
17
+ },
18
+ error => {
19
+ console.error('Recommendation error:', error);
20
+ return Promise.reject(error);
21
+ }
22
+ );
23
+ },
24
+ };
25
+
26
+ const mutations = {
27
+ resetRecommendation() {
28
+ state.current = {
29
+ recommendation: false,
30
+ };
31
+ },
32
+ };
33
+
34
+ export default {
35
+ state,
36
+ actions,
37
+ mutations,
38
+ };
@@ -19,7 +19,6 @@ import ProductImages from './components/blocks/ProductImages.vue';
19
19
  // Sections
20
20
  import EditVariants from './components/sections/EditVariants.vue';
21
21
  import FilterProducts from './components/sections/FilterProducts.vue';
22
- import HeroRecommendation from './components/sections/HeroRecommendation.vue';
23
22
  import ProductsPopular from './components/sections/ProductsPopular.vue';
24
23
  import SectionProduct from './components/sections/SectionProduct.vue';
25
24
 
@@ -28,7 +27,6 @@ import Price from './components/elements/Price.vue';
28
27
  // Pages
29
28
  import Product from './components/pages/Product.vue';
30
29
  import ProductEdit from './components/pages/ProductEdit.vue';
31
- import ProductRecommendation from './components/pages/ProductRecommmendation.vue';
32
30
  import Products from './components/pages/Products.vue';
33
31
 
34
32
  // Пример функции инициализации для модуля продуктов
@@ -69,14 +67,12 @@ const ModuleProducts = {
69
67
  CardPosition,
70
68
  // Sections
71
69
  SectionProduct,
72
- HeroRecommendation,
73
70
  FilterProducts,
74
71
  EditVariants,
75
72
  ProductsPopular,
76
73
  // Pages
77
74
  Product,
78
75
  ProductEdit,
79
- ProductRecommendation,
80
76
  Products,
81
77
  // Layouts
82
78
  },
@@ -89,7 +85,6 @@ export {
89
85
  CardProduct,
90
86
  EditVariants,
91
87
  FilterProducts,
92
- HeroRecommendation,
93
88
  Image360,
94
89
  // Blocks
95
90
  ProductImages,
@@ -99,7 +94,6 @@ export {
99
94
  // Pages
100
95
  Product,
101
96
  ProductEdit,
102
- ProductRecommendation,
103
97
  Products,
104
98
  // Sections
105
99
  SectionProduct,
@@ -74,20 +74,6 @@ export function getRoutes(options = {}) {
74
74
  ],
75
75
  component: () => import(/* webpackChunkName: "products-edit" */ './components/pages/ProductEdit.vue'),
76
76
  },
77
- {
78
- path: 'recommendation',
79
- name: 'ProductRecommmendation',
80
- meta: {
81
- title: {
82
- en: 'Product Recommmendation',
83
- ru: 'Рекомендации продукта',
84
- },
85
- header_theme: 'dark',
86
- footer_theme: 'dark',
87
- },
88
- component: () => import(/* webpackChunkName: 'products-recommendation' */ './components/pages/ProductRecommmendation.vue'),
89
- props: route => ({ mood: route.query.mood }),
90
- },
91
77
  ],
92
78
  }
93
79
  });
@@ -162,21 +148,6 @@ export function getRoutes(options = {}) {
162
148
  ],
163
149
  component: () => import(/* webpackChunkName: "products-edit" */ './components/pages/ProductEdit.vue'),
164
150
  },
165
- {
166
- path: 'recommendation',
167
- name: 'Organization_ProductRecommmendation',
168
- meta: {
169
- title: {
170
- en: 'Product Recommmendation',
171
- ru: 'Рекомендации продукта',
172
- },
173
- header_theme: 'dark',
174
- footer_theme: 'dark',
175
- context: 'organization',
176
- },
177
- component: () => import(/* webpackChunkName: 'products-recommendation' */ './components/pages/ProductRecommmendation.vue'),
178
- props: route => ({ mood: route.query.mood }),
179
- },
180
151
  ],
181
152
  }
182
153
  });
@@ -81,20 +81,6 @@ export function getRoutes(options = {}) {
81
81
  beforeEnter: [validationAuth.requiresAuth],
82
82
  component: () => import(/* webpackChunkName: "products-edit" */ '../components/pages/ProductEdit.vue'),
83
83
  },
84
- {
85
- path: 'recommendation',
86
- name: 'ProductRecommmendation',
87
- meta: {
88
- title: {
89
- en: 'Product Recommmendation',
90
- ru: 'Рекомендации продукта',
91
- },
92
- header_theme: 'dark',
93
- footer_theme: 'dark',
94
- },
95
- component: () => import(/* webpackChunkName: 'products-recommendation' */ '../components/pages/ProductRecommmendation.vue'),
96
- props: route => ({ mood: route.query.mood }),
97
- },
98
84
  ],
99
85
  },
100
86
  });
@@ -275,20 +261,6 @@ export function getRoutes(options = {}) {
275
261
  ],
276
262
  component: () => import(/* webpackChunkName: "products-edit" */ '../components/pages/ProductEdit.vue'),
277
263
  },
278
- {
279
- path: 'recommendation',
280
- name: 'ProductRecommmendation',
281
- meta: {
282
- title: {
283
- en: 'Product Recommmendation',
284
- ru: 'Рекомендации продукта',
285
- },
286
- header_theme: 'dark',
287
- footer_theme: 'dark',
288
- },
289
- component: () => import(/* webpackChunkName: 'products-recommendation' */ '../components/pages/ProductRecommmendation.vue'),
290
- props: route => ({ mood: route.query.mood }),
291
- },
292
264
  ],
293
265
  },
294
266
  });
@@ -9,6 +9,4 @@ export default (function (app, db, allowedOrigins) {
9
9
  app.post('/api/products/:_id', controller.Update);
10
10
  // (D) Delete product
11
11
  app.delete('/api/products/:_id', controller.Delete);
12
-
13
- app.post('/api/product/recommended', controller.getProductRecommendation);
14
12
  });