Spaces:
Paused
Paused
| <script lang="ts"> | |
| import { toast } from 'svelte-sonner'; | |
| import { createEventDispatcher, onMount, getContext } from 'svelte'; | |
| import { config, models } from '$lib/stores'; | |
| import Tags from '$lib/components/common/Tags.svelte'; | |
| const i18n = getContext('i18n'); | |
| const dispatch = createEventDispatcher(); | |
| export let message; | |
| export let show = false; | |
| let LIKE_REASONS = [ | |
| 'accurate_information', | |
| 'followed_instructions_perfectly', | |
| 'showcased_creativity', | |
| 'positive_attitude', | |
| 'attention_to_detail', | |
| 'thorough_explanation', | |
| 'other' | |
| ]; | |
| let DISLIKE_REASONS = [ | |
| 'dont_like_the_style', | |
| 'too_verbose', | |
| 'not_helpful', | |
| 'not_factually_correct', | |
| 'didnt_fully_follow_instructions', | |
| 'refused_when_it_shouldnt_have', | |
| 'being_lazy', | |
| 'other' | |
| ]; | |
| let tags = []; | |
| let reasons = []; | |
| let selectedReason = null; | |
| let comment = ''; | |
| let detailedRating = null; | |
| let selectedModel = null; | |
| $: if (message?.annotation?.rating === 1) { | |
| reasons = LIKE_REASONS; | |
| } else if (message?.annotation?.rating === -1) { | |
| reasons = DISLIKE_REASONS; | |
| } | |
| $: if (message) { | |
| init(); | |
| } | |
| const init = () => { | |
| if (!selectedReason) { | |
| selectedReason = message?.annotation?.reason ?? ''; | |
| } | |
| if (!comment) { | |
| comment = message?.annotation?.comment ?? ''; | |
| } | |
| tags = (message?.annotation?.tags ?? []).map((tag) => ({ | |
| name: tag | |
| })); | |
| if (!detailedRating) { | |
| detailedRating = message?.annotation?.details?.rating ?? null; | |
| } | |
| }; | |
| onMount(() => { | |
| if (message?.arena) { | |
| selectedModel = $models.find((m) => m.id === message.selectedModelId); | |
| toast.success( | |
| $i18n.t('This response was generated by "{{model}}"', { | |
| model: selectedModel ? (selectedModel?.name ?? selectedModel.id) : message.selectedModelId | |
| }) | |
| ); | |
| } | |
| }); | |
| const saveHandler = () => { | |
| console.log('saveHandler'); | |
| // if (!selectedReason) { | |
| // toast.error($i18n.t('Please select a reason')); | |
| // return; | |
| // } | |
| dispatch('save', { | |
| reason: selectedReason, | |
| comment: comment, | |
| tags: tags.map((tag) => tag.name), | |
| details: { | |
| rating: detailedRating | |
| } | |
| }); | |
| toast.success($i18n.t('Thanks for your feedback!')); | |
| show = false; | |
| }; | |
| </script> | |
| {#if message?.arena} | |
| <div class="text-xs font-medium pt-1.5 -mb-0.5"> | |
| {$i18n.t('This response was generated by "{{model}}"', { | |
| model: selectedModel ? (selectedModel?.name ?? selectedModel.id) : message.selectedModelId | |
| })} | |
| </div> | |
| {/if} | |
| <div | |
| class=" my-2.5 rounded-xl px-4 py-3 border border-gray-100 dark:border-gray-850" | |
| id="message-feedback-{message.id}" | |
| > | |
| <div class="flex justify-between items-center"> | |
| <div class="text-sm font-medium">{$i18n.t('How would you rate this response?')}</div> | |
| <!-- <div class=" text-sm">{$i18n.t('Tell us more:')}</div> --> | |
| <button | |
| on:click={() => { | |
| show = false; | |
| }} | |
| > | |
| <svg | |
| xmlns="http://www.w3.org/2000/svg" | |
| fill="none" | |
| viewBox="0 0 24 24" | |
| stroke-width="1.5" | |
| stroke="currentColor" | |
| class="size-4" | |
| > | |
| <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /> | |
| </svg> | |
| </button> | |
| </div> | |
| <div class="w-full flex justify-center"> | |
| <div class=" relative w-fit"> | |
| <div class="mt-1.5 w-fit flex gap-1 pb-5"> | |
| <!-- 1-10 scale --> | |
| {#each Array.from({ length: 10 }).map((_, i) => i + 1) as rating} | |
| <button | |
| class="size-7 text-sm border border-gray-100 dark:border-gray-850 hover:bg-gray-50 dark:hover:bg-gray-850 {detailedRating === | |
| rating | |
| ? 'bg-gray-100 dark:bg-gray-800' | |
| : ''} transition rounded-full disabled:cursor-not-allowed disabled:text-gray-500 disabled:bg-white dark:disabled:bg-gray-900" | |
| on:click={() => { | |
| detailedRating = rating; | |
| }} | |
| disabled={message?.annotation?.rating === -1 ? rating > 5 : rating < 6} | |
| > | |
| {rating} | |
| </button> | |
| {/each} | |
| </div> | |
| <div class="absolute bottom-0 left-0 right-0 flex justify-between text-xs"> | |
| <div> | |
| 1 - {$i18n.t('Awful')} | |
| </div> | |
| <div> | |
| 10 - {$i18n.t('Amazing')} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| {#if reasons.length > 0} | |
| <div class="text-sm mt-1.5 font-medium">{$i18n.t('Why?')}</div> | |
| <div class="flex flex-wrap gap-1.5 text-sm mt-1.5"> | |
| {#each reasons as reason} | |
| <button | |
| class="px-3 py-0.5 border border-gray-100 dark:border-gray-850 hover:bg-gray-50 dark:hover:bg-gray-850 {selectedReason === | |
| reason | |
| ? 'bg-gray-100 dark:bg-gray-800' | |
| : ''} transition rounded-xl" | |
| on:click={() => { | |
| selectedReason = reason; | |
| }} | |
| > | |
| {#if reason === 'accurate_information'} | |
| {$i18n.t('Accurate information')} | |
| {:else if reason === 'followed_instructions_perfectly'} | |
| {$i18n.t('Followed instructions perfectly')} | |
| {:else if reason === 'showcased_creativity'} | |
| {$i18n.t('Showcased creativity')} | |
| {:else if reason === 'positive_attitude'} | |
| {$i18n.t('Positive attitude')} | |
| {:else if reason === 'attention_to_detail'} | |
| {$i18n.t('Attention to detail')} | |
| {:else if reason === 'thorough_explanation'} | |
| {$i18n.t('Thorough explanation')} | |
| {:else if reason === 'dont_like_the_style'} | |
| {$i18n.t("Don't like the style")} | |
| {:else if reason === 'too_verbose'} | |
| {$i18n.t('Too verbose')} | |
| {:else if reason === 'not_helpful'} | |
| {$i18n.t('Not helpful')} | |
| {:else if reason === 'not_factually_correct'} | |
| {$i18n.t('Not factually correct')} | |
| {:else if reason === 'didnt_fully_follow_instructions'} | |
| {$i18n.t("Didn't fully follow instructions")} | |
| {:else if reason === 'refused_when_it_shouldnt_have'} | |
| {$i18n.t("Refused when it shouldn't have")} | |
| {:else if reason === 'being_lazy'} | |
| {$i18n.t('Being lazy')} | |
| {:else if reason === 'other'} | |
| {$i18n.t('Other')} | |
| {:else} | |
| {reason} | |
| {/if} | |
| </button> | |
| {/each} | |
| </div> | |
| {/if} | |
| </div> | |
| <div class="mt-2"> | |
| <textarea | |
| bind:value={comment} | |
| class="w-full text-sm px-1 py-2 bg-transparent outline-hidden resize-none rounded-xl" | |
| placeholder={$i18n.t('Feel free to add specific details')} | |
| rows="3" | |
| /> | |
| </div> | |
| <div class="mt-2 gap-1.5 flex justify-between"> | |
| <div class="flex items-end group"> | |
| <Tags | |
| {tags} | |
| on:delete={(e) => { | |
| tags = tags.filter( | |
| (tag) => | |
| tag.name.replaceAll(' ', '_').toLowerCase() !== | |
| e.detail.replaceAll(' ', '_').toLowerCase() | |
| ); | |
| }} | |
| on:add={(e) => { | |
| tags = [...tags, { name: e.detail }]; | |
| }} | |
| /> | |
| </div> | |
| <button | |
| class="px-3.5 py-1.5 text-sm font-medium bg-black hover:bg-gray-900 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full" | |
| on:click={() => { | |
| saveHandler(); | |
| }} | |
| > | |
| {$i18n.t('Save')} | |
| </button> | |
| </div> | |
| </div> | |