|
<script lang="ts"> |
|
import { getContext, onMount, tick } from 'svelte'; |
|
import Modal from '$lib/components/common/Modal.svelte'; |
|
import Tooltip from '$lib/components/common/Tooltip.svelte'; |
|
|
|
const i18n = getContext('i18n'); |
|
|
|
export let show = false; |
|
export let citation; |
|
export let showPercentage = false; |
|
export let showRelevance = true; |
|
|
|
let mergedDocuments = []; |
|
|
|
function calculatePercentage(distance: number) { |
|
if (distance < 0) return 100; |
|
if (distance > 1) return 0; |
|
return Math.round((1 - distance) * 10000) / 100; |
|
} |
|
|
|
function getRelevanceColor(percentage: number) { |
|
if (percentage >= 80) |
|
return 'bg-green-200 dark:bg-green-800 text-green-800 dark:text-green-200'; |
|
if (percentage >= 60) |
|
return 'bg-yellow-200 dark:bg-yellow-800 text-yellow-800 dark:text-yellow-200'; |
|
if (percentage >= 40) |
|
return 'bg-orange-200 dark:bg-orange-800 text-orange-800 dark:text-orange-200'; |
|
return 'bg-red-200 dark:bg-red-800 text-red-800 dark:text-red-200'; |
|
} |
|
|
|
$: if (citation) { |
|
mergedDocuments = citation.document?.map((c, i) => { |
|
return { |
|
source: citation.source, |
|
document: c, |
|
metadata: citation.metadata?.[i], |
|
distance: citation.distances?.[i] |
|
}; |
|
}); |
|
if (mergedDocuments.every((doc) => doc.distance !== undefined)) { |
|
mergedDocuments.sort((a, b) => (a.distance ?? Infinity) - (b.distance ?? Infinity)); |
|
} |
|
} |
|
</script> |
|
|
|
<Modal size="lg" bind:show> |
|
<div> |
|
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-2"> |
|
<div class=" text-lg font-medium self-center capitalize"> |
|
{$i18n.t('Citation')} |
|
</div> |
|
<button |
|
class="self-center" |
|
on:click={() => { |
|
show = false; |
|
}} |
|
> |
|
<svg |
|
xmlns="http://www.w3.org/2000/svg" |
|
viewBox="0 0 20 20" |
|
fill="currentColor" |
|
class="w-5 h-5" |
|
> |
|
<path |
|
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" |
|
/> |
|
</svg> |
|
</button> |
|
</div> |
|
|
|
<div class="flex flex-col md:flex-row w-full px-6 pb-5 md:space-x-4"> |
|
<div |
|
class="flex flex-col w-full dark:text-gray-200 overflow-y-scroll max-h-[22rem] scrollbar-hidden" |
|
> |
|
{#each mergedDocuments as document, documentIdx} |
|
<div class="flex flex-col w-full"> |
|
<div class="text-sm font-medium dark:text-gray-300"> |
|
{$i18n.t('Source')} |
|
</div> |
|
|
|
{#if document.source?.name} |
|
<Tooltip |
|
className="w-fit" |
|
content={$i18n.t('Open file')} |
|
placement="top-start" |
|
tippyOptions={{ duration: [500, 0] }} |
|
> |
|
<div class="text-sm dark:text-gray-400 flex items-center gap-2 w-fit"> |
|
<a |
|
class="hover:text-gray-500 hover:dark:text-gray-100 underline flex-grow" |
|
href={document?.metadata?.file_id |
|
? `/api/v1/files/${document?.metadata?.file_id}/content${document?.metadata?.page !== undefined ? `#page=${document.metadata.page + 1}` : ''}` |
|
: document.source?.url?.includes('http') |
|
? document.source.url |
|
: `#`} |
|
target="_blank" |
|
> |
|
{document?.metadata?.name ?? document.source.name} |
|
</a> |
|
{#if document?.metadata?.page} |
|
<span class="text-xs text-gray-500 dark:text-gray-400"> |
|
({$i18n.t('page')} |
|
{document.metadata.page + 1}) |
|
</span> |
|
{/if} |
|
</div> |
|
</Tooltip> |
|
{#if showRelevance} |
|
<div class="text-sm font-medium dark:text-gray-300 mt-2"> |
|
{$i18n.t('Relevance')} |
|
</div> |
|
{#if document.distance !== undefined} |
|
<Tooltip |
|
className="w-fit" |
|
content={$i18n.t('Semantic distance to query')} |
|
placement="top-start" |
|
tippyOptions={{ duration: [500, 0] }} |
|
> |
|
<div class="text-sm my-1 dark:text-gray-400 flex items-center gap-2 w-fit"> |
|
{#if showPercentage} |
|
{@const percentage = calculatePercentage(document.distance)} |
|
<span class={`px-1 rounded font-medium ${getRelevanceColor(percentage)}`}> |
|
{percentage.toFixed(2)}% |
|
</span> |
|
<span class="text-gray-500 dark:text-gray-500"> |
|
({document.distance.toFixed(4)}) |
|
</span> |
|
{:else} |
|
<span class="text-gray-500 dark:text-gray-500"> |
|
{document.distance.toFixed(4)} |
|
</span> |
|
{/if} |
|
</div> |
|
</Tooltip> |
|
{:else} |
|
<div class="text-sm dark:text-gray-400"> |
|
{$i18n.t('No distance available')} |
|
</div> |
|
{/if} |
|
{/if} |
|
{:else} |
|
<div class="text-sm dark:text-gray-400"> |
|
{$i18n.t('No source available')} |
|
</div> |
|
{/if} |
|
</div> |
|
<div class="flex flex-col w-full"> |
|
<div class=" text-sm font-medium dark:text-gray-300 mt-2"> |
|
{$i18n.t('Content')} |
|
</div> |
|
<pre class="text-sm dark:text-gray-400 whitespace-pre-line"> |
|
{document.document} |
|
</pre> |
|
</div> |
|
|
|
{#if documentIdx !== mergedDocuments.length - 1} |
|
<hr class=" dark:border-gray-850 my-3" /> |
|
{/if} |
|
{/each} |
|
</div> |
|
</div> |
|
</div> |
|
</Modal> |
|
|