@@ -17,6 +17,8 @@ import {
1717 stopNativeAudioCapture ,
1818 isNativeAudioAvailable ,
1919} from './nativeAudio' ;
20+ import { loadRemOptimizedModel , trainRemOptimizedModel } from './remOptimizedClassifier' ;
21+ import * as healthConnect from './healthConnect' ;
2022
2123export type SleepTrackingSource = 'audio' | 'wearable' | 'manual' ;
2224
@@ -127,16 +129,66 @@ function generateId(): string {
127129 return `sleep_${ Date . now ( ) } _${ Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) } ` ;
128130}
129131
132+ const MODEL_STALE_HOURS = 24 ;
133+
134+ async function shouldRetrainModel ( ) : Promise < boolean > {
135+ const model = await loadRemOptimizedModel ( ) ;
136+ if ( ! model ) return true ;
137+
138+ const lastUpdated = new Date ( model . lastUpdated ) ;
139+ const hoursSinceUpdate = ( Date . now ( ) - lastUpdated . getTime ( ) ) / ( 1000 * 60 * 60 ) ;
140+ return hoursSinceUpdate >= MODEL_STALE_HOURS ;
141+ }
142+
143+ async function hasEnoughSleepData ( ) : Promise < boolean > {
144+ if ( Platform . OS !== 'android' && Platform . OS !== 'ios' ) return false ;
145+
146+ try {
147+ const sleepStages = await healthConnect . getRecentSleepSessions ( 48 ) ;
148+ return sleepStages . length >= 10 ;
149+ } catch {
150+ return false ;
151+ }
152+ }
153+
154+ async function maybeRetrainInBackground ( ) : Promise < void > {
155+ const needsRetrain = await shouldRetrainModel ( ) ;
156+ if ( ! needsRetrain ) {
157+ console . log ( '[Sleep] Model is fresh, skipping retrain' ) ;
158+ return ;
159+ }
160+
161+ const hasData = await hasEnoughSleepData ( ) ;
162+ if ( ! hasData ) {
163+ console . log ( '[Sleep] Insufficient sleep data for training, using defaults' ) ;
164+ return ;
165+ }
166+
167+ console . log ( '[Sleep] Starting background model training...' ) ;
168+ try {
169+ const { model, report } = await trainRemOptimizedModel ( 87600 ) ;
170+ console . log ( '[Sleep] Model trained:' , {
171+ accuracy : report . validationResults ?. overallAccuracy ,
172+ remSens : report . validationResults ?. remSensitivity ,
173+ nights : model . nightsAnalyzed ,
174+ } ) ;
175+ } catch ( err ) {
176+ console . error ( '[Sleep] Background training failed:' , err ) ;
177+ }
178+ }
179+
130180export async function startSleepSession (
131181 source : SleepTrackingSource = 'manual'
132182) : Promise < SleepSession > {
133183 if ( currentSession ?. isActive ) {
134184 return currentSession ;
135185 }
136186
137- learnFromRecentNights ( 87600 ) . catch ( console . error ) ; // ~10 years - get all available data
187+ learnFromRecentNights ( 87600 ) . catch ( console . error ) ;
138188 await startHybridSession ( ) ;
139189
190+ maybeRetrainInBackground ( ) . catch ( console . error ) ;
191+
140192 const session : SleepSession = {
141193 id : generateId ( ) ,
142194 startTime : new Date ( ) . toISOString ( ) ,
0 commit comments