|
<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 selectedModel = null; |
|
|
|
$: if (message?.annotation?.rating === 1) { |
|
reasons = LIKE_REASONS; |
|
} else if (message?.annotation?.rating === -1) { |
|
reasons = DISLIKE_REASONS; |
|
} |
|
|
|
$: if (message) { |
|
init(); |
|
} |
|
|
|
const init = () => { |
|
selectedReason = message?.annotation?.reason ?? ''; |
|
comment = message?.annotation?.comment ?? ''; |
|
tags = (message?.annotation?.tags ?? []).map((tag) => ({ |
|
name: tag |
|
})); |
|
}; |
|
|
|
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'); |
|
|
|
|
|
|
|
|
|
|
|
dispatch('save', { |
|
reason: selectedReason, |
|
comment: comment, |
|
tags: tags.map((tag) => tag.name) |
|
}); |
|
|
|
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-50 dark:border-gray-850" |
|
id="message-feedback-{message.id}" |
|
> |
|
<div class="flex justify-between items-center"> |
|
<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> |
|
|
|
{#if reasons.length > 0} |
|
<div class="flex flex-wrap gap-1.5 text-sm mt-2.5"> |
|
{#each reasons as reason} |
|
<button |
|
class="px-3 py-0.5 border border-gray-50 dark:border-gray-850 hover:bg-gray-100 dark:hover:bg-gray-850 {selectedReason === |
|
reason |
|
? 'bg-gray-200 dark:bg-gray-800' |
|
: ''} transition rounded-lg" |
|
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 class="mt-2"> |
|
<textarea |
|
bind:value={comment} |
|
class="w-full text-sm px-1 py-2 bg-transparent outline-none 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=" bg-emerald-700 hover:bg-emerald-800 transition text-white text-sm font-medium rounded-xl px-3.5 py-1.5" |
|
on:click={() => { |
|
saveHandler(); |
|
}} |
|
> |
|
{$i18n.t('Save')} |
|
</button> |
|
</div> |
|
</div> |
|
|