|
|
|
@ -17,15 +17,16 @@ import { |
|
|
|
Input, |
|
|
|
InputNumber, |
|
|
|
Modal, |
|
|
|
Radio, |
|
|
|
RangePicker, |
|
|
|
Row, |
|
|
|
Select, |
|
|
|
Space, |
|
|
|
Spin, |
|
|
|
Steps, |
|
|
|
Switch, |
|
|
|
Table, |
|
|
|
Tabs, |
|
|
|
Radio, |
|
|
|
} from 'ant-design-vue' |
|
|
|
import VueECharts from 'vue-echarts' |
|
|
|
import PointTransfer from '../components/PointTransfer.vue' |
|
|
|
@ -37,7 +38,9 @@ import { |
|
|
|
bottomModelApi, |
|
|
|
createDraftVersionApi, |
|
|
|
modelInfoApi, |
|
|
|
testModelAnnApi, |
|
|
|
testModelApi, |
|
|
|
trainModelAnnApi, |
|
|
|
trainModelApi, |
|
|
|
updateModelInfo, |
|
|
|
versionListApi, |
|
|
|
@ -79,6 +82,7 @@ export default defineComponent({ |
|
|
|
ASpace: Space, |
|
|
|
ARadio: Radio, |
|
|
|
ARadioGroup: Radio.Group, |
|
|
|
ASwitch: Switch, |
|
|
|
Icon, |
|
|
|
PointTransfer, |
|
|
|
}, |
|
|
|
@ -134,12 +138,20 @@ export default defineComponent({ |
|
|
|
|
|
|
|
const pointData = computed(() => { |
|
|
|
const list = model.value?.pointInfo || [] |
|
|
|
const normalizeBool = (val: any) => { |
|
|
|
if (val === true || val === '是' || val === 1 || val === '1' || val === '输出' || val === 'output') |
|
|
|
return true |
|
|
|
if (val === false || val === '否' || val === 0 || val === '0' || val === '输入' || val === 'input') |
|
|
|
return false |
|
|
|
return !!val |
|
|
|
} |
|
|
|
return list.map((p: any) => ({ |
|
|
|
description: p.description ?? p.Description, |
|
|
|
PointId: p.PointId ?? p.pointId, |
|
|
|
unit: p.unit ?? p.Unit, |
|
|
|
Upper: p.Upper ?? p.upper, |
|
|
|
Lower: p.Lower ?? p.lower, |
|
|
|
type: normalizeBool(p.type), |
|
|
|
dead: p.dead === true ? '是' : '否', |
|
|
|
limit: p.limit === true ? '是' : '否', |
|
|
|
upperBound: p.upperBound ?? p.upperbound ?? p.upperBound, |
|
|
|
@ -174,6 +186,26 @@ export default defineComponent({ |
|
|
|
return sum + (Number.isFinite(modeVal) ? modeVal : 0) |
|
|
|
}, 500) |
|
|
|
}) |
|
|
|
function handlePointTypeChange(pointId: any, value: boolean) { |
|
|
|
if (!isANNAlgorithm.value) |
|
|
|
return |
|
|
|
if (!showTrainActions.value) { |
|
|
|
createMessage.warning('非草稿版本不可修改测点类型') |
|
|
|
return |
|
|
|
} |
|
|
|
const infoList = model.value?.pointInfo |
|
|
|
if (!Array.isArray(infoList)) |
|
|
|
return |
|
|
|
const idx = infoList.findIndex(item => (item?.PointId ?? item?.pointId) === pointId) |
|
|
|
if (idx === -1) |
|
|
|
return |
|
|
|
infoList[idx] = { |
|
|
|
...infoList[idx], |
|
|
|
type: value, |
|
|
|
} |
|
|
|
model.value.pointInfo = [...infoList] |
|
|
|
updateModelInfoDebounced() |
|
|
|
} |
|
|
|
|
|
|
|
const activeKey = ref('1') |
|
|
|
type RangeValue = [Dayjs, Dayjs] |
|
|
|
@ -230,18 +262,43 @@ export default defineComponent({ |
|
|
|
createMessage.error('未获取到模型信息,无法获取测试数据') |
|
|
|
return |
|
|
|
} |
|
|
|
const params = { |
|
|
|
Model_id: id, |
|
|
|
version: model.value?.version ? model.value?.version : 'v-test', |
|
|
|
Test_Data: { |
|
|
|
time: timeRange |
|
|
|
.map(t => dayjs(t).format('YYYY-MM-DD HH:mm:ss')) |
|
|
|
.join(','), |
|
|
|
points: model.value.pointInfo.map(t => t.PointId).join(','), |
|
|
|
interval: model.value.sampling * 1000, |
|
|
|
}, |
|
|
|
const algorithm = (model.value?.algorithm || 'PCA').toUpperCase() |
|
|
|
const timeStr = timeRange |
|
|
|
.map(t => dayjs(t).format('YYYY-MM-DD HH:mm:ss')) |
|
|
|
.join(',') |
|
|
|
const pointStr = model.value.pointInfo.map(t => t.PointId).join(',') |
|
|
|
const intervalMs = model.value.sampling * 1000 |
|
|
|
let result |
|
|
|
if (algorithm === 'ANN') { |
|
|
|
const normalizeTypeFlag = (val: any) => { |
|
|
|
if (val === true || val === '是' || val === 1 || val === '1' || val === '输出' || val === 'output') |
|
|
|
return true |
|
|
|
if (val === false || val === '否' || val === 0 || val === '0' || val === '输入' || val === 'input') |
|
|
|
return false |
|
|
|
return !!val |
|
|
|
} |
|
|
|
const typeStr = model.value.pointInfo.map(t => (normalizeTypeFlag(t?.type) ? '1' : '0')).join(',') |
|
|
|
const params = { |
|
|
|
time: timeStr, |
|
|
|
points: pointStr, |
|
|
|
interval: intervalMs, |
|
|
|
model: JSON.stringify(model.value?.para ?? ''), |
|
|
|
type: typeStr, |
|
|
|
} |
|
|
|
result = await testModelAnnApi(params) |
|
|
|
} |
|
|
|
else { |
|
|
|
const params = { |
|
|
|
Model_id: id, |
|
|
|
version: model.value?.version ? model.value?.version : 'v-test', |
|
|
|
Test_Data: { |
|
|
|
time: timeStr, |
|
|
|
points: pointStr, |
|
|
|
interval: intervalMs, |
|
|
|
}, |
|
|
|
} |
|
|
|
result = await testModelApi(params) |
|
|
|
} |
|
|
|
const result = await testModelApi(params) |
|
|
|
const sampleData = result?.sampleData ?? result?.SampleData ?? [] |
|
|
|
const reconData = result?.reconData ?? result?.ReconData ?? [] |
|
|
|
if (!Array.isArray(sampleData) || !Array.isArray(reconData) || sampleData.length === 0 || reconData.length === 0) { |
|
|
|
@ -561,35 +618,59 @@ export default defineComponent({ |
|
|
|
console.error('模型参数点信息为空,无法训练') |
|
|
|
return |
|
|
|
} |
|
|
|
const params = { |
|
|
|
conditon: modelInfo.alarmmodelset?.alarmcondition || '1=1', |
|
|
|
Hyper_para: { |
|
|
|
percent: modelInfo.rate, |
|
|
|
}, |
|
|
|
Train_Data: { |
|
|
|
points: pointInfo.map(item => item.PointId).join(','), |
|
|
|
dead: pointInfo.map(item => (item.dead ? '1' : '0')).join(','), |
|
|
|
limit: pointInfo.map(item => (item.limit ? '1' : '0')).join(','), |
|
|
|
uplow: pointInfo |
|
|
|
.map( |
|
|
|
item => |
|
|
|
`${item.Upper ? item.Upper : null},${ |
|
|
|
item.Lower ? item.Lower : null |
|
|
|
}`, |
|
|
|
) |
|
|
|
.join(';'), |
|
|
|
interval: modelInfo.sampling * 1000, |
|
|
|
time: modelInfo.trainTime |
|
|
|
.map(item => `${item.st},${item.et}`) |
|
|
|
.join(';'), |
|
|
|
}, |
|
|
|
type: 'PCA', |
|
|
|
smote_config: [], |
|
|
|
smote: true, |
|
|
|
const algorithm = (modelInfo.algorithm || 'PCA').toUpperCase() |
|
|
|
const condition = modelInfo.alarmmodelset?.alarmcondition || '1=1' |
|
|
|
const trainData = { |
|
|
|
points: pointInfo.map(item => item.PointId).join(','), |
|
|
|
dead: pointInfo.map(item => (item.dead ? '1' : '0')).join(','), |
|
|
|
limit: pointInfo.map(item => (item.limit ? '1' : '0')).join(','), |
|
|
|
uplow: pointInfo |
|
|
|
.map( |
|
|
|
item => |
|
|
|
`${item.Upper ?? ''},${item.Lower ?? ''}`, |
|
|
|
) |
|
|
|
.join(';'), |
|
|
|
interval: modelInfo.sampling * 1000, |
|
|
|
time: modelInfo.trainTime.map(item => `${item.st},${item.et}`).join(';'), |
|
|
|
} |
|
|
|
spinning.value = true |
|
|
|
try { |
|
|
|
const response = await trainModelApi(params) |
|
|
|
let response |
|
|
|
if (algorithm === 'ANN') { |
|
|
|
const normalizeTypeFlag = (val: any) => { |
|
|
|
if (val === true || val === '是' || val === 1 || val === '1' || val === '输出' || val === 'output') |
|
|
|
return true |
|
|
|
if (val === false || val === '否' || val === 0 || val === '0' || val === '输入' || val === 'input') |
|
|
|
return false |
|
|
|
return !!val |
|
|
|
} |
|
|
|
const typeStr = pointInfo.map(item => (normalizeTypeFlag(item?.type) ? '1' : '0')).join(',') |
|
|
|
const params = { |
|
|
|
type: typeStr, |
|
|
|
iter: modelInfo.iter, |
|
|
|
hide: modelInfo.layer, |
|
|
|
conditon: condition, |
|
|
|
condition, |
|
|
|
Train_Data: trainData, |
|
|
|
} |
|
|
|
response = await trainModelAnnApi(params) |
|
|
|
response = JSON.parse(response) |
|
|
|
response.filename = JSON.parse(response.filename) |
|
|
|
} |
|
|
|
else { |
|
|
|
const hyperPara: Record<string, any> = {} |
|
|
|
if (algorithm === 'PCA') |
|
|
|
hyperPara.percent = modelInfo.rate |
|
|
|
const params = { |
|
|
|
conditon: condition, |
|
|
|
Hyper_para: hyperPara, |
|
|
|
Train_Data: trainData, |
|
|
|
type: algorithm, |
|
|
|
smote_config: [], |
|
|
|
smote: true, |
|
|
|
} |
|
|
|
response = await trainModelApi(params) |
|
|
|
} |
|
|
|
model.value.para = response |
|
|
|
|
|
|
|
const modelInfoDetail = response.Model_info || response.modelInfo |
|
|
|
@ -770,8 +851,13 @@ export default defineComponent({ |
|
|
|
const editModelForm = ref({ |
|
|
|
sampling: 0, |
|
|
|
rate: 0, |
|
|
|
iter: 0, |
|
|
|
layer: '', |
|
|
|
selectedKeys: [], |
|
|
|
}) |
|
|
|
const algorithmValue = computed(() => (model.value?.algorithm || 'PCA').toUpperCase()) |
|
|
|
const isPCAAlgorithm = computed(() => algorithmValue.value === 'PCA') |
|
|
|
const isANNAlgorithm = computed(() => algorithmValue.value === 'ANN') |
|
|
|
|
|
|
|
function openEditModel() { |
|
|
|
if (!canEditModel.value) { |
|
|
|
@ -780,6 +866,8 @@ export default defineComponent({ |
|
|
|
} |
|
|
|
editModelForm.value.sampling = model.value?.sampling || 0 |
|
|
|
editModelForm.value.rate = model.value?.rate || 0 |
|
|
|
editModelForm.value.iter = model.value?.iter || 0 |
|
|
|
editModelForm.value.layer = model.value?.layer || '' |
|
|
|
editModelForm.value.selectedKeys = (model.value?.pointInfo || []).map(item => buildPointKeyFromInfo({ |
|
|
|
description: item.description ?? item.Description, |
|
|
|
PointId: item.PointId ?? item.pointId, |
|
|
|
@ -795,7 +883,22 @@ export default defineComponent({ |
|
|
|
return |
|
|
|
} |
|
|
|
model.value.sampling = editModelForm.value.sampling |
|
|
|
model.value.rate = editModelForm.value.rate |
|
|
|
if (isPCAAlgorithm.value) { |
|
|
|
model.value.rate = editModelForm.value.rate |
|
|
|
delete model.value.layer |
|
|
|
delete model.value.iter |
|
|
|
} |
|
|
|
else if (isANNAlgorithm.value) { |
|
|
|
model.value.layer = editModelForm.value.layer |
|
|
|
model.value.iter = editModelForm.value.iter |
|
|
|
if (!Array.isArray(model.value.pointInfo)) |
|
|
|
model.value.pointInfo = [] |
|
|
|
model.value.pointInfo = model.value.pointInfo.map((item: any) => ({ |
|
|
|
...item, |
|
|
|
type: item?.type ?? true, |
|
|
|
})) |
|
|
|
delete model.value.rate |
|
|
|
} |
|
|
|
model.value.pointInfo = editModelForm.value.selectedKeys.map((key) => { |
|
|
|
const { description, PointId, unit, Lower, Upper } = parsePointKey(key) |
|
|
|
return { |
|
|
|
@ -804,6 +907,7 @@ export default defineComponent({ |
|
|
|
unit, |
|
|
|
Lower, |
|
|
|
Upper, |
|
|
|
type: isANNAlgorithm.value ? true : undefined, |
|
|
|
dead: true, |
|
|
|
limit: false, |
|
|
|
} |
|
|
|
@ -899,9 +1003,9 @@ export default defineComponent({ |
|
|
|
else { |
|
|
|
queryParts.push('sampleType=train') |
|
|
|
} |
|
|
|
if (assessSampleCount.value !== null && assessSampleCount.value !== undefined && assessSampleCount.value !== '') { |
|
|
|
if (assessSampleCount.value !== null && assessSampleCount.value !== undefined && assessSampleCount.value !== '') |
|
|
|
queryParts.push(`sampleCount=${assessSampleCount.value}`) |
|
|
|
} |
|
|
|
|
|
|
|
assessConfigVisible.value = false |
|
|
|
go(`/model/assess-report/${id}?${queryParts.join('&')}`) |
|
|
|
} |
|
|
|
@ -1135,6 +1239,9 @@ export default defineComponent({ |
|
|
|
createDraftVersion, |
|
|
|
goAssessReport, |
|
|
|
showTrainActions, |
|
|
|
isPCAAlgorithm, |
|
|
|
isANNAlgorithm, |
|
|
|
handlePointTypeChange, |
|
|
|
canEditModel, |
|
|
|
effectiveSampleCount, |
|
|
|
assessConfigVisible, |
|
|
|
@ -1219,12 +1326,18 @@ export default defineComponent({ |
|
|
|
<a-descriptions-item label="参数个数"> |
|
|
|
{{ model?.pointInfo.length || "暂无" }} |
|
|
|
</a-descriptions-item> |
|
|
|
<a-descriptions-item label="最小主元贡献率"> |
|
|
|
<a-descriptions-item v-if="isPCAAlgorithm" label="最小主元贡献率"> |
|
|
|
{{ model?.rate }} |
|
|
|
</a-descriptions-item> |
|
|
|
<a-descriptions-item label="最小主元个数"> |
|
|
|
<a-descriptions-item v-if="isPCAAlgorithm" label="最小主元个数"> |
|
|
|
{{ model?.principal }} |
|
|
|
</a-descriptions-item> |
|
|
|
<a-descriptions-item v-if="isANNAlgorithm" label="隐藏层结构"> |
|
|
|
{{ model?.layer || '暂无' }} |
|
|
|
</a-descriptions-item> |
|
|
|
<a-descriptions-item v-if="isANNAlgorithm" label="最大迭代次数"> |
|
|
|
{{ model?.iter }} |
|
|
|
</a-descriptions-item> |
|
|
|
<a-descriptions-item label="模型性能"> |
|
|
|
{{ model?.precision }} |
|
|
|
</a-descriptions-item> |
|
|
|
@ -1272,6 +1385,18 @@ export default defineComponent({ |
|
|
|
</a-tab-pane> |
|
|
|
<a-tab-pane key="2" tab="测点参数"> |
|
|
|
<BasicTable class="compact-table" @register="pointTable"> |
|
|
|
<template #pointType="{ record }"> |
|
|
|
<template v-if="isANNAlgorithm"> |
|
|
|
<a-switch |
|
|
|
:checked="record.type" |
|
|
|
:disabled="!showTrainActions" |
|
|
|
checked-children="输出" |
|
|
|
un-checked-children="输入" |
|
|
|
@change="(val) => handlePointTypeChange(record.PointId, val as boolean)" |
|
|
|
/> |
|
|
|
</template> |
|
|
|
<span v-else>--</span> |
|
|
|
</template> |
|
|
|
<template #action="{ record, index }"> |
|
|
|
<a-button |
|
|
|
v-if="showTrainActions" |
|
|
|
@ -1522,7 +1647,7 @@ export default defineComponent({ |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
<a-col :span="12"> |
|
|
|
<a-col v-if="isPCAAlgorithm" :span="12"> |
|
|
|
<a-form-item label="最小主元贡献率" required> |
|
|
|
<a-input-number |
|
|
|
v-model:value="editModelForm.rate" |
|
|
|
@ -1531,6 +1656,25 @@ export default defineComponent({ |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
<a-col v-if="isANNAlgorithm" :span="12"> |
|
|
|
<a-form-item label="隐藏层结构" required> |
|
|
|
<a-input |
|
|
|
v-model:value="editModelForm.layer" |
|
|
|
placeholder="请输入隐藏层结构" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
<a-row v-if="isANNAlgorithm" :gutter="16"> |
|
|
|
<a-col :span="12"> |
|
|
|
<a-form-item label="最大迭代次数" required> |
|
|
|
<a-input-number |
|
|
|
v-model:value="editModelForm.iter" |
|
|
|
placeholder="请输入最大迭代次数" |
|
|
|
style="width: 100%" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
<div style="display: flex; justify-content: center; margin-top: 24px;margin-bottom: 10px;"> |
|
|
|
<PointTransfer |
|
|
|
@ -1563,8 +1707,8 @@ export default defineComponent({ |
|
|
|
|
|
|
|
.assess-option { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 8px; |
|
|
|
align-items: center; |
|
|
|
} |
|
|
|
|
|
|
|
.assess-label { |
|
|
|
@ -1573,8 +1717,8 @@ export default defineComponent({ |
|
|
|
} |
|
|
|
|
|
|
|
.assess-hint { |
|
|
|
color: #9098a4; |
|
|
|
font-size: 12px; |
|
|
|
color: #9098a4; |
|
|
|
} |
|
|
|
|
|
|
|
.compact-card { |
|
|
|
@ -1639,7 +1783,7 @@ export default defineComponent({ |
|
|
|
} |
|
|
|
|
|
|
|
.tab-card :deep(.ant-card-body) { |
|
|
|
padding: 4px 6px 4px; |
|
|
|
padding: 4px 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.train-toolbar { |
|
|
|
|