RateComment.svelte 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <script lang="ts">
  2. import { toast } from 'svelte-sonner';
  3. import { createEventDispatcher, onMount, getContext } from 'svelte';
  4. import { config, models } from '$lib/stores';
  5. const i18n = getContext('i18n');
  6. const dispatch = createEventDispatcher();
  7. export let message;
  8. export let show = false;
  9. let LIKE_REASONS = [];
  10. let DISLIKE_REASONS = [];
  11. function loadReasons() {
  12. LIKE_REASONS = [
  13. $i18n.t('Accurate information'),
  14. $i18n.t('Followed instructions perfectly'),
  15. $i18n.t('Showcased creativity'),
  16. $i18n.t('Positive attitude'),
  17. $i18n.t('Attention to detail'),
  18. $i18n.t('Thorough explanation'),
  19. $i18n.t('Other')
  20. ];
  21. DISLIKE_REASONS = [
  22. $i18n.t("Don't like the style"),
  23. $i18n.t('Not factually correct'),
  24. $i18n.t("Didn't fully follow instructions"),
  25. $i18n.t("Refused when it shouldn't have"),
  26. $i18n.t('Being lazy'),
  27. $i18n.t('Other')
  28. ];
  29. }
  30. let reasons = [];
  31. let selectedReason = null;
  32. let comment = '';
  33. let selectedModel = null;
  34. $: if (message?.annotation?.rating === 1) {
  35. reasons = LIKE_REASONS;
  36. } else if (message?.annotation?.rating === -1) {
  37. reasons = DISLIKE_REASONS;
  38. }
  39. onMount(() => {
  40. selectedReason = message?.annotation?.reason ?? '';
  41. comment = message?.annotation?.comment ?? '';
  42. if (message?.arena) {
  43. selectedModel = $models.find((m) => m.id === message.selectedModelId);
  44. toast.success(
  45. $i18n.t('This response was generated by "{{model}}"', {
  46. model: selectedModel ? (selectedModel?.name ?? selectedModel.id) : message.selectedModelId
  47. })
  48. );
  49. }
  50. loadReasons();
  51. });
  52. const saveHandler = () => {
  53. console.log('saveHandler');
  54. if (!selectedReason) {
  55. toast.error($i18n.t('Please select a reason'));
  56. return;
  57. }
  58. dispatch('save', {
  59. reason: selectedReason,
  60. comment: comment
  61. });
  62. toast.success($i18n.t('Thanks for your feedback!'));
  63. show = false;
  64. };
  65. </script>
  66. {#if message?.arena}
  67. <div class="text-xs font-medium translate-y-1.5">
  68. {$i18n.t('This response was generated by "{{model}}"', {
  69. model: selectedModel ? (selectedModel?.name ?? selectedModel.id) : message.selectedModelId
  70. })}
  71. </div>
  72. {/if}
  73. <div
  74. class=" my-2.5 rounded-xl px-4 py-3 border border-gray-50 dark:border-gray-850"
  75. id="message-feedback-{message.id}"
  76. >
  77. <div class="flex justify-between items-center">
  78. <div class=" text-sm">{$i18n.t('Tell us more:')}</div>
  79. <button
  80. on:click={() => {
  81. show = false;
  82. }}
  83. >
  84. <svg
  85. xmlns="http://www.w3.org/2000/svg"
  86. fill="none"
  87. viewBox="0 0 24 24"
  88. stroke-width="1.5"
  89. stroke="currentColor"
  90. class="size-4"
  91. >
  92. <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
  93. </svg>
  94. </button>
  95. </div>
  96. {#if reasons.length > 0}
  97. <div class="flex flex-wrap gap-2 text-sm mt-2.5">
  98. {#each reasons as reason}
  99. <button
  100. class="px-3.5 py-1 border border-gray-50 dark:border-gray-850 hover:bg-gray-100 dark:hover:bg-gray-850 {selectedReason ===
  101. reason
  102. ? 'bg-gray-200 dark:bg-gray-800'
  103. : ''} transition rounded-lg"
  104. on:click={() => {
  105. selectedReason = reason;
  106. }}
  107. >
  108. {reason}
  109. </button>
  110. {/each}
  111. </div>
  112. {/if}
  113. <div class="mt-2">
  114. <textarea
  115. bind:value={comment}
  116. class="w-full text-sm px-1 py-2 bg-transparent outline-none resize-none rounded-xl"
  117. placeholder={$i18n.t('Feel free to add specific details')}
  118. rows="2"
  119. />
  120. </div>
  121. <div class="mt-2 gap-1.5 flex justify-end">
  122. <!-- {#if $config?.features.enable_community_sharing && selectedModel}
  123. <button
  124. class=" self-center px-3.5 py-2 rounded-xl text-sm font-medium bg-gray-50 hover:bg-gray-100 text-gray-800 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-white transition"
  125. type="button"
  126. on:click={() => {
  127. show = false;
  128. }}
  129. >
  130. {$i18n.t('Share to OpenWebUI Community')}
  131. </button>
  132. {/if} -->
  133. <button
  134. class=" bg-emerald-700 hover:bg-emerald-800 transition text-white text-sm font-medium rounded-xl px-3.5 py-1.5"
  135. on:click={() => {
  136. saveHandler();
  137. }}
  138. >
  139. {$i18n.t('Save')}
  140. </button>
  141. </div>
  142. </div>