llm_token_visualizer/
data.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub struct TokenInfo {
5 pub text: String,
6 pub confidence: f64,
7}
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct TokenFlag {
11 pub start: usize,
12 pub end: usize,
13 pub flag: String,
14 pub description: Option<String>,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct TokenAnalysis {
19 pub tokens: Vec<TokenInfo>,
20 pub flags: Vec<TokenFlag>,
21}
22
23#[derive(Debug, Clone)]
24pub struct VisualizationConfig {
25 pub verbose: bool,
26 pub show_confidence_scores: bool,
27 pub show_flags: bool,
28}
29
30impl Default for VisualizationConfig {
31 fn default() -> Self {
32 Self {
33 verbose: false,
34 show_confidence_scores: true,
35 show_flags: true,
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq)]
41pub enum ConfidenceLevel {
42 VeryLow, Low, Medium, High, VeryHigh, }
48
49impl From<f64> for ConfidenceLevel {
50 fn from(confidence: f64) -> Self {
51 match confidence {
52 c if c < 0.3 => ConfidenceLevel::VeryLow,
53 c if c < 0.5 => ConfidenceLevel::Low,
54 c if c < 0.7 => ConfidenceLevel::Medium,
55 c if c < 0.9 => ConfidenceLevel::High,
56 _ => ConfidenceLevel::VeryHigh,
57 }
58 }
59}
60
61#[derive(Debug, Clone, PartialEq)]
62pub enum FlagType {
63 Fact,
64 Uncertain,
65 Overconfident,
66 Hallucination,
67 Other(String),
68}
69
70impl From<&str> for FlagType {
71 fn from(s: &str) -> Self {
72 match s.to_lowercase().as_str() {
73 "fact" => FlagType::Fact,
74 "uncertain" => FlagType::Uncertain,
75 "overconfident" => FlagType::Overconfident,
76 "hallucination" => FlagType::Hallucination,
77 _ => FlagType::Other(s.to_string()),
78 }
79 }
80}
81
82impl TokenAnalysis {
83 pub fn validate(&self) -> Result<(), String> {
84 if self.tokens.is_empty() {
85 return Err("No tokens provided".to_string());
86 }
87
88 for (i, token) in self.tokens.iter().enumerate() {
89 if token.confidence < 0.0 || token.confidence > 1.0 {
90 return Err(format!(
91 "Invalid confidence score for token {}: {}",
92 i, token.confidence
93 ));
94 }
95 }
96
97 for flag in &self.flags {
98 if flag.start >= self.tokens.len() || flag.end > self.tokens.len() {
99 return Err(format!(
100 "Flag span out of bounds: {} to {}",
101 flag.start, flag.end
102 ));
103 }
104 if flag.start >= flag.end {
105 return Err(format!("Invalid flag span: {} to {}", flag.start, flag.end));
106 }
107 }
108
109 Ok(())
110 }
111
112 pub fn get_flags_for_token(&self, token_index: usize) -> Vec<&TokenFlag> {
113 self.flags
114 .iter()
115 .filter(|flag| token_index >= flag.start && token_index < flag.end)
116 .collect()
117 }
118
119 pub fn get_confidence_stats(&self) -> (f64, f64, f64) {
120 let confidences: Vec<f64> = self.tokens.iter().map(|t| t.confidence).collect();
121 let sum: f64 = confidences.iter().sum();
122 let avg = sum / confidences.len() as f64;
123 let min = confidences.iter().fold(f64::INFINITY, |a, &b| a.min(b));
124 let max = confidences.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
125 (min, max, avg)
126 }
127}