wineater-bot 3.7.0 → 3.8.1

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/index.html CHANGED
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Chatbot</title>
7
- <script>window.wineaterData = {CLIENT_TOKEN: 'dRBwg6wB6LeEKFUiLHdlXa84TgSVDuR8HhE0hhq1l4vVeq3cE12DJkPDwXvuhT01', TYPE: 'widget', WIDGET_TYPE: 'store', WIDGET_WRAPPER: 'wineater-widget-conteiner'};</script>
7
+ <script>window.wineaterData = {CLIENT_TOKEN: 'OjvAprylAugk5pKTHRIzZxcPPb6HMPr9qHhrazG0sF3uHjkrvBzufPZ65igfRJJa', TYPE: 'widget', WIDGET_TYPE: 'bar', WIDGET_WRAPPER: 'wineater-widget-conteiner'};</script>
8
8
  <!-- <script type="module" src="./dist/wineater-chatbot.umd.js"></script> -->
9
9
  <script type="module" src="./src/index.js"></script>
10
10
  </head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wineater-bot",
3
- "version": "3.7.0",
3
+ "version": "3.8.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "src/index.js",
package/src/js/i18n.js CHANGED
@@ -470,8 +470,8 @@ class Translator {
470
470
  headerOccasion: "случай",
471
471
  headerOr: "или",
472
472
  },
