文件接口
This commit is contained in:
parent
a256f25ea9
commit
01bf39bc89
|
|
@ -3,7 +3,7 @@ import { api } from './api'
|
|||
|
||||
export const chat = (params: any) => {
|
||||
return api({
|
||||
url: '/chat-docs/chatno',
|
||||
url: '/chat',
|
||||
method: 'post',
|
||||
data: JSON.stringify(params),
|
||||
})
|
||||
|
|
@ -17,20 +17,18 @@ export const chatfile = (params: any) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const getfilelist = () => {
|
||||
export const getfilelist = (knowledge_base_id: any) => {
|
||||
return api({
|
||||
url: '/chat-docs/list',
|
||||
url: '/local_doc_qa/list_files',
|
||||
method: 'get',
|
||||
params: {
|
||||
knowledge_base_id: '123',
|
||||
},
|
||||
params: { knowledge_base_id },
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export const deletefile = (params: any) => {
|
||||
return api({
|
||||
url: '/chat-docs/delete',
|
||||
url: '/local_doc_qa/delete_file',
|
||||
method: 'post',
|
||||
data: JSON.stringify(params),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -13,19 +13,18 @@ import HeaderComponent from './components/Header/index.vue'
|
|||
import { HoverButton, SvgIcon } from '@/components/common'
|
||||
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
||||
import { useChatStore, usePromptStore } from '@/store'
|
||||
import { fetchChatAPIProcess } from '@/api'
|
||||
import { t } from '@/locales'
|
||||
import { chat, chatfile } from '@/api/chat'
|
||||
let controller = new AbortController()
|
||||
|
||||
const openLongReply = import.meta.env.VITE_GLOB_OPEN_LONG_REPLY === 'true'
|
||||
// const openLongReply = import.meta.env.VITE_GLOB_OPEN_LONG_REPLY === 'true'
|
||||
|
||||
const route = useRoute()
|
||||
const dialog = useDialog()
|
||||
const ms = useMessage()
|
||||
|
||||
const chatStore = useChatStore()
|
||||
|
||||
const history = ref<any>([])
|
||||
const { isMobile } = useBasicLayout()
|
||||
const { addChat, updateChat, updateChatSome, getChatByUuidAndIndex } = useChat()
|
||||
const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom } = useScroll()
|
||||
|
|
@ -61,7 +60,9 @@ function handleSubmit() {
|
|||
|
||||
async function onConversation() {
|
||||
const message = prompt.value
|
||||
|
||||
dataSources.value.forEach((item) => {
|
||||
console.log(item)
|
||||
})
|
||||
if (loading.value)
|
||||
return
|
||||
|
||||
|
|
@ -110,13 +111,13 @@ async function onConversation() {
|
|||
const lastText = ''
|
||||
const fetchChatAPIOnce = async () => {
|
||||
const res = active.value
|
||||
? await chatfile({ message })
|
||||
? await chatfile({
|
||||
question: message,
|
||||
history: history.value,
|
||||
})
|
||||
: await chat({
|
||||
question: message,
|
||||
history: [[
|
||||
'工伤保险是什么?',
|
||||
'工伤保险是指用人单位按照国家规定,为本单位的职工和用人单位的其他人员,缴纳工伤保险费,由保险机构按照国家规定的标准,给予工伤保险待遇的社会保险制度。',
|
||||
]],
|
||||
history: history.value,
|
||||
})
|
||||
const result = active.value ? res.data.response.text : res.data.response
|
||||
updateChat(
|
||||
|
|
@ -230,7 +231,6 @@ async function onConversation() {
|
|||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onRegenerate(index: number) {
|
||||
if (loading.value)
|
||||
return
|
||||
|
|
@ -239,7 +239,7 @@ async function onRegenerate(index: number) {
|
|||
|
||||
const { requestOptions } = dataSources.value[index]
|
||||
|
||||
let message = requestOptions?.prompt ?? ''
|
||||
const message = requestOptions?.prompt ?? ''
|
||||
|
||||
let options: Chat.ConversationRequest = {}
|
||||
|
||||
|
|
@ -263,48 +263,30 @@ async function onRegenerate(index: number) {
|
|||
)
|
||||
|
||||
try {
|
||||
let lastText = ''
|
||||
const lastText = ''
|
||||
const fetchChatAPIOnce = async () => {
|
||||
await fetchChatAPIProcess<Chat.ConversationResponse>({
|
||||
prompt: message,
|
||||
options,
|
||||
signal: controller.signal,
|
||||
onDownloadProgress: ({ event }) => {
|
||||
const xhr = event.target
|
||||
const { responseText } = xhr
|
||||
// Always process the final line
|
||||
const lastIndex = responseText.lastIndexOf('\n', responseText.length - 2)
|
||||
let chunk = responseText
|
||||
if (lastIndex !== -1)
|
||||
chunk = responseText.substring(lastIndex)
|
||||
try {
|
||||
const data = JSON.parse(chunk)
|
||||
const res = active.value
|
||||
? await chatfile({ message })
|
||||
: await chat({
|
||||
question: message,
|
||||
history: history.value,
|
||||
})
|
||||
const result = active.value ? res.data.response.text : res.data.response
|
||||
updateChat(
|
||||
+uuid,
|
||||
index,
|
||||
dataSources.value.length - 1,
|
||||
{
|
||||
dateTime: new Date().toLocaleString(),
|
||||
text: lastText + (data.text ?? ''),
|
||||
text: lastText + (result ?? ''),
|
||||
inversion: false,
|
||||
error: false,
|
||||
loading: true,
|
||||
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
|
||||
loading: false,
|
||||
conversationOptions: null,
|
||||
requestOptions: { prompt: message, options: { ...options } },
|
||||
},
|
||||
)
|
||||
|
||||
if (openLongReply && data.detail.choices[0].finish_reason === 'length') {
|
||||
options.parentMessageId = data.id
|
||||
lastText = data.text
|
||||
message = ''
|
||||
return fetchChatAPIOnce()
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
//
|
||||
}
|
||||
},
|
||||
})
|
||||
scrollToBottomIfAtBottom()
|
||||
loading.value = false
|
||||
updateChatSome(+uuid, index, { loading: false })
|
||||
}
|
||||
await fetchChatAPIOnce()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup lang='ts'>
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { NButton, NLayoutSider, NUpload } from 'naive-ui'
|
||||
import { NButton, NLayoutSider, NRadioButton, NRadioGroup } from 'naive-ui'
|
||||
import List from './List.vue'
|
||||
import filelist from './filelist.vue'
|
||||
import Knowledge from './knowledge-base/index.vue'
|
||||
import Footer from './Footer.vue'
|
||||
import { useAppStore, useChatStore } from '@/store'
|
||||
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
||||
|
|
@ -46,6 +46,25 @@ const mobileSafeArea = computed(() => {
|
|||
}
|
||||
return {}
|
||||
})
|
||||
|
||||
const songs = [
|
||||
{
|
||||
value: 1,
|
||||
label: '会话',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '模型',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '知识库',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: '提示词',
|
||||
},
|
||||
]
|
||||
//
|
||||
watch(
|
||||
isMobile,
|
||||
|
|
@ -75,39 +94,20 @@ watch(
|
|||
<div class="flex flex-col h-full " :style="mobileSafeArea">
|
||||
<main class="flex flex-col flex-1 min-h-0">
|
||||
<div class=" flex justify-between">
|
||||
<NButton dashed @click="menu = 1">
|
||||
会话
|
||||
</NButton>
|
||||
<NButton dashed @click="menu = 2">
|
||||
模型
|
||||
</NButton>
|
||||
<NButton dashed @click="menu = 3">
|
||||
知识库
|
||||
</NButton>
|
||||
<NButton dashed @click="menu = 4">
|
||||
提示词
|
||||
</NButton>
|
||||
<NRadioGroup v-model:value="menu" name="radiobuttongroup1">
|
||||
<NRadioButton
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</NRadioGroup>
|
||||
</div>
|
||||
|
||||
<!-- 知识库界面 -->
|
||||
<div v-if="menu === 3">
|
||||
<div class="p-4">
|
||||
<NUpload
|
||||
action="http://127.0.0.1:1002/api/chat-docs/uploadone"
|
||||
:headers="{
|
||||
'naive-info': 'hello!',
|
||||
}"
|
||||
:data="{
|
||||
knowledge_base_id: '123',
|
||||
}"
|
||||
>
|
||||
<NButton block>
|
||||
文件上传
|
||||
</NButton>
|
||||
</NUpload>
|
||||
</div>
|
||||
<div class="p-2 flex-1 min-h-0 pb-4 overflow-hidden">
|
||||
<filelist />
|
||||
<Knowledge />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 会话界面 -->
|
||||
|
|
@ -121,11 +121,6 @@ watch(
|
|||
<List />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="p-4">
|
||||
<NButton block @click="show = true">
|
||||
{{ $t('store.siderButton') }}
|
||||
</NButton>
|
||||
</div> -->
|
||||
</main>
|
||||
</div>
|
||||
</NLayoutSider>
|
||||
|
|
|
|||
|
|
@ -1,42 +1,32 @@
|
|||
<script setup lang='ts'>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { NInput, NPopconfirm, NScrollbar } from 'naive-ui'
|
||||
import { onMounted, ref, toRef } from 'vue'
|
||||
import { NInput, NP, NPopconfirm, NScrollbar, NText, NUpload, NUploadDragger } from 'naive-ui'
|
||||
import { SvgIcon } from '@/components/common'
|
||||
import { useAppStore, useChatStore } from '@/store'
|
||||
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
||||
import { useChatStore } from '@/store'
|
||||
import { deletefile, getfilelist } from '@/api/chat'
|
||||
const knowledge = defineProps({
|
||||
knowledgebaseid: {
|
||||
type: String, // 类型字符串
|
||||
},
|
||||
})
|
||||
const knowledge_base_id = toRef(knowledge, 'knowledgebaseid')
|
||||
|
||||
const { isMobile } = useBasicLayout()
|
||||
|
||||
const appStore = useAppStore()
|
||||
const chatStore = useChatStore()
|
||||
const dataSources = ref<any[]>([])
|
||||
const dataSources = ref<any>([])
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await getfilelist()
|
||||
const res = await getfilelist(knowledge_base_id.value)
|
||||
dataSources.value = res.data.data
|
||||
})
|
||||
|
||||
async function handleSelect({ uuid }: Chat.History) {
|
||||
if (isActive(uuid))
|
||||
return
|
||||
|
||||
if (chatStore.active)
|
||||
chatStore.updateHistory(chatStore.active, { isEdit: false })
|
||||
await chatStore.setActive(uuid)
|
||||
|
||||
if (isMobile.value)
|
||||
appStore.setSiderCollapsed(true)
|
||||
}
|
||||
|
||||
/* function handleEdit({ uuid }: Chat.History, isEdit: boolean, event?: MouseEvent) {
|
||||
event?.stopPropagation()
|
||||
chatStore.updateHistory(uuid, { isEdit })
|
||||
} */
|
||||
|
||||
async function handleDelete(item: any) {
|
||||
/* const mid = */await deletefile({ knowledge_base_id: '123', doc_name: item })
|
||||
const res = await getfilelist()
|
||||
/* const mid = */await deletefile({ knowledge_base_id: knowledge_base_id.value, doc_name: item })
|
||||
const res = await getfilelist(knowledge_base_id.value)
|
||||
dataSources.value = res.data.data
|
||||
}
|
||||
|
||||
|
|
@ -45,13 +35,34 @@ function handleEnter({ uuid }: Chat.History, isEdit: boolean, event: KeyboardEve
|
|||
if (event.key === 'Enter')
|
||||
chatStore.updateHistory(uuid, { isEdit })
|
||||
}
|
||||
|
||||
function isActive(uuid: number) {
|
||||
return chatStore.active === uuid
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NUpload
|
||||
multiple
|
||||
directory-dnd
|
||||
action="http://192.168.1.128:1002/api/local_doc_qa/upload_file"
|
||||
:headers="{
|
||||
'naive-info': 'hello!',
|
||||
}"
|
||||
:data="{
|
||||
knowledge_base_id: knowledge.knowledgebaseid as string,
|
||||
}"
|
||||
>
|
||||
<NUploadDragger>
|
||||
<!-- <div style="margin-bottom: 12px">
|
||||
<NIcon size="48" :depth="3">
|
||||
<archive-icon />
|
||||
</NIcon>
|
||||
</div> -->
|
||||
<NText style="font-size: 16px">
|
||||
点击或者拖动文件到该区域来上传
|
||||
</NText>
|
||||
<NP depth="3" style="margin: 8px 0 0 0">
|
||||
在弹出的文件选择框,按住ctrl或shift进行多选
|
||||
</NP>
|
||||
</NUploadDragger>
|
||||
</NUpload>
|
||||
<NScrollbar class="px-4">
|
||||
<div class="flex flex-col gap-2 text-sm">
|
||||
<template v-if="!dataSources.length">
|
||||
|
|
@ -64,8 +75,6 @@ function isActive(uuid: number) {
|
|||
<div v-for="(item, index) of dataSources" :key="index">
|
||||
<a
|
||||
class="relative flex items-center gap-3 px-3 py-3 break-all border rounded-md cursor-pointer hover:bg-neutral-100 group dark:border-neutral-800 dark:hover:bg-[#24272e]"
|
||||
:class="isActive(item.uuid) && ['border-[#4b9e5f]', 'bg-neutral-100', 'text-[#4b9e5f]', 'dark:bg-[#24272e]', 'dark:border-[#4b9e5f]', 'pr-14']"
|
||||
@click="handleSelect(item)"
|
||||
>
|
||||
<span>
|
||||
<SvgIcon icon="ri:message-3-line" />
|
||||
|
|
@ -91,10 +100,10 @@ function isActive(uuid: number) {
|
|||
<NPopconfirm placement="bottom" @positive-click="handleDelete(item)">
|
||||
<template #trigger>
|
||||
<button class="p-1">
|
||||
<SvgIcon icon="ri:delete-bin-line" />
|
||||
<!-- <SvgIcon icon="ri:delete-bin-line" /> -->
|
||||
</button>
|
||||
</template>
|
||||
{{ $t('chat.deleteHistoryConfirm') }}
|
||||
确定删除此文件?
|
||||
</NPopconfirm>
|
||||
</template>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<script setup lang='ts'>
|
||||
import { NButton, NForm, NFormItem, NInput } from 'naive-ui'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import filelist from './filelist.vue'
|
||||
import { getfilelist } from '@/api/chat'
|
||||
const items = ref<any>([])
|
||||
onMounted(async () => {
|
||||
const res = await getfilelist({})
|
||||
res.data.data.forEach((item: any) => {
|
||||
items.value.push({
|
||||
value: item,
|
||||
show: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
const formValue = ref({
|
||||
user: {
|
||||
name: '',
|
||||
},
|
||||
})
|
||||
const rules = {
|
||||
user: {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
}
|
||||
const handleValidateClick = (item: any) => {
|
||||
items.value.forEach((res: { value: any; show: boolean }) => {
|
||||
if (res.value === item)
|
||||
res.show = !res.show
|
||||
},
|
||||
|
||||
)
|
||||
}
|
||||
const handleClick = () => {
|
||||
if (formValue.value.user.name.trim() !== '') {
|
||||
items.value.push({
|
||||
value: formValue.value.user.name.trim(),
|
||||
show: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NForm
|
||||
ref="formRef"
|
||||
inline
|
||||
:label-width="80"
|
||||
:model="formValue"
|
||||
:rules="rules"
|
||||
>
|
||||
<NFormItem label="" path="user.name">
|
||||
<NInput v-model:value="formValue.user.name" placeholder="起个知识库名吧!" />
|
||||
</NFormItem>
|
||||
<NFormItem>
|
||||
<NButton attr-type="button" @click="handleClick">
|
||||
新增
|
||||
</NButton>
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
<div v-for="item in items" :key="item.value">
|
||||
<NButton block size="large" @click="handleValidateClick(item.value)">
|
||||
{{ item.value }}
|
||||
</NButton>
|
||||
<div v-if="item.show" class="p-2 flex-1 min-h-0 pb-4 overflow-hidden">
|
||||
<filelist v-if="item.value" :knowledgebaseid="item.value" />
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -37,7 +37,8 @@ export default defineConfig((env) => {
|
|||
open: false,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://127.0.0.1:7861',
|
||||
target: 'http://146.56.190.29',
|
||||
// target: 'http://127.0.0.1:7861',
|
||||
changeOrigin: true, // 允许跨域
|
||||
rewrite: path => path.replace('/api/', ''),
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue