1use super::Recipe;
6
7pub fn register_all(cookbook: &mut super::Cookbook) {
9 register_wasm_recipes(cookbook);
10 register_ml_recipes(cookbook);
11 register_transpilation_recipes(cookbook);
12 register_distributed_recipes(cookbook);
13 register_quality_recipes(cookbook);
14 register_speech_recipes(cookbook);
15 super::recipes_more::register_training_recipes(cookbook);
16 super::recipes_more::register_data_recipes(cookbook);
17 super::recipes_more::register_registry_recipes(cookbook);
18 super::recipes_more::register_rag_recipes(cookbook);
19 super::recipes_more::register_viz_recipes(cookbook);
20 super::recipes_more::register_rlhf_recipes(cookbook);
21}
22
23fn register_wasm_recipes(cookbook: &mut super::Cookbook) {
28 cookbook.add(
30 Recipe::new("wasm-zero-js", "Zero-JS WASM Application")
31 .with_problem("Build interactive web apps with pure Rust/WASM, eliminating JavaScript entirely")
32 .with_components(vec!["simular", "trueno", "web-sys", "wasm-bindgen"])
33 .with_tags(vec!["wasm", "zero-js", "web", "canvas", "animation"])
34 .with_code(r##"// Cargo.toml
35[lib]
36crate-type = ["cdylib"]
37
38[dependencies]
39wasm-bindgen = "0.2"
40web-sys = { version = "0.3", features = [
41 "Window", "Document", "HtmlCanvasElement",
42 "CanvasRenderingContext2d", "Element"
43]}
44console_error_panic_hook = "0.1"
45
46// src/lib.rs
47use std::cell::RefCell;
48use std::rc::Rc;
49use wasm_bindgen::prelude::*;
50use wasm_bindgen::JsCast;
51
52struct AppState {
53 canvas: web_sys::HtmlCanvasElement,
54 ctx: web_sys::CanvasRenderingContext2d,
55 frame: u32,
56}
57
58impl AppState {
59 fn tick(&mut self) {
60 self.frame += 1;
61 self.render();
62 }
63
64 fn render(&self) {
65 let w = self.canvas.width() as f64;
66 let h = self.canvas.height() as f64;
67
68 // Clear
69 self.ctx.set_fill_style_str("#0a0a1a");
70 self.ctx.fill_rect(0.0, 0.0, w, h);
71
72 // Draw
73 self.ctx.set_fill_style_str("#4ecdc4");
74 self.ctx.begin_path();
75 let _ = self.ctx.arc(w/2.0, h/2.0, 50.0, 0.0, std::f64::consts::PI * 2.0);
76 self.ctx.fill();
77 }
78}
79
80fn request_animation_frame(f: &Closure<dyn FnMut()>) {
81 web_sys::window().expect("no global window")
82 .request_animation_frame(f.as_ref().unchecked_ref()).expect("raf failed");
83}
84
85#[wasm_bindgen(js_name = initApp)]
86pub fn init_app() -> Result<(), JsValue> {
87 console_error_panic_hook::set_once();
88
89 let window = web_sys::window().expect("no window");
90 let document = window.document().expect("no document");
91 let canvas = document.get_element_by_id("canvas")
92 .expect("no canvas")
93 .dyn_into::<web_sys::HtmlCanvasElement>()?;
94
95 let ctx = canvas.get_context("2d")?.expect("no 2d context")
96 .dyn_into::<web_sys::CanvasRenderingContext2d>()?;
97
98 let state = Rc::new(RefCell::new(AppState { canvas, ctx, frame: 0 }));
99
100 // Animation loop
101 let f: Rc<RefCell<Option<Closure<dyn FnMut()>>>> = Rc::new(RefCell::new(None));
102 let g = Rc::clone(&f);
103 let state_clone = Rc::clone(&state);
104
105 *g.borrow_mut() = Some(Closure::new(move || {
106 state_clone.borrow_mut().tick();
107 request_animation_frame(f.borrow().as_ref().expect("closure not set"));
108 }));
109
110 request_animation_frame(g.borrow().as_ref().expect("closure not set"));
111 Ok(())
112}
113
114// index.html - ONE LINE OF JAVASCRIPT
115// <script type="module">import init, { initApp } from './pkg/app.js'; init().then(initApp);</script>
116"##)
117 .with_related(vec!["wasm-event-handling", "wasm-canvas-rendering"])
118 .with_test_code(r#"#[cfg(all(test, not(target_arch = "wasm32")))]
119mod tests {
120 #[test]
121 fn test_frame_increment() {
122 let mut frame = 0u32;
123 frame += 1;
124 assert_eq!(frame, 1);
125 }
126
127 #[test]
128 fn test_circle_radius_positive() {
129 let radius = 50.0_f64;
130 assert!(radius > 0.0);
131 }
132
133 #[test]
134 fn test_canvas_center_calculation() {
135 let w = 800_u32;
136 let h = 600_u32;
137 let center_x = (w as f64) / 2.0;
138 let center_y = (h as f64) / 2.0;
139 assert_eq!(center_x, 400.0);
140 assert_eq!(center_y, 300.0);
141 }
142}"#),
143 );
144
145 cookbook.add(
147 Recipe::new("wasm-event-handling", "WASM Event Handling")
148 .with_problem("Handle DOM events (click, input, keypress) in pure Rust")
149 .with_components(vec!["simular", "web-sys", "wasm-bindgen"])
150 .with_tags(vec!["wasm", "events", "dom", "closure"])
151 .with_code(r#"use wasm_bindgen::prelude::*;
152use wasm_bindgen::JsCast;
153
154fn setup_button<F>(document: &web_sys::Document, id: &str, mut callback: F) -> Result<(), JsValue>
155where
156 F: FnMut() + 'static,
157{
158 if let Some(btn) = document.get_element_by_id(id) {
159 let closure = Closure::wrap(Box::new(move |_: web_sys::Event| {
160 callback();
161 }) as Box<dyn FnMut(_)>);
162
163 btn.add_event_listener_with_callback("click", closure.as_ref().unchecked_ref())?;
164 closure.forget(); // Prevent closure from being dropped
165 }
166 Ok(())
167}
168
169fn setup_slider(document: &web_sys::Document, id: &str, state: Rc<RefCell<AppState>>) -> Result<(), JsValue> {
170 if let Some(slider) = document.get_element_by_id(id) {
171 let closure = Closure::wrap(Box::new(move |e: web_sys::Event| {
172 if let Some(target) = e.target() {
173 if let Some(input) = target.dyn_ref::<web_sys::HtmlInputElement>() {
174 if let Ok(value) = input.value().parse::<u32>() {
175 state.borrow_mut().set_speed(value);
176 }
177 }
178 }
179 }) as Box<dyn FnMut(_)>);
180
181 slider.add_event_listener_with_callback("input", closure.as_ref().unchecked_ref())?;
182 closure.forget();
183 }
184 Ok(())
185}
186"#)
187 .with_related(vec!["wasm-zero-js", "wasm-canvas-rendering"])
188 .with_test_code(r#"#[cfg(all(test, not(target_arch = "wasm32")))]
189mod tests {
190 use std::cell::RefCell;
191 use std::rc::Rc;
192
193 #[test]
194 fn test_closure_state_capture() {
195 let counter = Rc::new(RefCell::new(0u32));
196 let counter_clone = Rc::clone(&counter);
197 let increment = move || { *counter_clone.borrow_mut() += 1; };
198 increment();
199 assert_eq!(*counter.borrow(), 1);
200 }
201
202 #[test]
203 fn test_input_value_parsing() {
204 let input_value = "42";
205 let parsed = input_value.parse::<u32>();
206 assert_eq!(parsed.expect("unexpected failure"), 42);
207 }
208
209 #[test]
210 fn test_speed_state_update() {
211 let mut speed = 0_u32;
212 let new_value = 10_u32;
213 speed = new_value;
214 assert_eq!(speed, 10);
215 }
216}"#),
217 );
218
219 cookbook.add(
221 Recipe::new("wasm-canvas-rendering", "WASM Canvas 2D Rendering")
222 .with_problem("Render graphics to HTML5 Canvas from Rust/WASM")
223 .with_components(vec!["simular", "web-sys"])
224 .with_tags(vec!["wasm", "canvas", "graphics", "rendering"])
225 .with_code(
226 r##"use web_sys::CanvasRenderingContext2d;
227
228fn render(ctx: &CanvasRenderingContext2d, w: f64, h: f64, trail: &[(f64, f64)]) {
229 // Clear background
230 ctx.set_fill_style_str("#0f0f23");
231 ctx.fill_rect(0.0, 0.0, w, h);
232
233 // Draw grid
234 ctx.set_stroke_style_str("#1a1a2e");
235 ctx.set_line_width(1.0);
236 for i in 1..=10 {
237 let x = w * (i as f64) / 10.0;
238 ctx.begin_path();
239 ctx.move_to(x, 0.0);
240 ctx.line_to(x, h);
241 ctx.stroke();
242 }
243
244 // Draw circle with glow
245 ctx.set_fill_style_str("#ffd93d");
246 ctx.begin_path();
247 let _ = ctx.arc(w/2.0, h/2.0, 15.0, 0.0, std::f64::consts::PI * 2.0);
248 ctx.fill();
249
250 // Semi-transparent glow
251 ctx.set_global_alpha(0.3);
252 ctx.begin_path();
253 let _ = ctx.arc(w/2.0, h/2.0, 25.0, 0.0, std::f64::consts::PI * 2.0);
254 ctx.fill();
255 ctx.set_global_alpha(1.0);
256
257 // Draw trail with fading alpha
258 ctx.begin_path();
259 if let Some((x, y)) = trail.first() {
260 ctx.move_to(*x, *y);
261 }
262 for (i, (x, y)) in trail.iter().enumerate().skip(1) {
263 let alpha = (i as f64) / (trail.len() as f64) * 0.5;
264 ctx.set_global_alpha(alpha);
265 ctx.line_to(*x, *y);
266 }
267 ctx.set_global_alpha(1.0);
268 ctx.stroke();
269
270 // Text labels
271 ctx.set_fill_style_str("#888888");
272 ctx.set_font("12px monospace");
273 let _ = ctx.fill_text("Label", 100.0, 100.0);
274}
275"##,
276 )
277 .with_related(vec!["wasm-zero-js", "wasm-event-handling"])
278 .with_test_code(
279 r#"#[cfg(all(test, not(target_arch = "wasm32")))]
280mod tests {
281 #[test]
282 fn test_grid_spacing_calculation() {
283 let width = 800.0_f64;
284 let divisions = 10;
285 let spacing = width / (divisions as f64);
286 assert_eq!(spacing, 80.0);
287 }
288
289 #[test]
290 fn test_trail_alpha_fade() {
291 let trail_len = 10;
292 let index = 5;
293 let alpha = (index as f64) / (trail_len as f64) * 0.5;
294 assert!((alpha - 0.25).abs() < 0.001);
295 }
296
297 #[test]
298 fn test_trail_data_structure() {
299 let mut trail: Vec<(f64, f64)> = Vec::new();
300 trail.push((100.0, 200.0));
301 trail.push((150.0, 250.0));
302 assert_eq!(trail.len(), 2);
303 }
304}"#,
305 ),
306 );
307}
308
309fn register_ml_recipes(cookbook: &mut super::Cookbook) {
314 cookbook.add(
316 Recipe::new("ml-random-forest", "Random Forest Classification")
317 .with_problem("Train a random forest classifier and export for serving")
318 .with_components(vec!["aprender", "realizar", "alimentar"])
319 .with_tags(vec!["ml", "classification", "random-forest", "supervised"])
320 .with_code(
321 r#"use aprender::prelude::*;
322use alimentar::CsvReader;
323
324// Load data
325let data = CsvReader::from_path("data.csv")?.load()?;
326let (X, y) = data.split_target("label")?;
327
328// Train-test split
329let (X_train, X_test, y_train, y_test) = train_test_split(&X, &y, 0.2, Some(42))?;
330
331// Train model
332let model = RandomForestClassifier::new()
333 .n_estimators(100)
334 .max_depth(Some(10))
335 .min_samples_split(5)
336 .fit(&X_train, &y_train)?;
337
338// Evaluate
339let predictions = model.predict(&X_test)?;
340let accuracy = accuracy_score(&y_test, &predictions);
341println!("Accuracy: {:.2}%", accuracy * 100.0);
342
343// Export for serving
344model.save_apr("model.apr")?;
345
346// Load in realizar for inference
347// realizar serve --model model.apr --port 8080
348"#,
349 )
350 .with_related(vec!["ml-serving", "ml-preprocessing"])
351 .with_test_code(
352 r#"#[cfg(test)]
353mod tests {
354 #[test]
355 fn test_random_forest_builder_config() {
356 let n_estimators = 100;
357 let max_depth = Some(10);
358 assert_eq!(n_estimators, 100);
359 assert!(max_depth.expect("unexpected failure") > 0);
360 }
361
362 #[test]
363 fn test_predictions_collection() {
364 let predictions = vec![0, 1, 1, 0, 1];
365 assert_eq!(predictions.len(), 5);
366 }
367
368 #[test]
369 fn test_accuracy_in_range() {
370 let correct = 85;
371 let total = 100;
372 let accuracy = correct as f64 / total as f64;
373 assert!(accuracy >= 0.0 && accuracy <= 1.0);
374 }
375}"#,
376 ),
377 );
378
379 cookbook.add(
381 Recipe::new("ml-serving", "Model Serving with Realizar")
382 .with_problem("Deploy trained models as HTTP API or Lambda function")
383 .with_components(vec!["realizar", "aprender"])
384 .with_tags(vec!["ml", "serving", "inference", "api", "lambda"])
385 .with_code(
386 r#"// Command line serving
387// realizar serve --model model.apr --port 8080
388
389// Programmatic serving
390use realizar::prelude::*;
391
392let model = Model::load("model.apr")?;
393let server = Server::new(model)
394 .port(8080)
395 .batch_size(32)
396 .workers(4);
397
398server.run()?;
399
400// Lambda deployment
401// realizar package --model model.apr --output lambda.zip
402// aws lambda create-function --function-name my-model \
403// --runtime provided.al2 --handler bootstrap \
404// --zip-file fileb://lambda.zip
405
406// Request format
407// POST /predict
408// Content-Type: application/json
409// {"features": [1.0, 2.0, 3.0, 4.0]}
410"#,
411 )
412 .with_related(vec!["ml-random-forest", "distributed-inference"])
413 .with_test_code(
414 r"#[cfg(test)]
415mod tests {
416 #[test]
417 fn test_server_config_port() {
418 let port = 8080_u16;
419 assert!(port >= 1024);
420 }
421
422 #[test]
423 fn test_server_config_batch_and_workers() {
424 let batch_size = 32;
425 let workers = 4;
426 assert_eq!(batch_size, 32);
427 assert_eq!(workers, 4);
428 }
429
430 #[test]
431 fn test_feature_vector_format() {
432 let features: Vec<f32> = vec![1.0, 2.5, 3.7, 4.2];
433 assert_eq!(features.len(), 4);
434 }
435}",
436 ),
437 );
438}
439
440fn register_transpilation_recipes(cookbook: &mut super::Cookbook) {
445 cookbook.add(
447 Recipe::new("transpile-python", "Python to Rust Migration")
448 .with_problem("Convert Python ML code to Rust using depyler")
449 .with_components(vec!["depyler", "aprender", "trueno", "batuta"])
450 .with_tags(vec!["transpilation", "python", "migration"])
451 .with_code(
452 r"# Original Python code (sklearn_model.py)
453from sklearn.ensemble import RandomForestClassifier
454from sklearn.model_selection import train_test_split
455import numpy as np
456
457X = np.random.rand(100, 4)
458y = np.random.randint(0, 2, 100)
459
460X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
461model = RandomForestClassifier(n_estimators=100)
462model.fit(X_train, y_train)
463
464# Transpile with depyler
465# batuta transpile sklearn_model.py --output src/model.rs
466
467// Generated Rust code (src/model.rs)
468use aprender::prelude::*;
469use trueno::prelude::*;
470
471fn main() -> Result<(), Box<dyn std::error::Error>> {
472 let X = Tensor::rand(&[100, 4]);
473 let y = Tensor::randint(0, 2, &[100]);
474
475 let (X_train, X_test, y_train, y_test) = train_test_split(&X, &y, 0.2, None)?;
476 let model = RandomForestClassifier::new()
477 .n_estimators(100)
478 .fit(&X_train, &y_train)?;
479
480 Ok(())
481}
482",
483 )
484 .with_related(vec!["transpile-numpy", "quality-golden-trace"])
485 .with_test_code(
486 r"#[cfg(test)]
487mod tests {
488 #[test]
489 fn test_tensor_shape() {
490 let rows = 100;
491 let cols = 4;
492 let total_elements = rows * cols;
493 assert_eq!(total_elements, 400);
494 }
495
496 #[test]
497 fn test_train_test_split_ratio() {
498 let total = 100;
499 let train_ratio = 0.8;
500 let train_size = (total as f64 * train_ratio) as usize;
501 assert_eq!(train_size, 80);
502 }
503
504 #[test]
505 fn test_label_values_binary() {
506 let labels = vec![0, 1, 1, 0, 1];
507 assert!(labels.iter().all(|&l| l == 0 || l == 1));
508 }
509}",
510 ),
511 );
512
513 cookbook.add(
515 Recipe::new("transpile-numpy", "NumPy to Trueno Conversion")
516 .with_problem("Convert NumPy operations to SIMD-accelerated Trueno")
517 .with_components(vec!["depyler", "trueno"])
518 .with_tags(vec!["transpilation", "numpy", "simd", "tensors"])
519 .with_code(
520 r"# Python NumPy
521import numpy as np
522a = np.array([1, 2, 3, 4])
523b = np.array([5, 6, 7, 8])
524dot = np.dot(a, b)
525matmul = np.matmul(X, W)
526
527// Rust Trueno (SIMD-accelerated)
528use trueno::prelude::*;
529
530let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
531let b = Tensor::from_vec(vec![5.0, 6.0, 7.0, 8.0]);
532let dot = a.dot(&b); // SIMD auto-vectorized
533let matmul = X.matmul(&W); // GPU if available
534",
535 )
536 .with_related(vec!["transpile-python"])
537 .with_test_code(
538 r"#[cfg(test)]
539mod tests {
540 #[test]
541 fn test_vector_creation() {
542 let a = vec![1.0, 2.0, 3.0, 4.0];
543 let b = vec![5.0, 6.0, 7.0, 8.0];
544 assert_eq!(a.len(), b.len());
545 }
546
547 #[test]
548 fn test_dot_product_computation() {
549 let a = vec![1.0, 2.0, 3.0, 4.0];
550 let b = vec![5.0, 6.0, 7.0, 8.0];
551 let dot: f64 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
552 assert_eq!(dot, 70.0);
553 }
554
555 #[test]
556 fn test_simd_element_type() {
557 let vec: Vec<f64> = vec![1.0, 2.0, 3.0];
558 assert!(vec.iter().all(|x| x.is_finite()));
559 }
560}",
561 ),
562 );
563}
564
565fn register_distributed_recipes(cookbook: &mut super::Cookbook) {
570 cookbook.add(
572 Recipe::new("distributed-work-stealing", "Work-Stealing Task Distribution")
573 .with_problem("Distribute computation across CPU cores with work-stealing")
574 .with_components(vec!["repartir", "trueno"])
575 .with_tags(vec!["distributed", "parallel", "work-stealing", "cpu"])
576 .with_code(
577 r"use repartir::prelude::*;
578
579// Create pool with work-stealing scheduler
580let pool = Pool::builder()
581 .num_workers(num_cpus::get())
582 .build()?;
583
584// Submit tasks
585let results: Vec<f64> = pool.map(data.chunks(1000), |chunk| {
586 // Each chunk processed by a worker
587 chunk.iter().map(|x| x * x).sum()
588})?;
589
590// Reduce results
591let total: f64 = results.iter().sum();
592",
593 )
594 .with_related(vec!["distributed-gpu", "distributed-remote"])
595 .with_test_code(
596 r"#[cfg(test)]
597mod tests {
598 #[test]
599 fn test_pool_worker_count() {
600 let workers = 8;
601 assert!(workers > 0);
602 }
603
604 #[test]
605 fn test_chunk_processing() {
606 let data = vec![1, 2, 3, 4, 5];
607 let chunks: Vec<_> = data.chunks(2).collect();
608 assert_eq!(chunks.len(), 3);
609 }
610
611 #[test]
612 fn test_result_reduction() {
613 let results = vec![10.0, 20.0, 30.0, 40.0];
614 let total: f64 = results.iter().sum();
615 assert_eq!(total, 100.0);
616 }
617}",
618 ),
619 );
620
621 cookbook.add(
623 Recipe::new("distributed-gpu", "GPU Compute Distribution")
624 .with_problem("Offload computation to GPU using wgpu")
625 .with_components(vec!["repartir", "trueno"])
626 .with_tags(vec!["distributed", "gpu", "wgpu", "compute"])
627 .with_code(
628 r"use repartir::prelude::*;
629use trueno::prelude::*;
630
631// Create GPU executor
632let executor = GpuExecutor::new()?;
633
634// GPU-accelerated matrix multiplication
635let result = executor.submit(|gpu| {
636 let a = gpu.tensor(&matrix_a)?;
637 let b = gpu.tensor(&matrix_b)?;
638 a.matmul(&b)
639})?;
640
641// Hybrid CPU/GPU
642let pool = Pool::builder()
643 .add_gpu_executor(executor)
644 .add_cpu_executor(CpuExecutor::new())
645 .build()?;
646",
647 )
648 .with_related(vec!["distributed-work-stealing"])
649 .with_test_code(
650 r"#[cfg(test)]
651mod tests {
652 #[test]
653 fn test_matrix_dimensions_valid() {
654 let m = 1024;
655 let k = 512;
656 let n = 2048;
657 assert!(m > 0 && k > 0 && n > 0);
658 }
659
660 #[test]
661 fn test_hybrid_pool_worker_total() {
662 let cpu_workers = 4;
663 let gpu_workers = 2;
664 let total = cpu_workers + gpu_workers;
665 assert_eq!(total, 6);
666 }
667
668 #[test]
669 fn test_matmul_output_shape() {
670 let rows_a = 128;
671 let cols_b = 256;
672 let output_elements = rows_a * cols_b;
673 assert_eq!(output_elements, 32768);
674 }
675}",
676 ),
677 );
678}
679
680fn register_quality_recipes(cookbook: &mut super::Cookbook) {
685 cookbook.add(
687 Recipe::new("quality-edd", "Equation-Driven Development")
688 .with_problem("Implement simulations with verifiable governing equations")
689 .with_components(vec!["simular", "probar", "certeza"])
690 .with_tags(vec!["quality", "testing", "edd", "simulation", "falsification"])
691 .with_code(
692 r"use simular::prelude::*;
693
694/// EDD Demo following the complete cycle:
695/// 1. Equation - Define governing equation
696/// 2. Failing Test - Test fails without implementation
697/// 3. Implementation - Implement the simulation
698/// 4. Verification - Test passes, equation verified
699/// 5. Falsification - Demonstrate conditions that break
700
701pub trait DemoEngine {
702 /// Load from YAML configuration (YAML-first)
703 fn from_yaml(yaml: &str) -> Result<Self, DemoError> where Self: Sized;
704
705 /// Advance simulation by one timestep
706 fn step(&mut self, dt: f64) -> StepResult;
707
708 /// Verify governing equation invariants
709 fn verify_invariants(&self) -> bool;
710
711 /// Get falsification status
712 fn falsification_status(&self) -> FalsificationStatus;
713}
714
715// Example: Harmonic Oscillator
716// Governing equation: E = (1/2)kx² + (1/2)mv²
717// Falsification: Energy drift > tolerance indicates integrator failure
718
719impl DemoEngine for HarmonicOscillator {
720 fn verify_invariants(&self) -> bool {
721 let energy = self.kinetic_energy() + self.potential_energy();
722 let error = (energy - self.initial_energy).abs() / self.initial_energy;
723 error < 1e-9 // Energy conservation within tolerance
724 }
725}
726",
727 )
728 .with_related(vec!["quality-probar", "quality-golden-trace"])
729 .with_test_code(
730 r"#[cfg(test)]
731mod tests {
732 #[test]
733 fn test_energy_conservation_invariant() {
734 let kinetic = 60.0;
735 let potential = 40.0;
736 let initial_energy = 100.0;
737 assert!((kinetic + potential - initial_energy).abs() < 1e-6);
738 }
739
740 #[test]
741 fn test_timestep_positivity() {
742 let dt = 0.01_f64;
743 assert!(dt > 0.0);
744 }
745
746 #[test]
747 fn test_falsification_detection() {
748 let tolerance = 1e-9_f64;
749 let error = 1e-5;
750 assert!(error > tolerance);
751 }
752}",
753 ),
754 );
755
756 cookbook.add(
758 Recipe::new("quality-probar", "Probar Property-Based Testing")
759 .with_problem("Validate WASM demos with property-based and GUI coverage testing")
760 .with_components(vec!["probar", "simular", "certeza"])
761 .with_tags(vec!["quality", "testing", "probar", "property-testing", "gui-coverage"])
762 .with_code(
763 r#"use probar::prelude::*;
764
765// Property-based tests
766#[probar::property]
767fn prop_tour_length_positive(cities: Vec<City>) -> bool {
768 let tour = solve_tsp(&cities);
769 tour.length() > 0.0
770}
771
772#[probar::property]
773fn prop_energy_conserved(dt: f64) -> bool {
774 let mut sim = OrbitSimulation::new();
775 let e0 = sim.total_energy();
776 sim.step(dt);
777 let e1 = sim.total_energy();
778 (e1 - e0).abs() / e0.abs() < 1e-9
779}
780
781// Metamorphic relations
782#[probar::metamorphic]
783fn mr_scale_invariance(scale: f64, cities: Vec<City>) {
784 let tour1 = solve_tsp(&cities);
785 let scaled = cities.iter().map(|c| c * scale).collect();
786 let tour2 = solve_tsp(&scaled);
787 assert!((tour2.length() / tour1.length() - scale).abs() < 1e-6);
788}
789
790// GUI coverage
791#[probar::gui_coverage]
792fn test_canvas_coverage(app: &mut App) {
793 app.click_button("start");
794 app.wait_frames(100);
795 let coverage = app.pixel_coverage();
796 assert!(coverage > 0.8, "Must render to >80% of canvas");
797}
798"#,
799 )
800 .with_related(vec!["quality-edd", "quality-certeza"])
801 .with_test_code(
802 r"#[cfg(test)]
803mod tests {
804 #[test]
805 fn test_tour_length_positivity() {
806 let distances = vec![10.5, 20.3, 15.7, 8.2];
807 let tour_length: f64 = distances.iter().sum();
808 assert!(tour_length > 0.0);
809 }
810
811 #[test]
812 fn test_energy_conservation_property() {
813 let initial = 100.0_f64;
814 let final_energy = 100.0_f64;
815 assert!((initial - final_energy).abs() < 1e-10);
816 }
817
818 #[test]
819 fn test_coverage_threshold() {
820 let covered = 950;
821 let total = 1000;
822 let coverage = covered as f64 / total as f64;
823 assert!(coverage >= 0.95);
824 }
825}",
826 ),
827 );
828
829 cookbook.add(
831 Recipe::new("quality-golden-trace", "Golden Trace Validation")
832 .with_problem("Validate transpiled code produces identical behavior to original")
833 .with_components(vec!["renacer", "certeza"])
834 .with_tags(vec!["quality", "validation", "trace", "transpilation"])
835 .with_code(
836 r#"use renacer::prelude::*;
837
838// Capture golden trace from Python
839// renacer trace python sklearn_model.py --output golden.trace
840
841// Capture Rust trace
842// renacer trace ./target/release/model --output rust.trace
843
844// Compare traces
845let comparison = renacer::compare("golden.trace", "rust.trace")?;
846
847assert!(comparison.semantically_equivalent(),
848 "Transpiled code must produce identical results");
849assert!(comparison.syscall_compatible(),
850 "System calls must match (file I/O, network, etc.)");
851
852// Performance comparison
853println!("Python: {:.2}ms", comparison.baseline_time_ms());
854println!("Rust: {:.2}ms", comparison.target_time_ms());
855println!("Speedup: {:.1}x", comparison.speedup());
856"#,
857 )
858 .with_related(vec!["transpile-python", "quality-edd"])
859 .with_test_code(
860 r#"#[cfg(test)]
861mod tests {
862 #[test]
863 fn test_semantic_equivalence_check() {
864 let baseline = vec![1.0, 2.0, 3.0];
865 let candidate = vec![1.0, 2.0, 3.0];
866 assert_eq!(baseline, candidate);
867 }
868
869 #[test]
870 fn test_speedup_calculation() {
871 let baseline_ms = 1000.0_f64;
872 let optimized_ms = 250.0_f64;
873 let speedup = baseline_ms / optimized_ms;
874 assert_eq!(speedup, 4.0);
875 }
876
877 #[test]
878 fn test_trace_comparison_length() {
879 let golden = vec!["step1", "step2", "step3"];
880 let actual = vec!["step1", "step2", "step3"];
881 assert_eq!(golden.len(), actual.len());
882 }
883}"#,
884 ),
885 );
886}
887
888fn register_speech_recipes(cookbook: &mut super::Cookbook) {
893 cookbook.add(
895 Recipe::new("speech-whisper", "Whisper Speech Recognition")
896 .with_problem("Transcribe audio to text using pure-Rust Whisper implementation")
897 .with_components(vec!["whisper-apr", "aprender", "trueno"])
898 .with_tags(vec!["speech", "asr", "whisper", "transcription", "wasm"])
899 .with_code(
900 r#"use whisper_apr::prelude::*;
901
902// Load model (downloads from HuggingFace on first run)
903let model = WhisperModel::load("tiny.en")?;
904
905// Transcribe audio file
906let audio = Audio::load("recording.wav")?;
907let result = model.transcribe(&audio)?;
908
909println!("Transcription: {}", result.text);
910
911// With timestamps
912for segment in result.segments {
913 println!("[{:.2}s - {:.2}s] {}",
914 segment.start, segment.end, segment.text);
915}
916
917// Streaming transcription (real-time)
918let mut stream = model.stream()?;
919for chunk in audio_chunks {
920 if let Some(text) = stream.process(&chunk)? {
921 print!("{}", text);
922 }
923}
924
925// WASM deployment
926// wasm-pack build --target web --features wasm
927// <script type="module">
928// import init, { transcribe } from './pkg/whisper_apr.js';
929// await init();
930// const text = await transcribe(audioBuffer);
931// </script>
932"#,
933 )
934 .with_related(vec!["speech-streaming", "ml-serving"])
935 .with_test_code(
936 r#"#[cfg(test)]
937mod tests {
938 #[test]
939 fn test_model_name_validation() {
940 let model = "tiny.en";
941 let valid = vec!["tiny", "tiny.en", "base", "base.en"];
942 assert!(valid.contains(&model));
943 }
944
945 #[test]
946 fn test_transcription_result_non_empty() {
947 let text = "Hello world";
948 assert!(!text.is_empty());
949 }
950
951 #[test]
952 fn test_segment_timestamp_ordering() {
953 let start = 0.5_f64;
954 let end = 2.0_f64;
955 assert!(start < end);
956 }
957}"#,
958 ),
959 );
960
961 cookbook.add(
963 Recipe::new("speech-streaming", "Real-time Speech Streaming")
964 .with_problem("Process audio in real-time with low latency")
965 .with_components(vec!["whisper-apr", "trueno"])
966 .with_tags(vec!["speech", "streaming", "real-time", "low-latency"])
967 .with_code(
968 r#"use whisper_apr::streaming::*;
969
970// Configure streaming decoder
971let config = StreamConfig {
972 chunk_size_ms: 500, // Process every 500ms
973 overlap_ms: 100, // Overlap for continuity
974 vad_enabled: true, // Voice activity detection
975 language: Some("en"),
976};
977
978let mut decoder = StreamingDecoder::new(model, config)?;
979
980// Process microphone input
981let mut mic = Microphone::open()?;
982loop {
983 let samples = mic.read_chunk()?;
984
985 // VAD filters silence
986 if let Some(result) = decoder.process(&samples)? {
987 // Partial results for UI feedback
988 if result.is_partial {
989 print!("\r{}", result.text);
990 } else {
991 println!("\n[Final] {}", result.text);
992 }
993 }
994}
995"#,
996 )
997 .with_related(vec!["speech-whisper"])
998 .with_test_code(
999 r"#[cfg(test)]
1000mod tests {
1001 #[test]
1002 fn test_stream_config_chunk_size_positive() {
1003 let chunk_size_ms = 500_u32;
1004 assert!(chunk_size_ms > 0);
1005 }
1006
1007 #[test]
1008 fn test_overlap_less_than_chunk_size() {
1009 let chunk_size_ms = 500;
1010 let overlap_ms = 100;
1011 assert!(overlap_ms < chunk_size_ms);
1012 }
1013
1014 #[test]
1015 fn test_vad_enabled_flag() {
1016 let vad_enabled = true;
1017 assert!(vad_enabled);
1018 }
1019}",
1020 ),
1021 );
1022}
1023
1024