Skip to content

Commit

Permalink
Merge branch 'main' into add_import_export
Browse files Browse the repository at this point in the history
  • Loading branch information
WongSaang authored May 10, 2023
2 parents 49cac30 + da03f36 commit cd9b6ae
Show file tree
Hide file tree
Showing 8 changed files with 389 additions and 10 deletions.
38 changes: 35 additions & 3 deletions components/Conversation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,29 @@ const abortFetch = () => {
const fetchReply = async (message) => {
ctrl = new AbortController()
let msg = message
if (Array.isArray(message)) {
msg = message[message.length - 1]
} else {
message = [message]
}
let webSearchParams = {}
if (enableWebSearch.value) {
if (enableWebSearch.value || msg.tool == 'web_search') {
webSearchParams['web_search'] = {
ua: navigator.userAgent,
default_prompt: $i18n.t('webSearchDefaultPrompt')
}
}
if (msg.tool == 'web_search') {
msg.tool_args = webSearchParams['web_search']
msg.type = 100
} else if (msg.tool == 'arxiv') {
msg.tool_args = null
msg.type = 110
}
const data = Object.assign({}, currentModel.value, {
openaiApiKey: $settings.open_api_key_setting === 'True' ? openaiApiKey.value : null,
message: message,
Expand Down Expand Up @@ -116,6 +131,9 @@ const fetchReply = async (message) => {
props.conversation.id = data.conversationId
genTitle(props.conversation.id)
}
if (data.newDocId) {
editor.value.refreshDocList()
}
return;
}
Expand Down Expand Up @@ -145,7 +163,11 @@ const send = (message) => {
if (props.conversation.messages.length === 0) {
addConversation(props.conversation)
}
props.conversation.messages.push({message: message})
if (Array.isArray(message)) {
props.conversation.messages.push(...message.map(i => ({message: i.content, message_type: i.message_type})))
} else {
props.conversation.messages.push({ message: message.content, message_type: message.message_type })
}
fetchReply(message)
scrollChatWindow()
}
Expand All @@ -169,6 +191,10 @@ const deleteMessage = (index) => {
props.conversation.messages.splice(index, 1)
}
const toggleMessage = (index) => {
props.conversation.messages[index].is_disabled = !props.conversation.messages[index].is_disabled
}
const enableWebSearch = ref(false)
Expand Down Expand Up @@ -210,8 +236,14 @@ onNuxtReady(() => {
:message-index="index"
:use-prompt="usePrompt"
:delete-message="deleteMessage"
:toggle-message="toggleMessage"
/>
<MsgContent
:message="message"
:index="index"
:use-prompt="usePrompt"
:delete-message="deleteMessage"
/>
<MsgContent :message="message" />
<MessageActions
v-if="message.is_bot"
:message="message"
Expand Down
200 changes: 200 additions & 0 deletions components/DocumentsManage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<script setup>
const { $i18n } = useNuxtApp()
const props = defineProps({
sendMessage: {
type: Function,
required: false,
},
control: {
type: Object,
required: true,
}
})
const ps = toRefs(props);
const loadingDoc = ref(false)
const deletingDocIndex = ref(null)
const embeddingDocs = ref([])
const selectedEmbeddingDocs = ref([])
const fileInputMessage = ref("")
const uploadDocObject = ref({
title: "",
file: null,
})
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
const snackbar = ref(false)
const snackbarText = ref('')
const showSnackbar = (text) => {
snackbarText.value = text
snackbar.value = true
}
function fileUploadRules(value) {
let fileSizeLimit = 8
return !value || !value.length || value[0].size < fileSizeLimit * 1024 * 1024 || `size no more than ${fileSizeLimit} MB`
}
function onFileChange() {
let newfile = document.getElementById('file_upload_input').files[0];
if (fileUploadRules([newfile])) {
uploadDocObject.value.file = newfile
}
}
async function uploadFile() {
const file = uploadDocObject.value.file
if (!file) return
loadingDoc.value = true
const base64Data = await fileToBase64(file)
try {
const { data, error } = await useAuthFetch('/api/chat/embedding_document/', {
method: 'POST',
headers: {
'accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: file.name,
file: base64Data,
}),
})
if (!error.value) {
embeddingDocs.value.splice(0, 0, data.value)
} else {
console.log(error.value)
showSnackbar(error.value)
}
} catch (err) {
console.log(err)
showSnackbar(err.message)
}
uploadDocObject.value.file = null
loadingDoc.value = false
}
async function loadDocs() {
loadingDoc.value = true
const { data, error } = await useAuthFetch('/api/chat/embedding_document/')
if (!error.value) {
embeddingDocs.value = data.value
}
loadingDoc.value = false
}
async function deleteDocs(index_list) {
let survival = []
for (let i = 0; i < index_list.length; i++) {
let index = index_list[i]
deletingDocIndex.value = index
const { data, error } = await useAuthFetch(`/api/chat/embedding_document/${embeddingDocs.value[index].id}/`, {
method: 'DELETE'
})
deletingDocIndex.value = null
if (!error.value) {
embeddingDocs.value[index] = 0
} else {
console.log(`${index}: ${error.value}`)
}
}
let l = embeddingDocs.value.length
for (let i = 0; i < l; i++) {
if (embeddingDocs.value[i] != 0) {
survival.push(embeddingDocs.value[i])
}
}
embeddingDocs.value.splice(0, l)
embeddingDocs.value.push(...survival)
}
async function insertSelectedDocs() {
ps.control.value.dialog = false
let messages = selectedEmbeddingDocs.value.map((i) => {
let doc = embeddingDocs.value[i]
return {
content: `${doc.title}\n${doc.created_at}`,
message_type: 120,
embedding_message_doc: doc.id,
}
})
props.sendMessage(messages)
let l = selectedEmbeddingDocs.value.length
selectedEmbeddingDocs.value.splice(0, l)
}
async function deleteSelectedDocs() {
await deleteDocs(selectedEmbeddingDocs.value)
let l = selectedEmbeddingDocs.value.length
selectedEmbeddingDocs.value.splice(0, l)
}
defineExpose({
loadDocs
})
onNuxtReady(() => {
loadDocs()
})
</script>

<template>
<v-dialog v-model="control.dialog" scrollable>
<v-card class="pa-3">
<v-card-title> Add Documents </v-card-title>
<v-row align="center" justify="center">
<v-col cols="10">
<v-file-input id="file_upload_input" label="New Documents" :disabled="loadingDoc" :loading="loadingDoc"
:messages="fileInputMessage" density="compact" variant="solo" show-size :rules="[fileUploadRules]"
accept="text/plain,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.presentationml.presentation"
class="ma-2 pa-2" @change="onFileChange()" append-icon="upload" @click:append="uploadFile()"></v-file-input>
</v-col>
</v-row>
<v-divider></v-divider>
<v-card-text style='height: 480px;'>
<v-item-group v-model="selectedEmbeddingDocs" multiple>
<v-row v-for="(item, i) in embeddingDocs" :key="i" justify="center">
<v-col>
<v-item v-slot="{ isSelected, toggle }">
<v-list-item @click="toggle" :prepend-icon="isSelected ? 'check_box' : 'check_box_outline_blank'">
<v-list-item-title>{{ item.title }}</v-list-item-title>
<v-list-item-subtitle>{{ item.created_at }}</v-list-item-subtitle>
</v-list-item>
</v-item>
</v-col>
</v-row>
</v-item-group>
</v-card-text>
<v-divider></v-divider>
<v-row justify="center" class="pa-2">
<v-card-actions>
<v-btn elevation="2" class="ma-2" @click="insertSelectedDocs()">Insert</v-btn>
<v-btn elevation="2" class="ma-2" @click="deleteSelectedDocs()">Delete</v-btn>
<v-btn elevation="2" class="ma-2" @click="control.dialog = false">Close</v-btn>
</v-card-actions>
</v-row>
</v-card>
</v-dialog>
<v-snackbar v-model="snackbar" multi-line location="top">
{{ snackbarText }}

<template v-slot:actions>
<v-btn color="red" variant="text" @click="snackbar = false" density="compact" size="default">
Close
</v-btn>
</template>
</v-snackbar>
</template>

<style></style>
52 changes: 51 additions & 1 deletion components/MessageActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const props = defineProps({
deleteMessage: {
type: Function,
required: true
},
toggleMessage: {
type: Function,
required: true
}
})
Expand Down Expand Up @@ -47,17 +51,63 @@ const deleteMessage = async () => {
showSnackbar('Delete failed')
}
const toggle_message = async() => {
const msg = Object.assign({}, props.message)
msg.is_disabled = !msg.is_disabled
const { data, error } = await useAuthFetch(`/api/chat/messages/${props.message.id}/`, {
method: 'PUT',
body: JSON.stringify(msg),
})
if (!error.value) {
props.toggleMessage(props.messageIndex)
}
}
function selectMessageIcon(message) {
if (message.is_bot) return ""
if (message.message_type == 100) {
return "travel_explore"
} else if (message.message_type == 110) {
return "local_library"
} else if (message.message_type == 120) {
return "article"
}
return ""
}
const message_icon = selectMessageIcon(props.message)
</script>

<template>
<v-menu>
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
v-if="message_icon"
variant="text"
class="ma-2"
>
<v-icon :icon="message_icon"></v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
@click="toggle_message()"
title="toggle"
:prepend-icon="message.is_disabled ? 'toggle_off' : 'toggle_on'"
>
</v-list-item>
</v-list>
</v-menu>
<v-menu
>
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
icon
variant="text"
class="mx-1"
class="mx-1 ma-2"
>
<v-icon icon="more_horiz"></v-icon>
</v-btn>
Expand Down
Loading

0 comments on commit cd9b6ae

Please sign in to comment.