use std::{fs, path::Path, time::Duration};
use anyhow::Result;
use reqwest::blocking::{Client, multipart};
use serde::{Deserialize, Serialize};
use crate::{
cli::EvalArgs, config::ResolvedConfig, generator::prepare_upload, service::endpoint_url,
};
pub fn evaluate(input: &Path, args: &EvalArgs, config: &ResolvedConfig) -> Result<i32> {
if !input.exists() {
eprintln!("error: input does not exist: {}", input.display());
return Ok(2);
}
let upload_path = match prepare_upload(input) {
Ok(path) => path,
Err(e) => {
eprintln!("error: failed to prepare upload: {:#}", e);
return Ok(2);
}
};
let client = match Client::builder()
.timeout(Duration::from_secs(config.timeout_seconds))
.build()
{
Ok(c) => c,
Err(e) => {
eprintln!("error: failed to build HTTP client: {:#}", e);
return Ok(2);
}
};
let upload_name = upload_path
.file_name()
.and_then(|name| name.to_str())
.unwrap_or("model.zip")
.to_string();
let file_bytes = match fs::read(&upload_path) {
Ok(b) => b,
Err(e) => {
eprintln!(
"error: failed to read upload file {}: {:#}",
upload_path.display(),
e
);
if upload_path != input {
let _ = fs::remove_file(&upload_path);
}
return Ok(2);
}
};
let file_part = multipart::Part::bytes(file_bytes).file_name(upload_name);
let form = multipart::Form::new().part("file", file_part);
let request_url = endpoint_url(&config.endpoint_prefix, "evaluate");
let response = match client.post(&request_url).multipart(form).send() {
Ok(res) => res,
Err(e) => {
eprintln!("error: request to {} failed: {:#}", request_url, e);
if upload_path != input {
let _ = fs::remove_file(&upload_path);
}
return Ok(2);
}
};
if upload_path != input {
let _ = fs::remove_file(&upload_path);
}
let status = response.status();
if status == reqwest::StatusCode::NOT_FOUND {
eprintln!(
"Server does not support /evaluate. Please upgrade the TeaQL generator server or \
use a server URL that supports KSML evaluation."
);
return Ok(2);
}
if !status.is_success() {
eprintln!("error: server returned HTTP {} for {}", status, request_url);
return Ok(2);
}
let response_text = match response.text() {
Ok(t) => t,
Err(e) => {
eprintln!("error: failed to read response text: {:#}", e);
return Ok(2);
}
};
if let Some(ref out_path) = args.output {
if let Some(parent) = out_path.parent() {
let _ = fs::create_dir_all(parent);
}
if let Err(e) = fs::write(out_path, &response_text) {
eprintln!(
"warning: failed to write output file {}: {:#}",
out_path.display(),
e
);
}
}
println!("{}", response_text);
let mut exit_code = 0;
if response_text.contains("## ❌ Errors") {
exit_code = 1;
} else if response_text.contains("## ⚠️ Warnings") && args.fail_on_warning {
exit_code = 1;
}
Ok(exit_code)
}