LLM支持优化
This commit is contained in:
@@ -55,6 +55,10 @@ pub struct ChangelogCommand {
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
|
||||
/// Enable thinking mode for this changelog (override config)
|
||||
#[arg(long)]
|
||||
think: bool,
|
||||
|
||||
/// Skip interactive prompts
|
||||
#[arg(short = 'y', long)]
|
||||
yes: bool,
|
||||
@@ -74,8 +78,7 @@ impl ChangelogCommand {
|
||||
|
||||
// Initialize changelog if requested
|
||||
if self.init {
|
||||
let path = self.output.as_ref()
|
||||
.map(|p| p.clone())
|
||||
let path = self.output.clone()
|
||||
.unwrap_or_else(|| PathBuf::from(&config.changelog.path));
|
||||
|
||||
init_changelog(&path)?;
|
||||
@@ -84,8 +87,7 @@ impl ChangelogCommand {
|
||||
}
|
||||
|
||||
// Determine output path
|
||||
let output_path = self.output.as_ref()
|
||||
.map(|p| p.clone())
|
||||
let output_path = self.output.clone()
|
||||
.unwrap_or_else(|| PathBuf::from(&config.changelog.path));
|
||||
|
||||
// Determine format
|
||||
@@ -148,7 +150,7 @@ impl ChangelogCommand {
|
||||
println!("{}", "─".repeat(60));
|
||||
|
||||
let confirm = Confirm::new()
|
||||
.with_prompt(&messages.write_to_file(&format!("{:?}", output_path)))
|
||||
.with_prompt(messages.write_to_file(&format!("{:?}", output_path)))
|
||||
.default(true)
|
||||
.interact()?;
|
||||
|
||||
@@ -208,7 +210,7 @@ impl ChangelogCommand {
|
||||
|
||||
println!("{}", messages.ai_generating_changelog());
|
||||
|
||||
let generator = ContentGenerator::new(&manager).await?;
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think).await?;
|
||||
generator.generate_changelog_entry(version, commits, language).await
|
||||
}
|
||||
|
||||
@@ -237,7 +239,8 @@ impl ChangelogCommand {
|
||||
}
|
||||
|
||||
fn translate_changelog_categories(&self, changelog: &str, language: Language) -> String {
|
||||
let translated = changelog
|
||||
|
||||
changelog
|
||||
.lines()
|
||||
.map(|line| {
|
||||
if line.starts_with("## ") || line.starts_with("### ") {
|
||||
@@ -253,7 +256,6 @@ impl ChangelogCommand {
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
translated
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,10 @@ pub struct CommitCommand {
|
||||
#[arg(long)]
|
||||
no_verify: bool,
|
||||
|
||||
/// Enable thinking mode for this commit (override config)
|
||||
#[arg(short = 't', long)]
|
||||
think: bool,
|
||||
|
||||
/// Skip interactive prompts
|
||||
#[arg(short = 'y', long)]
|
||||
yes: bool,
|
||||
@@ -198,7 +202,7 @@ impl CommitCommand {
|
||||
if let Some(commit_oid) = result {
|
||||
println!("{} {}", messages.commit_created().green().bold(), commit_oid.to_string()[..8].to_string().cyan());
|
||||
} else {
|
||||
println!("{} {}", messages.commit_amended().green().bold(), "successfully");
|
||||
println!("{} successfully", messages.commit_amended().green().bold());
|
||||
}
|
||||
|
||||
// Push after commit if requested or ask user
|
||||
@@ -258,7 +262,7 @@ impl CommitCommand {
|
||||
async fn generate_commit(&self, repo: &GitRepo, format: CommitFormat, messages: &Messages) -> Result<String> {
|
||||
let manager = ConfigManager::new()?;
|
||||
|
||||
let generator = ContentGenerator::new(&manager).await
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think).await
|
||||
.context("Failed to initialize LLM. Use --manual for manual commit.")?;
|
||||
|
||||
println!("{}", messages.ai_analyzing());
|
||||
|
||||
@@ -393,8 +393,15 @@ impl ConfigCommand {
|
||||
let timeout: u64 = value.parse()?;
|
||||
manager.config_mut().llm.timeout = timeout;
|
||||
}
|
||||
"llm.thinking_enabled" => {
|
||||
manager.config_mut().llm.thinking_enabled = value == "true";
|
||||
}
|
||||
"llm.thinking_budget_tokens" => {
|
||||
let budget: u32 = value.parse()?;
|
||||
manager.config_mut().llm.thinking_budget_tokens = Some(budget);
|
||||
}
|
||||
"llm.api_key_storage" => {
|
||||
let valid_values = vec!["keyring", "config", "environment"];
|
||||
let valid_values = ["keyring", "config", "environment"];
|
||||
if !valid_values.contains(&value) {
|
||||
bail!("Invalid value: {}. Use: {}", value, valid_values.join(", "));
|
||||
}
|
||||
@@ -433,6 +440,8 @@ impl ConfigCommand {
|
||||
"llm.max_tokens" => config.llm.max_tokens.to_string(),
|
||||
"llm.temperature" => config.llm.temperature.to_string(),
|
||||
"llm.timeout" => config.llm.timeout.to_string(),
|
||||
"llm.thinking_enabled" => config.llm.thinking_enabled.to_string(),
|
||||
"llm.thinking_budget_tokens" => config.llm.thinking_budget_tokens.map(|v| v.to_string()).unwrap_or_else(|| "none".to_string()),
|
||||
"llm.api_key_storage" => config.llm.api_key_storage.clone(),
|
||||
"commit.format" => config.commit.format.to_string(),
|
||||
"commit.auto_generate" => config.commit.auto_generate.to_string(),
|
||||
@@ -681,15 +690,13 @@ impl ConfigCommand {
|
||||
l.to_string()
|
||||
} else {
|
||||
println!("{}", "Select Output Language:".bold());
|
||||
let languages = vec![
|
||||
("en", "English"),
|
||||
let languages = [("en", "English"),
|
||||
("zh", "中文"),
|
||||
("ja", "日本語"),
|
||||
("ko", "한국어"),
|
||||
("es", "Español"),
|
||||
("fr", "Français"),
|
||||
("de", "Deutsch"),
|
||||
];
|
||||
("de", "Deutsch")];
|
||||
|
||||
let lang_names: Vec<&str> = languages.iter().map(|(_, n)| *n).collect();
|
||||
let idx = Select::new()
|
||||
@@ -879,8 +886,8 @@ impl ConfigCommand {
|
||||
manager.import(&config_content)?;
|
||||
manager.save()?;
|
||||
|
||||
if let (Some(pats), Some(pwd)) = (encrypted_pats, pwd) {
|
||||
if !pats.is_empty() {
|
||||
if let (Some(pats), Some(pwd)) = (encrypted_pats, pwd)
|
||||
&& !pats.is_empty() {
|
||||
println!();
|
||||
println!("{}", "Importing Personal Access Tokens...".bold());
|
||||
|
||||
@@ -951,7 +958,6 @@ impl ConfigCommand {
|
||||
println!("{} {} token(s) failed to import", "⚠".yellow(), failed_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("{} Configuration imported from {}", "✓".green(), file);
|
||||
Ok(())
|
||||
@@ -969,31 +975,35 @@ impl ConfigCommand {
|
||||
println!("Ollama models (local):");
|
||||
println!(" llama2, llama2-uncensored, llama2:13b");
|
||||
println!(" codellama, codellama:34b");
|
||||
println!(" mistral, mixtral");
|
||||
println!(" phi, gemma");
|
||||
println!(" mistral, mixtral, phi, gemma");
|
||||
println!("\nRun 'ollama list' to see installed models");
|
||||
}
|
||||
"openai" => {
|
||||
println!("OpenAI models:");
|
||||
println!(" gpt-4, gpt-4-turbo, gpt-4o");
|
||||
println!(" gpt-3.5-turbo, gpt-3.5-turbo-16k");
|
||||
println!(" o-series (reasoning): o4-mini, o3, o3-mini, o1, o1-mini, o1-pro");
|
||||
println!(" GPT-4: gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-4o, gpt-4o-mini");
|
||||
println!(" Legacy: gpt-4-turbo, gpt-4, gpt-3.5-turbo");
|
||||
println!("\nUse --think/-t with o-series models for reasoning mode.");
|
||||
}
|
||||
"anthropic" => {
|
||||
println!("Anthropic Claude models:");
|
||||
println!(" claude-3-opus-20240229");
|
||||
println!(" claude-3-sonnet-20240229");
|
||||
println!(" claude-3-haiku-20240307");
|
||||
println!(" Claude 4 (thinking): claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5");
|
||||
println!(" Claude 3.5: claude-3-opus-20240229, claude-3-sonnet-20240229, claude-3-haiku-20240307");
|
||||
println!(" Legacy: claude-2.1, claude-2.0, claude-instant-1.2");
|
||||
println!("\nUse --think/-t with Claude 4 models for extended thinking.");
|
||||
}
|
||||
"kimi" => {
|
||||
println!("Kimi (Moonshot AI) models:");
|
||||
println!(" moonshot-v1-8k");
|
||||
println!(" moonshot-v1-32k");
|
||||
println!(" moonshot-v1-128k");
|
||||
println!(" K2 (thinking): kimi-k2.6, kimi-k2.5, kimi-k2-thinking, kimi-k2-thinking-turbo");
|
||||
println!(" K2 instruct: kimi-k2-instruct, kimi-k2-instruct-0905");
|
||||
println!(" Legacy: moonshot-v1-8k, moonshot-v1-32k, moonshot-v1-128k");
|
||||
println!("\nUse --think/-t with K2 models for thinking mode.");
|
||||
}
|
||||
"deepseek" => {
|
||||
println!("DeepSeek models:");
|
||||
println!(" deepseek-chat");
|
||||
println!(" deepseek-reasoner");
|
||||
println!(" V4: deepseek-v4-flash, deepseek-v4-pro");
|
||||
println!(" Legacy: deepseek-chat, deepseek-reasoner (deprecated 2026-07-24)");
|
||||
println!("\nUse --think/-t for reasoning mode.");
|
||||
}
|
||||
"openrouter" => {
|
||||
println!("OpenRouter models (examples):");
|
||||
|
||||
@@ -102,15 +102,13 @@ impl InitCommand {
|
||||
println!("\n{}", messages.setup_profile().bold());
|
||||
|
||||
println!("\n{}", messages.select_output_language().bold());
|
||||
let languages = vec![
|
||||
Language::English,
|
||||
let languages = [Language::English,
|
||||
Language::Chinese,
|
||||
Language::Japanese,
|
||||
Language::Korean,
|
||||
Language::Spanish,
|
||||
Language::French,
|
||||
Language::German,
|
||||
];
|
||||
Language::German];
|
||||
let language_names: Vec<String> = languages.iter().map(|l| l.display_name().to_string()).collect();
|
||||
let language_idx = Select::new()
|
||||
.items(&language_names)
|
||||
@@ -297,12 +295,11 @@ impl InitCommand {
|
||||
manager.set_llm_model(model);
|
||||
manager.set_llm_base_url(base_url);
|
||||
|
||||
if let Some(key) = api_key {
|
||||
if provider_needs_api_key(&provider) {
|
||||
if let Some(key) = api_key
|
||||
&& provider_needs_api_key(&provider) {
|
||||
manager.set_api_key(&key)?;
|
||||
println!("\n{} {}", "✓".green(), "API key stored securely in system keyring.".green());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ impl ProfileCommand {
|
||||
}
|
||||
|
||||
let confirm = Confirm::new()
|
||||
.with_prompt(&format!("Are you sure you want to remove profile '{}'?", name))
|
||||
.with_prompt(format!("Are you sure you want to remove profile '{}'?", name))
|
||||
.default(false)
|
||||
.interact()?;
|
||||
|
||||
@@ -564,7 +564,7 @@ impl ProfileCommand {
|
||||
|
||||
if manager.has_profile(&profile_name) {
|
||||
let overwrite = Confirm::new()
|
||||
.with_prompt(&format!("Profile '{}' already exists. Overwrite?", profile_name))
|
||||
.with_prompt(format!("Profile '{}' already exists. Overwrite?", profile_name))
|
||||
.default(false)
|
||||
.interact()?;
|
||||
if !overwrite {
|
||||
@@ -575,7 +575,7 @@ impl ProfileCommand {
|
||||
|
||||
let description: String = Input::new()
|
||||
.with_prompt("Description (optional)")
|
||||
.default(format!("Imported from existing git config"))
|
||||
.default("Imported from existing git config".to_string())
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
|
||||
@@ -849,7 +849,7 @@ impl ProfileCommand {
|
||||
println!("{}", "─".repeat(40));
|
||||
|
||||
let token_value: String = Input::new()
|
||||
.with_prompt(&format!("Token for {}", service))
|
||||
.with_prompt(format!("Token for {}", service))
|
||||
.interact_text()?;
|
||||
|
||||
let token_type_options = vec!["Personal", "OAuth", "Deploy", "App"];
|
||||
@@ -895,7 +895,7 @@ impl ProfileCommand {
|
||||
}
|
||||
|
||||
let confirm = Confirm::new()
|
||||
.with_prompt(&format!("Remove token '{}' from profile '{}'?", service, profile_name))
|
||||
.with_prompt(format!("Remove token '{}' from profile '{}'?", service, profile_name))
|
||||
.default(false)
|
||||
.interact()?;
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@ pub struct TagCommand {
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
|
||||
/// Enable thinking mode for this tag (override config)
|
||||
#[arg(short = 't', long)]
|
||||
think: bool,
|
||||
|
||||
/// Skip interactive prompts
|
||||
#[arg(short = 'y', long)]
|
||||
yes: bool,
|
||||
@@ -285,7 +289,7 @@ impl TagCommand {
|
||||
|
||||
println!("{}", messages.ai_generating_tag(commits.len()));
|
||||
|
||||
let generator = ContentGenerator::new(&manager).await?;
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think).await?;
|
||||
generator.generate_tag_message(version, &commits, language).await
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user