/icon: the picture for one fact.
POST /icon: the best admitted picture for the words of a fact, or that none fits. Needs the embedder (to
shortlist by meaning), the judge (to choose), the cache of the picture names' vectors and the clock.
12pub struct PickIcon;
14impl sealed::Sealed for PickIcon {} 15 16impl<C: HasEmbedder + HasJudge + HasIcons + HasClock> Route<C> for PickIcon { 17 const PATHS: &'static [&'static str] = &["/icon"]; 18 async fn answer(&self, adapter: &C, _: &str, body: &str) -> Response { 19 let reply = match serde_json::from_str::<IconRequest>(body) { 20 Ok(req) => { 21 debug!("/icon: a fact of {} chars", req.text.len()); 22 let started = adapter.clock().now(); 23 let answer = pick_icon(adapter.embedder(), adapter.judge(), adapter.icon_vectors(), &req.text).await; 24 let ms = adapter.clock().now().get().saturating_sub(started.get()); 25 match answer { 26 Ok(Some(icon)) => { 27 info!("/icon: a picture chosen in {ms} ms"); 28 IconReply::Icon(icon) 29 } 30 Ok(None) => { 31 info!("/icon: none fits ({ms} ms)"); 32 IconReply::NoneFits 33 } 34 Err(e) => { 35 warn!("/icon unavailable after {ms} ms: {e}"); 36 IconReply::Unavailable(e.to_string()) 37 } 38 } 39 } 40 Err(e) => { 41 warn!("/icon: bad request: {}", super::kind_of(&e)); 42 IconReply::Unavailable(format!("bad request: {e}")) 43 } 44 }; 45 Response::of(&reply) 46 } 47}