Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,17 @@ declare module 'vue' {
DynamicForm: typeof import('./src/components/DynamicForm.vue')['default']
ErrorBox: typeof import('./src/components/ErrorBox.vue')['default']
Header: typeof import('./src/components/Header.vue')['default']
HeroiconsAdjustmentsVertical: typeof import('~icons/heroicons/adjustments-vertical')['default']
HeroiconsArrowDown20Solid: typeof import('~icons/heroicons/arrow-down20-solid')['default']
HeroiconsArrowPath: typeof import('~icons/heroicons/arrow-path')['default']
HeroiconsArrowRightOnRectangle: typeof import('~icons/heroicons/arrow-right-on-rectangle')['default']
HeroiconsBars3Solid: typeof import('~icons/heroicons/bars3-solid')['default']
HeroiconsBoltSolid: typeof import('~icons/heroicons/bolt-solid')['default']
HeroiconsChevronUpDown20Solid: typeof import('~icons/heroicons/chevron-up-down20-solid')['default']
HeroiconsClipboard: typeof import('~icons/heroicons/clipboard')['default']
HeroiconsCloudArrowDownSolid: typeof import('~icons/heroicons/cloud-arrow-down-solid')['default']
HeroiconsCog6Tooth20Solid: typeof import('~icons/heroicons/cog6-tooth20-solid')['default']
HeroiconsDocumentTextSolid: typeof import('~icons/heroicons/document-text-solid')['default']
HeroiconsGlobeAlt: typeof import('~icons/heroicons/globe-alt')['default']
HeroiconsHome20Solid: typeof import('~icons/heroicons/home20-solid')['default']
HeroiconsInformationCircleSolid: typeof import('~icons/heroicons/information-circle-solid')['default']
HeroiconsLink20Solid: typeof import('~icons/heroicons/link20-solid')['default']
HeroiconsLogout: typeof import('~icons/heroicons/logout')['default']
HeroiconsLogoutSolid: typeof import('~icons/heroicons/logout-solid')['default']
HeroiconsMagnifyingGlass20Solid: typeof import('~icons/heroicons/magnifying-glass20-solid')['default']
HeroiconsMicrophoneSolid: typeof import('~icons/heroicons/microphone-solid')['default']
HeroiconsMoonSolid: typeof import('~icons/heroicons/moon-solid')['default']
Expand All @@ -53,36 +47,24 @@ declare module 'vue' {
ModalBox: typeof import('./src/components/ModalBox.vue')['default']
NotificationStack: typeof import('./src/components/NotificationStack.vue')['default']
Pagination: typeof import('./src/components/Pagination.vue')['default']
PhArrowCounterClockwiseBold: typeof import('~icons/ph/arrow-counter-clockwise-bold')['default']
PhBrainFill: typeof import('~icons/ph/brain-fill')['default']
PhCaretLeftFill: typeof import('~icons/ph/caret-left-fill')['default']
PhCaretRightFill: typeof import('~icons/ph/caret-right-fill')['default']
PhChatCenteredDots: typeof import('~icons/ph/chat-centered-dots')['default']
PhChats: typeof import('~icons/ph/chats')['default']
PhExportBold: typeof import('~icons/ph/export-bold')['default']
PhFileFill: typeof import('~icons/ph/file-fill')['default']
PhFiles: typeof import('~icons/ph/files')['default']
PhFloppyDiskBold: typeof import('~icons/ph/floppy-disk-bold')['default']
PhInfo: typeof import('~icons/ph/info')['default']
PhLightbulbFilamentFill: typeof import('~icons/ph/lightbulb-filament-fill')['default']
PhListMagnifyingGlass: typeof import('~icons/ph/list-magnifying-glass')['default']
PhNut: typeof import('~icons/ph/nut')['default']
PhPencilFill: typeof import('~icons/ph/pencil-fill')['default']
PhPlugFill: typeof import('~icons/ph/plug-fill')['default']
PhPlus: typeof import('~icons/ph/plus')['default']
PhQuestionMark: typeof import('~icons/ph/question-mark')['default']
PhTextbox: typeof import('~icons/ph/textbox')['default']
PhToolbox: typeof import('~icons/ph/toolbox')['default']
PhTrashFill: typeof import('~icons/ph/trash-fill')['default']
PhUser: typeof import('~icons/ph/user')['default']
PhUserFill: typeof import('~icons/ph/user-fill')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SelectBox: typeof import('./src/components/SelectBox.vue')['default']
SidePanel: typeof import('./src/components/SidePanel.vue')['default']
TransitionChild: typeof import('@headlessui/vue')['TransitionChild']
TransitionRoot: typeof import('@headlessui/vue')['TransitionRoot']
UseImage: typeof import('@vueuse/components')['UseImage']
UserDropdown: typeof import('./src/components/UserDropdown.vue')['default']
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"animate.css": "^4.1.1",
"apexcharts": "^3.54.1",
"axios": "^1.7.7",
"ccat-api": "github:cheshire-cat-ai/api-client-ts#develop",
"ccat-api": "^0.11.3",
"daisyui": "^4.12.13",
"highlight.js": "^11.10.0",
"jwt-decode": "^4.0.0",
Expand Down
11 changes: 5 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions src/services/RabbitHoleService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import { apiClient, tryRequest } from '@services/ApiService'
* Meaning this service sends files to the backend.
*/
const RabbitHoleService = Object.freeze({
sendFile: async (file: File) => {
sendFile: async (file: File, metadata?: Record<string, any>) => {
return await tryRequest(
apiClient?.api?.rabbitHole.uploadFile({ file }),
apiClient?.api?.rabbitHole.uploadFile({
file,
metadata: JSON.stringify(metadata),
}),
`File ${file.name} successfully sent down the rabbit hole!`,
'Unable to send the file to the rabbit hole!',
'Sending a file to the rabbit hole',
Expand Down
72 changes: 71 additions & 1 deletion src/views/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useMessages } from '@stores/useMessages'
import { useMemory } from '@stores/useMemory'
import ModalBox from '@components/ModalBox.vue'
import { capitalize } from 'lodash'
import RabbitHoleService from '@services/RabbitHoleService'

const route = useRoute()
const messagesStore = useMessages()
Expand All @@ -14,6 +15,51 @@ const userMessage = ref(''),
insertedURL = ref(''),
isScrollable = ref(false),
isTwoLines = ref(false)

/**
* File Upload w/ Metadata Management
* **/

const uploadFileDialog = useFileDialog()

// User selects a file and then the Metadata Modal opens up
const selectedFiles = ref<File[]>([])
uploadFileDialog.onChange((files) => {
selectedFiles!.value = files
fileMetadata.value[0].value = selectedFiles.value[0].name
boxUploadFile.value?.toggleModal()
})

const fileMetadata = ref<{key: string, value: string}[]>([
{ key: 'source', value: 'filename.pdf'},
])

const addMetadata = () => {
fileMetadata.value.push(
{ key: '', value: '' }
)
}
const removeMetadata = (index: number) => {
fileMetadata.value.splice(index, 1)
}

const boxUploadFile = ref<InstanceType<typeof ModalBox>>()

const dispatchFiles = async () => {
boxUploadFile.value?.toggleModal()
const json: Record<string, string> = {};
// turn metadata into Json
for (const md of fileMetadata.value)
json[md.key] = md.value
for (const file of selectedFiles.value)
await RabbitHoleService.sendFile(file, json)
uploadFileDialog.reset()
}

/**
* End Custom Metadata Management
* */

const boxUploadURL = ref<InstanceType<typeof ModalBox>>()

const { textarea: textArea } = useTextareaAutosize({
Expand Down Expand Up @@ -123,6 +169,7 @@ useEventListener(document, 'scroll', () => {
isScrollable.value = doc.scrollHeight > doc.clientHeight + doc.scrollTop
})


/**
* Dispatches the inserted url to the RabbitHole service and closes the modal.
*/
Expand Down Expand Up @@ -281,7 +328,7 @@ const scrollToBottom = () => {
<button
:disabled="rabbitHoleState.loading"
class="btn join-item w-full flex-nowrap px-2 text-left font-medium"
@click="uploadFile('content')">
@click="uploadFileDialog.open">
<span class="rounded-lg p-1 text-warning">
<heroicons-document-text-solid class="size-5" />
</span>
Expand Down Expand Up @@ -332,6 +379,29 @@ const scrollToBottom = () => {
<heroicons-arrow-down-20-solid class="size-5" />
</button>
</div>
<Teleport to="#modal">
<ModalBox ref="boxUploadFile" class="text-center">
<div class="flex flex-col text-center justify-center gap-4 text-neutral">
<h3 class="text-lg font-bold">File Upload</h3>
<p>Selected file(s): <b>{{ `${selectedFiles.length} ${selectedFiles.length === 1 ? 'file' : 'files'}` }}</b></p>
<li v-for="file of selectedFiles" :key="file.name">
{{ file.name }}
</li>
<p>Add metadata to file:</p>
<div class="bg-amber-50" v-for="(md, index) in fileMetadata" :key="index">
<label>Label you will query for:</label>
<InputBox v-model="md.key" placeholder="Metadata Key ..." />
<label>Value of the metadata:</label>
<InputBox v-model="md.value" placeholder="Value ..." />
<button class="btn btn-sm btn-neutral" @click="removeMetadata(index)">-</button>
</div>
<button class="btn btn-active btn-sm btn-circle btn-primary p-3" @click="addMetadata">+</button>

<button class="btn btn-primary btn-sm" @click="dispatchFiles">Send</button>
</div>

</ModalBox>
</Teleport>
<Teleport to="#modal">
<ModalBox ref="boxUploadURL">
<div class="flex flex-col items-center justify-center gap-4 text-neutral">
Expand Down