Answers after verification: every value in range, every label or
level one that was asked, distributions in the question's order.
confidence is kept exactly as the vendor returned it.
5use serde::{Deserialize, Serialize};
Dollars per million INPUT tokens; output tokens are free. The vendor's
published price (jevsnes research/jev-api-digest.md: $42 per billion,
$0.042 per million), and postjevsql's default for jev.price_per_mtok.
10pub const DOLLARS_PER_MTOK: f64 = 0.042;
Every option with its probability, in the order they were asked.
Probability of each level, lowest first.
32 pub probabilities: Vec<f64>,
37impl ScoreAnswer {
score on 0 to 1, so rubrics of different lengths compare.
What this usage cost at the published price: input tokens only.
57impl std::ops::AddAssign for Usage { 58 fn add_assign(&mut self, other: Self) { 59 self.input_tokens += other.input_tokens; 60 self.output_tokens += other.output_tokens; 61 } 62} 63 64#[derive(Clone, Debug, PartialEq)] 65pub enum Answer { 66 Noul(NoulAnswer), 67 Choice(ChoiceAnswer), 68 Score(ScoreAnswer), 69}
Which answer a Key<A> reads. Sealed: only the three answer types.
77mod sealed { 78 pub trait Sealed {} 79 impl Sealed for super::NoulAnswer {} 80 impl Sealed for super::ChoiceAnswer {} 81 impl Sealed for super::ScoreAnswer {} 82} 83 84impl FromAnswer for NoulAnswer { 85 fn from_answer(answer: &Answer) -> Option<&Self> { 86 match answer { 87 Answer::Noul(a) => Some(a), 88 _ => None, 89 } 90 } 91} 92 93impl FromAnswer for ChoiceAnswer { 94 fn from_answer(answer: &Answer) -> Option<&Self> { 95 match answer { 96 Answer::Choice(a) => Some(a), 97 _ => None, 98 } 99 } 100} 101 102impl FromAnswer for ScoreAnswer { 103 fn from_answer(answer: &Answer) -> Option<&Self> { 104 match answer { 105 Answer::Score(a) => Some(a), 106 _ => None, 107 } 108 } 109} 110 111#[cfg(test)] 112mod tests { 113 use super::*; 114 115 #[test] 116 fn a_million_input_tokens_costs_the_published_price() { 117 let usage = Usage { input_tokens: 1_000_000, output_tokens: 999 }; 118 assert!((usage.dollars() - DOLLARS_PER_MTOK).abs() < 1e-12); 119 } 120 121 #[test] 122 fn an_answer_round_trips_through_a_record() { 123 let answer = ChoiceAnswer { 124 choice: "b".into(), 125 confidence: 0.4, 126 probabilities: vec![("b".into(), 0.6), ("a".into(), 0.4)], 127 }; 128 let line = serde_json::to_string(&answer).unwrap(); 129 assert_eq!(serde_json::from_str::<ChoiceAnswer>(&line).unwrap(), answer); 130 } 131}