ai / frontend /src /lib /components /chat /Messages /RateComment.svelte
fdrah
initial-commit
9e93b10
Raw
History Blame Contribute Delete
7.81 kB
<script lang="ts">
import { toast } from "svelte-sonner";
import { createEventDispatcher, onMount, getContext } from "svelte";
import { config, models, tags as _tags } from "$lib/stores";
import Tags from "$lib/components/common/Tags.svelte";
import XMark from "$lib/components/icons/XMark.svelte";
import ChevronRight from "$lib/components/icons/ChevronRight.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/30 dark:border-gray-850/30"
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
aria-label={$i18n.t("Close feedback")}
on:click={() => {
show = false;
}}
>
<XMark className={"size-4"} />
</button>
</div>
<div class="w-full flex justify-center">
<div class=" relative w-fit overflow-x-auto scrollbar-none">
<div class="mt-1.5 w-fit flex gap-1 pb-2">
<!-- 1-10 scale -->
{#each Array.from( { length: 10 }, ).map((_, i) => i + 1) as rating}
<button
aria-label={$i18n.t("Rate {{rating}} out of 10", {
rating,
})}
class="size-7 text-sm border border-gray-100/30 dark:border-gray-850/30 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="sticky top-0 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/30 dark:border-gray-850/30 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")}
aria-label={$i18n.t("Additional feedback comments")}
rows="3"
/>
</div>
<div class="mt-2 gap-1.5 flex justify-between">
<div class="flex items-end group">
<Tags
{tags}
suggestionTags={$_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>
{#if $config?.features.enable_community_sharing && message?.model}
<div
class="mt-3 pt-3 border-t border-gray-100/30 dark:border-gray-850/30"
>
<a
href={`https://rexpro-ai.rexpro.com/models?q=${encodeURIComponent(message.model)}`}
target="_blank"
class="flex cursor-pointer items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-850 w-full px-3 py-2 rounded-xl transition"
>
<div class="self-center">
<div class="text-sm font-medium">
{$i18n.t("Leave a public review for {{modelName}}", {
modelName: message.model,
})}
</div>
<div class="text-xs text-gray-500">
{$i18n.t("Help the community discover great models")}
</div>
</div>
<ChevronRight className="size-4" />
</a>
</div>
{/if}
</div>