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,
|
||||
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(
|
||||
|
||||
@@ -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() {
|
||||
/>
|
||||
</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 col-md-6">
|
||||
<FormField
|
||||
|
||||
Reference in New Issue
Block a user