@@ -54,25 +54,47 @@ function setupRemoteSettingsPreview() {
5454 return isPreview ;
5555}
5656
57- function setupReleasedModels ( ) {
57+ function setupReleaseChannelCheckbox ( ) {
5858 const releasedModelsCheckbox = /** @type {HTMLInputElement } */ (
5959 getElement ( "releasedModels" )
6060 ) ;
61+ const nightlyModelsCheckbox = /** @type {HTMLInputElement } */ (
62+ getElement ( "nightlyModels" )
63+ ) ;
6164 const urlParams = new URLSearchParams ( window . location . search ) ;
62- const urlValue = urlParams . get ( "releasedModels" ) ;
63- const isReleasedModels = urlValue === "true" || ! urlValue ;
65+ const releasedModelsUrlValue = urlParams . get ( "releasedModels" ) ;
66+ const isReleasedModels =
67+ releasedModelsUrlValue === "true" || ! releasedModelsUrlValue ;
68+
6469 releasedModelsCheckbox . checked = isReleasedModels ;
6570 releasedModelsCheckbox . addEventListener ( "change" , ( ) => {
6671 const urlParams = new URLSearchParams ( window . location . search ) ;
6772 if ( releasedModelsCheckbox . checked ) {
6873 urlParams . delete ( "releasedModels" ) ;
74+ nightlyModelsCheckbox . checked = false ;
75+ urlParams . delete ( "nightlyModels" ) ;
6976 } else {
7077 urlParams . set ( "releasedModels" , "false" ) ;
7178 }
7279 changeLocation ( urlParams ) ;
7380 } ) ;
7481
75- return isReleasedModels ;
82+ const nightlyModelsUrlValue = urlParams . get ( "nightlyModels" ) ;
83+ const isNightlyModels = ! isReleasedModels && nightlyModelsUrlValue === "true" ;
84+ nightlyModelsCheckbox . checked = isNightlyModels ;
85+ nightlyModelsCheckbox . addEventListener ( "change" , ( ) => {
86+ const urlParams = new URLSearchParams ( window . location . search ) ;
87+ if ( nightlyModelsCheckbox . checked ) {
88+ urlParams . set ( "nightlyModels" , "true" ) ;
89+ urlParams . set ( "releasedModels" , "false" ) ;
90+ releasedModelsCheckbox . checked = false ;
91+ } else {
92+ urlParams . delete ( "nightlyModels" ) ;
93+ }
94+ changeLocation ( urlParams ) ;
95+ } ) ;
96+
97+ return [ isReleasedModels , isNightlyModels ] ;
7698}
7799
78100function setupShowAdditionalDetails ( ) {
@@ -122,14 +144,33 @@ function getReleasedModels(models) {
122144 return ( models = [ ...langPairs . values ( ) ] ) ;
123145}
124146
147+ /**
148+ * @param {ModelRecord[] } models
149+ */
150+ function getNightlyModels ( models ) {
151+ /** @type {Map<string, ModelRecord> } */
152+ const langPairs = new Map ( ) ;
153+ for ( const model of models ) {
154+ const langPair = model . fromLang + "-" + model . toLang ;
155+ const existingModel = langPairs . get ( langPair ) ;
156+ if (
157+ ! existingModel ||
158+ versionCompare ( model . version , existingModel . version ) > 0
159+ ) {
160+ langPairs . set ( langPair , model ) ;
161+ }
162+ }
163+ return ( models = [ ...langPairs . values ( ) ] ) ;
164+ }
165+
125166async function main ( ) {
126167 getElement ( "counts" ) . style . display = "table" ;
127168
128169 const isPreview = setupRemoteSettingsPreview ( ) ;
129170 const bucket = isPreview ? "main-preview" : "main" ;
130171
131172 setupShowAdditionalDetails ( ) ;
132- const isReleasedModels = setupReleasedModels ( ) ;
173+ const [ isReleasedModels , isNightlyModels ] = setupReleaseChannelCheckbox ( ) ;
133174
134175 /** @type {{ data: ModelRecord[] } } */
135176 const records = await fetchJSON (
@@ -143,12 +184,9 @@ async function main() {
143184 const cometResults = await fetchJSON (
144185 "https://raw.githubusercontent.com/mozilla/firefox-translations-models/main/evaluation/comet-results.json"
145186 ) ;
187+ exposeAsGlobal ( "cometResults" , cometResults ) ;
146188
147- logCometResults ( cometResults ) ;
148-
149- /** @type {Record<string, string> } */
150- const byHash = await fetchJSON ( REPO_URL + "models/by-hash.json" ) ;
151- exposeAsGlobal ( "byHash" , byHash ) ;
189+ const modelMetadataFetcher = await ModelMetadataFetcher . create ( ) ;
152190
153191 /**
154192 * @typedef {Object } ModelEntry
@@ -164,10 +202,13 @@ async function main() {
164202 const releasedModels = getReleasedModels ( models ) ;
165203
166204 countModels ( models , releasedModels ) ;
205+ logModelTableData ( cometResults , models , modelMetadataFetcher ) ;
167206
168207 if ( isReleasedModels ) {
169208 // Get the released model with the latest version.
170209 models = releasedModels ;
210+ } else if ( isNightlyModels ) {
211+ models = getNightlyModels ( models ) ;
171212 }
172213 exposeAsGlobal ( "models" , models ) ;
173214
@@ -183,7 +224,7 @@ async function main() {
183224 * @param {string } version
184225 */
185226 function getModelKey ( lang , version ) {
186- if ( isReleasedModels ) {
227+ if ( isReleasedModels || isNightlyModels ) {
187228 return lang ;
188229 }
189230 return lang + " " + version ;
@@ -275,7 +316,7 @@ async function main() {
275316 `${ lang } -en` ,
276317 records . data ,
277318 cometResults ,
278- byHash ,
319+ modelMetadataFetcher ,
279320 attachmentsByKey ,
280321 toEn ,
281322 langPairScoreAdded
@@ -285,7 +326,7 @@ async function main() {
285326 `en-${ lang } ` ,
286327 records . data ,
287328 cometResults ,
288- byHash ,
329+ modelMetadataFetcher ,
289330 attachmentsByKey ,
290331 fromEn ,
291332 langPairScoreAdded
@@ -301,7 +342,7 @@ async function main() {
301342 * @param {string } pair
302343 * @param {ModelRecord[] } records
303344 * @param {EvalResults } cometResults
304- * @param {Record<string, string> } byHash
345+ * @param {ModelMetadataFetcher } modelMetadataFetcher
305346 * @param {Map<string, Array<[string, string]>> } attachmentsByKey
306347 * @param {ModelRecord | null } model
307348 * @param {Set<string> } langPairScoreAdded
@@ -311,7 +352,7 @@ function addToRow(
311352 pair ,
312353 records ,
313354 cometResults ,
314- byHash ,
355+ modelMetadataFetcher ,
315356 attachmentsByKey ,
316357 model ,
317358 langPairScoreAdded
@@ -401,7 +442,7 @@ function addToRow(
401442 const parametersEl = td ( ) ;
402443 parametersEl . className = "parametersColumn" ;
403444
404- getModelMetadata ( byHash , model ) . then ( ( modelMetadata ) => {
445+ modelMetadataFetcher . get ( model ) . then ( ( modelMetadata ) => {
405446 if ( ! modelMetadata ) {
406447 return ;
407448 }
@@ -641,21 +682,48 @@ assertComparison("1.0a", "1.1", aLessThanB);
641682
642683/**
643684 * @param {EvalResults } cometResults
685+ * @param {ModelRecord[] } models,
686+ * @param {ModelMetadataFetcher } modelMetadataFetcher
644687 */
645- function logCometResults ( cometResults ) {
688+ async function logModelTableData ( cometResults , models , modelMetadataFetcher ) {
646689 /** @type {Array<unknown[]> } */
647690 const xx_en = [ ] ;
648691 const en_xx = [ ] ;
649692
650- for ( const [ langPair , evaluation ] of Object . entries ( cometResults ) ) {
651- const flores = evaluation [ "flores-dev" ] ;
693+ /**
694+ * Combine the cometResults and model records into a single list of langpairs.
695+ * It's not guaranteed that both lists overlap, so we need to combine both.
696+ * @type {Map<string, ModelRecord | null> }
697+ */
698+ const modelsByLangPair = new Map ( ) ;
699+ for ( const langPair of Object . keys ( cometResults ) ) {
700+ modelsByLangPair . set ( langPair , null ) ;
701+ }
702+ for ( const model of getNightlyModels ( models ) ) {
703+ // Get the Nightly models as this will be a flattened list of all models without
704+ // duplicates of various versions.
705+ let { fromLang, toLang } = model ;
706+ if ( fromLang === "zh-Hans" ) {
707+ fromLang = "zh" ;
708+ }
709+ if ( toLang === "zh-Hans" ) {
710+ toLang = "zh" ;
711+ }
712+ modelsByLangPair . set ( `${ fromLang } -${ toLang } ` , model ) ;
713+ }
714+
715+ for ( const [ langPair , model ] of modelsByLangPair ) {
716+ const modelMetadata = await modelMetadataFetcher . get ( model ) ;
717+ const evaluation = cometResults [ langPair ] ;
652718 const [ fromLang , toLang ] = langPair . split ( "-" ) ;
653719 const row = [
654720 langPair ,
655721 fromLang ,
656722 toLang ,
657- flores . google || "" ,
658- flores . bergamot || "" ,
723+ evaluation ?. [ "flores-test" ] ?. google ?? "" ,
724+ modelMetadata ?. flores [ "comet" ] ?? "" ,
725+ getReleaseChannels ( model ) ?. label ?? "" ,
726+ modelMetadata ?. architecture ?? "" ,
659727 ] ;
660728 if ( fromLang === "en" ) {
661729 en_xx . push ( row ) ;
@@ -675,7 +743,7 @@ function logCometResults(cometResults) {
675743 en_xx . sort ( sortRow ) ;
676744
677745 const rows = [
678- [ "Lang Pair" , "From" , "To" , "Google" , "Bergamot " ] ,
746+ [ "Lang Pair" , "From" , "To" , "Google" , "Mozilla" , "Release" , "Architecture "] ,
679747 ...en_xx ,
680748 ...xx_en ,
681749 ] ;
@@ -751,25 +819,46 @@ function countModels(allModels, releasedModels) {
751819
752820 getElement ( "fromProd" ) . innerText = String ( fromProd . size ) ;
753821 getElement ( "toProd" ) . innerText = String ( toProd . size ) ;
754- getElement ( "fromNightly" ) . innerText = String ( toNightly . size ) ;
755- getElement ( "toNightly" ) . innerText = String ( fromNightly . size ) ;
822+ getElement ( "fromNightly" ) . innerText = String ( fromNightly . size ) ;
823+ getElement ( "toNightly" ) . innerText = String ( toNightly . size ) ;
756824 getElement ( "uniqueLanguages" ) . innerText = String ( unique . size ) ;
757825}
758826
759- /**
760- * @param {Record<string, string> } byHash
761- * @param {ModelRecord | null } model
762- * @return {Promise<ModelMetadata | null> }
763- */
764- async function getModelMetadata ( byHash , model ) {
765- if ( ! model ) {
766- return null ;
827+ class ModelMetadataFetcher {
828+ /** @type {Record<string, Promise<ModelMetadataFetcher | null>> } */
829+ metadataCache = { } ;
830+
831+ static async create ( ) {
832+ /** @type {Record<string, string> } */
833+ const byHash = await fetchJSON ( REPO_URL + "models/by-hash.json" ) ;
834+ exposeAsGlobal ( "byHash" , byHash ) ;
835+ return new ModelMetadataFetcher ( byHash ) ;
767836 }
768- const metadataUrl = byHash [ model . attachment . hash ] ;
769- if ( ! metadataUrl ) {
770- return null ;
837+ /**
838+ * @param {Record<string, string> } byHash
839+ */
840+ constructor ( byHash ) {
841+ this . byHash = byHash ;
771842 }
772843
773- const response = await fetch ( REPO_URL + metadataUrl ) ;
774- return response . json ( ) ;
844+ /**
845+ * @param {ModelRecord | null } model
846+ * @return {Promise<ModelMetadata | null> }
847+ */
848+ async get ( model ) {
849+ if ( ! model ) {
850+ return null ;
851+ }
852+ const metadataUrl = this . byHash [ model . attachment . hash ] ;
853+ if ( ! metadataUrl ) {
854+ return null ;
855+ }
856+
857+ const promise = fetch ( REPO_URL + metadataUrl ) . then ( ( response ) =>
858+ response . json ( )
859+ ) ;
860+ this . metadataCache [ metadataUrl ] = promise ;
861+
862+ return promise ;
863+ }
775864}
0 commit comments