scouter_client/drifter/
llm.rs1use pyo3::prelude::*;
2use scouter_drift::{error::DriftError, LLMEvaluator};
3use scouter_state::app_state;
4use scouter_types::llm::{LLMDriftConfig, LLMDriftMetric, LLMDriftProfile};
5use scouter_types::{LLMMetricRecord, LLMRecord};
6pub struct ClientLLMDrifter {}
8
9impl Default for ClientLLMDrifter {
10 fn default() -> Self {
11 Self::new()
12 }
13}
14
15impl ClientLLMDrifter {
16 pub fn new() -> Self {
17 Self {}
18 }
19
20 pub fn create_drift_profile(
21 &mut self,
22 config: LLMDriftConfig,
23 metrics: Vec<LLMDriftMetric>,
24 workflow: Option<Bound<'_, PyAny>>,
25 ) -> Result<LLMDriftProfile, DriftError> {
26 let profile = LLMDriftProfile::new(config, metrics, workflow)?;
27 Ok(profile)
28 }
29
30 pub async fn compute_drift_single(
31 record: &LLMRecord,
32 profile: &LLMDriftProfile,
33 ) -> Result<Vec<LLMMetricRecord>, DriftError> {
34 let (metrics, _score, _workflow_duration) =
35 LLMEvaluator::process_drift_record(record, profile).await?;
36 Ok(metrics)
37 }
38
39 pub fn compute_drift(
40 &mut self,
41 data: Vec<LLMRecord>,
42 profile: &LLMDriftProfile,
43 ) -> Result<Vec<LLMMetricRecord>, DriftError> {
44 let results = app_state().handle().block_on(async move {
45 let mut results = Vec::new();
46 for record in data {
47 let metrics = Self::compute_drift_single(&record, profile).await?;
48 results.extend(metrics);
49 }
50 Ok::<_, DriftError>(results)
51 })?; Ok(results)
54 }
55}