/
Netrunners
/
Millenium_UI
Обзор
Документация
Войти
/
Netrunners
/
Millenium_UI
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/lib/components/chat/Messages/Citations.svelte
206 строк
6 KB
Валерий Конюхов
first_commit
08 июл 2025, 22:20
08 июл 2025, 22:20
a4e8dc9
Код
Авторство
О чём код?
<script lang="ts"> import { getContext } from 'svelte'; import CitationsModal from './CitationsModal.svelte'; import Collapsible from '$lib/components/common/Collapsible.svelte'; import ChevronDown from '$lib/components/icons/ChevronDown.svelte'; import ChevronUp from '$lib/components/icons/ChevronUp.svelte'; const i18n = getContext('i18n'); export let id = ''; export let sources = []; let citations = []; let showPercentage = false; let showRelevance = true; let showCitationModal = false; let selectedCitation: any = null; let isCollapsibleOpen = false; function calculateShowRelevance(sources: any[]) { const distances = sources.flatMap((citation) => citation.distances ?? []); const inRange = distances.filter((d) => d !== undefined && d >= -1 && d <= 1).length; const outOfRange = distances.filter((d) => d !== undefined && (d < -1 || d > 1)).length; if (distances.length === 0) { return false; } if ( (inRange === distances.length - 1 && outOfRange === 1) || (outOfRange === distances.length - 1 && inRange === 1) ) { return false; } return true; } function shouldShowPercentage(sources: any[]) { const distances = sources.flatMap((citation) => citation.distances ?? []); return distances.every((d) => d !== undefined && d >= -1 && d <= 1); } $: { console.log('sources', sources); citations = sources.reduce((acc, source) => { if (Object.keys(source).length === 0) { return acc; } source.document.forEach((document, index) => { const metadata = source.metadata?.[index]; const distance = source.distances?.[index]; // Within the same citation there could be multiple documents const id = metadata?.source ?? source?.source?.id ?? 'N/A'; let _source = source?.source; if (metadata?.name) { _source = { ..._source, name: metadata.name }; } if (id.startsWith('http://') || id.startsWith('https://')) { _source = { ..._source, name: id, url: id }; } const existingSource = acc.find((item) => item.id === id); if (existingSource) { existingSource.document.push(document); existingSource.metadata.push(metadata); if (distance !== undefined) existingSource.distances.push(distance); } else { acc.push({ id: id, source: _source, document: [document], metadata: metadata ? [metadata] : [], distances: distance !== undefined ? [distance] : undefined }); } }); return acc; }, []); showRelevance = calculateShowRelevance(citations); showPercentage = shouldShowPercentage(citations); } </script> <CitationsModal bind:show={showCitationModal} citation={selectedCitation} {showPercentage} {showRelevance} /> {#if citations.length > 0} <div class=" py-0.5 -mx-0.5 w-full flex gap-1 items-center flex-wrap"> {#if citations.length <= 3} <div class="flex text-xs font-medium flex-wrap"> {#each citations as citation, idx} <button id={`source-${id}-${idx}`} class="no-toggle outline-hidden flex dark:text-gray-300 p-1 bg-white dark:bg-gray-900 rounded-xl max-w-96" on:click={() => { showCitationModal = true; selectedCitation = citation; }} > {#if citations.every((c) => c.distances !== undefined)} <div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4"> {idx + 1} </div> {/if} <div class="flex-1 mx-1 truncate text-black/60 hover:text-black dark:text-white/60 dark:hover:text-white transition" > {citation.source.name} </div> </button> {/each} </div> {:else} <Collapsible id="collapsible-sources" bind:open={isCollapsibleOpen} className="w-full max-w-full " buttonClassName="w-fit max-w-full" > <div class="flex w-full overflow-auto items-center gap-2 text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 transition cursor-pointer" > <div class="flex-1 flex items-center gap-1 overflow-auto scrollbar-none w-full max-w-full" > <span class="whitespace-nowrap hidden sm:inline shrink-0" >{$i18n.t('References from')}</span > <div class="flex items-center overflow-auto scrollbar-none w-full max-w-full flex-1"> <div class="flex text-xs font-medium items-center"> {#each citations.slice(0, 2) as citation, idx} <button class="no-toggle outline-hidden flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96" on:click={() => { showCitationModal = true; selectedCitation = citation; }} on:pointerup={(e) => { e.stopPropagation(); }} > {#if citations.every((c) => c.distances !== undefined)} <div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4"> {idx + 1} </div> {/if} <div class="flex-1 mx-1 truncate"> {citation.source.name} </div> </button> {/each} </div> </div> <div class="flex items-center gap-1 whitespace-nowrap shrink-0"> <span class="hidden sm:inline">{$i18n.t('and')}</span> {citations.length - 2} <span>{$i18n.t('more')}</span> </div> </div> <div class="shrink-0"> {#if isCollapsibleOpen} <ChevronUp strokeWidth="3.5" className="size-3.5" /> {:else} <ChevronDown strokeWidth="3.5" className="size-3.5" /> {/if} </div> </div> <div slot="content"> <div class="flex text-xs font-medium flex-wrap"> {#each citations as citation, idx} <button id={`source-${id}-${idx}`} class="no-toggle outline-hidden flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96" on:click={() => { showCitationModal = true; selectedCitation = citation; }} > {#if citations.every((c) => c.distances !== undefined)} <div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4"> {idx + 1} </div> {/if} <div class="flex-1 mx-1 truncate"> {citation.source.name} </div> </button> {/each} </div> </div> </Collapsible> {/if} </div> {/if}