Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 5x 11x 11x 4x 4x 5x 7x 7x 7x 5x 5x 5x 5x 2x 3x 2x | import { metadataOptionId, parseMetadataOptionId } from './schemas/metadata.js';
import { entries, groupBy, nonnull, sum } from './utils.js';
/**
* @import { RuntimeValue } from './metadata.js'
*/
/**
* Get all metadata the given MetadataValue cascades into
* Confidence scores are the sum of confidences of all metadata options that cascade into a metadata
*
* For example, if we have the following cascades:
*
* - species:40 -> genus:1
* - species:41 -> genus:1
* - species:42 -> genus:2
* - species:44 -> genus:3
*
* And make the following call
*
* ```js
* computeCascades({
* metadataId: "species",
* confidence: 0.4,
* value: 40,
* alternatives: { "41": 0.3, "42": 0.2, "44": 0.1 }
* })
* ```
*
* We'll get the following cascades, ready for another round of `storeMetadataValue` calls:
*
* ```js
* // Only one object in the array
* // since we only have cascades for a single other metadata
* [
* {
* metadataId: "genus",
* value: "1",
* confidence: 0.7, // 0.4 + 0.3, from species:40 and species:41
* alternatives: {
* "2": 0.2, // from species:42
* "3": 0.1 // from species:44
* }
* }
* ]
* ```
*
* @param {object} param0
* @param {import('./idb.svelte.js').DatabaseHandle} param0.db
* @param {string} param0.metadataId
* @param {number} param0.confidence
* @param {RuntimeValue} param0.value
* @param { Array<{ value: RuntimeValue, confidence: number }> } param0.alternatives
*/
export async function computeCascades({ db, metadataId, confidence, value, alternatives }) {
return await Promise.all(
// List of { value, confidence }, that includes the main value as well as the alternatives
[{ value, confidence }, ...alternatives].map(async ({ confidence, value }) => {
// Get the cascades for the corresponding metadata option
const option = await db.get('MetadataOption', metadataOptionId(metadataId, value));
if (!option?.cascade) return undefined;
const { cascade } = option;
return { cascade, confidence };
})
).then((options) => {
// Combine all cascades that lead to the same metadata option, and sum their confidences
const groupedByOption = groupBy(
// Get a list of { option id, confidence } for every cascaded value,
// the confidence coming from the value that triggers it
options.filter(nonnull).flatMap(({ cascade, confidence }) => {
return entries(cascade).map(([metadataId, value]) => ({
optionId: metadataOptionId(metadataId, value),
confidence
}));
}),
(c) => c.optionId,
(c) => c.confidence
);
// Combine all options of a same metadataId into alternatives.
// The confidence of every option is the sum of confidences of all
// cascades that lead to that option
const groupedByMetadata = groupBy(
groupedByOption.entries(),
([optionId]) => parseMetadataOptionId(optionId).metadataId,
([optionId, confidences]) =>
/** @type {const} */ ({
value: parseMetadataOptionId(optionId).key,
confidence: sum(confidences)
})
);
// Return a list of data ready for storeMetadataValue() for every cascaded metadata
return [...groupedByMetadata.entries()].map(([metadataId, options]) => {
const [{ value, confidence }, ...alternatives] = options.toSorted(
({ confidence: a }, { confidence: b }) => b - a
);
return {
metadataId,
value,
confidence,
alternatives
};
});
});
}
|