use std::path::PathBuf;
use lindera::LinderaResult;
use lindera::error::LinderaErrorKind;
use lindera_cli::get_version;
use super::io_err;
#[derive(Debug, clap::Args)]
#[clap(
author,
about = "Export dictionary files from trained model",
version = get_version(),
)]
pub struct ExportArgs {
#[clap(
short = 'm',
long = "model",
required = true,
help = "Trained model file (.dat format)"
)]
model: PathBuf,
#[clap(
short = 'o',
long = "output",
required = true,
help = "Output directory (creates lex.csv, matrix.def, unk.def, char.def, feature.def, rewrite.def)"
)]
output: PathBuf,
#[clap(
long = "metadata",
help = "Base metadata.json file to update with trained model values"
)]
metadata: Option<PathBuf>,
#[clap(
long = "cost-factor",
help = "Override cost factor for weight-to-cost conversion (default: value from trained model, typically 700)"
)]
cost_factor: Option<i32>,
}
pub fn export(args: ExportArgs) -> LinderaResult<()> {
use lindera::dictionary::trainer::SerializableModel;
use std::fs::{self, File};
let model_file = File::open(&args.model).map_err(io_err)?;
let mut model: SerializableModel =
lindera::dictionary::trainer::model::Model::read_model(model_file)
.map_err(|err| LinderaErrorKind::Deserialize.with_error(anyhow::anyhow!(err)))?;
if let Some(cost_factor) = args.cost_factor {
model.cost_factor = cost_factor;
}
fs::create_dir_all(&args.output).map_err(io_err)?;
let lexicon_path = args.output.join("lex.csv");
let connector_path = args.output.join("matrix.def");
let unk_path = args.output.join("unk.def");
let char_def_path = args.output.join("char.def");
let feature_def_path = args.output.join("feature.def");
let rewrite_def_path = args.output.join("rewrite.def");
let mut lexicon_file = File::create(&lexicon_path).map_err(io_err)?;
model
.write_lexicon(&mut lexicon_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let mut connector_file = File::create(&connector_path).map_err(io_err)?;
model
.write_connection_costs(&mut connector_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let mut unk_file = File::create(&unk_path).map_err(io_err)?;
model
.write_unknown_dictionary(&mut unk_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let mut char_def_file = File::create(&char_def_path).map_err(io_err)?;
model
.write_char_def(&mut char_def_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let mut feature_def_file = File::create(&feature_def_path).map_err(io_err)?;
model
.write_feature_def(&mut feature_def_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let mut rewrite_def_file = File::create(&rewrite_def_path).map_err(io_err)?;
model
.write_rewrite_def(&mut rewrite_def_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let left_id_path = args.output.join("left-id.def");
let mut left_id_file = File::create(&left_id_path).map_err(io_err)?;
model
.write_left_id_def(&mut left_id_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let right_id_path = args.output.join("right-id.def");
let mut right_id_file = File::create(&right_id_path).map_err(io_err)?;
model
.write_right_id_def(&mut right_id_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
let mut files_created = vec![
lexicon_path.clone(),
connector_path.clone(),
unk_path.clone(),
char_def_path.clone(),
feature_def_path.clone(),
rewrite_def_path.clone(),
left_id_path.clone(),
right_id_path.clone(),
];
if let Some(metadata_path) = &args.metadata {
let output_metadata_path = args.output.join("metadata.json");
let mut metadata_file = File::create(&output_metadata_path).map_err(io_err)?;
model
.update_metadata_json(metadata_path, &mut metadata_file)
.map_err(|err| LinderaErrorKind::Io.with_error(err))?;
files_created.push(output_metadata_path);
println!("Updated metadata.json with trained model values");
}
println!("Dictionary files exported to: {:?}", args.output);
println!("Files created:");
for file in &files_created {
println!(" - {file:?}");
}
Ok(())
}