feat: simple application debug chat (#3244)

This commit is contained in:
shaohuzhang1 2025-06-12 20:07:31 +08:00 committed by GitHub
parent b624de75be
commit c7e30bb098
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 267 additions and 116 deletions

View File

@ -704,14 +704,14 @@ class ApplicationOperateSerializer(serializers.Serializer):
self.is_valid() self.is_valid()
application_id = self.data.get("application_id") application_id = self.data.get("application_id")
application = QuerySet(Application).get(id=application_id) application = QuerySet(Application).get(id=application_id)
dataset_list = self.list_knowledge(with_valid=False) knowledge_list = self.list_knowledge(with_valid=False)
mapping_knowledge_id_list = [akm.knowledge_id for akm in mapping_knowledge_id_list = [akm.knowledge_id for akm in
QuerySet(ApplicationKnowledgeMapping).filter(application_id=application_id)] QuerySet(ApplicationKnowledgeMapping).filter(application_id=application_id)]
knowledge_id_list = [d.get('id') for d in knowledge_id_list = [d.get('id') for d in
list(filter(lambda row: mapping_knowledge_id_list.__contains__(row.get('id')), list(filter(lambda row: mapping_knowledge_id_list.__contains__(row.get('id')),
dataset_list))] knowledge_list))]
return {**ApplicationSerializerModel(application).data, return {**ApplicationSerializerModel(application).data,
'dataset_id_list': knowledge_id_list} 'knowledge_id_list': knowledge_id_list}
def list_knowledge(self, with_valid=True): def list_knowledge(self, with_valid=True):
if with_valid: if with_valid:

View File

@ -15,7 +15,8 @@ from django.db.models import QuerySet
from rest_framework import serializers from rest_framework import serializers
from rest_framework.utils.formatting import lazy_format from rest_framework.utils.formatting import lazy_format
from application.models import ChatRecord from application.models import ChatRecord, ApplicationAccessToken
from application.serializers.common import ChatInfo
from common.db.search import page_search from common.db.search import page_search
from common.exception.app_exception import AppApiException from common.exception.app_exception import AppApiException
from common.utils.common import post from common.utils.common import post
@ -37,6 +38,40 @@ class ChatRecordSerializerModel(serializers.ModelSerializer):
'create_time', 'update_time'] 'create_time', 'update_time']
class ChatRecordOperateSerializer(serializers.Serializer):
chat_id = serializers.UUIDField(required=True, label=_("Conversation ID"))
workspace_id = serializers.CharField(required=False, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
chat_record_id = serializers.UUIDField(required=True, label=_("Conversation record id"))
def is_valid(self, *, debug=False, raise_exception=False):
super().is_valid(raise_exception=True)
application_access_token = QuerySet(ApplicationAccessToken).filter(
application_id=self.data.get('application_id')).first()
if application_access_token is None:
raise AppApiException(500, gettext('Application authentication information does not exist'))
if not application_access_token.show_source and not debug:
raise AppApiException(500, gettext('Displaying knowledge sources is not enabled'))
def get_chat_record(self):
chat_record_id = self.data.get('chat_record_id')
chat_id = self.data.get('chat_id')
chat_info: ChatInfo = ChatInfo.get_cache(chat_id)
if chat_info is not None:
chat_record_list = [chat_record for chat_record in chat_info.chat_record_list if
str(chat_record.id) == str(chat_record_id)]
if chat_record_list is not None and len(chat_record_list):
return chat_record_list[-1]
return QuerySet(ChatRecord).filter(id=chat_record_id, chat_id=chat_id).first()
def one(self, debug):
self.is_valid(debug=debug, raise_exception=True)
chat_record = self.get_chat_record()
if chat_record is None:
raise AppApiException(500, gettext("Conversation does not exist"))
return ApplicationChatRecordQuerySerializers.reset_chat_record(chat_record)
class ApplicationChatRecordQuerySerializers(serializers.Serializer): class ApplicationChatRecordQuerySerializers(serializers.Serializer):
application_id = serializers.UUIDField(required=True, label=_("Application ID")) application_id = serializers.UUIDField(required=True, label=_("Application ID"))
chat_id = serializers.UUIDField(required=True, label=_("Chat ID")) chat_id = serializers.UUIDField(required=True, label=_("Chat ID"))

View File

@ -34,6 +34,9 @@ urlpatterns = [
path( path(
'workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record', 'workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record',
views.ApplicationChatRecord.as_view()), views.ApplicationChatRecord.as_view()),
path(
'workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>',
views.ApplicationChatRecordOperateAPI.as_view()),
path( path(
'workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<int:current_page>/<int:page_size>', 'workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<int:current_page>/<int:page_size>',
views.ApplicationChatRecord.Page.as_view()), views.ApplicationChatRecord.Page.as_view()),

View File

@ -14,7 +14,8 @@ from rest_framework.views import APIView
from application.api.application_chat_record import ApplicationChatRecordQueryAPI, \ from application.api.application_chat_record import ApplicationChatRecordQueryAPI, \
ApplicationChatRecordImproveParagraphAPI, ApplicationChatRecordAddKnowledgeAPI ApplicationChatRecordImproveParagraphAPI, ApplicationChatRecordAddKnowledgeAPI
from application.serializers.application_chat_record import ApplicationChatRecordQuerySerializers, \ from application.serializers.application_chat_record import ApplicationChatRecordQuerySerializers, \
ApplicationChatRecordImproveSerializer, ChatRecordImproveSerializer, ApplicationChatRecordAddKnowledgeSerializer ApplicationChatRecordImproveSerializer, ChatRecordImproveSerializer, ApplicationChatRecordAddKnowledgeSerializer, \
ChatRecordOperateSerializer
from common import result from common import result
from common.auth import TokenAuth from common.auth import TokenAuth
from common.auth.authentication import has_permissions from common.auth.authentication import has_permissions
@ -67,6 +68,30 @@ class ApplicationChatRecord(APIView):
page_size=page_size)) page_size=page_size))
class ApplicationChatRecordOperateAPI(APIView):
authentication_classes = [TokenAuth]
@extend_schema(
methods=['GET'],
description=_("Get conversation record details"),
summary=_("Get conversation record details"),
operation_id=_("Get conversation record details"), # type: ignore
request=ApplicationChatRecordQueryAPI.get_request(),
parameters=ApplicationChatRecordQueryAPI.get_parameters(),
responses=ApplicationChatRecordQueryAPI.get_response(),
tags=[_("Application/Conversation Log")] # type: ignore
)
@has_permissions(PermissionConstants.APPLICATION_CHAT_LOG.get_workspace_application_permission(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str, chat_id: str, chat_record_id: str):
return result.success(ChatRecordOperateSerializer(
data={
'workspace_id': workspace_id,
'application_id': application_id,
'chat_id': chat_id,
'chat_record_id': chat_record_id}).one(True))
class ApplicationChatRecordAddKnowledge(APIView): class ApplicationChatRecordAddKnowledge(APIView):
authentication_classes = [TokenAuth] authentication_classes = [TokenAuth]

View File

@ -101,6 +101,8 @@ class DebugChatSerializers(serializers.Serializer):
self.is_valid(raise_exception=True) self.is_valid(raise_exception=True)
chat_id = self.data.get('chat_id') chat_id = self.data.get('chat_id')
chat_info: ChatInfo = ChatInfo.get_cache(chat_id) chat_info: ChatInfo = ChatInfo.get_cache(chat_id)
application = QuerySet(Application).filter(id=chat_info.application_id).first()
chat_info.application = application
return ChatSerializers(data={ return ChatSerializers(data={
'chat_id': chat_id, "chat_user_id": chat_info.chat_user_id, 'chat_id': chat_id, "chat_user_id": chat_info.chat_user_id,
"chat_user_type": chat_info.chat_user_type, "chat_user_type": chat_info.chat_user_type,

View File

@ -140,6 +140,27 @@ const getStatistics: (
) => Promise<Result<any>> = (application_id, data, loading) => { ) => Promise<Result<any>> = (application_id, data, loading) => {
return get(`${prefix}/${application_id}/application_stats`, data, loading) return get(`${prefix}/${application_id}/application_stats`, data, loading)
} }
/**
* id
* @param application_id id
* @param loading
* @returns
*/
const open: (application_id: string, loading?: Ref<boolean>) => Promise<Result<string>> = (
application_id,
loading,
) => {
return get(`${prefix}/${application_id}/open`, {}, loading)
}
/**
*
* @param
* chat_id: string
* data
*/
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
return postStream(`/api/chat_message/${chat_id}`, data)
}
export default { export default {
getAllApplication, getAllApplication,
@ -153,4 +174,6 @@ export default {
exportApplication, exportApplication,
importApplication, importApplication,
getStatistics, getStatistics,
open,
chat,
} }

View File

@ -188,7 +188,18 @@ const postExportChatLog: (
loading, loading,
) )
} }
const getChatRecordDetails: (
application_id: string,
chat_id: string,
chat_record_id: string,
loading?: Ref<boolean>,
) => Promise<any> = (application_id, chat_id, chat_record_id, loading) => {
return get(
`${prefix}/${application_id}/chat/${chat_id}/chat_record/${chat_record_id}`,
{},
loading,
)
}
export default { export default {
postChatLogAddKnowledge, postChatLogAddKnowledge,
getChatLog, getChatLog,
@ -197,4 +208,5 @@ export default {
putChatRecordLog, putChatRecordLog,
delMarkChatRecord, delMarkChatRecord,
postExportChatLog, postExportChatLog,
getChatRecordDetails,
} }

View File

@ -1,13 +1,13 @@
import {Result} from '@/request/Result' import { Result } from '@/request/Result'
import {get, post, del, put} from '@/request/index' import { get, post, del, put } from '@/request/index'
import {type Ref} from 'vue' import { type Ref } from 'vue'
import type { import type {
ListModelRequest, ListModelRequest,
Model, Model,
CreateModelRequest, CreateModelRequest,
EditModelRequest, EditModelRequest,
} from '@/api/type/model' } from '@/api/type/model'
import type {FormField} from '@/components/dynamics-form/type' import type { FormField } from '@/components/dynamics-form/type'
const prefix = '/workspace/' + localStorage.getItem('workspace_id') const prefix = '/workspace/' + localStorage.getItem('workspace_id')
@ -21,7 +21,61 @@ const getModel: (
) => Promise<Result<Array<Model>>> = (data, loading) => { ) => Promise<Result<Array<Model>>> = (data, loading) => {
return get(`${prefix}/model`, data, loading) return get(`${prefix}/model`, data, loading)
} }
/**
* 使
* @param application_id
* @param loading
* @query { query_text: string, top_number: number, similarity: number }
* @returns
*/
const getApplicationRerankerModel: (
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'RERANKER' }, loading)
}
/**
* 使
* @param application_id
* @param loading
* @query { query_text: string, top_number: number, similarity: number }
* @returns
*/
const getApplicationSTTModel: (
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'STT' }, loading)
}
/**
* 使
* @param application_id
* @param loading
* @query { query_text: string, top_number: number, similarity: number }
* @returns
*/
const getApplicationTTSModel: (
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'TTS' }, loading)
}
const getApplicationImageModel: (
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'IMAGE' }, loading)
}
const getApplicationTTIModel: (
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'TTI' }, loading)
}
/** /**
* *
* @param model_id id * @param model_id id
@ -82,10 +136,10 @@ const updateModelParamsForm: (
* @param loading * @param loading
* @returns * @returns
*/ */
const getModelById: ( const getModelById: (model_id: string, loading?: Ref<boolean>) => Promise<Result<Model>> = (
model_id: string, model_id,
loading?: Ref<boolean>, loading,
) => Promise<Result<Model>> = (model_id, loading) => { ) => {
return get(`${prefix}/model/${model_id}`, {}, loading) return get(`${prefix}/model/${model_id}`, {}, loading)
} }
/** /**
@ -94,10 +148,10 @@ const getModelById: (
* @param loading * @param loading
* @returns * @returns
*/ */
const getModelMetaById: ( const getModelMetaById: (model_id: string, loading?: Ref<boolean>) => Promise<Result<Model>> = (
model_id: string, model_id,
loading?: Ref<boolean>, loading,
) => Promise<Result<Model>> = (model_id, loading) => { ) => {
return get(`${prefix}/model/${model_id}/meta`, {}, loading) return get(`${prefix}/model/${model_id}/meta`, {}, loading)
} }
/** /**
@ -106,16 +160,16 @@ const getModelMetaById: (
* @param loading * @param loading
* @returns * @returns
*/ */
const pauseDownload: ( const pauseDownload: (model_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
model_id: string, model_id,
loading?: Ref<boolean>, loading,
) => Promise<Result<boolean>> = (model_id, loading) => { ) => {
return put(`${prefix}/model/${model_id}/pause_download`, undefined, {}, loading) return put(`${prefix}/model/${model_id}/pause_download`, undefined, {}, loading)
} }
const deleteModel: ( const deleteModel: (model_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
model_id: string, model_id,
loading?: Ref<boolean>, loading,
) => Promise<Result<boolean>> = (model_id, loading) => { ) => {
return del(`${prefix}/model/${model_id}`, undefined, {}, loading) return del(`${prefix}/model/${model_id}`, undefined, {}, loading)
} }
export default { export default {
@ -128,4 +182,9 @@ export default {
pauseDownload, pauseDownload,
getModelParamsForm, getModelParamsForm,
updateModelParamsForm, updateModelParamsForm,
getApplicationRerankerModel,
getApplicationSTTModel,
getApplicationTTSModel,
getApplicationImageModel,
getApplicationTTIModel,
} }

View File

@ -5,7 +5,7 @@
:class="type" :class="type"
:style="{ :style="{
height: firsUserInput ? '100%' : undefined, height: firsUserInput ? '100%' : undefined,
paddingBottom: applicationDetails.disclaimer ? '20px' : 0 paddingBottom: applicationDetails.disclaimer ? '20px' : 0,
}" }"
> >
<div <div
@ -120,7 +120,7 @@ defineOptions({ name: 'AiChat' })
const route = useRoute() const route = useRoute()
const { const {
params: { accessToken, id }, params: { accessToken, id },
query: { mode } query: { mode },
} = route as any } = route as any
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -134,8 +134,8 @@ const props = withDefaults(
{ {
applicationDetails: () => ({}), applicationDetails: () => ({}),
available: true, available: true,
type: 'ai-chat' type: 'ai-chat',
} },
) )
const emit = defineEmits(['refresh', 'scroll']) const emit = defineEmits(['refresh', 'scroll'])
const { application, common } = useStore() const { application, common } = useStore()
@ -163,13 +163,13 @@ const initialApiFormData = ref({})
const isUserInput = computed( const isUserInput = computed(
() => () =>
props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0] props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0]
.properties.user_input_field_list.length > 0 .properties.user_input_field_list.length > 0,
) )
const isAPIInput = computed( const isAPIInput = computed(
() => () =>
props.type === 'debug-ai-chat' && props.type === 'debug-ai-chat' &&
props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0] props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0]
.properties.api_input_field_list.length > 0 .properties.api_input_field_list.length > 0,
) )
const showUserInputContent = computed(() => { const showUserInputContent = computed(() => {
return ( return (
@ -192,7 +192,7 @@ watch(
} }
} }
}, },
{ deep: true, immediate: true } { deep: true, immediate: true },
) )
watch( watch(
@ -200,7 +200,7 @@ watch(
() => { () => {
chartOpenId.value = '' chartOpenId.value = ''
}, },
{ deep: true } { deep: true },
) )
watch( watch(
@ -209,8 +209,8 @@ watch(
chatList.value = value ? value : [] chatList.value = value ? value : []
}, },
{ {
immediate: true immediate: true,
} },
) )
const toggleUserInput = () => { const toggleUserInput = () => {
@ -292,9 +292,9 @@ const handleDebounceClick = debounce((val, other_params_data?: any, chat?: chatT
*/ */
const openChatId: () => Promise<string> = () => { const openChatId: () => Promise<string> = () => {
const obj = props.applicationDetails const obj = props.applicationDetails
if (props.appId) { if (props.type === 'debug-ai-chat') {
return applicationApi return applicationApi
.getChatOpen(props.appId) .open(obj.id)
.then((res) => { .then((res) => {
chartOpenId.value = res.data chartOpenId.value = res.data
return res.data return res.data
@ -308,21 +308,7 @@ const openChatId: () => Promise<string> = () => {
return Promise.reject(res) return Promise.reject(res)
}) })
} else { } else {
if (isWorkFlow(obj.type)) { return Promise.reject('暂不支持')
const submitObj = {
work_flow: obj.work_flow,
user_id: obj.user
}
return applicationApi.postWorkflowChatOpen(submitObj).then((res) => {
chartOpenId.value = res.data
return res.data
})
} else {
return applicationApi.postChatOpen(obj).then((res) => {
chartOpenId.value = res.data
return res.data
})
}
} }
} }
/** /**
@ -447,8 +433,8 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
audio_list: audio_list:
other_params_data && other_params_data.audio_list ? other_params_data.audio_list : [], other_params_data && other_params_data.audio_list ? other_params_data.audio_list : [],
other_list: other_list:
other_params_data && other_params_data.other_list ? other_params_data.other_list : [] other_params_data && other_params_data.other_list ? other_params_data.other_list : [],
} },
}) })
chatList.value.push(chat) chatList.value.push(chat)
ChatManagement.addChatRecord(chat, 50, loading) ChatManagement.addChatRecord(chat, 50, loading)
@ -470,16 +456,17 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
} else { } else {
const obj = { const obj = {
message: chat.problem_text, message: chat.problem_text,
stream: true,
re_chat: re_chat || false, re_chat: re_chat || false,
...other_params_data, ...other_params_data,
form_data: { form_data: {
...form_data.value, ...form_data.value,
...api_form_data.value ...api_form_data.value,
} },
} }
// //
applicationApi applicationApi
.postChatMessage(chartOpenId.value, obj) .chat(chartOpenId.value, obj)
.then((response) => { .then((response) => {
if (response.status === 401) { if (response.status === 401) {
application application
@ -504,7 +491,7 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
const write = getWrite( const write = getWrite(
chat, chat,
reader, reader,
response.headers.get('Content-Type') !== 'application/json' response.headers.get('Content-Type') !== 'application/json',
) )
return reader.read().then(write) return reader.read().then(write)
} }
@ -530,14 +517,16 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
*/ */
function getSourceDetail(row: any) { function getSourceDetail(row: any) {
if (row.record_id) { if (row.record_id) {
chatLogApi.getRecordDetail(id || props.appId, row.chat_id, row.record_id, loading).then((res) => { chatLogApi
const exclude_keys = ['answer_text', 'id', 'answer_text_list'] .getChatRecordDetails(id || props.appId, row.chat_id, row.record_id, loading)
Object.keys(res.data).forEach((key) => { .then((res) => {
if (!exclude_keys.includes(key)) { const exclude_keys = ['answer_text', 'id', 'answer_text_list']
row[key] = res.data[key] Object.keys(res.data).forEach((key) => {
} if (!exclude_keys.includes(key)) {
row[key] = res.data[key]
}
})
}) })
})
} }
return true return true
} }
@ -617,11 +606,11 @@ watch(
() => { () => {
handleScroll() handleScroll()
}, },
{ deep: true, immediate: true } { deep: true, immediate: true },
) )
defineExpose({ defineExpose({
setScrollBottom setScrollBottom,
}) })
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -102,7 +102,7 @@ const modelValue = computed({
}, },
get: () => { get: () => {
return props.modelValue return props.modelValue
} },
}) })
const { model } = useStore() const { model } = useStore()

