From aab9ed06018c21a49dbc984db20d77d7bbb0a669 Mon Sep 17 00:00:00 2001 From: shats Date: Thu, 5 Mar 2026 11:00:46 +0700 Subject: [PATCH] feat(route-optimizer): add configurable download and upload weights for bandwidth scoring in AI settings --- backend/routes/routeOptimizerRoutes.js | 16 ++++++++-- frontend/src/SettingsPage.jsx | 44 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/backend/routes/routeOptimizerRoutes.js b/backend/routes/routeOptimizerRoutes.js index 515f744..ffffca8 100644 --- a/backend/routes/routeOptimizerRoutes.js +++ b/backend/routes/routeOptimizerRoutes.js @@ -15,6 +15,8 @@ const DEFAULT_AI_SETTINGS = { latencyWeight: 0.55, bandwidthWeight: 0.35, freshnessWeight: 0.1, + downloadWeight: 0.5, + uploadWeight: 0.5, combineHomeToJumphostWeight: 0.45, combineJumphostToExitWeight: 0.55, probabilityScale: 5, @@ -47,6 +49,11 @@ function positiveNumber(v, fallback) { return Number.isFinite(n) && n > 0 ? n : fallback; } +function nonNegativeNumber(v, fallback) { + const n = Number(v); + return Number.isFinite(n) && n >= 0 ? n : fallback; +} + function makeServerKey(server) { if (!server || typeof server !== 'object') return ''; return String(server.id || server.dns || server.ip || '').trim(); @@ -97,10 +104,10 @@ function freshnessScore(cacheUpdatedAt, aiSettings) { } function bandwidthScore({ speedDownloadMbps, speedUploadMbps, aiSettings }) { - // DL/UL considered separately with equal 50/50 contribution. + // DL/UL considered separately with configurable weights. const dl = normalizeBandwidthValue(speedDownloadMbps, aiSettings); const ul = normalizeBandwidthValue(speedUploadMbps, aiSettings); - return clamp((dl + ul) / 2, 0, 1); + return clamp(dl * aiSettings.downloadWeight + ul * aiSettings.uploadWeight, 0, 1); } function buildSegmentScore({ @@ -252,6 +259,9 @@ async function loadAiSettings() { const bandwidthWeight = positiveNumber(src.bandwidthWeight, DEFAULT_AI_SETTINGS.bandwidthWeight); const freshnessWeight = positiveNumber(src.freshnessWeight, DEFAULT_AI_SETTINGS.freshnessWeight); const sum = latencyWeight + bandwidthWeight + freshnessWeight || 1; + const downloadWeight = nonNegativeNumber(src.downloadWeight, DEFAULT_AI_SETTINGS.downloadWeight); + const uploadWeight = nonNegativeNumber(src.uploadWeight, DEFAULT_AI_SETTINGS.uploadWeight); + const sumDu = downloadWeight + uploadWeight; const hjW = positiveNumber( src.combineHomeToJumphostWeight, DEFAULT_AI_SETTINGS.combineHomeToJumphostWeight @@ -276,6 +286,8 @@ async function loadAiSettings() { latencyWeight: latencyWeight / sum, bandwidthWeight: bandwidthWeight / sum, freshnessWeight: freshnessWeight / sum, + downloadWeight: sumDu > 0 ? downloadWeight / sumDu : DEFAULT_AI_SETTINGS.downloadWeight, + uploadWeight: sumDu > 0 ? uploadWeight / sumDu : DEFAULT_AI_SETTINGS.uploadWeight, combineHomeToJumphostWeight: hjW / sum2, combineJumphostToExitWeight: jeW / sum2, probabilityScale: clamp( diff --git a/frontend/src/SettingsPage.jsx b/frontend/src/SettingsPage.jsx index 14271d5..1f3879b 100644 --- a/frontend/src/SettingsPage.jsx +++ b/frontend/src/SettingsPage.jsx @@ -125,6 +125,8 @@ export default function SettingsPage() { const [aiLatencyWeight, setAiLatencyWeight] = useState('0.55'); const [aiBandwidthWeight, setAiBandwidthWeight] = useState('0.35'); const [aiFreshnessWeight, setAiFreshnessWeight] = useState('0.10'); + const [aiDownloadWeight, setAiDownloadWeight] = useState('0.5'); + const [aiUploadWeight, setAiUploadWeight] = useState('0.5'); const [aiHomeToJhWeight, setAiHomeToJhWeight] = useState('0.45'); const [aiJhToExitWeight, setAiJhToExitWeight] = useState('0.55'); const [aiProbabilityScale, setAiProbabilityScale] = useState('5'); @@ -529,6 +531,12 @@ export default function SettingsPage() { setAiFreshnessWeight( ai?.freshnessWeight != null ? String(ai.freshnessWeight) : '0.10' ); + setAiDownloadWeight( + ai?.downloadWeight != null ? String(ai.downloadWeight) : '0.5' + ); + setAiUploadWeight( + ai?.uploadWeight != null ? String(ai.uploadWeight) : '0.5' + ); setAiHomeToJhWeight( ai?.combineHomeToJumphostWeight != null ? String(ai.combineHomeToJumphostWeight) @@ -773,6 +781,14 @@ export default function SettingsPage() { latencyWeight: Math.max(0, parseFloat(aiLatencyWeight) || 0.55), bandwidthWeight: Math.max(0, parseFloat(aiBandwidthWeight) || 0.35), freshnessWeight: Math.max(0, parseFloat(aiFreshnessWeight) || 0.1), + downloadWeight: Math.max( + 0, + Number.isFinite(parseFloat(aiDownloadWeight)) ? parseFloat(aiDownloadWeight) : 0.5 + ), + uploadWeight: Math.max( + 0, + Number.isFinite(parseFloat(aiUploadWeight)) ? parseFloat(aiUploadWeight) : 0.5 + ), combineHomeToJumphostWeight: Math.max( 0, parseFloat(aiHomeToJhWeight) || 0.45 @@ -1585,6 +1601,34 @@ export default function SettingsPage() { /> +

Баланс bandwidth (DL/UL)

+
+ +
+
+ +
+

Сборка полного маршрута