fix(i18n): cost-predict.ts hash key 清理 + 硬编码中文清零 + 错误 key 引用修复

- 23 个 predictutilsts.s* hash-style 键重命名为 costPredict.* 语义化键
- 7 处 buildCostInsightPrompt 硬编码中文模板字面量→i18n.t() 插值调用
- 修复 costRecommendation 函数引用错误 key (predictMemLeak→costPredict.rec*)
- 修复 dimension 字段引用 predictDiskFull→costPredict.allProviders
- 修复 providerLabel 引用 predictIn24h→costPredict.allProviders
- 新增 34 个语义化翻译键 (aiops.costPredict.*), zh/en 8102→8113 对齐
- tsc -b=0, npm build✓ (19.29s), ESLint=0/43/any=0, go build=0
- 17/17 集成测试通过
This commit is contained in:
attacker committed 2026-07-17 04:05:32 +08:00
1 parent d6ed1978ef
commit 083f4477db
3 files changed
+117 -83

No files matched your search

+47 -35
View File
@@ -83,20 +83,20 @@ function costTrendFromSlope(slope: number): 'up' | 'down' | 'stable' {
/** 成本优化建议 */
export function costRecommendation(trend: 'up' | 'down' | 'stable', ratio: number): string {
if (trend === 'up' && ratio >= 0.85) {
return i18n.t('aiops.predictMemLeak');
return i18n.t('aiops.costPredict.recHighSpend');
}
if (trend === 'up') {
return i18n.t('aiops.predictMemLeak');
return i18n.t('aiops.costPredict.recRising');
}
if (trend === 'down') {
return i18n.t('aiops.predictMemLeak');
return i18n.t('aiops.costPredict.recDeclining');
}
return i18n.t('aiops.predictutilsts.sa3b5c7d9');
return i18n.t('aiops.costPredict.recStable');
}
/** 预算风险建议 */
function budgetRiskAction(metric: 'daily' | 'monthly', provider: string): string {
const scope = provider && provider !== i18n.t('aiops.predictutilsts.sg5a3d8e1') ? `${provider} ` : '';
const scope = provider && provider !== i18n.t('aiops.costPredict.allProviders') ? `${provider} ` : '';
if (metric === 'daily') {
return i18n.t('aiops.predictUtils.dailyCostHint', { scope });
}
@@ -139,7 +139,7 @@ function topServicesByCost(records: JsonData[], limit = 5): { service: string; c
records.forEach((r) => {
const date = String(r.billing_date || '');
if (date < start) return;
const svc = String(r.service || i18n.t('aiops.predictutilsts.sh7c2b9d6'));
const svc = String(r.service || i18n.t('aiops.costPredict.unknownService'));
map.set(svc, (map.get(svc) || 0) + (Number(r.cost) || 0));
});
return [...map.entries()]
@@ -256,7 +256,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
const allRatio =
summary.predictedMonthEnd > 0 ? summary.monthCost / summary.predictedMonthEnd : 0;
dimensionForecasts.push({
dimension: i18n.t('aiops.predictDiskFull'),
dimension: i18n.t('aiops.costPredict.allProviders'),
currentMonth: summary.monthCost,
predictedMonthEnd: summary.predictedMonthEnd,
dailyAvg: summary.dailyAvg,
@@ -302,7 +302,7 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
const metric = (rule.metric === 'daily' ? 'daily' : 'monthly') as 'daily' | 'monthly';
const ruleProvider = String(rule.provider || '');
const providerLabel = ruleProvider ? PROVIDER_LABELS[ruleProvider] || ruleProvider : i18n.t('aiops.predictIn24h');
const providerLabel = ruleProvider ? PROVIDER_LABELS[ruleProvider] || ruleProvider : i18n.t('aiops.costPredict.allProviders');
let current = 0;
let predicted = 0;
@@ -339,17 +339,17 @@ export function computeCostPredictions(input: ComputeCostPredictionsInput): Comp
if (current >= threshold) probability += 25;
probability = Math.max(5, Math.min(92, probability));
let timeframe = metric === 'daily' ? i18n.t('aiops.predictNext24h') : i18n.t('aiops.predictutilsts.sd4e5f6g7');
let timeframe = metric === 'daily' ? i18n.t('aiops.predictNext24h') : i18n.t('aiops.costPredict.monthEnd');
if (slope > 0.01 && threshold > current) {
const days = (threshold - current) / slope;
if (days < 1) timeframe = metric === 'daily' ? i18n.t('aiops.predictutilsts.se5f6g7h8') : i18n.t('aiops.predictutilsts.sf6g7h8i9');
else if (days <= 7) timeframe = i18n.t('aiops.predictutilsts.sg7h8i9j0', { days: Math.ceil(days) });
else timeframe = i18n.t('aiops.predictutilsts.sh8i9j0k1', { days: Math.ceil(days) });
if (days < 1) timeframe = metric === 'daily' ? i18n.t('aiops.costPredict.withinToday') : i18n.t('aiops.costPredict.withinOneDay');
else if (days <= 7) timeframe = i18n.t('aiops.costPredict.withinDays', { days: Math.ceil(days) });
else timeframe = i18n.t('aiops.costPredict.approxAfterDays', { days: Math.ceil(days) });
}
if (probability >= 30 || current >= threshold * 0.7) {
budgetRisks.push({
ruleName: String(rule.name || i18n.t('aiops.predictutilsts.si9j0k1l2')),
ruleName: String(rule.name || i18n.t('aiops.costPredict.budgetRule')),
provider: providerLabel,
metric,
threshold,
@@ -386,49 +386,61 @@ export function buildCostInsightPrompt(data: ComputedCostPredictions): string {
const patternHint =
billingPattern === 'front_loaded'
? i18n.t('aiops.predictutilsts.sj0k1l2m3')
? i18n.t('aiops.costPredict.frontLoadedHint')
: billingPattern === 'sparse'
? i18n.t('aiops.predictutilsts.sk1l2m3n4')
: i18n.t('aiops.predictutilsts.sl2m3n4o5');
? i18n.t('aiops.costPredict.sparseHint')
: i18n.t('aiops.costPredict.steadyHint');
const dimLines = dimensionForecasts.slice(0, 6).map(
(d) =>
`- ${d.dimension}:本月 ${d.currentMonth.toFixed(2)} 元 → 预测月末 ${d.predictedMonthEnd.toFixed(2)} 元(趋势 ${d.trend})`,
i18n.t('aiops.costPredict.dimLine', {
dim: d.dimension,
current: d.currentMonth.toFixed(2),
predicted: d.predictedMonthEnd.toFixed(2),
trend: d.trend,
}),
);
const riskLines =
budgetRisks.length > 0
? budgetRisks.slice(0, 5).map(
(r) =>
`- ${r.ruleName}(${r.provider}):当前 ${r.current} / 阈值 ${r.threshold},预测 ${r.predicted},触线概率 ${r.probability}%`,
i18n.t('aiops.costPredict.riskLine', {
rule: r.ruleName,
provider: r.provider,
current: r.current,
threshold: r.threshold,
predicted: r.predicted,
probability: r.probability,
}),
)
: [`- ${i18n.t('aiops.predictutilsts.sm3n4o5p6')}`];
: [`- ${i18n.t('aiops.costPredict.noBudgetRisk')}`];
const serviceLines =
topServices.length > 0
? topServices.map((s) => `- ${s.service}:${s.cost.toFixed(2)} 元`)
: [`- ${i18n.t('aiops.predictutilsts.sn4o5p6q7')}`];
? topServices.map((s) => i18n.t('aiops.costPredict.serviceLine', { service: s.service, cost: s.cost.toFixed(2) }))
: [`- ${i18n.t('aiops.costPredict.noServiceDetail')}`];
return [
i18n.t('aiops.predictutilsts.so5p6q7r8'),
i18n.t('aiops.costPredict.promptIntro'),
'',
i18n.t('aiops.predictutilsts.sp6q7r8s9'),
`- 本月已花:${summary.monthCost.toFixed(2)} 元`,
`- 预测月末:${summary.predictedMonthEnd.toFixed(2)} 元(置信 ${summary.confidence}%)`,
`- 全月日均:${summary.dailyAvg.toFixed(2)} 元;近7日日均:${recentDailyAvg.toFixed(2)} 元;剩余 ${summary.daysRemaining} 天`,
`- 账单形态:${patternHint}`,
i18n.t('aiops.costPredict.sectionOverview'),
i18n.t('aiops.costPredict.monthSpent', { amount: summary.monthCost.toFixed(2) }),
i18n.t('aiops.costPredict.predictedEnd', { amount: summary.predictedMonthEnd.toFixed(2), confidence: summary.confidence }),
i18n.t('aiops.costPredict.dailySummary', { dailyAvg: summary.dailyAvg.toFixed(2), recentAvg: recentDailyAvg.toFixed(2), daysRemaining: summary.daysRemaining }),
i18n.t('aiops.costPredict.billingPatternLabel', { hint: patternHint }),
'',
i18n.t('aiops.predictutilsts.sq7r8s9t0'),
i18n.t('aiops.costPredict.sectionTopServices'),
...serviceLines,
'',
i18n.t('aiops.predictutilsts.sr8s9t0u1'),
i18n.t('aiops.costPredict.sectionDimensionForecast'),
...dimLines,
'',
i18n.t('aiops.predictutilsts.ss9t0u1v2'),
i18n.t('aiops.costPredict.sectionBudgetRisk'),
...riskLines,
'',
i18n.t('aiops.predictutilsts.st0u1v2w3'),
i18n.t('aiops.predictutilsts.su1v2w3x4'),
i18n.t('aiops.predictutilsts.sv2w3x4y5'),
i18n.t('aiops.predictutilsts.sw3x4y5z6'),
i18n.t('aiops.predictutilsts.sx4y5z6a7'),
i18n.t('aiops.costPredict.promptRequirements'),
i18n.t('aiops.costPredict.promptReq1'),
i18n.t('aiops.costPredict.promptReq2'),
i18n.t('aiops.costPredict.promptReq3'),
i18n.t('aiops.costPredict.promptReq4'),
].join('\n');
}
+35 -24
View File
@@ -8602,29 +8602,6 @@
"predictutilsts.providerAliyun": "Alibaba Cloud",
"predictutilsts.providerHuawei": "Huawei Cloud",
"predictutilsts.providerTencent": "Tencent Cloud",
"predictutilsts.sd4e5f6g7": "End of month",
"predictutilsts.se5f6g7h8": "Within today",
"predictutilsts.sf6g7h8i9": "Within 1 day",
"predictutilsts.sg5a3d8e1": "All",
"predictutilsts.sg7h8i9j0": "Within {{days}} days",
"predictutilsts.sh7c2b9d6": "Other",
"predictutilsts.sh8i9j0k1": "In about {{days}} days",
"predictutilsts.si9j0k1l2": "Budget Rule",
"predictutilsts.sj0k1l2m3": "Bills front-loaded at month start, may contain pre-paid or retired resources; prediction uses recent 7-day run rate",
"predictutilsts.sk1l2m3n4": "Insufficient daily bill samples, lower prediction confidence",
"predictutilsts.sl2m3n4o5": "Daily bills are relatively stable, extrapolated by trend",
"predictutilsts.sm3n4o5p6": "No budget threshold risk",
"predictutilsts.sn4o5p6q7": "No service-level detail",
"predictutilsts.so5p6q7r8": "You are a FinOps cloud cost optimization expert. Based on the following cloud billing prediction data, provide comprehensive cost risk assessment and actionable cost-reduction recommendations:",
"predictutilsts.sp6q7r8s9": "[Overview]",
"predictutilsts.sq7r8s9t0": "[Top Service Costs]",
"predictutilsts.sr8s9t0u1": "[Dimension Forecasts]",
"predictutilsts.ss9t0u1v2": "[Budget Risks]",
"predictutilsts.st0u1v2w3": "Output requirements (Markdown, Chinese):",
"predictutilsts.su1v2w3x4": "1. Use **bold subtitles** for sections with 1 key point each, e.g.: **Data Anomalies**, **Idle Resource Cleanup**, **Billing Mode Optimization**, **Storage Lifecycle**",
"predictutilsts.sv2w3x4y5": "2. If monthly avg and recent 7-day avg clearly contradict predicted month-end, explain in 'Data Anomalies' (pre-paid/shutdown etc.)",
"predictutilsts.sw3x4y5z6": "3. Give actionable recommendations per top service (EIP/disk/ECS spec/OSS lifecycle/reserved instances etc.)",
"predictutilsts.sx4y5z6a7": "4. Pick 3-5 most relevant recommendations, under 350 words, no generic platitudes",
"probabilityColon": "Probability: ",
"processing": "Processing...",
"providerAndCredential": "Model & Credential",
@@ -8775,7 +8752,41 @@
"recentReleases": "Recent releases:",
"overviewFallback": "Servers:{{servers}}(running {{running}}) | K8s clusters:{{clusters}} Nodes:{{nodes}} Pods:{{pods}} | Alerts:{{alerts}}(firing {{firing}}) | Pipelines:{{pipelines}}(success {{rate}}%) | Monthly cost:¥{{cost}}",
"noAgentData": "(No Agent data currently, monitoring Agent may not be deployed)"
}
},
"costPredict.allProviders": "All",
"costPredict.unknownService": "Other",
"costPredict.monthEnd": "End of month",
"costPredict.withinToday": "Within today",
"costPredict.withinOneDay": "Within 1 day",
"costPredict.withinDays": "Within {{days}} days",
"costPredict.approxAfterDays": "In about {{days}} days",
"costPredict.budgetRule": "Budget Rule",
"costPredict.frontLoadedHint": "Bills front-loaded at month start, may contain pre-paid or retired resources; prediction uses recent 7-day run rate",
"costPredict.sparseHint": "Insufficient daily bill samples, lower prediction confidence",
"costPredict.steadyHint": "Daily bills are relatively stable, extrapolated by trend",
"costPredict.noBudgetRisk": "No budget threshold risk",
"costPredict.noServiceDetail": "No service-level detail",
"costPredict.promptIntro": "You are a FinOps cloud cost optimization expert. Based on the following cloud billing prediction data, provide comprehensive cost risk assessment and actionable cost-reduction recommendations:",
"costPredict.sectionOverview": "[Overview]",
"costPredict.sectionTopServices": "[Top Service Costs]",
"costPredict.sectionDimensionForecast": "[Dimension Forecasts]",
"costPredict.sectionBudgetRisk": "[Budget Risks]",
"costPredict.promptRequirements": "Output requirements (Markdown, Chinese):",
"costPredict.promptReq1": "1. Use **bold subtitles** for sections with 1 key point each, e.g.: **Data Anomalies**, **Idle Resource Cleanup**, **Billing Mode Optimization**, **Storage Lifecycle**",
"costPredict.promptReq2": "2. If monthly avg and recent 7-day avg clearly contradict predicted month-end, explain in 'Data Anomalies' (pre-paid/shutdown etc.)",
"costPredict.promptReq3": "3. Give actionable recommendations per top service (EIP/disk/ECS spec/OSS lifecycle/reserved instances etc.)",
"costPredict.promptReq4": "4. Pick 3-5 most relevant recommendations, under 350 words, no generic platitudes",
"costPredict.dimLine": "- {{dim}}: This month {{current}} CNY → Predicted month-end {{predicted}} CNY (trend {{trend}})",
"costPredict.riskLine": "- {{rule}} ({{provider}}): Current {{current}} / Threshold {{threshold}}, Predicted {{predicted}}, Probability {{probability}}%",
"costPredict.serviceLine": "- {{service}}: {{cost}} CNY",
"costPredict.monthSpent": "- Spent this month: {{amount}} CNY",
"costPredict.predictedEnd": "- Predicted month-end: {{amount}} CNY (confidence {{confidence}}%)",
"costPredict.dailySummary": "- Monthly avg: {{dailyAvg}} CNY; Recent 7-day avg: {{recentAvg}} CNY; {{daysRemaining}} days remaining",
"costPredict.billingPatternLabel": "- Billing pattern: {{hint}}",
"costPredict.recHighSpend": "Cost rising rapidly, investigate high-spend resources and optimize specs",
"costPredict.recRising": "Cost trending up, monitor new service spending",
"costPredict.recDeclining": "Cost declining, optimization is effective",
"costPredict.recStable": "Cost stable, maintain current strategy"
},
"breadcrumb": {
"aiAlertAnalyzer": "Alert Analysis",
+35 -24
View File
@@ -8602,29 +8602,6 @@
"predictutilsts.providerAliyun": "阿里云",
"predictutilsts.providerHuawei": "华为云",
"predictutilsts.providerTencent": "腾讯云",
"predictutilsts.sd4e5f6g7": "本月末",
"predictutilsts.se5f6g7h8": "今日内",
"predictutilsts.sf6g7h8i9": "1 天内",
"predictutilsts.sg5a3d8e1": "全部",
"predictutilsts.sg7h8i9j0": "{{days}} 天内",
"predictutilsts.sh7c2b9d6": "其他",
"predictutilsts.sh8i9j0k1": "约 {{days}} 天后",
"predictutilsts.si9j0k1l2": "预算规则",
"predictutilsts.sj0k1l2m3": "账单呈月初集中、近期趋零,可能含包年包月预付费或资源已停用,预测已按近7日运行费率外推",
"predictutilsts.sk1l2m3n4": "日账单样本不足,预测置信度较低",
"predictutilsts.sl2m3n4o5": "日账单相对平稳,按趋势外推",
"predictutilsts.sm3n4o5p6": "暂无预算触线风险",
"predictutilsts.sn4o5p6q7": "暂无服务维度明细",
"predictutilsts.so5p6q7r8": "你是 FinOps 云成本优化专家。基于以下云账单预测数据,给出综合成本风险评估与可执行的降本建议:",
"predictutilsts.sp6q7r8s9": "【总览】",
"predictutilsts.sq7r8s9t0": "【Top 服务消费】",
"predictutilsts.sr8s9t0u1": "【分维度预测】",
"predictutilsts.ss9t0u1v2": "【预算风险】",
"predictutilsts.st0u1v2w3": "输出要求(Markdown,中文):",
"predictutilsts.su1v2w3x4": "1. 用 **加粗小标题** 分段,每段下 1 条要点,例如:**数据疑点**、**闲置资源清理**、**计费模式优化**、**存储生命周期**",
"predictutilsts.sv2w3x4y5": "2. 若全月日均与近7日日均、预测月末存在明显矛盾,必须在「数据疑点」中说明原因(预付费/资源停机等)",
"predictutilsts.sw3x4y5z6": "3. 结合 Top 服务给出可落地建议(EIP/云盘/ECS规格/OSS生命周期/预留实例等)",
"predictutilsts.sx4y5z6a7": "4. 选 3~5 条最相关建议,总字数 350 字以内,不要空泛套话",
"probabilityColon": "概率:",
"processing": "处理中...",
"providerAndCredential": "模型与凭证",
@@ -8775,7 +8752,41 @@
"recentReleases": "最近发布:",
"overviewFallback": "服务器:{{servers}}(运行{{running}}) | Kubernetes集群:{{clusters}} 节点:{{nodes}} Pod:{{pods}} | 告警:{{alerts}}(firing {{firing}}) | 流水线:{{pipelines}}(成功率{{rate}}%) | 本月成本:¥{{cost}}",
"noAgentData": "(当前无 Agent 上报数据,可能未部署监控 Agent)"
}
},
"costPredict.allProviders": "全部",
"costPredict.unknownService": "其他",
"costPredict.monthEnd": "本月末",
"costPredict.withinToday": "今日内",
"costPredict.withinOneDay": "1 天内",
"costPredict.withinDays": "{{days}} 天内",
"costPredict.approxAfterDays": "约 {{days}} 天后",
"costPredict.budgetRule": "预算规则",
"costPredict.frontLoadedHint": "账单呈月初集中、近期趋零,可能含包年包月预付费或资源已停用,预测已按近7日运行费率外推",
"costPredict.sparseHint": "日账单样本不足,预测置信度较低",
"costPredict.steadyHint": "日账单相对平稳,按趋势外推",
"costPredict.noBudgetRisk": "暂无预算触线风险",
"costPredict.noServiceDetail": "暂无服务维度明细",
"costPredict.promptIntro": "你是 FinOps 云成本优化专家。基于以下云账单预测数据,给出综合成本风险评估与可执行的降本建议:",
"costPredict.sectionOverview": "【总览】",
"costPredict.sectionTopServices": "【Top 服务消费】",
"costPredict.sectionDimensionForecast": "【分维度预测】",
"costPredict.sectionBudgetRisk": "【预算风险】",
"costPredict.promptRequirements": "输出要求(Markdown,中文):",
"costPredict.promptReq1": "1. 用 **加粗小标题** 分段,每段下 1 条要点,例如:**数据疑点**、**闲置资源清理**、**计费模式优化**、**存储生命周期**",
"costPredict.promptReq2": "2. 若全月日均与近7日日均、预测月末存在明显矛盾,必须在「数据疑点」中说明原因(预付费/资源停机等)",
"costPredict.promptReq3": "3. 结合 Top 服务给出可落地建议(EIP/云盘/ECS规格/OSS生命周期/预留实例等)",
"costPredict.promptReq4": "4. 选 3~5 条最相关建议,总字数 350 字以内,不要空泛套话",
"costPredict.dimLine": "- {{dim}}:本月 {{current}} 元 → 预测月末 {{predicted}} 元(趋势 {{trend}})",
"costPredict.riskLine": "- {{rule}}({{provider}}):当前 {{current}} / 阈值 {{threshold}},预测 {{predicted}},触线概率 {{probability}}%",
"costPredict.serviceLine": "- {{service}}:{{cost}} 元",
"costPredict.monthSpent": "- 本月已花:{{amount}} 元",
"costPredict.predictedEnd": "- 预测月末:{{amount}} 元(置信 {{confidence}}%)",
"costPredict.dailySummary": "- 全月日均:{{dailyAvg}} 元;近7日日均:{{recentAvg}} 元;剩余 {{daysRemaining}} 天",
"costPredict.billingPatternLabel": "- 账单形态:{{hint}}",
"costPredict.recHighSpend": "费用增长迅猛,建议排查高消费资源并优化规格",
"costPredict.recRising": "费用呈上升趋势,建议关注新增服务消费",
"costPredict.recDeclining": "费用持续下降,成本优化有效",
"costPredict.recStable": "费用平稳,保持当前成本策略"
},
"breadcrumb": {
"aiAlertAnalyzer": "告警分析",