Skip to main content

zai_rs/model/
traits.rs

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