mod cli;
mod git;
mod llms;
mod utils;
use anyhow::Result;
use clap::Parser;
use dotenvy;
use git2::Repository;
use std::path::PathBuf;
use toml;
use crate::llms::gemini;
#[derive(Debug)]
struct AppConfig {
max_commit_depth: usize,
output_dir: PathBuf,
}
#[tokio::main]
async fn main() -> Result<()> {
dotenvy::dotenv()?;
let cli_args = cli::CliOptions::parse();
match cli_args.choice {
cli::Choice::Generate { config_file } => {
let repo = Repository::open(&cli_args.project_path)?;
let (app_config, llm_config) = utils::parse_gitory_config_file(&config_file)?;
let app_config = {
let output_dir = match app_config.get("output_dir") {
Some(output_dir) => {
let dir = &cli_args.project_path;
dir.join(output_dir.as_str().unwrap()).to_owned()
}
None => {
let dir = &cli_args.project_path;
dir.join("gitory").to_owned()
}
};
let max_commit_depth = if output_dir.exists() {
match app_config.get("max_commit_depth") {
Some(max_commit_depth) => match max_commit_depth.as_integer() {
Some(max_commit_depth) => max_commit_depth as usize,
None => 2,
},
None => 2,
}
} else {
std::fs::create_dir_all(&output_dir)?;
10
};
AppConfig {
max_commit_depth,
output_dir,
}
};
let (api_config, generation_config) =
if llm_config["provider"] == toml::Value::String("google_gemini".to_string()) {
let api_config = &llm_config["api_config"];
let generation_config = &llm_config.get("generation_config");
utils::load_llm_configs_for_gemini(api_config, generation_config)?
} else {
return Err(anyhow::anyhow!("Unsupported `provider`"));
};
let (parent_oid, merged_oid) = git::get_commit_oid(&repo, app_config.max_commit_depth)?;
let commit_diff = git::get_commit_diff(&repo, &parent_oid, &merged_oid)?;
let (from_timestamp, to_timestamp) =
git::get_commit_timestamps(&repo, &parent_oid, &merged_oid)?;
let response =
gemini::sdk::generate_text_from_text(&commit_diff, &api_config, generation_config)
.await?;
write_response_to_file(
response,
from_timestamp,
to_timestamp,
&app_config.output_dir,
)?;
}
};
Ok(())
}
fn write_response_to_file(
response: Vec<String>,
from: chrono::DateTime<chrono::Utc>,
to: chrono::DateTime<chrono::Utc>,
output_dir: &PathBuf,
) -> Result<()> {
let file_name = format!(
"{}_to_{}.md",
from.format("%Y-%m-%d"),
to.format("%Y-%m-%d")
);
let title_string = format!("## {} - {}", from.to_string(), to.to_string());
let response_string = response.join("\n");
let data = format!("{}\n\n{}", title_string, response_string);
std::fs::write(output_dir.join(file_name), data).expect("Unable to write file");
Ok(())
}