use async_trait::async_trait;
use serde::{Deserialize, Serialize};
#[derive(Debug, thiserror::Error)]
pub enum EvalError {
#[error("IO 错误: {0}")]
IoError(String),
#[error("解析错误: {0}")]
ParseError(String),
#[error("嵌入错误: {0}")]
EmbeddingError(String),
#[error("预测错误: {0}")]
PredictorError(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Score {
pub value: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}
impl Score {
pub fn new(value: f64) -> Self {
Self {
value: value.clamp(0.0, 1.0),
label: None,
}
}
pub fn with_label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Example {
pub input: String,
pub reference: String,
}
impl Example {
pub fn new(input: impl Into<String>, reference: impl Into<String>) -> Self {
Self {
input: input.into(),
reference: reference.into(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dataset {
pub examples: Vec<Example>,
}
impl Dataset {
pub fn new(examples: Vec<Example>) -> Self {
Self { examples }
}
pub fn from_jsonl(path: &str) -> Result<Self, EvalError> {
let content =
std::fs::read_to_string(path).map_err(|e| EvalError::IoError(e.to_string()))?;
let mut examples = Vec::new();
for (i, line) in content.lines().enumerate() {
let line = line.trim();
if line.is_empty() {
continue;
}
let ex: Example = serde_json::from_str(line)
.map_err(|e| EvalError::ParseError(format!("第 {} 行: {}", i + 1, e)))?;
examples.push(ex);
}
Ok(Self { examples })
}
pub fn len(&self) -> usize {
self.examples.len()
}
pub fn is_empty(&self) -> bool {
self.examples.is_empty()
}
}
#[async_trait]
pub trait Evaluator: Send + Sync {
async fn eval(
&self,
input: &str,
prediction: &str,
reference: &str,
) -> Result<Score, EvalError>;
fn name(&self) -> &str;
}
#[async_trait]
pub trait Predictor: Send + Sync {
async fn predict(&self, input: &str) -> Result<String, EvalError>;
}