#[cfg(not(feature = "std"))]
compile_error!("asimov-openai-prompter requires the 'std' feature");
use asimov_module::SysexitsError::{self, *};
use asimov_module::tracing;
use clap::Parser;
use clientele::StandardOptions;
use std::{error::Error, io::Read};
#[derive(Debug, Parser)]
struct Options {
#[clap(flatten)]
flags: StandardOptions,
#[clap(long, short = 'm')]
model: Option<String>,
input: Option<String>,
output: Option<String>,
}
pub fn main() -> Result<SysexitsError, Box<dyn Error>> {
asimov_module::dotenv().ok();
let args = asimov_module::args_os()?;
let options = Options::parse_from(args);
if options.flags.version {
println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
return Ok(EX_OK);
}
if options.flags.license {
print!("{}", include_str!("../../UNLICENSE"));
return Ok(EX_OK);
}
let Ok(manifest) = asimov_module::ModuleManifest::read_manifest("openai")
.inspect_err(|e| eprintln!("failed to read module manifest: {e}"))
else {
return Ok(EX_CONFIG);
};
let Ok(api_key) = manifest
.variable("api-key", None)
.inspect_err(|e| eprintln!("failed to read configured API key: {e}"))
else {
return Ok(EX_CONFIG); };
let Ok(endpoint) = manifest
.variable("endpoint", None)
.inspect_err(|e| eprintln!("failed to read configured endpoint: {e}"))
else {
return Ok(EX_CONFIG); };
let Some(model) = options.model.or_else(|| {
manifest
.variable("model", None)
.inspect_err(|e| eprintln!("failed to read configured model: {e}"))
.ok()
}) else {
return Ok(EX_CONFIG); };
#[cfg(feature = "tracing")]
asimov_module::init_tracing_subscriber(&options.flags).expect("failed to initialize logging");
let input = if let Some(input) = options.input {
let file = std::path::Path::new(&input);
std::fs::read_to_string(file)
.inspect_err(|e| tracing::error!("unable to read input file: {e}"))?
} else {
let mut buf = String::new();
std::io::stdin()
.read_to_string(&mut buf)
.inspect_err(|e| tracing::error!("unable to read STDIN: {e}"))?;
buf.trim().to_string()
};
let mut output: Box<dyn std::io::Write> = if let Some(output) = options.output {
let file = std::path::Path::new(&output);
let out = std::fs::File::create(file)
.inspect_err(|e| tracing::error!("unable to open output file: {e}"))?;
Box::new(out)
} else {
let out = std::io::stdout().lock();
Box::new(out)
};
let options = asimov_openai_module::Options::builder()
.endpoint(endpoint)
.model(model)
.api_key(api_key)
.build();
let response = asimov_openai_module::generate(&input, &options)?;
for text in response {
output.write_all(text.as_bytes()).unwrap();
}
Ok(EX_OK)
}