feat: sync deployed v1.0.0-rc.38-custom.42
Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
1 parent
aa6c3f50f4
commit
ceddfd3d6b
828 files changed
+122253
-13702
No files matched your search
@@ -0,0 +1,212 @@
|
||||
export const VALUE_MIN = 1;
|
||||
export const VALUE_MAX = 355;
|
||||
export const DIMENSION = VALUE_MAX - VALUE_MIN + 1;
|
||||
export const ALPHA = 0.5;
|
||||
export const ORDERED_BLOCK_WEIGHT = 0.25;
|
||||
|
||||
export function parseNumbers(text) {
|
||||
const runs = [];
|
||||
let current = [];
|
||||
let previousEnd = 0;
|
||||
for (const match of String(text).matchAll(/\d+/g)) {
|
||||
const separator = String(text).slice(previousEnd, match.index);
|
||||
const value = Number(match[0]);
|
||||
if (current.length && /\p{L}/u.test(separator)) {
|
||||
runs.push(current);
|
||||
current = [];
|
||||
}
|
||||
if (value >= VALUE_MIN && value <= VALUE_MAX) current.push(value);
|
||||
previousEnd = match.index + match[0].length;
|
||||
}
|
||||
if (current.length) runs.push(current);
|
||||
return runs.reduce((best, run) => run.length > best.length ? run : best, []);
|
||||
}
|
||||
|
||||
export function countNumbers(numbers) {
|
||||
const counts = Array(DIMENSION).fill(0);
|
||||
numbers.forEach((number) => { counts[number - VALUE_MIN] += 1; });
|
||||
return counts;
|
||||
}
|
||||
|
||||
function mean(values) {
|
||||
return values.reduce((total, value) => total + value, 0) / values.length;
|
||||
}
|
||||
|
||||
function standardize(values) {
|
||||
const center = mean(values);
|
||||
const variance = mean(values.map((value) => (value - center) ** 2));
|
||||
const scale = Math.max(Math.sqrt(variance), 1e-12);
|
||||
return values.map((value) => (value - center) / scale);
|
||||
}
|
||||
|
||||
function dot(left, right) {
|
||||
let value = 0;
|
||||
for (let index = 0; index < left.length; index += 1) value += left[index] * right[index];
|
||||
return value;
|
||||
}
|
||||
|
||||
function norm(values) {
|
||||
return Math.sqrt(dot(values, values));
|
||||
}
|
||||
|
||||
function normalized(values) {
|
||||
const scale = Math.max(norm(values), 1e-12);
|
||||
return values.map((value) => value / scale);
|
||||
}
|
||||
|
||||
function subtractBasis(values, basis) {
|
||||
const output = values.slice();
|
||||
for (const vector of basis || []) {
|
||||
const projection = dot(output, vector);
|
||||
for (let index = 0; index < output.length; index += 1) output[index] -= projection * vector[index];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function hellingerFeature(counts) {
|
||||
const total = counts.reduce((sum, value) => sum + value, 0) + ALPHA * DIMENSION;
|
||||
return counts.map((value) => Math.sqrt((value + ALPHA) / total));
|
||||
}
|
||||
|
||||
function splitIntoFour(values) {
|
||||
const base = Math.floor(values.length / 4);
|
||||
const remainder = values.length % 4;
|
||||
const chunks = [];
|
||||
let start = 0;
|
||||
for (let index = 0; index < 4; index += 1) {
|
||||
const size = base + (index < remainder ? 1 : 0);
|
||||
chunks.push(values.slice(start, start + size));
|
||||
start += size;
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function orderedBlockFeature(numbers) {
|
||||
const pieces = [];
|
||||
for (const chunk of splitIntoFour(numbers)) {
|
||||
const bins = Array(16).fill(0.5);
|
||||
for (const value of chunk) {
|
||||
const index = Math.min(15, Math.floor(((value - 1) / 355) * 16));
|
||||
bins[index] += 1;
|
||||
}
|
||||
const total = bins.reduce((sum, value) => sum + value, 0);
|
||||
pieces.push(...bins.map((value) => Math.sqrt(value / total)));
|
||||
}
|
||||
const lastDigits = Array(10).fill(0.5);
|
||||
numbers.forEach((value) => { lastDigits[value % 10] += 1; });
|
||||
const lastTotal = lastDigits.reduce((sum, value) => sum + value, 0);
|
||||
pieces.push(...lastDigits.map((value) => Math.sqrt(value / lastTotal)));
|
||||
return pieces;
|
||||
}
|
||||
|
||||
function robustScoreCounts(counts, bank) {
|
||||
const artifact = bank.robust.hellinger;
|
||||
const feature = hellingerFeature(counts);
|
||||
let projected = feature.map((value, index) => (value - artifact.feature_mean[index]) / artifact.feature_scale[index]);
|
||||
projected = subtractBasis(projected, artifact.nuisance_basis);
|
||||
projected = normalized(projected);
|
||||
const scores = artifact.centroids.map((centroid) => dot(projected, centroid));
|
||||
return standardize(scores);
|
||||
}
|
||||
|
||||
function orderedBlockScores(numbers, bank) {
|
||||
const artifact = bank.robust.ordered_blocks;
|
||||
const feature = orderedBlockFeature(numbers);
|
||||
const standardizedFeature = feature.map((value, index) => (value - artifact.feature_mean[index]) / artifact.feature_scale[index]);
|
||||
const unit = normalized(standardizedFeature);
|
||||
const environmentScores = artifact.environment_centroids.map(
|
||||
(centroids) => centroids.map((centroid) => dot(unit, centroid)),
|
||||
);
|
||||
const template = standardize(artifact.centroids.map((_, modelIndex) => Math.max(
|
||||
...environmentScores.map((scores) => scores[modelIndex]),
|
||||
)));
|
||||
const projected = normalized(subtractBasis(standardizedFeature, artifact.nuisance_basis));
|
||||
const nuisance = standardize(artifact.centroids.map((centroid) => dot(projected, centroid)));
|
||||
return standardize(template.map((value, index) => 0.5 * value + 0.5 * nuisance[index]));
|
||||
}
|
||||
|
||||
function robustScoreNumbers(numbers, bank) {
|
||||
const marginal = robustScoreCounts(countNumbers(numbers), bank);
|
||||
const artifact = bank.robust.ordered_blocks;
|
||||
const weight = artifact ? Number(artifact.weight || 0) : 0;
|
||||
if (!artifact || weight === 0) return marginal;
|
||||
const ordered = orderedBlockScores(numbers, bank);
|
||||
return marginal.map((value, index) => (1 - weight) * value + weight * ordered[index]);
|
||||
}
|
||||
|
||||
function softmax(values) {
|
||||
const maximum = Math.max(...values);
|
||||
const weights = values.map((value) => Math.exp(value - maximum));
|
||||
const total = weights.reduce((sum, value) => sum + value, 0);
|
||||
return weights.map((value) => value / total);
|
||||
}
|
||||
|
||||
function jsSimilarity(left, right) {
|
||||
const leftTotal = left.reduce((sum, value) => sum + value, 0);
|
||||
const rightTotal = right.reduce((sum, value) => sum + value, 0) + ALPHA * DIMENSION;
|
||||
const p = left.map((value) => value / leftTotal);
|
||||
const q = right.map((value) => (value + ALPHA) / rightTotal);
|
||||
const midpoint = p.map((value, index) => (value + q[index]) / 2);
|
||||
const divergence = (values) => values.reduce(
|
||||
(total, value, index) => total + (value ? value * Math.log(value / midpoint[index]) : 0),
|
||||
0,
|
||||
);
|
||||
const js = (divergence(p) + divergence(q)) / 2;
|
||||
return 1 - Math.sqrt(js / Math.log(2));
|
||||
}
|
||||
|
||||
export function analyzeGlobalOutputs(outputs, bank) {
|
||||
const modelIds = bank.models.map((model) => model.id);
|
||||
const valid = [];
|
||||
const diagnostics = [];
|
||||
outputs.forEach((item, index) => {
|
||||
const expected = Number(item.expected_count || 0);
|
||||
const numbers = parseNumbers(item.text || "");
|
||||
const minimum = expected ? Math.max(80, Math.ceil(expected * 0.55)) : 80;
|
||||
const accepted = numbers.length >= minimum;
|
||||
diagnostics.push({ index, parsed_numbers: numbers.length, minimum_numbers: minimum, accepted });
|
||||
if (accepted) valid.push({ numbers, counts: countNumbers(numbers), scores: robustScoreNumbers(numbers, bank) });
|
||||
});
|
||||
if (!valid.length) throw new Error("没有可用回答:请粘贴完整数字序列;拒答或严重截断的回答不会计入。");
|
||||
|
||||
const combinedScores = modelIds.map((_, modelIndex) => mean(valid.map((item) => item.scores[modelIndex])));
|
||||
const calibrationKey = String(Math.min(valid.length, 3));
|
||||
const beta = Number(bank.calibration[calibrationKey].beta);
|
||||
const probabilities = softmax(combinedScores.map((value) => beta * value));
|
||||
const pooledCounts = Array.from({ length: DIMENSION }, (_, index) => valid.reduce((sum, item) => sum + item.counts[index], 0));
|
||||
const modelEntries = Object.fromEntries(bank.models.map((model) => [model.id, model]));
|
||||
const familyOrder = [...new Set(bank.models.map((model) => model.family || "models"))];
|
||||
const familyNames = Object.fromEntries(familyOrder.map((family) => [
|
||||
family,
|
||||
bank.models.find((model) => (model.family || "models") === family)?.family_name || family,
|
||||
]));
|
||||
const results = modelIds.map((model, index) => ({
|
||||
model,
|
||||
display_name: modelEntries[model].display_name,
|
||||
probability: probabilities[index],
|
||||
profile_similarity: jsSimilarity(pooledCounts, modelEntries[model].counts),
|
||||
score: combinedScores[index],
|
||||
family: modelEntries[model].family || "models",
|
||||
family_name: familyNames[modelEntries[model].family || "models"],
|
||||
})).sort((left, right) => right.probability - left.probability);
|
||||
const familyProbabilities = Object.fromEntries(familyOrder.map((family) => [
|
||||
family,
|
||||
results.filter((item) => item.family === family).reduce((sum, item) => sum + item.probability, 0),
|
||||
]));
|
||||
results.forEach((item) => { item.conditional_probability = item.probability / familyProbabilities[item.family]; });
|
||||
const winningFamily = familyOrder.reduce((best, family) => familyProbabilities[family] > familyProbabilities[best] ? family : best);
|
||||
return {
|
||||
prediction: results[0].model,
|
||||
prediction_name: results[0].display_name,
|
||||
probability: results[0].probability,
|
||||
used_outputs: valid.length,
|
||||
results,
|
||||
diagnostics,
|
||||
calibration: { queries: calibrationKey, beta, cv_accuracy: bank.calibration[calibrationKey].cv_accuracy },
|
||||
family_prediction: winningFamily,
|
||||
family_prediction_name: familyNames[winningFamily],
|
||||
family_probability: familyProbabilities[winningFamily],
|
||||
family_probabilities: familyOrder.map((family) => ({ family, display_name: familyNames[family], probability: familyProbabilities[family] })),
|
||||
method: "统一全局稳健数字指纹",
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user