feat: 知识来源

This commit is contained in:
wangdan-fit2cloud 2024-01-18 15:59:30 +08:00
parent cd9fe3c6f2
commit af7c28868d
5 changed files with 157 additions and 10 deletions

View File

@ -116,10 +116,29 @@ const getMarkRecord: (
) )
} }
/**
*
* @param
* application_id, chart_id, chart_record_id
*/
const getRecordDetail: (
applicaiton_id: String,
chart_id: String,
chart_record_id: String,
loading?: Ref<boolean>
) => Promise<Result<any>> = (applicaiton_id, chart_id, chart_record_id, loading) => {
return get(
`${prefix}/${applicaiton_id}/chat/${chart_id}/chat_record/${chart_record_id}`,
undefined,
loading
)
}
export default { export default {
getChatLog, getChatLog,
delChatLog, delChatLog,
getChatRecordLog, getChatRecordLog,
putChatRecordLog, putChatRecordLog,
getMarkRecord getMarkRecord,
getRecordDetail
} }

View File

@ -0,0 +1,93 @@
<template>
<el-dialog title="知识库引用" v-model="dialogVisible" destroy-on-close>
<el-scrollbar height="450">
<el-form label-position="top">
<el-form-item label="用户问题">
<el-input v-model="detail.problem_text" disabled />
</el-form-item>
<el-form-item label="优化后问题">
<el-input v-model="detail.padding_problem_text" disabled />
</el-form-item>
<el-form-item label="引用分段">
<template v-for="(item, index) in detail.paragraph_list" :key="index">
<CardBox
shadow="hover"
:title="item.title || '-'"
:description="item.content"
class="paragraph-source-card cursor mb-8"
:class="item.is_active ? '' : 'disabled'"
:showIcon="false"
@click="editParagraph(item)"
>
<template #icon>
<AppAvatar :name="index + 1 + ''" class="mr-12 avatar-light" :size="22" />
</template>
<div class="active-button primary">{{ item.similarity?.toFixed(3) }}</div>
<template #footer>
<div class="footer-content flex-between">
<el-text>
<el-icon>
<Document />
</el-icon>
{{ item?.document_name }}
</el-text>
<div class="flex align-center">
<AppAvatar class="mr-8" shape="square" :size="18">
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
</AppAvatar>
<span class="ellipsis"> {{ item?.dataset_name }}</span>
</div>
</div>
</template>
</CardBox>
</template>
</el-form-item>
</el-form>
</el-scrollbar>
<ParagraphDialog ref="ParagraphDialogRef" title="分段详情" @refresh="refresh" />
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue'
import ParagraphDialog from '@/views/paragraph/component/ParagraphDialog.vue'
const emit = defineEmits(['refresh'])
const ParagraphDialogRef = ref()
const dialogVisible = ref(false)
const detail = ref<any>({})
watch(dialogVisible, (bool) => {
if (!bool) {
detail.value = {}
}
})
const open = (data: any) => {
detail.value = data
dialogVisible.value = true
}
function editParagraph(row: any) {
ParagraphDialogRef.value.open(row)
}
function refresh(data: any) {
if (data) {
const index = detail.value.paragraph_list.findIndex((v) => v.id === data.id)
detail.value.paragraph_list.splice(index, 1, data)
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.paragraph-source-card {
height: 210px;
width: 100%;
:deep(.description) {
-webkit-line-clamp: 5 !important;
height: 110px !important;
}
}
</style>

View File

@ -62,7 +62,7 @@
<el-card v-else shadow="always" class="dialog-card"> <el-card v-else shadow="always" class="dialog-card">
<MdRenderer :source="item.answer_text"></MdRenderer> <MdRenderer :source="item.answer_text"></MdRenderer>
<div v-if="item.write_ed || log"> <div v-if="(id && !props.appId && item.write_ed) || log">
<el-divider> <el-text type="info">知识来源</el-text> </el-divider> <el-divider> <el-text type="info">知识来源</el-text> </el-divider>
<div class="mb-8"> <div class="mb-8">
<el-space wrap> <el-space wrap>
@ -72,20 +72,26 @@
type="primary" type="primary"
plain plain
size="small" size="small"
@click="openParagraph(item, dataset.id)"
>{{ dataset.name }}</el-button >{{ dataset.name }}</el-button
> >
</el-space> </el-space>
</div> </div>
<div> <div>
<el-button class="mr-8" type="primary" plain size="small" <el-button
>引用分段{{ item.paragraph_list.length }}</el-button class="mr-8"
type="primary"
plain
size="small"
@click="openParagraph(item)"
>引用分段{{ item.paragraph_list?.length }}</el-button
> >
<el-tag type="info" effect="plain"> <el-tag type="info" effect="plain">
消耗 tokens: {{ item?.message_tokens + item?.answer_tokens }} 消耗 tokens: {{ item?.message_tokens + item?.answer_tokens }}
</el-tag> </el-tag>
<el-tag class="ml-8" type="info" effect="plain"> <el-tag class="ml-8" type="info" effect="plain">
耗时: {{ item.run_time.toFixed(2) }} s 耗时: {{ item.run_time?.toFixed(2) }} s
</el-tag> </el-tag>
</div> </div>
</div> </div>
@ -149,6 +155,8 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 知识库引用 dialog -->
<ParagraphSourceDialog ref="ParagraphSourceDialogRef" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -156,7 +164,9 @@ import { ref, nextTick, computed, watch } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import LogOperationButton from './LogOperationButton.vue' import LogOperationButton from './LogOperationButton.vue'
import OperationButton from './OperationButton.vue' import OperationButton from './OperationButton.vue'
import ParagraphSourceDialog from './ParagraphSourceDialog.vue'
import applicationApi from '@/api/application' import applicationApi from '@/api/application'
import logApi from '@/api/log'
import { ChatManagement, type chatType } from '@/api/type/application' import { ChatManagement, type chatType } from '@/api/type/application'
import { randomId } from '@/utils/utils' import { randomId } from '@/utils/utils'
import useStore from '@/stores' import useStore from '@/stores'
@ -165,7 +175,7 @@ import { MdPreview } from 'md-editor-v3'
defineOptions({ name: 'AiChat' }) defineOptions({ name: 'AiChat' })
const route = useRoute() const route = useRoute()
const { const {
params: { accessToken } params: { accessToken, id }
} = route as any } = route as any
const props = defineProps({ const props = defineProps({
data: { data: {
@ -181,6 +191,7 @@ const props = defineProps({
}) })
const { application } = useStore() const { application } = useStore()
const ParagraphSourceDialogRef = ref()
const aiChatRef = ref() const aiChatRef = ref()
const quickInputRef = ref() const quickInputRef = ref()
const scrollDiv = ref() const scrollDiv = ref()
@ -213,6 +224,10 @@ watch(
} }
) )
function openParagraph(row: any, id?: string) {
ParagraphSourceDialogRef.value.open(row, id)
}
function quickProblemHandel(val: string) { function quickProblemHandel(val: string) {
if (!props.log) { if (!props.log) {
inputValue.value = val inputValue.value = val
@ -348,6 +363,9 @@ function chatMessage() {
reader reader
.read() .read()
.then(write) .then(write)
.then((ok: any) => {
getSourceDetail(row)
})
.finally((ok: any) => { .finally((ok: any) => {
ChatManagement.close(id) ChatManagement.close(id)
}) })
@ -364,6 +382,14 @@ function regenerationChart(item: chatType) {
chatMessage() chatMessage()
} }
function getSourceDetail(row: chatType) {
logApi.getRecordDetail(id, row.id, row.record_id, loading).then((res) => {
const obj = { row, ...res.data }
const index = chatList.value.findIndex((v) => v.id === row.id)
chatList.value.splice(index, 1, obj)
})
}
/** /**
* 滚动条距离最上面的高度 * 滚动条距离最上面的高度
*/ */

View File

@ -12,7 +12,7 @@
</div> </div>
</slot> </slot>
</div> </div>
<div class="description pre-line mt-12" v-if="$slots.description || description"> <div class="description mt-12" v-if="$slots.description || description">
<slot name="description"> <slot name="description">
{{ description }} {{ description }}
</slot> </slot>

View File

@ -225,7 +225,11 @@
<template #label> <template #label>
<div class="flex align-center"> <div class="flex align-center">
<span>问题优化</span> <span>问题优化</span>
<el-tooltip effect="dark" content="根据历史聊天优化完善当前问题,更利于匹配知识点。" placement="right"> <el-tooltip
effect="dark"
content="根据历史聊天优化完善当前问题,更利于匹配知识点。"
placement="right"
>
<el-icon style="font-size: 16px"> <el-icon style="font-size: 16px">
<Warning /> <Warning />
</el-icon> </el-icon>
@ -259,7 +263,12 @@
<p>通过调整提示词内容可以引导大模型聊天方向该提示词会被固定在上下文的开头</p> <p>通过调整提示词内容可以引导大模型聊天方向该提示词会被固定在上下文的开头</p>
<p>可以使用变量{data} 是携带知识库中已知信息{question}是用户提出的问题</p> <p>可以使用变量{data} 是携带知识库中已知信息{question}是用户提出的问题</p>
</el-alert> </el-alert>
<el-input v-model="model_setting_prompt" :rows="13" type="textarea" /> <el-input
v-model="model_setting_prompt"
:rows="13"
type="textarea"
:placeholder="defaultPrompt"
/>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button> <el-button @click="dialogFormVisible = false">取消</el-button>
@ -357,7 +366,7 @@ const applicationForm = ref<ApplicationFormType>({
model_setting: { model_setting: {
prompt: defaultPrompt prompt: defaultPrompt
}, },
problem_optimization: true problem_optimization: false
}) })
const popoverVisible = ref(false) const popoverVisible = ref(false)