use std::path::Path;
use anyhow::{Result, anyhow};
use clap::Subcommand;
use mnem_core::id::NodeId;
use super::*;
#[derive(clap::Args, Debug)]
pub(crate) struct EmbeddingArgs {
#[command(subcommand)]
pub cmd: EmbeddingCmd,
}
#[derive(Subcommand, Debug)]
pub(crate) enum EmbeddingCmd {
Get(GetArgs),
Ls(LsArgs),
}
#[derive(clap::Args, Debug)]
pub(crate) struct GetArgs {
pub node_id: String,
pub model: String,
}
#[derive(clap::Args, Debug)]
pub(crate) struct LsArgs {
pub node_id: String,
}
pub(crate) fn run(override_path: Option<&Path>, args: EmbeddingArgs) -> Result<()> {
match args.cmd {
EmbeddingCmd::Get(a) => run_get(override_path, a),
EmbeddingCmd::Ls(a) => run_ls(override_path, a),
}
}
fn run_get(override_path: Option<&Path>, args: GetArgs) -> Result<()> {
let id = NodeId::parse_uuid(&args.node_id).map_err(|e| anyhow!("invalid UUID: {e}"))?;
let (_dir, r, _bs, _ohs) = repo::open_all(override_path)?;
let node = r
.lookup_node(&id)?
.ok_or_else(|| anyhow!("no node with id={}", args.node_id))?;
let (_, node_cid) =
mnem_core::codec::hash_to_cid(&node).map_err(|e| anyhow!("hash node: {e}"))?;
let emb = r.embedding_for(&node_cid, &args.model)?.ok_or_else(|| {
anyhow!(
"no embedding for model={} on node {}",
args.model,
args.node_id
)
})?;
let bytes = emb.vector.as_ref();
let floats: Vec<f32> = bytes
.chunks_exact(4)
.map(|c| f32::from_le_bytes(c.try_into().unwrap()))
.collect();
let line: Vec<String> = floats.iter().map(ToString::to_string).collect();
println!("{}", line.join(" "));
let dtype_str = match emb.dtype {
mnem_core::objects::Dtype::F32 => "f32",
mnem_core::objects::Dtype::F16 => "f16",
mnem_core::objects::Dtype::F64 => "f64",
mnem_core::objects::Dtype::I8 => "i8",
};
eprintln!("model={} dim={} dtype={}", emb.model, emb.dim, dtype_str);
Ok(())
}
fn run_ls(override_path: Option<&Path>, args: LsArgs) -> Result<()> {
let id = NodeId::parse_uuid(&args.node_id).map_err(|e| anyhow!("invalid UUID: {e}"))?;
let (_dir, r, _bs, _ohs) = repo::open_all(override_path)?;
let node = r
.lookup_node(&id)?
.ok_or_else(|| anyhow!("no node with id={}", args.node_id))?;
let (_, node_cid) =
mnem_core::codec::hash_to_cid(&node).map_err(|e| anyhow!("hash node: {e}"))?;
let models = r.embedding_models_for(&node_cid)?;
if models.is_empty() {
anyhow::bail!("no embeddings for node {}", args.node_id);
}
for m in models {
println!("{m}");
}
Ok(())
}