View File

@ -208,7 +208,7 @@ export const postStream: (url: string, data?: unknown) => Promise<Result<any> |
const language = user.getLanguage() const language = user.getLanguage()
const headers: HeadersInit = { 'Content-Type': 'application/json' } const headers: HeadersInit = { 'Content-Type': 'application/json' }
if (token) { if (token) {
headers['AUTHORIZATION'] = `${token}` headers['AUTHORIZATION'] = `Bearer ${token}`
} }
headers['Accept-Language'] = `${language}` headers['Accept-Language'] = `${language}`
return fetch(url, { return fetch(url, {

View File

@ -1,5 +1,6 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import applicationApi from '@/api/application/application' import applicationApi from '@/api/application/application'
import knowledgeAPI from '@/api/knowledge/knowledge.ts'
import applicationXpackApi from '@/api/application/application-xpack' import applicationXpackApi from '@/api/application/application-xpack'
import { type Ref } from 'vue' import { type Ref } from 'vue'
import { getBrowserLang } from '@/locales/index' import { getBrowserLang } from '@/locales/index'
@ -37,8 +38,8 @@ const useApplicationStore = defineStore('application', {
async asyncGetApplicationKnowledge(id: string, loading?: Ref<boolean>) { async asyncGetApplicationKnowledge(id: string, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
applicationApi knowledgeAPI
.getApplicationDataset(id, loading) .getAllKnowledge(loading)
.then((data) => { .then((data) => {
resolve(data) resolve(data)
}) })

View File

@ -465,6 +465,7 @@ import ParamSettingDialog from './component/ParamSettingDialog.vue'
import AddKnowledgeDialog from './component/AddKnowledgeDialog.vue' import AddKnowledgeDialog from './component/AddKnowledgeDialog.vue'
import EditAvatarDialog from '@/views/application-overview/component/EditAvatarDialog.vue' import EditAvatarDialog from '@/views/application-overview/component/EditAvatarDialog.vue'
import applicationApi from '@/api/application/application' import applicationApi from '@/api/application/application'
import modelAPI from '@/api/model/model.ts'
import { isAppIcon } from '@/utils/common' import { isAppIcon } from '@/utils/common'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import type { ApplicationFormType } from '@/api/type/application' import type { ApplicationFormType } from '@/api/type/application'
@ -671,8 +672,8 @@ function getKnowledge() {
function getModel() { function getModel() {
loading.value = true loading.value = true
applicationApi modelAPI
.getApplicationModel(id) .getModel({})
.then((res: any) => { .then((res: any) => {
modelOptions.value = groupBy(res?.data, 'provider') modelOptions.value = groupBy(res?.data, 'provider')
loading.value = false loading.value = false
@ -684,7 +685,7 @@ function getModel() {
function getSTTModel() { function getSTTModel() {
loading.value = true loading.value = true
applicationApi modelAPI
.getApplicationSTTModel(id) .getApplicationSTTModel(id)
.then((res: any) => { .then((res: any) => {
sttModelOptions.value = groupBy(res?.data, 'provider') sttModelOptions.value = groupBy(res?.data, 'provider')
@ -697,7 +698,7 @@ function getSTTModel() {
function getTTSModel() { function getTTSModel() {
loading.value = true loading.value = true
applicationApi modelAPI
.getApplicationTTSModel(id) .getApplicationTTSModel(id)
.then((res: any) => { .then((res: any) => {
ttsModelOptions.value = groupBy(res?.data, 'provider') ttsModelOptions.value = groupBy(res?.data, 'provider')
@ -718,14 +719,14 @@ function ttsModelChange() {
function ttsModelEnableChange() { function ttsModelEnableChange() {
if (!applicationForm.value.tts_model_enable) { if (!applicationForm.value.tts_model_enable) {
applicationForm.value.tts_model_id = '' applicationForm.value.tts_model_id = undefined
applicationForm.value.tts_type = 'BROWSER' applicationForm.value.tts_type = 'BROWSER'
} }
} }
function sttModelEnableChange() { function sttModelEnableChange() {
if (!applicationForm.value.stt_model_enable) { if (!applicationForm.value.stt_model_enable) {
applicationForm.value.stt_model_id = '' applicationForm.value.stt_model_id = undefined
} }
} }
@ -741,11 +742,12 @@ function refresh() {
} }
onMounted(() => { onMounted(() => {
// getModel() getModel()
// todo
// getKnowledge() // getKnowledge()
// getDetail() getDetail()
// getSTTModel() getSTTModel()
// getTTSModel() getTTSModel()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -45,9 +45,7 @@ const form_data = ref<any>({})
const dialogVisible = ref(false) const dialogVisible = ref(false)
const loading = ref(false) const loading = ref(false)
const getApi = (model_id: string, application_id?: string) => { const getApi = (model_id: string, application_id?: string) => {
return application_id return modelAPi.getModelParamsForm(model_id, loading)
? applicationApi.getModelParamsForm(application_id, model_id, loading)
: modelAPi.getModelParamsForm(model_id, loading)
} }
const open = (model_id: string, application_id?: string, model_setting_data?: any) => { const open = (model_id: string, application_id?: string, model_setting_data?: any) => {
form_data.value = {} form_data.value = {}

View File

@ -14,7 +14,7 @@
<el-form label-position="top" ref="paramFormRef" :model="form" v-loading="loading"> <el-form label-position="top" ref="paramFormRef" :model="form" v-loading="loading">
<el-form-item :label="$t('views.application.dialog.selectSearchMode')"> <el-form-item :label="$t('views.application.dialog.selectSearchMode')">
<el-radio-group <el-radio-group
v-model="form.dataset_setting.search_mode" v-model="form.knowledge_setting.search_mode"
class="card__radio" class="card__radio"
@change="changeHandle" @change="changeHandle"
> >
@ -35,7 +35,7 @@
<el-card <el-card
shadow="never" shadow="never"
class="mb-16" class="mb-16"
:class="form.dataset_setting.search_mode === 'keywords' ? 'active' : ''" :class="form.knowledge_setting.search_mode === 'keywords' ? 'active' : ''"
> >
<el-radio value="keywords" size="large"> <el-radio value="keywords" size="large">
<p class="mb-4"> <p class="mb-4">
@ -48,7 +48,7 @@
</el-card> </el-card>
<el-card <el-card
shadow="never" shadow="never"
:class="form.dataset_setting.search_mode === 'blend' ? 'active' : ''" :class="form.knowledge_setting.search_mode === 'blend' ? 'active' : ''"
> >
<el-radio value="blend" size="large"> <el-radio value="blend" size="large">
<p class="mb-4"> <p class="mb-4">
@ -79,9 +79,9 @@
</div> </div>
</template> </template>
<el-input-number <el-input-number
v-model="form.dataset_setting.similarity" v-model="form.knowledge_setting.similarity"
:min="0" :min="0"
:max="form.dataset_setting.search_mode === 'blend' ? 2 : 1" :max="form.knowledge_setting.search_mode === 'blend' ? 2 : 1"
:precision="3" :precision="3"
:step="0.1" :step="0.1"
:value-on-clear="0" :value-on-clear="0"
@ -93,7 +93,7 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item :label="$t('views.application.dialog.topReferences')"> <el-form-item :label="$t('views.application.dialog.topReferences')">
<el-input-number <el-input-number
v-model="form.dataset_setting.top_n" v-model="form.knowledge_setting.top_n"
:min="1" :min="1"
:max="10000" :max="10000"
:value-on-clear="1" :value-on-clear="1"
@ -106,7 +106,7 @@
<el-form-item :label="$t('views.application.dialog.maxCharacters')"> <el-form-item :label="$t('views.application.dialog.maxCharacters')">
<el-slider <el-slider
v-model="form.dataset_setting.max_paragraph_char_number" v-model="form.knowledge_setting.max_paragraph_char_number"
show-input show-input
:show-input-controls="false" :show-input-controls="false"
:min="500" :min="500"
@ -128,7 +128,7 @@
class="w-full" class="w-full"
> >
<el-radio-group <el-radio-group
v-model="form.dataset_setting.no_references_setting.status" v-model="form.knowledge_setting.no_references_setting.status"
class="radio-block-avatar" class="radio-block-avatar"
> >
<el-radio value="ai_questioning"> <el-radio value="ai_questioning">
@ -140,7 +140,9 @@
<el-radio value="designated_answer"> <el-radio value="designated_answer">
<p>{{ $t('views.application.dialog.provideAnswer') }}</p> <p>{{ $t('views.application.dialog.provideAnswer') }}</p>
<el-form-item <el-form-item
v-if="form.dataset_setting.no_references_setting.status === 'designated_answer'" v-if="
form.knowledge_setting.no_references_setting.status === 'designated_answer'
"
prop="designated_answer" prop="designated_answer"
> >
<el-input <el-input
@ -205,34 +207,34 @@ const noReferencesformRef = ref()
const defaultValue = { const defaultValue = {
ai_questioning: '{question}', ai_questioning: '{question}',
// @ts-ignore // @ts-ignore
designated_answer: t('views.application.dialog.designated_answer') designated_answer: t('views.application.dialog.designated_answer'),
} }
const defaultPrompt = const defaultPrompt =
t('views.application.dialog.defaultPrompt1', { t('views.application.dialog.defaultPrompt1', {
question: '{question}' question: '{question}',
}) + }) +
'<data></data>' + '<data></data>' +
t('views.application.dialog.defaultPrompt2') t('views.application.dialog.defaultPrompt2')
const form = ref<any>({ const form = ref<any>({
dataset_setting: { knowledge_setting: {
search_mode: 'embedding', search_mode: 'embedding',
top_n: 3, top_n: 3,
similarity: 0.6, similarity: 0.6,
max_paragraph_char_number: 5000, max_paragraph_char_number: 5000,
no_references_setting: { no_references_setting: {
status: 'ai_questioning', status: 'ai_questioning',
value: '{question}' value: '{question}',
} },
}, },
problem_optimization: false, problem_optimization: false,
problem_optimization_prompt: defaultPrompt problem_optimization_prompt: defaultPrompt,
}) })
const noReferencesform = ref<any>({ const noReferencesform = ref<any>({
ai_questioning: defaultValue['ai_questioning'], ai_questioning: defaultValue['ai_questioning'],
designated_answer: defaultValue['designated_answer'] designated_answer: defaultValue['designated_answer'],
}) })
const noReferencesRules = reactive<FormRules<any>>({ const noReferencesRules = reactive<FormRules<any>>({
@ -240,16 +242,16 @@ const noReferencesRules = reactive<FormRules<any>>({
{ {
required: true, required: true,
message: t('views.application.form.aiModel.placeholder'), message: t('views.application.form.aiModel.placeholder'),
trigger: 'blur' trigger: 'blur',
} },
], ],
designated_answer: [ designated_answer: [
{ {
required: true, required: true,
message: t('views.application.form.prompt.requiredMessage'), message: t('views.application.form.prompt.requiredMessage'),
trigger: 'blur' trigger: 'blur',
} },
] ],
}) })
const dialogVisible = ref<boolean>(false) const dialogVisible = ref<boolean>(false)
@ -260,7 +262,7 @@ const isWorkflowType = ref(false)
watch(dialogVisible, (bool) => { watch(dialogVisible, (bool) => {
if (!bool) { if (!bool) {
// form.value = { // form.value = {
// dataset_setting: { // knowledge_setting: {
// search_mode: 'embedding', // search_mode: 'embedding',
// top_n: 3, // top_n: 3,
// similarity: 0.6, // similarity: 0.6,
@ -275,7 +277,7 @@ watch(dialogVisible, (bool) => {
// } // }
noReferencesform.value = { noReferencesform.value = {
ai_questioning: defaultValue['ai_questioning'], ai_questioning: defaultValue['ai_questioning'],
designated_answer: defaultValue['designated_answer'] designated_answer: defaultValue['designated_answer'],
} }
noReferencesformRef.value?.clearValidate() noReferencesformRef.value?.clearValidate()
} }
@ -284,13 +286,13 @@ watch(dialogVisible, (bool) => {
const open = (data: any, type?: string) => { const open = (data: any, type?: string) => {
isWorkflowType.value = isWorkFlow(type) isWorkflowType.value = isWorkFlow(type)
form.value = { form.value = {
dataset_setting: { ...data.dataset_setting }, knowledge_setting: { ...data.knowledge_setting },
problem_optimization: data.problem_optimization, problem_optimization: data.problem_optimization,
problem_optimization_prompt: data.problem_optimization_prompt problem_optimization_prompt: data.problem_optimization_prompt,
} }
if (!isWorkflowType.value) { if (!isWorkflowType.value) {
noReferencesform.value[form.value.dataset_setting.no_references_setting.status] = noReferencesform.value[form.value.knowledge_setting.no_references_setting.status] =
form.value.dataset_setting.no_references_setting.value form.value.knowledge_setting.no_references_setting.value
} }
dialogVisible.value = true dialogVisible.value = true
@ -305,8 +307,8 @@ const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
await formEl.validate((valid, fields) => { await formEl.validate((valid, fields) => {
if (valid) { if (valid) {
form.value.dataset_setting.no_references_setting.value = form.value.knowledge_setting.no_references_setting.value =
noReferencesform.value[form.value.dataset_setting.no_references_setting.status] noReferencesform.value[form.value.knowledge_setting.no_references_setting.status]
emit('refresh', form.value) emit('refresh', form.value)
dialogVisible.value = false dialogVisible.value = false
} }
@ -316,9 +318,9 @@ const submit = async (formEl: FormInstance | undefined) => {
function changeHandle(val: string) { function changeHandle(val: string) {
if (val === 'keywords') { if (val === 'keywords') {
form.value.dataset_setting.similarity = 0 form.value.knowledge_setting.similarity = 0
} else { } else {
form.value.dataset_setting.similarity = 0.6 form.value.knowledge_setting.similarity = 0.6
} }
} }