/usage: what the parents' screen shows about thinking and the natural voice.
POST /usage: both allowances, for the parents' screen. Needs the household's choices, the allowance, the
voice (whose credits it reports) and the clock.
12pub struct Usage;
The thinking half of the reply.
When the oldest spending leaves the window, so room starts to return; None if nothing is spent.
The voice half of the reply.
The service's own daily allowance, in characters.
The voice service's monthly credits; None when they could not be read (see plan_error).
55async fn usage<C: HasHousehold + HasAllowance + HasVoice + HasClock>(adapter: &C) -> Response { 56 let config = match adapter.household().current().await { 57 Ok(h) => h.config(), 58 Err(e) => { 59 error!("/usage: the household's choices cannot be read: {e}"); 60 return Response::empty(500); 61 } 62 }; 63 let now = adapter.clock().now(); 64 let tokens: TokenUsage = match adapter.allowance().thinking_usage(now, &config.tokens).await { 65 Ok(u) => u.into(), 66 Err(e) => { 67 error!("/usage: the thinking allowance cannot be read: {e}"); 68 return Response::empty(500); 69 } 70 }; 71 debug!("/usage: tokens used {} of {:?}", tokens.used, tokens.limit); 72 let voice = match voice_usage(adapter, config.voice_daily_chars).await { 73 Ok(v) => v, 74 Err(e) => { 75 error!("/usage: the voice allowance cannot be read: {e}"); 76 return Response::empty(500); 77 } 78 }; 79 Response::of(&serde_json::json!({ "voice": voice, "tokens": tokens })) 80}
The usage the parents see: the service's own counters now, and the voice service's monthly credits (only if it is set up, since asking is a call out).
84async fn voice_usage<C: HasAllowance + HasVoice + HasClock>(adapter: &C, daily_cap: u32) -> Result<VoiceUsage, whiskers_ports::StoreError> { 85 let spend = adapter.allowance().voice_spend(adapter.clock().now()).await?; 86 let configured = adapter.voice().configured().await; 87 let mut u = VoiceUsage { 88 configured, 89 daily_cap, 90 daily_spent: spend.spent_today, 91 last_error: spend.last_failure.map(|f| f.to_string()), 92 ..VoiceUsage::default() 93 }; 94 if configured { 95 match adapter.voice().credits().await { 96 Ok(c) => { 97 u.tier = c.tier; 98 u.used = c.used; 99 u.limit = c.limit; 100 u.resets_at_unix = c.resets_at_unix; 101 } 102 Err(e) => { 103 warn!("voice usage: the voice service's credits could not be read: {e}"); 104 u.plan_error = Some(e.to_string()); 105 } 106 } 107 } 108 trace!("voice usage: {} of {} chars spent today", u.daily_spent, u.daily_cap); 109 Ok(u) 110}