llm_worker/timeline/
text_block_collector.rs1use crate::handler::{Handler, TextBlockEvent, TextBlockKind};
7use std::sync::{Arc, Mutex};
8
9#[derive(Debug, Default)]
11pub struct TextCollectorState {
12 buffer: String,
14}
15
16#[derive(Clone)]
21pub struct TextBlockCollector {
22 collected: Arc<Mutex<Vec<String>>>,
24}
25
26impl TextBlockCollector {
27 pub fn new() -> Self {
29 Self {
30 collected: Arc::new(Mutex::new(Vec::new())),
31 }
32 }
33
34 pub fn take_collected(&self) -> Vec<String> {
36 let mut guard = self.collected.lock().unwrap();
37 std::mem::take(&mut *guard)
38 }
39
40 pub fn collected(&self) -> Vec<String> {
42 self.collected.lock().unwrap().clone()
43 }
44
45 pub fn has_content(&self) -> bool {
47 !self.collected.lock().unwrap().is_empty()
48 }
49
50 pub fn clear(&self) {
52 self.collected.lock().unwrap().clear();
53 }
54}
55
56impl Default for TextBlockCollector {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl Handler<TextBlockKind> for TextBlockCollector {
63 type Scope = TextCollectorState;
64
65 fn on_event(&mut self, scope: &mut Self::Scope, event: &TextBlockEvent) {
66 match event {
67 TextBlockEvent::Start(_) => {
68 scope.buffer.clear();
69 }
70 TextBlockEvent::Delta(text) => {
71 scope.buffer.push_str(text);
72 }
73 TextBlockEvent::Stop(_) => {
74 if !scope.buffer.is_empty() {
76 let text = std::mem::take(&mut scope.buffer);
77 self.collected.lock().unwrap().push(text);
78 }
79 }
80 }
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use crate::timeline::Timeline;
88 use crate::timeline::event::Event;
89
90 #[test]
92 fn test_collect_single_text_block() {
93 let collector = TextBlockCollector::new();
94 let mut timeline = Timeline::new();
95 timeline.on_text_block(collector.clone());
96
97 timeline.dispatch(&Event::text_block_start(0));
99 timeline.dispatch(&Event::text_delta(0, "Hello, "));
100 timeline.dispatch(&Event::text_delta(0, "World!"));
101 timeline.dispatch(&Event::text_block_stop(0, None));
102
103 let texts = collector.take_collected();
105 assert_eq!(texts.len(), 1);
106 assert_eq!(texts[0], "Hello, World!");
107 }
108
109 #[test]
111 fn test_collect_multiple_text_blocks() {
112 let collector = TextBlockCollector::new();
113 let mut timeline = Timeline::new();
114 timeline.on_text_block(collector.clone());
115
116 timeline.dispatch(&Event::text_block_start(0));
118 timeline.dispatch(&Event::text_delta(0, "First"));
119 timeline.dispatch(&Event::text_block_stop(0, None));
120
121 timeline.dispatch(&Event::text_block_start(1));
123 timeline.dispatch(&Event::text_delta(1, "Second"));
124 timeline.dispatch(&Event::text_block_stop(1, None));
125
126 let texts = collector.take_collected();
127 assert_eq!(texts.len(), 2);
128 assert_eq!(texts[0], "First");
129 assert_eq!(texts[1], "Second");
130 }
131}