feat(route-optimizer): add configurable download and upload weights for bandwidth scoring in AI settings
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m34s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m34s
This commit is contained in:
@@ -15,6 +15,8 @@ const DEFAULT_AI_SETTINGS = {
|
|||||||
latencyWeight: 0.55,
|
latencyWeight: 0.55,
|
||||||
bandwidthWeight: 0.35,
|
bandwidthWeight: 0.35,
|
||||||
freshnessWeight: 0.1,
|
freshnessWeight: 0.1,
|
||||||
|
downloadWeight: 0.5,
|
||||||
|
uploadWeight: 0.5,
|
||||||
combineHomeToJumphostWeight: 0.45,
|
combineHomeToJumphostWeight: 0.45,
|
||||||
combineJumphostToExitWeight: 0.55,
|
combineJumphostToExitWeight: 0.55,
|
||||||
probabilityScale: 5,
|
probabilityScale: 5,
|
||||||
@@ -47,6 +49,11 @@ function positiveNumber(v, fallback) {
|
|||||||
return Number.isFinite(n) && n > 0 ? n : 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) {
|
function makeServerKey(server) {
|
||||||
if (!server || typeof server !== 'object') return '';
|
if (!server || typeof server !== 'object') return '';
|
||||||
return String(server.id || server.dns || server.ip || '').trim();
|
return String(server.id || server.dns || server.ip || '').trim();
|
||||||
@@ -97,10 +104,10 @@ function freshnessScore(cacheUpdatedAt, aiSettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bandwidthScore({ speedDownloadMbps, speedUploadMbps, 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 dl = normalizeBandwidthValue(speedDownloadMbps, aiSettings);
|
||||||
const ul = normalizeBandwidthValue(speedUploadMbps, 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({
|
function buildSegmentScore({
|
||||||
@@ -252,6 +259,9 @@ async function loadAiSettings() {
|
|||||||
const bandwidthWeight = positiveNumber(src.bandwidthWeight, DEFAULT_AI_SETTINGS.bandwidthWeight);
|
const bandwidthWeight = positiveNumber(src.bandwidthWeight, DEFAULT_AI_SETTINGS.bandwidthWeight);
|
||||||
const freshnessWeight = positiveNumber(src.freshnessWeight, DEFAULT_AI_SETTINGS.freshnessWeight);
|
const freshnessWeight = positiveNumber(src.freshnessWeight, DEFAULT_AI_SETTINGS.freshnessWeight);
|
||||||
const sum = latencyWeight + bandwidthWeight + freshnessWeight || 1;
|
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(
|
const hjW = positiveNumber(
|
||||||
src.combineHomeToJumphostWeight,
|
src.combineHomeToJumphostWeight,
|
||||||
DEFAULT_AI_SETTINGS.combineHomeToJumphostWeight
|
DEFAULT_AI_SETTINGS.combineHomeToJumphostWeight
|
||||||
@@ -276,6 +286,8 @@ async function loadAiSettings() {
|
|||||||
latencyWeight: latencyWeight / sum,
|
latencyWeight: latencyWeight / sum,
|
||||||
bandwidthWeight: bandwidthWeight / sum,
|
bandwidthWeight: bandwidthWeight / sum,
|
||||||
freshnessWeight: freshnessWeight / 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,
|
combineHomeToJumphostWeight: hjW / sum2,
|
||||||
combineJumphostToExitWeight: jeW / sum2,
|
combineJumphostToExitWeight: jeW / sum2,
|
||||||
probabilityScale: clamp(
|
probabilityScale: clamp(
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ export default function SettingsPage() {
|
|||||||
const [aiLatencyWeight, setAiLatencyWeight] = useState('0.55');
|
const [aiLatencyWeight, setAiLatencyWeight] = useState('0.55');
|
||||||
const [aiBandwidthWeight, setAiBandwidthWeight] = useState('0.35');
|
const [aiBandwidthWeight, setAiBandwidthWeight] = useState('0.35');
|
||||||
const [aiFreshnessWeight, setAiFreshnessWeight] = useState('0.10');
|
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 [aiHomeToJhWeight, setAiHomeToJhWeight] = useState('0.45');
|
||||||
const [aiJhToExitWeight, setAiJhToExitWeight] = useState('0.55');
|
const [aiJhToExitWeight, setAiJhToExitWeight] = useState('0.55');
|
||||||
const [aiProbabilityScale, setAiProbabilityScale] = useState('5');
|
const [aiProbabilityScale, setAiProbabilityScale] = useState('5');
|
||||||
@@ -529,6 +531,12 @@ export default function SettingsPage() {
|
|||||||
setAiFreshnessWeight(
|
setAiFreshnessWeight(
|
||||||
ai?.freshnessWeight != null ? String(ai.freshnessWeight) : '0.10'
|
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(
|
setAiHomeToJhWeight(
|
||||||
ai?.combineHomeToJumphostWeight != null
|
ai?.combineHomeToJumphostWeight != null
|
||||||
? String(ai.combineHomeToJumphostWeight)
|
? String(ai.combineHomeToJumphostWeight)
|
||||||
@@ -773,6 +781,14 @@ export default function SettingsPage() {
|
|||||||
latencyWeight: Math.max(0, parseFloat(aiLatencyWeight) || 0.55),
|
latencyWeight: Math.max(0, parseFloat(aiLatencyWeight) || 0.55),
|
||||||
bandwidthWeight: Math.max(0, parseFloat(aiBandwidthWeight) || 0.35),
|
bandwidthWeight: Math.max(0, parseFloat(aiBandwidthWeight) || 0.35),
|
||||||
freshnessWeight: Math.max(0, parseFloat(aiFreshnessWeight) || 0.1),
|
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(
|
combineHomeToJumphostWeight: Math.max(
|
||||||
0,
|
0,
|
||||||
parseFloat(aiHomeToJhWeight) || 0.45
|
parseFloat(aiHomeToJhWeight) || 0.45
|
||||||
@@ -1585,6 +1601,34 @@ export default function SettingsPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12 mt-1"><h4 className="subheader">Баланс bandwidth (DL/UL)</h4></div>
|
||||||
|
<div className="col-12 col-md-6">
|
||||||
|
<FormField
|
||||||
|
label="Вес Download (DL)"
|
||||||
|
name="aiDownloadWeight"
|
||||||
|
type="number"
|
||||||
|
value={aiDownloadWeight}
|
||||||
|
onChange={setAiDownloadWeight}
|
||||||
|
helpText="Внутренний вес DL в bandwidth score сегмента."
|
||||||
|
disabled={saving}
|
||||||
|
min={0}
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="col-12 col-md-6">
|
||||||
|
<FormField
|
||||||
|
label="Вес Upload (UL)"
|
||||||
|
name="aiUploadWeight"
|
||||||
|
type="number"
|
||||||
|
value={aiUploadWeight}
|
||||||
|
onChange={setAiUploadWeight}
|
||||||
|
helpText="Внутренний вес UL в bandwidth score сегмента."
|
||||||
|
disabled={saving}
|
||||||
|
min={0}
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="col-12 mt-2"><h4 className="subheader">Сборка полного маршрута</h4></div>
|
<div className="col-12 mt-2"><h4 className="subheader">Сборка полного маршрута</h4></div>
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
<FormField
|
<FormField
|
||||||
|
|||||||
Reference in New Issue
Block a user