@@ -90,10 +90,10 @@ class TrainingDashboard {
9090 const rows = lines . filter ( l => l . includes ( '|' ) && ! l . includes ( '---' ) && ! / ^ # / . test ( l . trim ( ) ) && ! / E p o c h \s * \| / i. test ( l ) ) ;
9191 this . state . totalEpochs = rows . length || null ;
9292 if ( rows . length ) {
93- const last = rows [ rows . length - 1 ] . split ( '|' ) . map ( s => s . trim ( ) ) . filter ( Boolean ) ;
94- if ( last . length >= 3 ) {
95- const acc = parseFloat ( last [ 2 ] ) ;
96- if ( ! Number . isNaN ( acc ) ) this . state . finalTrainAccuracy = acc ;
93+ const last = rows [ rows . length - 1 ] . split ( '|' ) . map ( s => s . trim ( ) ) ;
94+ // Accuracy is column 3 (index 3)
95+ if ( last . length >= 4 && ! isNaN ( parseFloat ( last [ 3 ] ) ) ) {
96+ this . state . finalTrainAccuracy = parseFloat ( last [ 3 ] ) ;
9797 }
9898 }
9999 }
@@ -240,7 +240,8 @@ class TrainingDashboard {
240240 const grid = this . imagesGrid ;
241241 if ( ! grid ) return ;
242242 grid . innerHTML = '' ;
243- const imgLines = md . split ( '\n' ) . filter ( l => / ! \[ [ ^ \] ] * \] \( ( i m a g e s \/ [ ^ ) ] + ) \) / . test ( l ) ) ;
243+ // Limit to 5 images only
244+ const imgLines = md . split ( '\n' ) . filter ( l => / ! \[ [ ^ \] ] * \] \( ( i m a g e s \/ [ ^ ) ] + ) \) / . test ( l ) ) . slice ( 0 , 5 ) ;
244245 if ( imgLines . length === 0 ) {
245246 grid . innerHTML = '<div class="no-data">No images listed</div>' ;
246247 return ;
@@ -260,11 +261,76 @@ class TrainingDashboard {
260261 } ) ;
261262 }
262263
263- startAutoRefresh ( ) {
264- setInterval ( ( ) => this . init ( ) , 300000 ) ; // 5 minutes
264+ async init ( ) {
265+ let lastUpdated = 'Loading...' ;
266+ try {
267+ // Try outputs.txt first
268+ try {
269+ const text = await this . fetchText ( 'outputs.txt' ) ;
270+ outputs = this . parseKV ( text ) ;
271+ } catch ( err ) {
272+ // Ignore missing outputs.txt
273+ }
274+
275+ // Always try to load markdowns
276+ try {
277+ [ trainMD , testMD ] = await Promise . all ( [
278+ this . fetchText ( 'train_output.md' ) ,
279+ this . fetchText ( 'test_output.md' ) ,
280+ ] ) ;
281+ // Get last modified time from markdown files
282+ const trainRes = await fetch ( 'train_output.md' , { method : 'HEAD' } ) ;
283+ const testRes = await fetch ( 'test_output.md' , { method : 'HEAD' } ) ;
284+ let trainDate = trainRes . headers . get ( 'last-modified' ) ;
285+ let testDate = testRes . headers . get ( 'last-modified' ) ;
286+ if ( trainDate || testDate ) {
287+ // Use the most recent
288+ const d1 = trainDate ? new Date ( trainDate ) : null ;
289+ const d2 = testDate ? new Date ( testDate ) : null ;
290+ let latest = d1 && d2 ? ( d1 > d2 ? d1 : d2 ) : ( d1 || d2 ) ;
291+ if ( latest ) {
292+ lastUpdated = latest . toLocaleString ( ) ;
293+ }
294+ }
295+ } catch ( err ) {
296+ // If markdowns missing, fail
297+ throw new Error ( 'Missing training or test markdown' ) ;
298+ }
299+
300+ // If outputs.txt present, use it for metrics and predictions
301+ if ( outputs ) {
302+ this . applyOutputs ( outputs ) ;
303+ dataLoaded = true ;
304+ }
305+ // Always parse markdowns for images and fallback metrics
306+ if ( trainMD && testMD ) {
307+ this . parseTraining ( trainMD ) ;
308+ this . parseTest ( testMD ) ;
309+ this . renderImagesFromMarkdown ( testMD ) ;
310+ dataLoaded = true ;
311+ }
312+
313+ this . renderMetrics ( ) ;
314+ this . renderCharts ( outputs ) ;
315+ if ( this . statusBadge ) {
316+ this . statusBadge . textContent = dataLoaded ? 'Data Loaded' : 'No Data' ;
317+ this . statusBadge . classList . toggle ( 'error' , ! dataLoaded ) ;
318+ }
319+ // Update last updated in footer
320+ const footerText = document . querySelector ( '.footer-text' ) ;
321+ if ( footerText ) {
322+ footerText . textContent = `Last updated: ${ lastUpdated } ` ;
323+ }
324+ } catch ( err ) {
325+ console . error ( 'Init error:' , err ) ;
326+ this . failBadge ( 'Data Load Error' ) ;
327+ }
328+ // Always hide preloader after 1.2 seconds, regardless of data loading
329+ setTimeout ( ( ) => {
330+ this . hideLoading ( ) ;
331+ } , 1200 ) ;
332+ this . startAutoRefresh ( ) ;
265333 }
334+
266335}
267336
268- document . addEventListener ( 'DOMContentLoaded' , ( ) => {
269- new TrainingDashboard ( ) ;
270- } ) ;
0 commit comments