diff --git a/frontend/src/components/aiops/cost-predict.ts b/frontend/src/components/aiops/cost-predict.ts index 21d8b80..5fa153b 100644 --- a/frontend/src/components/aiops/cost-predict.ts +++ b/frontend/src/components/aiops/cost-predict.ts @@ -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'); } diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 6b9f59c..4d8c5da 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -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", diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index 797e781..ea8feff 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -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": "告警分析",