use std::path::Path;
use rmcp::handler::server::wrapper::Parameters;
use rmcp::model::{CallToolResult, ContentBlock, ErrorData};
use rmcp::{tool, tool_router};
use crate::engine::{ReadOptions, Reader};
use super::types::ReadTextRequest;
#[derive(Clone)]
pub struct SceptreServer {
reader: Reader,
}
impl SceptreServer {
pub fn new(reader: Reader) -> Self {
Self { reader }
}
}
#[tool_router(vis = "pub(crate)")]
impl SceptreServer {
#[tool(description = "Run CRAFT+CRNN OCR over an image file and return the recognized \
text lines with their bounding boxes and confidences.")]
pub async fn readtext(&self, Parameters(req): Parameters<ReadTextRequest>) -> Result<CallToolResult, ErrorData> {
let detail = req.detail.unwrap_or(true);
match self
.reader
.readtext(Path::new(&req.image_path), &ReadOptions { detail })
{
Ok(result) => Ok(CallToolResult::structured(tool_payload(&result, detail)?)),
Err(ocr_error) => Ok(CallToolResult::error(vec![ContentBlock::text(format!(
"OCR failed: {ocr_error}"
))])),
}
}
}
fn tool_payload(result: &crate::OcrResult, detail: bool) -> Result<rmcp::serde_json::Value, ErrorData> {
if detail {
rmcp::serde_json::to_value(result).map_err(|error| ErrorData::internal_error(error.to_string(), None))
} else {
let lines: Vec<&str> = result.lines.iter().map(|line| line.text.as_str()).collect();
Ok(rmcp::serde_json::json!({ "lines": lines }))
}
}