You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.4 KiB
136 lines
4.4 KiB
'use strict';
|
|
|
|
const { ensureObjectPayload, toInt } = require('./helpers');
|
|
const {
|
|
sanitizeQueryBlockConfig,
|
|
buildChartSnapshotPayload,
|
|
buildTableSnapshotPayload,
|
|
buildKpiSnapshotPayload,
|
|
} = require('./chartSnapshot');
|
|
const { analyzeBlockSnapshotWithPrompt } = require('./ai');
|
|
|
|
const normalizeOptionalString = value => {
|
|
const normalized = String(value || '').trim();
|
|
return normalized || null;
|
|
};
|
|
|
|
const deepCloneJson = value => {
|
|
if (value === null || value === undefined) return value;
|
|
return JSON.parse(JSON.stringify(value));
|
|
};
|
|
|
|
const rewriteAiAnalysisConfig = (config = {}, blockIdMap = null) => {
|
|
const nextConfig = deepCloneJson(config) || {};
|
|
if (!(blockIdMap instanceof Map) || !blockIdMap.size) {
|
|
return sanitizeQueryBlockConfig(nextConfig);
|
|
}
|
|
|
|
const sourceTemplateBlockId = toInt(
|
|
nextConfig.sourceTemplateBlockId || nextConfig.sourceBlockId || nextConfig.linkedBlockId
|
|
);
|
|
if (!sourceTemplateBlockId) return sanitizeQueryBlockConfig(nextConfig);
|
|
|
|
const resolvedBlockId = blockIdMap.get(String(sourceTemplateBlockId));
|
|
if (resolvedBlockId) {
|
|
nextConfig.sourceBlockId = resolvedBlockId;
|
|
nextConfig.linkedBlockId = resolvedBlockId;
|
|
}
|
|
delete nextConfig.sourceTemplateBlockId;
|
|
return sanitizeQueryBlockConfig(nextConfig);
|
|
};
|
|
|
|
const resolveBlockPayload = async (ctx, options = {}) => {
|
|
const normalizedBlockType = String(options?.blockType || 'text').trim().toLowerCase();
|
|
const safeConfig = ensureObjectPayload(options?.config || {}, 'config');
|
|
const safeSnapshot = deepCloneJson(options?.contentSnapshot) || null;
|
|
const dataSourceId = toInt(options?.dataSourceId);
|
|
const transaction = options?.transaction || null;
|
|
|
|
if (normalizedBlockType === 'chart') {
|
|
if (!dataSourceId) throw '缺少参数: dataSourceId';
|
|
return buildChartSnapshotPayload(
|
|
ctx,
|
|
dataSourceId,
|
|
safeConfig,
|
|
transaction,
|
|
safeSnapshot
|
|
);
|
|
}
|
|
|
|
if (normalizedBlockType === 'table') {
|
|
if (!dataSourceId) throw '缺少参数: dataSourceId';
|
|
return buildTableSnapshotPayload(ctx, dataSourceId, safeConfig, transaction);
|
|
}
|
|
|
|
if (normalizedBlockType === 'kpi') {
|
|
if (!dataSourceId) throw '缺少参数: dataSourceId';
|
|
return buildKpiSnapshotPayload(ctx, dataSourceId, safeConfig, transaction);
|
|
}
|
|
|
|
return {
|
|
config: sanitizeQueryBlockConfig(safeConfig),
|
|
contentSnapshot: safeSnapshot,
|
|
};
|
|
};
|
|
|
|
const finalizeResolvedBlockPayload = async (ctx, options = {}) => {
|
|
const normalizedBlockType = String(options?.blockType || 'text').trim().toLowerCase();
|
|
const baseConfig = ensureObjectPayload(options?.config || {}, 'config');
|
|
const safeSnapshot = deepCloneJson(options?.contentSnapshot) || null;
|
|
|
|
if (normalizedBlockType !== 'ai_analysis') {
|
|
return {
|
|
config: sanitizeQueryBlockConfig(baseConfig),
|
|
contentSnapshot: safeSnapshot,
|
|
};
|
|
}
|
|
|
|
const rewrittenConfig = rewriteAiAnalysisConfig(baseConfig, options?.blockIdMap || null);
|
|
const sourceBlockId = toInt(rewrittenConfig.sourceBlockId || rewrittenConfig.linkedBlockId);
|
|
const prompt = normalizeOptionalString(rewrittenConfig.prompt);
|
|
if (!sourceBlockId || !prompt || typeof options?.getCreatedBlockStateByInstanceId !== 'function') {
|
|
return {
|
|
config: rewrittenConfig,
|
|
contentSnapshot: safeSnapshot,
|
|
};
|
|
}
|
|
|
|
const sourceBlockState = options.getCreatedBlockStateByInstanceId(sourceBlockId);
|
|
if (!sourceBlockState) {
|
|
return {
|
|
config: rewrittenConfig,
|
|
contentSnapshot: safeSnapshot,
|
|
};
|
|
}
|
|
|
|
let content = '';
|
|
try {
|
|
content = await analyzeBlockSnapshotWithPrompt(ctx, {
|
|
actionId: `report-block:${sourceBlockState.createdId || sourceBlockId}`,
|
|
prompt,
|
|
sourceBlock: {
|
|
id: sourceBlockState.createdId || sourceBlockId,
|
|
blockType: sourceBlockState.blockType,
|
|
config: sourceBlockState.config || {},
|
|
contentSnapshot: sourceBlockState.contentSnapshot || null,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
content = normalizeOptionalString(safeSnapshot?.content)
|
|
|| `AI 分析生成失败: ${error?.message || error || '未知错误'}`;
|
|
}
|
|
|
|
return {
|
|
config: rewrittenConfig,
|
|
contentSnapshot: {
|
|
kind: 'ai_analysis',
|
|
content,
|
|
},
|
|
};
|
|
};
|
|
|
|
module.exports = {
|
|
resolveBlockPayload,
|
|
finalizeResolvedBlockPayload,
|
|
rewriteAiAnalysisConfig,
|
|
};
|
|
|