-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(kb): Individual page and file upload
- Loading branch information
1 parent
d7a2f27
commit 4b91b96
Showing
14 changed files
with
278 additions
and
43 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
<template> | ||
<section v-if="knowledgeBaseRef" class="max-sm:tw-mx-4 md:tw-mx-10 tw-space-y-4 tw-my-5"> | ||
<q-btn | ||
:icon="`img:icons/svg/arrow-left${$q.dark.mode ? '_lighten' : ''}.svg`" | ||
class="tw-w-10 tw-h-10" | ||
to="/knowledge-base" | ||
unelevated | ||
/> | ||
<div> | ||
<h4 class="text-h4 text-semibold">{{ knowledgeBaseRef.name }}</h4> | ||
<div class="tw-mt-4 tw-flex md:tw-justify-end"> | ||
<q-btn | ||
class="border-primary-highlight" | ||
icon="img:icons/svg/add.svg" | ||
label="Upload document" | ||
no-caps | ||
rounded | ||
unelevated | ||
@click="($refs.documentUpload as any).click()" | ||
/> | ||
<!-- Hidden document upload --> | ||
<input ref="documentUpload" accept=".txt,.md,.pdf" hidden multiple type="file" @change="uploadDocuments" /> | ||
</div> | ||
</div> | ||
|
||
<div class="tw-space-y-4"> | ||
<div | ||
v-for="document of knowledgeBaseRef.documents" | ||
:key="document.id" | ||
class="tw-flex tw-border tw-items-center tw-rounded-lg tw-p-4" | ||
> | ||
<q-icon | ||
:color="$q.dark.mode ? 'primary-dark' : 'purple-700'" | ||
class="tw-h-5 tw-w-5 tw-mr-4" | ||
name="img:icons/svg/attachment.svg" | ||
/> | ||
|
||
<p class="tw-font-bold tw-text-base">{{ document.name }}</p> | ||
<div class="tw-ml-auto tw-flex tw-items-center tw-gap-4"> | ||
<p>{{ filesize(document.size, { round: 0 }) }}</p> | ||
<q-btn class="tw-w-10 tw-h-10" disable icon="img:icons/svg/chat.svg" unelevated /> | ||
|
||
<q-btn class="tw-w-10 tw-h-10" unelevated @click="downloadDocument(document)"> | ||
<q-icon :color="$q.dark.mode ? 'primary-dark' : 'purple-700'" name="download" /> | ||
</q-btn> | ||
|
||
<q-btn class="tw-w-10 tw-h-10" disable unelevated> | ||
<q-icon :color="$q.dark.mode ? 'primary-dark' : 'purple-700'" name="more_horiz" /> | ||
</q-btn> | ||
</div> | ||
</div> | ||
</div> | ||
</section> | ||
</template> | ||
<script lang="ts" setup> | ||
import { ref, watch } from 'vue'; | ||
import { useRoute, useRouter } from 'vue-router'; | ||
import { KnowledgeBase, KnowledgeDocument } from 'src/types/knowledge'; | ||
import { useKnowledgeStore } from 'stores/knowledge'; | ||
import { exportFile, useQuasar } from 'quasar'; | ||
import { useAccount } from '@wagmi/vue'; | ||
import { useAccountStore } from 'stores/account'; | ||
import { processDocument } from 'src/utils/knowledge/document'; | ||
import { filesize } from 'filesize'; | ||
const $q = useQuasar(); | ||
const route = useRoute(); | ||
const router = useRouter(); | ||
const account = useAccount(); | ||
const accountStore = useAccountStore(); | ||
const knowledgeStore = useKnowledgeStore(); | ||
const knowledgeBaseRef = ref<KnowledgeBase | undefined>(undefined); | ||
watch( | ||
() => route.params.id as string, | ||
async (newId: string) => { | ||
await loadKnowledgeBase(newId); | ||
}, | ||
{ immediate: true }, | ||
); | ||
async function loadKnowledgeBase(id: string) { | ||
if (!account.isConnected.value) { | ||
$q.notify({ message: 'Account not connected', color: 'negative' }); | ||
await router.push({ path: '/' }); | ||
return; | ||
} | ||
if (!knowledgeStore.isLoaded) { | ||
// This page was loaded directly, auto connect allowed us to get the wallet, | ||
// but we didn't load KB yet, waiting for it | ||
setTimeout(() => { | ||
loadKnowledgeBase(id); | ||
}, 100); | ||
return; | ||
} | ||
const knowledgeBase = knowledgeStore.knowledgeBases.find((kb) => kb.id === id); | ||
if (!knowledgeBase) { | ||
$q.notify({ message: 'Knowledge base not found', color: 'negative' }); | ||
await router.push({ path: '/knowledge-base' }); | ||
return; | ||
} | ||
// Set the ref with a copy to avoid modifying the store value | ||
knowledgeBaseRef.value = JSON.parse(JSON.stringify(knowledgeBase)); | ||
} | ||
const uploadDocuments = async (event: any) => { | ||
if (knowledgeBaseRef.value === undefined) { | ||
return; | ||
} | ||
if (accountStore.alephStorage === null) { | ||
$q.notify({ | ||
message: 'Connect your wallet to upload a document', | ||
color: 'negative', | ||
}); | ||
return; | ||
} | ||
const target = event.target as HTMLInputElement; | ||
const documents: KnowledgeDocument[] = []; | ||
await Promise.all( | ||
Array.from(target.files as FileList).map(async (file) => { | ||
try { | ||
const document = await processDocument(file); | ||
const uploadedFileMessage = await accountStore.alephStorage!.uploadFile(file); | ||
documents.push({ ...document, store_hash: uploadedFileMessage.content.item_hash }); | ||
} catch (error) { | ||
$q.notify({ | ||
message: (error as Error)?.message ?? 'Document processing failed, please try again', | ||
color: 'negative', | ||
}); | ||
} | ||
}), | ||
); | ||
knowledgeBaseRef.value.documents = knowledgeBaseRef.value.documents.concat(documents); | ||
await knowledgeStore.updateKnowledgeBase( | ||
knowledgeBaseRef.value.id, | ||
JSON.parse(JSON.stringify(knowledgeBaseRef.value)), | ||
); | ||
}; | ||
const downloadDocument = async (document: KnowledgeDocument) => { | ||
if (accountStore.alephStorage === null) { | ||
return; | ||
} | ||
const downloadedFile = await accountStore.alephStorage.downloadFile(document.store_hash); | ||
exportFile(document.name, downloadedFile); | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { v4 as uuidv4 } from 'uuid'; | ||
import { MessageAttachment } from 'src/types/chats'; | ||
import { extractFileContent } from 'src/utils/knowledge/parsing'; | ||
|
||
export const processAttachment = async (file: File): Promise<MessageAttachment> => { | ||
const title = file.name; | ||
const fileInfo = await extractFileContent(file); | ||
|
||
if (fileInfo.content.length > 4 * 1024) { | ||
// File is too big to be inlined, rejecting it. | ||
// Later we'll use a knowledge db to fix this. | ||
throw new Error('File is too big, please use a file of 4 KB of content or less.'); | ||
} | ||
|
||
return { title, content: fileInfo.content, type: fileInfo.content, id: uuidv4() }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { v4 as uuidv4 } from 'uuid'; | ||
|
||
import { KnowledgeDocument } from 'src/types/knowledge'; | ||
import { extractFileContent } from 'src/utils/knowledge/parsing'; | ||
|
||
export const processDocument = async (file: File): Promise<Omit<KnowledgeDocument, 'store_hash'>> => { | ||
const fileInfo = await extractFileContent(file); | ||
|
||
return { ...fileInfo, id: uuidv4(), name: file.name, size: file.size }; | ||
}; |
Oops, something went wrong.