tease 0.5.0

Rapidly prototype interfaces for your machine learning models
Documentation
use tease::{Choice, ClassScore, Input, Output, Plot, PlotKind, Preset, Series, Teaser, Value};
#[test]
fn rich_controls_validate_values_and_presets() {
    let fields = vec![
        Input::text("Notes", "", true),
        Input::checkbox("Flag", false),
        Input::MultiSelect {
            label: None,
            options: vec![Choice::text("A", "a"), Choice::text("B", "b")],
            initial_values: vec![],
        },
    ];
    let values = vec![
        Value::Text("🦀\n<literal>".into()),
        Value::Bool(true),
        Value::List(vec![Value::Text("a".into())]),
    ];
    let make = || {
        Teaser::default()
            .with_inputs(fields.clone())
            .with_output(Output::text("Notes"))
            .with_predictor(|v| Ok(vec![v[0].clone()]))
    };
    let session = make()
        .with_presets(vec![Preset::new("Example", values.clone())])
        .prepare()
        .unwrap();
    assert_eq!(session.predict(&values).unwrap()[0], values[0]);
    let mut invalid = values.clone();
    invalid[2] = Value::List(vec![Value::Text("a".into()); 2]);
    assert!(session.predict(&invalid).is_err());
    assert!(make()
        .with_presets(vec![Preset::new("Bad", invalid)])
        .validate()
        .is_err());
    assert!(make()
        .with_presets(vec![Preset::new("Bad count", vec![])])
        .validate()
        .is_err());
    assert!(Teaser::default()
        .with_inputs(vec![Input::checkbox("Flag", false)])
        .validate()
        .is_err());
    assert!(Teaser::default()
        .with_inputs(vec![Input::number("Distance", 2.0)
            .with_unit("m")
            .with_help("Length")])
        .prepare()
        .unwrap()
        .predict(&[Value::Number(3.0)])
        .is_ok());
}
#[test]
fn malformed_rich_results_are_rejected() {
    for points in [vec![], vec![[0.0, f64::NAN]], vec![[0.0, 1e101]]] {
        let value = Value::Plot(Plot {
            kind: PlotKind::Line,
            x_label: "x".into(),
            y_label: "y".into(),
            series: vec![Series {
                name: "test".into(),
                points,
            }],
        });
        let session = Teaser::default()
            .with_output(Output::plot("Plot"))
            .with_predictor(move |_| Ok(vec![value.clone()]))
            .prepare()
            .unwrap();
        assert!(session.predict(&[Value::Number(1.0)]).is_err());
    }
    for scores in [
        vec![],
        vec![ClassScore {
            label: "a".into(),
            score: -0.1,
        }],
        vec![ClassScore {
            label: "a".into(),
            score: 0.4,
        }],
        vec![
            ClassScore {
                label: "a".into(),
                score: 0.5
            };
            2
        ],
    ] {
        let session = Teaser::default()
            .with_output(Output::probabilities("Classes"))
            .with_predictor(move |_| Ok(vec![Value::Scores(scores.clone())]))
            .prepare()
            .unwrap();
        assert!(session.predict(&[Value::Number(1.0)]).is_err());
    }
}
#[test]
fn unicode_length_limits_preserve_empty_text() {
    let session = Teaser::default()
        .with_inputs(vec![Input::Text {
            label: None,
            initial_value: String::new(),
            multiline: true,
            max_length: 2,
        }])
        .with_output(Output::text("Text"))
        .with_predictor(|v| Ok(v.to_vec()))
        .prepare()
        .unwrap();
    for text in ["", "🦀é"] {
        assert!(session.predict(&[Value::Text(text.into())]).is_ok());
    }
    assert!(session.predict(&[Value::Text("abc".into())]).is_err());
}