zai_rs/model/traits.rs
1//! # Core Traits for AI Model Abstractions
2//!
3//! This module defines the fundamental traits that enable type-safe
4//! interactions with different AI models and capabilities in the Zhipu AI
5//! ecosystem.
6//!
7//! ## Trait Categories
8//!
9//! ### Model Identification
10//! - [`ModelName`] - Converts model types to string identifiers
11//!
12//! ### Capability Traits
13//! - [`Chat`] - Synchronous chat completion capability
14//! - [`AsyncChat`] - Asynchronous chat completion capability
15//! - [`ThinkEnable`] - Thinking/reasoning capability support
16//! - [`VideoGen`] - Video generation capability
17//! - [`ImageGen`] - Image generation capability
18//! - [`AudioToText`] - Speech recognition capability
19//! - [`TextToAudio`] - Text-to-speech capability
20//! - [`VoiceClone`] - Voice cloning capability
21//!
22//! ### Type Safety
23//! - [`Bounded`] - Compile-time model-message compatibility verification
24//! - [`StreamState`] - Type-state pattern for streaming capability control
25//!
26//! ## Type-State Pattern
27//!
28//! The `StreamState` trait and its implementations (`StreamOn`, `StreamOff`)
29//! provide compile-time guarantees about streaming capabilities, preventing
30//! runtime errors and enabling better API design.
31
32/// Trait for AI models that can be identified by name.
33///
34/// This trait enables conversion of model types to their string identifiers
35/// used in API requests. All AI model types must implement this trait.
36pub trait ModelName: Into<String> {}
37
38/// Marker trait for compile-time model-message compatibility checking.
39///
40/// This trait is used in conjunction with the type system to ensure that
41/// specific model types are only used with compatible message types,
42/// preventing invalid API calls at compile time.
43pub trait Bounded {}
44
45/// Indicates that a model supports synchronous chat completion.
46///
47/// Models implementing this trait can be used with the chat completion API
48/// API for real-time conversational interactions.
49pub trait Chat {}
50
51/// Indicates that a model supports asynchronous chat completion.
52///
53/// Models implementing this trait can be used with the async chat completion
54/// API API for queued, background processing of conversational requests.
55pub trait AsyncChat {}
56
57/// Indicates that a model supports thinking/reasoning capabilities.
58///
59/// Models implementing this trait can utilize advanced reasoning modes
60/// that show step-by-step thinking processes for complex problem solving.
61pub trait ThinkEnable {}
62
63/// Indicates that a model supports streaming tool calls (tool_stream
64/// parameter). Only models implementing this marker can enable tool_stream in
65/// requests.
66pub trait ToolStreamEnable {}
67
68/// Indicates that a model supports video generation.
69///
70/// Models implementing this trait can be used to generate videos from
71/// text descriptions or other inputs.
72pub trait VideoGen {}
73
74/// Indicates that a model supports image generation.
75///
76/// Models implementing this trait can be used to generate images from
77/// text descriptions or other inputs.
78pub trait ImageGen {}
79
80/// Indicates that a model supports speech recognition.
81///
82/// Models implementing this trait can convert audio input to text,
83/// supporting various audio formats and languages.
84pub trait AudioToText {}
85
86/// Indicates that a model supports text-to-speech synthesis.
87///
88/// Models implementing this trait can convert text input to audio output,
89/// supporting various voices and audio formats.
90pub trait TextToAudio {}
91
92/// Indicates that a model supports voice cloning.
93///
94/// Models implementing this trait can create synthetic voices that
95/// mimic specific speakers based on audio samples.
96pub trait VoiceClone {}
97
98/// Indicates that a model supports OCR (Optical Character Recognition).
99///
100/// Models implementing this trait can recognize and extract text content
101/// from images, supporting handwritten and printed text in multiple languages.
102pub trait Ocr {}
103
104/// Type-state trait for compile-time streaming capability control.
105///
106/// This trait enables the type system to enforce whether a request
107/// supports streaming (`StreamOn`) or non-streaming (`StreamOff`) responses,
108/// preventing invalid API usage patterns.
109pub trait StreamState {}
110
111/// Type-state indicating that streaming is enabled.
112///
113/// Types parameterized with this marker support Server-Sent Events (SSE)
114/// streaming for real-time response processing.
115pub struct StreamOn;
116
117/// Type-state indicating that streaming is disabled.
118///
119/// Types parameterized with this marker receive complete responses
120/// rather than streaming chunks.
121pub struct StreamOff;
122
123impl StreamState for StreamOn {}
124impl StreamState for StreamOff {}
125
126use futures::StreamExt;
127use tracing::info;
128
129use crate::client::http::HttpClient;
130
131/// Trait for types that support Server-Sent Events (SSE) streaming.
132///
133/// This trait provides streaming capabilities for API responses that support
134/// real-time data transmission. The default implementation handles SSE protocol
135/// parsing, logging, and callback invocation.
136///
137/// ## Streaming Protocol
138///
139/// The implementation expects SSE-formatted responses with `data: ` prefixed
140/// lines. Each data line is parsed and passed to the callback function. The
141/// stream terminates when a `[DONE]` marker is encountered.
142///
143/// ## Usage
144///
145/// ```rust,ignore
146/// let mut client = ChatCompletion::new(model, messages, api_key).enable_stream();
147/// client.stream_sse_for_each(|data| {
148/// println!("Received: {}", String::from_utf8_lossy(data));
149/// }).await?;
150/// ```
151pub trait SseStreamable: HttpClient {
152 fn stream_sse_for_each<'a, F>(
153 &'a mut self,
154 mut on_data: F,
155 ) -> impl core::future::Future<Output = crate::ZaiResult<()>> + 'a
156 where
157 F: FnMut(&[u8]) + 'a,
158 {
159 async move {
160 let resp = self.post().await?;
161 let mut stream = resp.bytes_stream();
162 let mut buf: Vec<u8> = Vec::new();
163
164 while let Some(next) = stream.next().await {
165 match next {
166 Ok(bytes) => {
167 let lines =
168 crate::model::sse_parser::extract_sse_data_lines(&mut buf, &bytes);
169 for rest in lines {
170 info!("SSE data: {}", String::from_utf8_lossy(&rest));
171 if rest == b"[DONE]" {
172 return Ok(());
173 }
174 on_data(&rest);
175 }
176 },
177 Err(e) => {
178 return Err(crate::client::error::ZaiError::NetworkError(
179 std::sync::Arc::new(e),
180 ));
181 },
182 }
183 }
184 Ok(())
185 }
186 }
187}
188
189/// Macro for defining AI model types with standard implementations.
190///
191/// This macro generates a model type with the following implementations:
192/// - `Debug` and `Clone` traits
193/// - `Into<String>` for API identifier conversion
194/// - `Serialize` for JSON serialization
195/// - `ModelName` trait marker
196///
197/// ## Usage Examples
198///
199/// ```rust,ignore
200/// // Basic model definition
201/// define_model_type!(GLM4_5, "glm-4.5");
202/// // Model with attributes
203/// define_model_type!(
204/// #[allow(non_camel_case_types)]
205/// GLM4_5_flash,
206/// "glm-4.5-flash"
207/// );
208/// ```
209#[macro_export]
210macro_rules! define_model_type {
211 ($(#[$meta:meta])* $name:ident, $s:expr) => {
212 #[derive(Debug, Clone)]
213 $(#[$meta])*
214 pub struct $name {}
215
216 impl ::core::convert::From<$name> for String {
217 fn from(_val: $name) -> Self { $s.to_string() }
218 }
219
220 impl ::serde::Serialize for $name {
221 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
222 where S: ::serde::Serializer {
223 let model_name: String = self.clone().into();
224 serializer.serialize_str(&model_name)
225 }
226 }
227
228 impl $crate::model::traits::ModelName for $name {}
229 };
230}
231
232/// Macro for binding message types to AI models.
233///
234/// This macro creates compile-time associations between model types and
235/// message types, ensuring type safety in chat completion requests.
236///
237/// ## Usage Examples
238///
239/// ```rust,ignore
240/// // Single message type binding
241/// impl_message_binding!(GLM4_5, TextMessage);
242/// // Multiple message type bindings
243/// impl_message_binding!(GLM4_5, TextMessage, VisionMessage);
244/// ```
245#[macro_export]
246macro_rules! impl_message_binding {
247 // Single message type
248 ($name:ident, $message_type:ty) => {
249 impl $crate::model::traits::Bounded for ($name, $message_type) {}
250 };
251 // Multiple message types
252 ($name:ident, $message_type:ty, $($message_types:ty),+) => {
253 impl $crate::model::traits::Bounded for ($name, $message_type) {}
254 $(
255 impl $crate::model::traits::Bounded for ($name, $message_types) {}
256 )+
257 };
258}
259
260/// Macro for implementing multiple capability traits on model types.
261///
262/// This macro provides a convenient way to mark models with multiple
263/// capabilities in a single declaration.
264///
265/// ## Usage Examples
266///
267/// ```rust,ignore
268/// // Single model, multiple traits
269/// impl_model_markers!(GLM4_5_flash: AsyncChat, Chat);
270///
271/// // Multiple models, same traits
272/// impl_model_markers!([GLM4_5, GLM4_5_air]: Chat);
273/// ```
274#[macro_export]
275macro_rules! impl_model_markers {
276 // Single model, multiple markers
277 ($model:ident : $($marker:path),+ $(,)?) => {
278 $( impl $marker for $model {} )+
279 };
280 // Multiple models, multiple markers
281 ([$($model:ident),+ ] : $($marker:path),+ $(,)?) => {
282 $( $( impl $marker for $model {} )+ )+
283 };
284}