473
- kz: {
474
- lang: 'kz',
473
+ kk: {
474
+ lang: 'kk',
475
475
  welcomeMessage: "Сіз не жегіңіз келеді? Тағамыңызды сипаттаңыз, мен оған керемет шарап ұсынамын.",
476
476
  noResultsFound: "Нәтижелер табылмады.",
477
477
  somethingWentWrong: "Кешіріңіз, бірдеңе дұрыс болмады.",
@@ -540,29 +540,31 @@ class Translator {
540
540
 
541
541
  async fetchConfig(storeName) {
542
542
  try {
543
- const config = await this.api.getStoreConfig(storeName);
544
- this.storeLanguage = config.lang;
545
- this.supportedLanguages = config.available_languages;
546
- this.OpenAIApiKey = config.open_ai_key;
547
- // ✅ Если язык уже сохранён в localStorage — использовать его
548
- const storedLang = localStorage.getItem('selectedLanguage');
549
- if (storedLang && this.translations[storedLang]) {
550
- this.language = storedLang;
551
- } else if (config.lang && this.translations[config.lang]) {
552
- // иначе использовать с бэкенда
553
- this.language = config.lang;
554
- localStorage.setItem('selectedLanguage', config.lang);
555
- } else {
556
- this.language = 'en';
557
- }
558
-
559
- this.currency = config.currency || 'USD';
560
-
543
+ const config = await this.api.getStoreConfig(storeName);
544
+ this.storeLanguage = config.lang;
545
+ this.supportedLanguages = config.available_languages;
546
+ this.OpenAIApiKey = config.open_ai_key;
547
+
548
+ const urlParams = new URLSearchParams(window.location.search);
549
+ const urlLang = urlParams.get('lang') || urlParams.get('language');
550
+
551
+ if (urlLang && this.translations[urlLang]) {
552
+ this.language = urlLang;
553
+ } else if (config.lang && this.translations[config.lang]) {
554
+ this.language = config.lang;
555
+ } else {
556
+ this.language = 'en';
557
+ }
558
+
559
+ this.currency = config.currency || 'USD';
561
560
  } catch (e) {
562
- this.language = localStorage.getItem('selectedLanguage') || 'en';
563
- this.currency = 'USD';
561
+ const urlParams = new URLSearchParams(window.location.search);
562
+ const urlLang = urlParams.get('lang') || urlParams.get('language');
563
+
564
+ this.language = this.translations[urlLang] ? urlLang : 'en';
565
+ this.currency = 'USD';
564
566
  }
565
- }
567
+ }
566
568
 
567
569
  getCurrency(key) {
568
570
  const keys = key.split('.'); // Разбиваем ключ на части
@@ -598,12 +600,19 @@ class Translator {
598
600
  return this.supportedLanguages;
599
601
  }
600
602
 
601
- async translateTexts(textObject) {
603
+ getLangFromURL() {
604
+ const urlParams = new URLSearchParams(window.location.search);
605
+ const lang = urlParams.get('lang') || urlParams.get('language');
606
+ return lang && this.translations[lang] ? lang : null;
607
+ }
608
+
609
+ async translateTexts(textObject) {
602
610
  if (this.storeLanguage === this.language || !this.supportedLanguages) {
611
+ console.log('gривет');
603
612
  return textObject;
604
613
  }
605
614
 
606
- const apiKey = this.OpenAIApiKey; // ✅ Заменить на твой реальный ключ
615
+ const apiKey = this.OpenAIApiKey;
607
616
  const url = 'https://api.openai.com/v1/chat/completions';
608
617
 
609
618
  const headers = {
@@ -611,12 +620,37 @@ class Translator {
611
620
  'Authorization': `Bearer ${apiKey}`,
612
621
  };
613
622
 
614
- const texts = Object.values(textObject);
615
- const joinedText = texts.join(' ||| ');
616
-
617
- const prompt = `Translate the following texts to ${this.language}. Return only the translated texts separated by " ||| " in the same order:
623
+ const entries = Object.entries(textObject).map(([key, text]) => ({
624
+ key,
625
+ text,
626
+ }));
618
627
 
619
- ${joinedText}`;
628
+ const prompt = `
629
+ You are a professional translator.
630
+
631
+ The input texts are written in language with code "${this.storeLanguage}". Your task is to translate them strictly to the target language with code "${this.language}".
632
+
633
+ ⚠️ DO NOT leave the original text.
634
+ ⚠️ DO NOT skip any entry.
635
+ ⚠️ Preserve the original order and keys exactly.
636
+
637
+ Translate only the "text" fields of the JSON array. Return an array of the same length and structure, like this:
638
+
639
+ Input:
640
+ [
641
+ { "key": "shortDescription", "text": "Red wine with rich cherry notes." },
642
+ { "key": "tags", "text": "fruity, dry, elegant" }
643
+ ]
644
+
645
+ Output:
646
+ [
647
+ { "key": "shortDescription", "text": "..." },
648
+ { "key": "tags", "text": "..." }
649
+ ]
650
+
651
+ Now translate the following input:
652
+ ${JSON.stringify(entries, null, 2)}
653
+ `;
620
654
 
621
655
  const body = JSON.stringify({
622
656
  model: 'gpt-3.5-turbo',
@@ -640,11 +674,13 @@ class Translator {
640
674
 
641
675
  if (!translatedRaw) throw new Error('No response from OpenAI');
642
676
 
643
- const translatedTexts = translatedRaw.split(' ||| ').map(t => t.trim());
677
+ const translatedArray = JSON.parse(translatedRaw);
644
678
 
645
679
  const translatedObject = {};
646
- Object.keys(textObject).forEach((key, index) => {
647
- translatedObject[key] = translatedTexts[index] || textObject[key];
680
+ translatedArray.forEach(entry => {
681
+ if (entry.key && entry.text !== undefined) {
682
+ translatedObject[entry.key] = entry.text;
683
+ }
648
684
  });
649
685
 
650
686
  return translatedObject;
package/src/js/widget.js CHANGED
@@ -399,53 +399,63 @@ export class WineWidget {
399
399
  if (translator.language === translator.storeLanguage || this.widgetType !== 'bar') {
400
400
  return;
401
401
  }
402
- const fieldsToTranslate = ['Short Description', 'reason', 'pairing_recommendation', 'Tags'];
403
- const language = translator.language;
404
402
 
403
+ const possibleFields = ['Short Description', 'reason', 'pairing_recommendation', 'Tags', 'tags'];
404
+ const firstWine = wines[0];
405
+
406
+ const fieldsToTranslate = possibleFields.filter(field => field in firstWine);
405
407
  const batchSize = 4;
408
+
406
409
  for (let i = 0; i < wines.length; i += batchSize) {
407
410
  const batch = wines.slice(i, i + batchSize);
408
411
 
409
412
  const translationPromises = batch.map(async (wine, index) => {
410
413
  const globalIndex = i + index;
411
- const textObject = {};
412
414
 
413
- fieldsToTranslate.forEach(field => {
414
- const val = wine[field] || wine[field.toLowerCase()];
415
- if (val) textObject[field] = Array.isArray(val) ? val.join(', ') : val;
416
- });
415
+ // Сбор оригинальных текстов в формате [{ key, text }]
416
+ const entries = fieldsToTranslate
417
+ .map(field => {
418
+ const val = wine[field] || wine[field.toLowerCase()];
419
+ if (!val) return null;
420
+ return { key: field, text: Array.isArray(val) ? val.join(', ') : val };
421
+ })
422
+ .filter(Boolean);
417
423
 
418
- if (Object.keys(textObject).length === 0) return;
424
+ if (entries.length === 0) return;
419
425
 
420
- const translated = await translator.translateTexts(textObject);
426
+ // Перевод
427
+ const translatedArray = await translator.translateTexts(
428
+ Object.fromEntries(entries.map(entry => [entry.key, entry.text]))
429
+ );
421
430
 
422
431
  const popup = document.querySelector(`.card-popup[data-wine-index="${globalIndex}"]`);
423
432
  if (!popup) return;
424
433
 
425
- if (translated['Short Description']) {
434
+ // Применение перевода
435
+ if (translatedArray['Short Description']) {
426
436
  const el = popup.querySelector('.popup-short-desc');
427
- if (el) el.textContent = translated['Short Description'];
437
+ if (el) el.textContent = translatedArray['Short Description'];
428
438
  }
429
439
 
430
- if (translated.reason) {
440
+ if (translatedArray.reason) {
431
441
  const el = popup.querySelector('.popup-reason');
432
- if (el) el.textContent = translated.reason;
442
+ if (el) el.textContent = translatedArray.reason;
433
443
  }
434
444
 
435
- if (translated.pairing_recommendation) {
445
+ if (translatedArray.pairing_recommendation) {
436
446
  const el = popup.querySelector('.popup-pairing');
437
- if (el) el.textContent = translated.pairing_recommendation;
447
+ if (el) el.textContent = translatedArray.pairing_recommendation;
438
448
  }
439
449
 
440
- if (translated.Tags) {
441
- const tagsArray = translated.Tags.split(',').map(tag => tag.trim());
442
- const tagHTML = tagsArray.map(tag => `<span class="popup-tag">${tag}</span>`).join('');
450
+ const tags = translatedArray.tags || translatedArray.Tags;
451
+ if (tags) {
452
+ const tagArray = tags.split(',').map(tag => tag.trim());
453
+ const tagHTML = tagArray.map(tag => `<span class="popup-tag">${tag}</span>`).join('');
443
454
  const tagsContainer = popup.querySelector('.popup-tags');
444
455
  if (tagsContainer) tagsContainer.innerHTML = tagHTML;
445
456
  }
446
457
  });
447
458
 
448
- // Ждём выполнения всей пачки
449
459
  await Promise.all(translationPromises);
450
460
  }
451
461
  }
@@ -510,9 +520,8 @@ export class WineWidget {
510
520
  createLanguageSwitcher() {
511
521
  const langContainer = document.querySelector('#powered-by-widget .powered-by-lang');
512
522
  const languages = translator.getSupportedLanguages();
513
- if (!languages) {
514
- return;
515
- }
523
+ if (!languages) return;
524
+
516
525
  const currentLanguage = translator.language;
517
526
 
518
527
  const dropdown = document.createElement('select');
@@ -520,18 +529,25 @@ createLanguageSwitcher() {
520
529
  dropdown.className = 'language-dropdown';
521
530
 
522
531
  languages.forEach(lang => {
523
- const option = document.createElement('option');
524
- option.value = lang;
525
- option.textContent = lang.toUpperCase();
526
- option.selected = lang === currentLanguage;
527
- dropdown.appendChild(option);
532
+ const option = document.createElement('option');
533
+ option.value = lang;
534
+ option.textContent = lang.toUpperCase();
535
+ option.selected = lang === currentLanguage;
536
+ dropdown.appendChild(option);
528
537
  });
529
538
 
530
539
  dropdown.onchange = (event) => {
531
- const selectedLang = event.target.value;
532
- translator.language = selectedLang;
533
- localStorage.setItem('selectedLanguage', selectedLang);
534
- location.reload(); // Reload to apply language change
540
+ const selectedLang = event.target.value;
541
+
542
+ // Обновляем URL без перезагрузки страницы
543
+ const url = new URL(window.location.href);
544
+ url.searchParams.set('lang', selectedLang);
545
+
546
+ // Обновляем localStorage тоже, на всякий случай
547
+ localStorage.setItem('selectedLanguage', selectedLang);
548
+
549
+ // Перенаправляем пользователя с обновлённым URL
550
+ window.location.href = url.toString();
535
551
  };
536
552
 
537
553
  langContainer.appendChild(dropdown);