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 {
getChatLog,
delChatLog,
getChatRecordLog,
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">
<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>
<div class="mb-8">
<el-space wrap>
@ -72,20 +72,26 @@
type="primary"
plain
size="small"
@click="openParagraph(item, dataset.id)"
>{{ dataset.name }}</el-button
>
</el-space>
</div>
<div>
<el-button class="mr-8" type="primary" plain size="small"
>引用分段{{ item.paragraph_list.length }}</el-button
<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">
消耗 tokens: {{ item?.message_tokens + item?.answer_tokens }}
</el-tag>
<el-tag class="ml-8" type="info" effect="plain">
耗时: {{ item.run_time.toFixed(2) }} s
耗时: {{ item.run_time?.toFixed(2) }} s
</el-tag>
</div>
</div>
@ -149,6 +155,8 @@
</div>
</div>
</div>
<!-- 知识库引用 dialog -->
<ParagraphSourceDialog ref="ParagraphSourceDialogRef" />
</div>
</template>
<script setup lang="ts">
@ -156,7 +164,9 @@ import { ref, nextTick, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import LogOperationButton from './LogOperationButton.vue'
import OperationButton from './OperationButton.vue'
import ParagraphSourceDialog from './ParagraphSourceDialog.vue'
import applicationApi from '@/api/application'
import logApi from '@/api/log'
import { ChatManagement, type chatType } from '@/api/type/application'
import { randomId } from '@/utils/utils'
import useStore from '@/stores'
@ -165,7 +175,7 @@ import { MdPreview } from 'md-editor-v3'
defineOptions({ name: 'AiChat' })
const route = useRoute()
const {
params: { accessToken }
params: { accessToken, id }
} = route as any
const props = defineProps({
data: {
@ -181,6 +191,7 @@ const props = defineProps({
})
const { application } = useStore()
const ParagraphSourceDialogRef = ref()
const aiChatRef = ref()
const quickInputRef = ref()
const scrollDiv = ref()
@ -213,6 +224,10 @@ watch(
}
)
function openParagraph(row: any, id?: string) {
ParagraphSourceDialogRef.value.open(row, id)
}
function quickProblemHandel(val: string) {
if (!props.log) {
inputValue.value = val
@ -348,6 +363,9 @@ function chatMessage() {
reader
.read()
.then(write)
.then((ok: any) => {
getSourceDetail(row)
})
.finally((ok: any) => {
ChatManagement.close(id)
})
@ -364,6 +382,14 @@ function regenerationChart(item: chatType) {
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>
</slot>
</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">
{{ description }}
</slot>

View File

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