Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
274
vendor/ruvector/crates/ruvector-tiny-dancer-wasm/src/lib.rs
vendored
Normal file
274
vendor/ruvector/crates/ruvector-tiny-dancer-wasm/src/lib.rs
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
//! WASM bindings for Tiny Dancer neural routing
|
||||
|
||||
use ruvector_tiny_dancer_core::{
|
||||
types::{
|
||||
Candidate as CoreCandidate, RouterConfig as CoreRouterConfig,
|
||||
RoutingRequest as CoreRoutingRequest, RoutingResponse as CoreRoutingResponse,
|
||||
},
|
||||
Router as CoreRouter,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
/// Initialize panic hook for better error messages in WASM
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn init() {
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
console_error_panic_hook::set_once();
|
||||
}
|
||||
|
||||
/// Router configuration for WASM
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone)]
|
||||
pub struct RouterConfig {
|
||||
model_path: String,
|
||||
confidence_threshold: f32,
|
||||
max_uncertainty: f32,
|
||||
enable_circuit_breaker: bool,
|
||||
circuit_breaker_threshold: u32,
|
||||
enable_quantization: bool,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RouterConfig {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
model_path: "./models/fastgrnn.safetensors".to_string(),
|
||||
confidence_threshold: 0.85,
|
||||
max_uncertainty: 0.15,
|
||||
enable_circuit_breaker: true,
|
||||
circuit_breaker_threshold: 5,
|
||||
enable_quantization: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_model_path(&mut self, path: String) {
|
||||
self.model_path = path;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_confidence_threshold(&mut self, threshold: f32) {
|
||||
self.confidence_threshold = threshold;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_max_uncertainty(&mut self, uncertainty: f32) {
|
||||
self.max_uncertainty = uncertainty;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RouterConfig> for CoreRouterConfig {
|
||||
fn from(config: RouterConfig) -> Self {
|
||||
CoreRouterConfig {
|
||||
model_path: config.model_path,
|
||||
confidence_threshold: config.confidence_threshold,
|
||||
max_uncertainty: config.max_uncertainty,
|
||||
enable_circuit_breaker: config.enable_circuit_breaker,
|
||||
circuit_breaker_threshold: config.circuit_breaker_threshold,
|
||||
enable_quantization: config.enable_quantization,
|
||||
database_path: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Candidate for routing
|
||||
#[wasm_bindgen]
|
||||
pub struct Candidate {
|
||||
id: String,
|
||||
embedding: Vec<f32>,
|
||||
metadata: String,
|
||||
created_at: i64,
|
||||
access_count: u64,
|
||||
success_rate: f32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Candidate {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(
|
||||
id: String,
|
||||
embedding: Vec<f32>,
|
||||
metadata: String,
|
||||
created_at: i64,
|
||||
access_count: u64,
|
||||
success_rate: f32,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
embedding,
|
||||
metadata,
|
||||
created_at,
|
||||
access_count,
|
||||
success_rate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Candidate> for CoreCandidate {
|
||||
type Error = JsValue;
|
||||
|
||||
fn try_from(candidate: Candidate) -> Result<Self, Self::Error> {
|
||||
let metadata: HashMap<String, serde_json::Value> =
|
||||
serde_json::from_str(&candidate.metadata)
|
||||
.map_err(|e| JsValue::from_str(&format!("Invalid metadata: {}", e)))?;
|
||||
|
||||
Ok(CoreCandidate {
|
||||
id: candidate.id,
|
||||
embedding: candidate.embedding,
|
||||
metadata,
|
||||
created_at: candidate.created_at,
|
||||
access_count: candidate.access_count,
|
||||
success_rate: candidate.success_rate,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Routing request
|
||||
#[wasm_bindgen]
|
||||
pub struct RoutingRequest {
|
||||
query_embedding: Vec<f32>,
|
||||
candidates: Vec<Candidate>,
|
||||
metadata: Option<String>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RoutingRequest {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(query_embedding: Vec<f32>, candidates: Vec<Candidate>) -> Self {
|
||||
Self {
|
||||
query_embedding,
|
||||
candidates,
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_metadata(&mut self, metadata: String) {
|
||||
self.metadata = Some(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RoutingRequest> for CoreRoutingRequest {
|
||||
type Error = JsValue;
|
||||
|
||||
fn try_from(request: RoutingRequest) -> Result<Self, Self::Error> {
|
||||
let candidates: Result<Vec<CoreCandidate>, JsValue> = request
|
||||
.candidates
|
||||
.into_iter()
|
||||
.map(|c| c.try_into())
|
||||
.collect();
|
||||
|
||||
let metadata = if let Some(meta_str) = request.metadata {
|
||||
Some(
|
||||
serde_json::from_str(&meta_str)
|
||||
.map_err(|e| JsValue::from_str(&format!("Invalid metadata: {}", e)))?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(CoreRoutingRequest {
|
||||
query_embedding: request.query_embedding,
|
||||
candidates: candidates?,
|
||||
metadata,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Routing response
|
||||
#[wasm_bindgen]
|
||||
pub struct RoutingResponse {
|
||||
decisions_json: String,
|
||||
inference_time_us: u64,
|
||||
candidates_processed: usize,
|
||||
feature_time_us: u64,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RoutingResponse {
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn decisions_json(&self) -> String {
|
||||
self.decisions_json.clone()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn inference_time_us(&self) -> u64 {
|
||||
self.inference_time_us
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn candidates_processed(&self) -> usize {
|
||||
self.candidates_processed
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn feature_time_us(&self) -> u64 {
|
||||
self.feature_time_us
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreRoutingResponse> for RoutingResponse {
|
||||
fn from(response: CoreRoutingResponse) -> Self {
|
||||
let decisions_json = serde_json::to_string(&response.decisions).unwrap_or_default();
|
||||
|
||||
Self {
|
||||
decisions_json,
|
||||
inference_time_us: response.inference_time_us,
|
||||
candidates_processed: response.candidates_processed,
|
||||
feature_time_us: response.feature_time_us,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tiny Dancer router for WASM
|
||||
#[wasm_bindgen]
|
||||
pub struct Router {
|
||||
inner: CoreRouter,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Router {
|
||||
/// Create a new router with configuration
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(config: RouterConfig) -> Result<Router, JsValue> {
|
||||
let core_config: CoreRouterConfig = config.into();
|
||||
let router = CoreRouter::new(core_config)
|
||||
.map_err(|e| JsValue::from_str(&format!("Failed to create router: {}", e)))?;
|
||||
|
||||
Ok(Router { inner: router })
|
||||
}
|
||||
|
||||
/// Route a request
|
||||
pub fn route(&self, request: RoutingRequest) -> Result<RoutingResponse, JsValue> {
|
||||
let core_request: CoreRoutingRequest = request.try_into()?;
|
||||
let core_response = self
|
||||
.inner
|
||||
.route(core_request)
|
||||
.map_err(|e| JsValue::from_str(&format!("Routing failed: {}", e)))?;
|
||||
|
||||
Ok(core_response.into())
|
||||
}
|
||||
|
||||
/// Check circuit breaker status
|
||||
pub fn circuit_breaker_status(&self) -> Option<bool> {
|
||||
self.inner.circuit_breaker_status()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get library version
|
||||
#[wasm_bindgen]
|
||||
pub fn version() -> String {
|
||||
env!("CARGO_PKG_VERSION").to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_version() {
|
||||
assert!(!version().is_empty());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user