streaming_chat/
streaming_chat.rs

1/// Example: Using streaming responses with Helios Engine
2/// 
3/// This example demonstrates how to use the streaming API to get
4/// real-time responses from the LLM, including detection of thinking tags.
5
6use helios_engine::{LLMClient, ChatMessage, ChatSession};
7use helios_engine::config::LLMConfig;
8use std::io::{self, Write};
9
10#[tokio::main]
11async fn main() -> helios_engine::Result<()> {
12    println!("šŸš€ Helios Engine - Streaming Example");
13    println!("=====================================\n");
14
15    // Setup LLM configuration
16    let llm_config = LLMConfig {
17        model_name: "gpt-3.5-turbo".to_string(),
18        base_url: "https://api.openai.com/v1".to_string(),
19        api_key: std::env::var("OPENAI_API_KEY")
20            .unwrap_or_else(|_| "your-api-key-here".to_string()),
21        temperature: 0.7,
22        max_tokens: 2048,
23    };
24
25    let client = LLMClient::new(llm_config);
26
27    println!("Example 1: Simple Streaming Response");
28    println!("======================================\n");
29    
30    let messages = vec![
31        ChatMessage::system("You are a helpful assistant."),
32        ChatMessage::user("Write a short poem about coding."),
33    ];
34
35    print!("Assistant: ");
36    io::stdout().flush()?;
37
38    let response = client.chat_stream(messages, None, |chunk| {
39        print!("{}", chunk);
40        io::stdout().flush().unwrap();
41    }).await?;
42
43    println!("\n\n");
44
45    println!("Example 2: Interactive Streaming Chat");
46    println!("======================================\n");
47
48    let mut session = ChatSession::new()
49        .with_system_prompt("You are a helpful coding assistant.");
50
51    let questions = vec![
52        "What is Rust?",
53        "What are its main benefits?",
54        "Show me a simple example.",
55    ];
56
57    for question in questions {
58        println!("User: {}", question);
59        session.add_user_message(question);
60
61        print!("Assistant: ");
62        io::stdout().flush()?;
63
64        let response = client.chat_stream(session.get_messages(), None, |chunk| {
65            print!("{}", chunk);
66            io::stdout().flush().unwrap();
67        }).await?;
68
69        session.add_assistant_message(&response.content);
70        println!("\n");
71    }
72
73    println!("\nExample 3: Streaming with Thinking Tags");
74    println!("=========================================\n");
75    println!("When using models that support thinking tags (like o1),");
76    println!("you can detect and display them during streaming.\n");
77
78    struct ThinkingTracker {
79        in_thinking: bool,
80        thinking_buffer: String,
81    }
82
83    impl ThinkingTracker {
84        fn new() -> Self {
85            Self {
86                in_thinking: false,
87                thinking_buffer: String::new(),
88            }
89        }
90
91        fn process_chunk(&mut self, chunk: &str) -> String {
92            let mut output = String::new();
93            let mut chars = chunk.chars().peekable();
94
95            while let Some(c) = chars.next() {
96                if c == '<' {
97                    let remaining: String = chars.clone().collect();
98                    if remaining.starts_with("thinking>") {
99                        self.in_thinking = true;
100                        self.thinking_buffer.clear();
101                        output.push_str("\nšŸ’­ [Thinking");
102                        for _ in 0..9 {
103                            chars.next();
104                        }
105                        continue;
106                    } else if remaining.starts_with("/thinking>") {
107                        self.in_thinking = false;
108                        output.push_str("]\n");
109                        for _ in 0..10 {
110                            chars.next();
111                        }
112                        continue;
113                    }
114                }
115
116                if self.in_thinking {
117                    self.thinking_buffer.push(c);
118                    if self.thinking_buffer.len() % 3 == 0 {
119                        output.push('.');
120                    }
121                } else {
122                    output.push(c);
123                }
124            }
125
126            output
127        }
128    }
129
130    let messages = vec![
131        ChatMessage::user("Solve this problem: What is 15 * 234 + 89?"),
132    ];
133
134    let mut tracker = ThinkingTracker::new();
135    print!("Assistant: ");
136    io::stdout().flush()?;
137
138    let _response = client.chat_stream(messages, None, |chunk| {
139        let output = tracker.process_chunk(chunk);
140        print!("{}", output);
141        io::stdout().flush().unwrap();
142    }).await?;
143
144    println!("\n\nāœ… Streaming examples completed!");
145    println!("\nKey benefits of streaming:");
146    println!("  • Real-time response display");
147    println!("  • Better user experience for long responses");
148    println!("  • Ability to show thinking/reasoning process");
149    println!("  • Early cancellation possible (future feature)");
150
151    Ok(())
152}