Files
gochat/frontend/app/javascript/dashboard/components-next/captain/pageComponents/response/CreateResponseDialog.vue
T
Rogee 63df5b8b91 fix(captain): 试验场不查 FAQ 知识库 + 添加常见问题报 400
三个问题修复:

1. 添加常见问题报 400 (assistant_id 类型不匹配)
   - CreateResponseDialog.vue: route.params.assistantId 是字符串,
     传给后端 uint 字段导致 JSON 反序列化失败
   - 修复: Number(route.params.assistantId) 转为数字
   - 同时修复 POST /assistant_responses 无尾部斜杠 307 重定向问题

2. 试验场 playground 不做 RAG 检索
   - generatePlaygroundLLMResponse 只构建 system prompt + 对话历史,
     从不查 FAQ 知识库
   - 新增 retrieveFAQContext(): embed 用户问题 → pgvector 搜索 approved
     FAQ → 注入 system prompt
   - 受 feature_faq 配置开关控制

3. FAQ embedding 无法写入 (pgvector 序列化 + 维度问题)
   - pgvector stub 无 driver.Valuer, GORM Save() 报 SQLSTATE 42804
   - 新增 UpdateEmbedding() 用 ?::vector 原始 SQL 绕过
   - SimilaritySearch 排除 embedding 列 + 手动格式化向量字面量
   - embedding 列从 vector(1536) 改为 vector (跟随模型维度)
   - FAQ 创建/更新时自动索引 embedding (SetRAGService 注入)
2026-08-01 19:37:19 +08:00

93 lines
2.2 KiB
Vue

<script setup>
import { ref, computed } from 'vue';
import { useStore } from 'dashboard/composables/store';
import { useAlert } from 'dashboard/composables';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
import ResponseForm from './ResponseForm.vue';
const props = defineProps({
selectedResponse: {
type: Object,
default: () => ({}),
},
type: {
type: String,
default: 'create',
validator: value => ['create', 'edit'].includes(value),
},
});
const emit = defineEmits(['close']);
const { t } = useI18n();
const store = useStore();
const route = useRoute();
const dialogRef = ref(null);
const responseForm = ref(null);
const updateResponse = responseDetails =>
store.dispatch('captainResponses/update', {
id: props.selectedResponse.id,
...responseDetails,
});
const i18nKey = computed(() => `CAPTAIN.RESPONSES.${props.type.toUpperCase()}`);
const createResponse = responseDetails =>
store.dispatch('captainResponses/create', responseDetails);
const handleSubmit = async updatedResponse => {
try {
if (props.type === 'edit') {
await updateResponse({
...updatedResponse,
assistant_id: Number(route.params.assistantId),
});
} else {
await createResponse({
...updatedResponse,
assistant_id: Number(route.params.assistantId),
});
}
useAlert(t(`${i18nKey.value}.SUCCESS_MESSAGE`));
dialogRef.value.close();
} catch (error) {
const errorMessage =
error?.response?.message || t(`${i18nKey.value}.ERROR_MESSAGE`);
useAlert(errorMessage);
}
};
const handleClose = () => {
emit('close');
};
const handleCancel = () => {
dialogRef.value.close();
};
defineExpose({ dialogRef });
</script>
<template>
<Dialog
ref="dialogRef"
:title="$t(`${i18nKey}.TITLE`)"
:description="$t('CAPTAIN.RESPONSES.FORM_DESCRIPTION')"
:show-cancel-button="false"
:show-confirm-button="false"
@close="handleClose"
>
<ResponseForm
ref="responseForm"
:mode="type"
:response="selectedResponse"
@submit="handleSubmit"
@cancel="handleCancel"
/>
<template #footer />
</Dialog>
</template>