feat: text fragment url in citations
This commit is contained in:
@@ -53,10 +53,40 @@
|
|||||||
const decodeString = (str: string) => {
|
const decodeString = (str: string) => {
|
||||||
try {
|
try {
|
||||||
return decodeURIComponent(str);
|
return decodeURIComponent(str);
|
||||||
} catch (e) {
|
} catch {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getTextFragmentUrl = (doc: any): string | null => {
|
||||||
|
const { metadata, source, document: content } = doc ?? {};
|
||||||
|
const { file_id, page } = metadata ?? {};
|
||||||
|
const sourceUrl = source?.url;
|
||||||
|
|
||||||
|
const baseUrl = file_id
|
||||||
|
? `${WEBUI_API_BASE_URL}/files/${file_id}/content${page !== undefined ? `#page=${page + 1}` : ''}`
|
||||||
|
: sourceUrl?.includes('http')
|
||||||
|
? sourceUrl
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!baseUrl || !content) return baseUrl;
|
||||||
|
|
||||||
|
// Extract first and last words for text fragment, filtering out URLs and emojis
|
||||||
|
const words = content
|
||||||
|
.trim()
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.split(' ')
|
||||||
|
.filter((w: string) => w.length > 0 && !/https?:\/\/|[\u{1F300}-\u{1F9FF}]/u.test(w));
|
||||||
|
|
||||||
|
if (words.length === 0) return baseUrl;
|
||||||
|
|
||||||
|
const clean = (w: string) => w.replace(/[^\w]/g, '');
|
||||||
|
const first = clean(words[0]);
|
||||||
|
const last = clean(words.at(-1));
|
||||||
|
const fragment = words.length === 1 ? first : `${first},${last}`;
|
||||||
|
|
||||||
|
return fragment ? `${baseUrl}#:~:text=${fragment}` : baseUrl;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal size="lg" bind:show>
|
<Modal size="lg" bind:show>
|
||||||
@@ -124,7 +154,20 @@
|
|||||||
<div
|
<div
|
||||||
class=" text-sm font-medium dark:text-gray-300 flex items-center gap-2 w-fit mb-1"
|
class=" text-sm font-medium dark:text-gray-300 flex items-center gap-2 w-fit mb-1"
|
||||||
>
|
>
|
||||||
{$i18n.t('Content')}
|
{#if document.source?.url?.includes('http')}
|
||||||
|
{@const snippetUrl = getTextFragmentUrl(document)}
|
||||||
|
{#if snippetUrl}
|
||||||
|
<a
|
||||||
|
href={snippetUrl}
|
||||||
|
target="_blank"
|
||||||
|
class="underline hover:text-gray-500 dark:hover:text-gray-100"
|
||||||
|
>{$i18n.t('Content')}</a>
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('Content')}
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('Content')}
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if showRelevance && document.distance !== undefined}
|
{#if showRelevance && document.distance !== undefined}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@@ -172,7 +215,7 @@
|
|||||||
<pre class="text-sm dark:text-gray-400 whitespace-pre-line">{document.document
|
<pre class="text-sm dark:text-gray-400 whitespace-pre-line">{document.document
|
||||||
.trim()
|
.trim()
|
||||||
.replace(/\n\n+/g, '\n\n')}</pre>
|
.replace(/\n\n+/g, '\n\n')}</pre>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
Reference in New Issue
Block a user