mockforge_intelligence/
ai_handler.rs1use mockforge_data::{
18 DataDriftConfig, DataDriftEngine, IntelligentMockConfig, IntelligentMockGenerator,
19};
20use mockforge_foundation::{Error, Result};
21use serde_json::Value;
22use std::sync::Arc;
23use tokio::sync::RwLock;
24use tracing::{debug, warn};
25
26pub struct AiResponseHandler {
28 intelligent_generator: Option<IntelligentMockGenerator>,
30 drift_engine: Option<Arc<RwLock<DataDriftEngine>>>,
32}
33
34impl AiResponseHandler {
35 pub fn new(
37 intelligent_config: Option<IntelligentMockConfig>,
38 drift_config: Option<DataDriftConfig>,
39 ) -> Result<Self> {
40 debug!("Creating AI response handler");
41
42 let intelligent_generator = if let Some(config) = intelligent_config {
44 debug!("Initializing intelligent mock generator with mode: {:?}", config.mode);
45 Some(IntelligentMockGenerator::new(config).map_err(|e| Error::Config {
46 message: format!("Failed to initialize intelligent generator: {}", e),
47 })?)
48 } else {
49 None
50 };
51
52 let drift_engine = if let Some(config) = drift_config {
54 debug!("Initializing data drift engine");
55 let engine = DataDriftEngine::new(config).map_err(|e| Error::Config {
56 message: format!("Failed to initialize drift engine: {}", e),
57 })?;
58 Some(Arc::new(RwLock::new(engine)))
59 } else {
60 None
61 };
62
63 Ok(Self {
64 intelligent_generator,
65 drift_engine,
66 })
67 }
68
69 pub fn is_enabled(&self) -> bool {
71 self.intelligent_generator.is_some() || self.drift_engine.is_some()
72 }
73
74 pub async fn generate_response(&mut self, base_response: Option<Value>) -> Result<Value> {
76 debug!("Generating AI-powered response");
77
78 let mut response = if let Some(generator) = &mut self.intelligent_generator {
80 match generator.generate().await {
81 Ok(resp) => {
82 debug!("Intelligent generation successful");
83 resp
84 }
85 Err(e) => {
86 warn!("Intelligent generation failed: {}, using fallback", e);
87 base_response.unwrap_or_else(|| serde_json::json!({}))
88 }
89 }
90 } else if let Some(base) = base_response {
91 base
92 } else {
93 serde_json::json!({})
94 };
95
96 if let Some(drift_engine) = &self.drift_engine {
98 match drift_engine.read().await.apply_drift(response.clone()).await {
99 Ok(drifted) => {
100 debug!("Data drift applied successfully");
101 response = drifted;
102 }
103 Err(e) => {
104 warn!("Data drift failed: {}, using non-drifted response", e);
105 }
106 }
107 }
108
109 Ok(response)
110 }
111
112 pub async fn reset_drift(&self) {
114 if let Some(drift_engine) = &self.drift_engine {
115 drift_engine.read().await.reset().await;
116 debug!("Drift state reset");
117 }
118 }
119
120 pub async fn drift_request_count(&self) -> u64 {
122 if let Some(drift_engine) = &self.drift_engine {
123 drift_engine.read().await.request_count().await
124 } else {
125 0
126 }
127 }
128}
129
130pub fn create_ai_handler(
132 intelligent_config: Option<IntelligentMockConfig>,
133 drift_config: Option<DataDriftConfig>,
134) -> Result<Option<AiResponseHandler>> {
135 if intelligent_config.is_some() || drift_config.is_some() {
136 Ok(Some(AiResponseHandler::new(intelligent_config, drift_config)?))
137 } else {
138 Ok(None)
139 }
140}
141
142pub async fn process_response_with_ai(
155 response_body: Option<Value>,
156 intelligent_config: Option<Value>,
157 drift_config: Option<Value>,
158) -> Result<Value> {
159 let intelligent: Option<IntelligentMockConfig> =
161 intelligent_config.and_then(|v| serde_json::from_value(v).ok());
162
163 let drift: Option<DataDriftConfig> = drift_config.and_then(|v| serde_json::from_value(v).ok());
164
165 if intelligent.is_none() && drift.is_none() {
167 return Ok(response_body.unwrap_or_else(|| serde_json::json!({})));
168 }
169
170 let mut handler = AiResponseHandler::new(intelligent, drift)?;
172 handler.generate_response(response_body).await
173}
174
175#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
177pub struct AiResponseConfig {
178 #[serde(skip_serializing_if = "Option::is_none")]
180 pub intelligent: Option<IntelligentMockConfig>,
181
182 #[serde(skip_serializing_if = "Option::is_none")]
184 pub drift: Option<DataDriftConfig>,
185}
186
187impl AiResponseConfig {
188 pub fn is_enabled(&self) -> bool {
190 self.intelligent.is_some() || self.drift.is_some()
191 }
192
193 pub fn create_handler(&self) -> Result<Option<AiResponseHandler>> {
195 create_ai_handler(self.intelligent.clone(), self.drift.clone())
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use mockforge_data::drift::{DriftRule, DriftStrategy};
203 use mockforge_data::ResponseMode;
204
205 #[test]
206 fn test_ai_handler_creation_intelligent_only() {
207 let config = IntelligentMockConfig::new(ResponseMode::Intelligent)
208 .with_prompt("Test prompt".to_string());
209
210 let result = AiResponseHandler::new(Some(config), None);
211 assert!(result.is_ok());
212
213 let handler = result.unwrap();
214 assert!(handler.is_enabled());
215 assert!(handler.intelligent_generator.is_some());
216 assert!(handler.drift_engine.is_none());
217 }
218
219 #[test]
220 fn test_ai_handler_creation_drift_only() {
221 let rule = DriftRule::new("field".to_string(), DriftStrategy::Linear).with_rate(1.0);
222 let drift_config = DataDriftConfig::new().with_rule(rule);
223
224 let result = AiResponseHandler::new(None, Some(drift_config));
225 assert!(result.is_ok());
226
227 let handler = result.unwrap();
228 assert!(handler.is_enabled());
229 assert!(handler.intelligent_generator.is_none());
230 assert!(handler.drift_engine.is_some());
231 }
232
233 #[test]
234 fn test_ai_handler_creation_both() {
235 let intelligent_config =
236 IntelligentMockConfig::new(ResponseMode::Intelligent).with_prompt("Test".to_string());
237 let rule = DriftRule::new("field".to_string(), DriftStrategy::Linear);
238 let drift_config = DataDriftConfig::new().with_rule(rule);
239
240 let result = AiResponseHandler::new(Some(intelligent_config), Some(drift_config));
241 assert!(result.is_ok());
242
243 let handler = result.unwrap();
244 assert!(handler.is_enabled());
245 assert!(handler.intelligent_generator.is_some());
246 assert!(handler.drift_engine.is_some());
247 }
248
249 #[test]
250 fn test_ai_handler_creation_neither() {
251 let result = AiResponseHandler::new(None, None);
252 assert!(result.is_ok());
253
254 let handler = result.unwrap();
255 assert!(!handler.is_enabled());
256 }
257
258 #[test]
259 fn test_ai_response_config_is_enabled() {
260 let config = AiResponseConfig {
261 intelligent: Some(IntelligentMockConfig::new(ResponseMode::Intelligent)),
262 drift: None,
263 };
264 assert!(config.is_enabled());
265
266 let config = AiResponseConfig {
267 intelligent: None,
268 drift: None,
269 };
270 assert!(!config.is_enabled());
271 }
272
273 #[tokio::test]
274 async fn test_generate_response_with_base() {
275 let mut handler = AiResponseHandler::new(None, None).unwrap();
276 let base = serde_json::json!({"test": "value"});
277
278 let result = handler.generate_response(Some(base.clone())).await;
279 assert!(result.is_ok());
280 assert_eq!(result.unwrap(), base);
281 }
282}