feat(editor): Logs overview panel (#14045)

This commit is contained in:
Suguru Inoue
2025-03-31 13:19:54 +02:00
committed by GitHub
parent 68d9460f2a
commit d1710a1da3
22 changed files with 912 additions and 123 deletions

View File

@@ -2,17 +2,14 @@
import type { IAiData, IAiDataContent } from '@/Interface';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import type {
INodeExecutionData,
INodeTypeDescription,
NodeConnectionType,
NodeError,
} from 'n8n-workflow';
import type { INodeTypeDescription, NodeConnectionType, NodeError } from 'n8n-workflow';
import { computed } from 'vue';
import NodeIcon from '@/components/NodeIcon.vue';
import AiRunContentBlock from './AiRunContentBlock.vue';
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
import { useI18n } from '@/composables/useI18n';
import { formatTokenUsageCount, getConsumedTokens } from '@/components/RunDataAi/utils';
import ConsumedTokensDetails from '@/components/ConsumedTokensDetails.vue';
interface RunMeta {
startTimeMs: number;
@@ -36,44 +33,11 @@ const workflowsStore = useWorkflowsStore();
const { trackOpeningRelatedExecution, resolveRelatedExecutionUrl } = useExecutionHelpers();
const i18n = useI18n();
type TokenUsageData = {
completionTokens: number;
promptTokens: number;
totalTokens: number;
};
const consumedTokensSum = computed(() => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const tokenUsage = outputRun.value?.data?.reduce(
(acc: TokenUsageData, curr: INodeExecutionData) => {
const tokenUsageData = (curr.json?.tokenUsage ??
curr.json?.tokenUsageEstimate) as TokenUsageData;
if (!tokenUsageData) return acc;
return {
completionTokens: acc.completionTokens + tokenUsageData.completionTokens,
promptTokens: acc.promptTokens + tokenUsageData.promptTokens,
totalTokens: acc.totalTokens + tokenUsageData.totalTokens,
};
},
{
completionTokens: 0,
promptTokens: 0,
totalTokens: 0,
},
);
return tokenUsage;
return getConsumedTokens(outputRun.value);
});
const usingTokensEstimates = computed(() => {
return outputRun.value?.data?.some((d) => d.json?.tokenUsageEstimate);
});
function formatTokenUsageCount(count: number) {
return usingTokensEstimates.value ? `~${count}` : count.toString();
}
function extractRunMeta(run: IAiDataContent) {
const uiNode = workflowsStore.getNodeByName(props.inputData.node);
const nodeType = nodeTypesStore.getNodeType(uiNode?.type ?? '');
@@ -155,34 +119,12 @@ const outputError = computed(() => {
{{
i18n.baseText('runData.aiContentBlock.tokens', {
interpolate: {
count: formatTokenUsageCount(consumedTokensSum?.totalTokens ?? 0),
count: formatTokenUsageCount(consumedTokensSum, 'total'),
},
})
}}
<n8n-info-tip type="tooltip" theme="info-light" tooltip-placement="right">
<div>
<n8n-text :bold="true" size="small">
{{ i18n.baseText('runData.aiContentBlock.tokens.prompt') }}
{{
i18n.baseText('runData.aiContentBlock.tokens', {
interpolate: {
count: formatTokenUsageCount(consumedTokensSum?.promptTokens ?? 0),
},
})
}}
</n8n-text>
<br />
<n8n-text :bold="true" size="small">
{{ i18n.baseText('runData.aiContentBlock.tokens.completion') }}
{{
i18n.baseText('runData.aiContentBlock.tokens', {
interpolate: {
count: formatTokenUsageCount(consumedTokensSum?.completionTokens ?? 0),
},
})
}}
</n8n-text>
</div>
<ConsumedTokensDetails :consumed-tokens="consumedTokensSum" />
</n8n-info-tip>
</li>
</ul>