♻️ refactor(generator):移除未使用的导入和剪贴板功能 ♻️ refactor(git):清理未使用的导入和优化代码结构 ♻️ refactor(i18n):简化翻译模块的导出结构 ♻️ refactor(llm):移除未使用的序列化导入 ♻️ refactor(openrouter):简化模型验证函数
1015 lines
35 KiB
Rust
1015 lines
35 KiB
Rust
use anyhow::{bail, Context, Result};
|
||
use async_trait::async_trait;
|
||
use std::time::Duration;
|
||
use crate::config::Language;
|
||
|
||
pub mod ollama;
|
||
pub mod openai;
|
||
pub mod anthropic;
|
||
pub mod kimi;
|
||
pub mod deepseek;
|
||
pub mod openrouter;
|
||
|
||
pub use ollama::OllamaClient;
|
||
pub use openai::OpenAiClient;
|
||
pub use anthropic::AnthropicClient;
|
||
pub use kimi::KimiClient;
|
||
pub use deepseek::DeepSeekClient;
|
||
pub use openrouter::OpenRouterClient;
|
||
|
||
/// LLM provider trait
|
||
#[async_trait]
|
||
pub trait LlmProvider: Send + Sync {
|
||
/// Generate text from prompt
|
||
async fn generate(&self, prompt: &str) -> Result<String>;
|
||
|
||
/// Generate with system prompt
|
||
async fn generate_with_system(&self, system: &str, user: &str) -> Result<String>;
|
||
|
||
/// Check if provider is available
|
||
async fn is_available(&self) -> bool;
|
||
|
||
/// Get provider name
|
||
fn name(&self) -> &str;
|
||
}
|
||
|
||
/// LLM client that wraps different providers
|
||
pub struct LlmClient {
|
||
provider: Box<dyn LlmProvider>,
|
||
config: LlmClientConfig,
|
||
}
|
||
|
||
#[derive(Debug, Clone)]
|
||
pub struct LlmClientConfig {
|
||
pub max_tokens: u32,
|
||
pub temperature: f32,
|
||
pub timeout: Duration,
|
||
}
|
||
|
||
impl Default for LlmClientConfig {
|
||
fn default() -> Self {
|
||
Self {
|
||
max_tokens: 500,
|
||
temperature: 0.7,
|
||
timeout: Duration::from_secs(30),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl LlmClient {
|
||
/// Create LLM client from configuration
|
||
pub async fn from_config(config: &crate::config::LlmConfig) -> Result<Self> {
|
||
let client_config = LlmClientConfig {
|
||
max_tokens: config.max_tokens,
|
||
temperature: config.temperature,
|
||
timeout: Duration::from_secs(config.timeout),
|
||
};
|
||
|
||
let provider: Box<dyn LlmProvider> = match config.provider.as_str() {
|
||
"ollama" => {
|
||
Box::new(OllamaClient::new(&config.ollama.url, &config.ollama.model))
|
||
}
|
||
"openai" => {
|
||
let api_key = config.openai.api_key.as_ref()
|
||
.ok_or_else(|| anyhow::anyhow!("OpenAI API key not configured"))?;
|
||
Box::new(OpenAiClient::new(
|
||
&config.openai.base_url,
|
||
api_key,
|
||
&config.openai.model,
|
||
)?)
|
||
}
|
||
"anthropic" => {
|
||
let api_key = config.anthropic.api_key.as_ref()
|
||
.ok_or_else(|| anyhow::anyhow!("Anthropic API key not configured"))?;
|
||
Box::new(AnthropicClient::new(api_key, &config.anthropic.model)?)
|
||
}
|
||
"kimi" => {
|
||
let api_key = config.kimi.api_key.as_ref()
|
||
.ok_or_else(|| anyhow::anyhow!("Kimi API key not configured"))?;
|
||
Box::new(KimiClient::with_base_url(api_key, &config.kimi.model, &config.kimi.base_url)?)
|
||
}
|
||
"deepseek" => {
|
||
let api_key = config.deepseek.api_key.as_ref()
|
||
.ok_or_else(|| anyhow::anyhow!("DeepSeek API key not configured"))?;
|
||
Box::new(DeepSeekClient::with_base_url(api_key, &config.deepseek.model, &config.deepseek.base_url)?)
|
||
}
|
||
"openrouter" => {
|
||
let api_key = config.openrouter.api_key.as_ref()
|
||
.ok_or_else(|| anyhow::anyhow!("OpenRouter API key not configured"))?;
|
||
Box::new(OpenRouterClient::with_base_url(api_key, &config.openrouter.model, &config.openrouter.base_url)?)
|
||
}
|
||
_ => bail!("Unknown LLM provider: {}", config.provider),
|
||
};
|
||
|
||
Ok(Self {
|
||
provider,
|
||
config: client_config,
|
||
})
|
||
}
|
||
|
||
/// Create with specific provider
|
||
pub fn with_provider(provider: Box<dyn LlmProvider>) -> Self {
|
||
Self {
|
||
provider,
|
||
config: LlmClientConfig::default(),
|
||
}
|
||
}
|
||
|
||
/// Generate commit message from git diff
|
||
pub async fn generate_commit_message(
|
||
&self,
|
||
diff: &str,
|
||
format: crate::config::CommitFormat,
|
||
language: Language,
|
||
) -> Result<GeneratedCommit> {
|
||
let system_prompt = get_commit_system_prompt(format, language);
|
||
|
||
// Add language instruction to the prompt
|
||
let language_instruction = match language {
|
||
Language::Chinese => "\n\n请用中文生成提交消息。",
|
||
Language::Japanese => "\n\n日本語でコミットメッセージを生成してください。",
|
||
Language::Korean => "\n\n한국어로 커밋 메시지를 생성하세요.",
|
||
Language::Spanish => "\n\nPor favor, genera el mensaje de commit en español.",
|
||
Language::French => "\n\nVeuillez générer le message de commit en français.",
|
||
Language::German => "\n\nBitte generieren Sie die Commit-Nachricht auf Deutsch.",
|
||
Language::English => "",
|
||
};
|
||
|
||
let prompt = format!("{}{}", diff, language_instruction);
|
||
let response = self.provider.generate_with_system(system_prompt, &prompt).await?;
|
||
|
||
self.parse_commit_response(&response, format)
|
||
}
|
||
|
||
/// Generate tag message from commits
|
||
pub async fn generate_tag_message(
|
||
&self,
|
||
version: &str,
|
||
commits: &[String],
|
||
language: Language,
|
||
) -> Result<String> {
|
||
let system_prompt = get_tag_system_prompt(language);
|
||
let commits_text = commits.join("\n");
|
||
|
||
// Add language instruction to the prompt
|
||
let language_instruction = match language {
|
||
Language::Chinese => "\n\n请用中文生成标签消息。",
|
||
Language::Japanese => "\n\n日本語でタグメッセージを生成してください。",
|
||
Language::Korean => "\n\n한국어로 태그 메시지를 생성하세요.",
|
||
Language::Spanish => "\n\nPor favor, genera el mensaje de etiqueta en español.",
|
||
Language::French => "\n\nVeuillez générer le message de balise en français.",
|
||
Language::German => "\n\nBitte generieren Sie die Tag-Nachricht auf Deutsch.",
|
||
Language::English => "",
|
||
};
|
||
|
||
let prompt = format!("Version: {}\n\nCommits:\n{}{}", version, commits_text, language_instruction);
|
||
|
||
self.provider.generate_with_system(system_prompt, &prompt).await
|
||
}
|
||
|
||
/// Generate changelog entry
|
||
pub async fn generate_changelog_entry(
|
||
&self,
|
||
version: &str,
|
||
commits: &[(String, String)], // (type, message)
|
||
language: Language,
|
||
) -> Result<String> {
|
||
let system_prompt = get_changelog_system_prompt(language);
|
||
|
||
let commits_text = commits
|
||
.iter()
|
||
.map(|(t, m)| format!("- [{}] {}", t, m))
|
||
.collect::<Vec<_>>()
|
||
.join("\n");
|
||
|
||
// Add language instruction to the prompt
|
||
let language_instruction = match language {
|
||
Language::Chinese => "\n\n请用中文生成变更日志。",
|
||
Language::Japanese => "\n\n日本語で変更ログを生成してください。",
|
||
Language::Korean => "\n\n한국어로 변경 로그를 생성하세요.",
|
||
Language::Spanish => "\n\nPor favor, genera el registro de cambios en español.",
|
||
Language::French => "\n\nVeuillez générer le journal des modifications en français.",
|
||
Language::German => "\n\nBitte generieren Sie das Changelog auf Deutsch.",
|
||
Language::English => "",
|
||
};
|
||
|
||
let prompt = format!("Version: {}\n\nCommits:\n{}{}", version, commits_text, language_instruction);
|
||
|
||
self.provider.generate_with_system(system_prompt, &prompt).await
|
||
}
|
||
|
||
/// Check if provider is available
|
||
pub async fn is_available(&self) -> bool {
|
||
self.provider.is_available().await
|
||
}
|
||
|
||
/// Parse commit response from LLM
|
||
fn parse_commit_response(&self, response: &str, format: crate::config::CommitFormat) -> Result<GeneratedCommit> {
|
||
let lines: Vec<&str> = response.lines().collect();
|
||
|
||
if lines.is_empty() {
|
||
bail!("Empty response from LLM");
|
||
}
|
||
|
||
let first_line = lines[0];
|
||
|
||
// Parse based on format
|
||
match format {
|
||
crate::config::CommitFormat::Conventional => {
|
||
self.parse_conventional_commit(first_line, lines)
|
||
}
|
||
crate::config::CommitFormat::Commitlint => {
|
||
self.parse_commitlint_commit(first_line, lines)
|
||
}
|
||
}
|
||
}
|
||
|
||
fn parse_conventional_commit(
|
||
&self,
|
||
first_line: &str,
|
||
lines: Vec<&str>,
|
||
) -> Result<GeneratedCommit> {
|
||
// Parse: type(scope)!: description
|
||
let parts: Vec<&str> = first_line.splitn(2, ':').collect();
|
||
if parts.len() != 2 {
|
||
bail!("Invalid conventional commit format: missing colon");
|
||
}
|
||
|
||
let type_part = parts[0];
|
||
let description = parts[1].trim();
|
||
|
||
// Extract type, scope, and breaking indicator
|
||
let breaking = type_part.ends_with('!');
|
||
let type_part = type_part.trim_end_matches('!');
|
||
|
||
let (commit_type, scope) = if let Some(start) = type_part.find('(') {
|
||
if let Some(end) = type_part.find(')') {
|
||
let t = &type_part[..start];
|
||
let s = &type_part[start + 1..end];
|
||
(t.to_string(), Some(s.to_string()))
|
||
} else {
|
||
bail!("Invalid scope format: missing closing parenthesis");
|
||
}
|
||
} else {
|
||
(type_part.to_string(), None)
|
||
};
|
||
|
||
// Extract body and footer
|
||
let (body, footer) = self.extract_body_footer(&lines);
|
||
|
||
Ok(GeneratedCommit {
|
||
commit_type,
|
||
scope,
|
||
description: description.to_string(),
|
||
body,
|
||
footer,
|
||
breaking,
|
||
})
|
||
}
|
||
|
||
fn parse_commitlint_commit(
|
||
&self,
|
||
first_line: &str,
|
||
lines: Vec<&str>,
|
||
) -> Result<GeneratedCommit> {
|
||
// Similar parsing but with commitlint rules
|
||
let parts: Vec<&str> = first_line.splitn(2, ':').collect();
|
||
if parts.len() != 2 {
|
||
bail!("Invalid commit format: missing colon");
|
||
}
|
||
|
||
let type_part = parts[0];
|
||
let subject = parts[1].trim();
|
||
|
||
let (commit_type, scope) = if let Some(start) = type_part.find('(') {
|
||
if let Some(end) = type_part.find(')') {
|
||
let t = &type_part[..start];
|
||
let s = &type_part[start + 1..end];
|
||
(t.to_string(), Some(s.to_string()))
|
||
} else {
|
||
(type_part.to_string(), None)
|
||
}
|
||
} else {
|
||
(type_part.to_string(), None)
|
||
};
|
||
|
||
let (body, footer) = self.extract_body_footer(&lines);
|
||
|
||
Ok(GeneratedCommit {
|
||
commit_type,
|
||
scope,
|
||
description: subject.to_string(),
|
||
body,
|
||
footer,
|
||
breaking: false,
|
||
})
|
||
}
|
||
|
||
fn extract_body_footer(&self, lines: &[&str]) -> (Option<String>, Option<String>) {
|
||
if lines.len() <= 1 {
|
||
return (None, None);
|
||
}
|
||
|
||
let rest: Vec<&str> = lines[1..]
|
||
.iter()
|
||
.skip_while(|l| l.trim().is_empty())
|
||
.copied()
|
||
.collect();
|
||
|
||
if rest.is_empty() {
|
||
return (None, None);
|
||
}
|
||
|
||
// Look for footer markers
|
||
let footer_markers = ["BREAKING CHANGE:", "Closes", "Fixes", "Refs", "Co-authored-by:"];
|
||
|
||
let mut body_lines = vec![];
|
||
let mut footer_lines = vec![];
|
||
let mut in_footer = false;
|
||
|
||
for line in &rest {
|
||
if footer_markers.iter().any(|m| line.starts_with(m)) {
|
||
in_footer = true;
|
||
}
|
||
|
||
if in_footer {
|
||
footer_lines.push(*line);
|
||
} else {
|
||
body_lines.push(*line);
|
||
}
|
||
}
|
||
|
||
let body = if body_lines.is_empty() {
|
||
None
|
||
} else {
|
||
Some(body_lines.join("\n"))
|
||
};
|
||
|
||
let footer = if footer_lines.is_empty() {
|
||
None
|
||
} else {
|
||
Some(footer_lines.join("\n"))
|
||
};
|
||
|
||
(body, footer)
|
||
}
|
||
}
|
||
|
||
/// Generated commit structure
|
||
#[derive(Debug, Clone)]
|
||
pub struct GeneratedCommit {
|
||
pub commit_type: String,
|
||
pub scope: Option<String>,
|
||
pub description: String,
|
||
pub body: Option<String>,
|
||
pub footer: Option<String>,
|
||
pub breaking: bool,
|
||
}
|
||
|
||
impl GeneratedCommit {
|
||
/// Format as conventional commit
|
||
pub fn to_conventional(&self) -> String {
|
||
crate::utils::formatter::format_conventional_commit(
|
||
&self.commit_type,
|
||
self.scope.as_deref(),
|
||
&self.description,
|
||
self.body.as_deref(),
|
||
self.footer.as_deref(),
|
||
self.breaking,
|
||
)
|
||
}
|
||
|
||
/// Format as commitlint commit
|
||
pub fn to_commitlint(&self) -> String {
|
||
crate::utils::formatter::format_commitlint_commit(
|
||
&self.commit_type,
|
||
self.scope.as_deref(),
|
||
&self.description,
|
||
self.body.as_deref(),
|
||
self.footer.as_deref(),
|
||
None,
|
||
)
|
||
}
|
||
}
|
||
|
||
/// HTTP client helper
|
||
pub(crate) fn create_http_client(timeout: Duration) -> Result<reqwest::Client> {
|
||
reqwest::Client::builder()
|
||
.timeout(timeout)
|
||
.build()
|
||
.context("Failed to create HTTP client")
|
||
}
|
||
|
||
/// Get commit system prompt based on format and language
|
||
fn get_commit_system_prompt(format: crate::config::CommitFormat, language: Language) -> &'static str {
|
||
match (format, language) {
|
||
(crate::config::CommitFormat::Conventional, Language::Chinese) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ZH,
|
||
(crate::config::CommitFormat::Conventional, Language::Japanese) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT_JA,
|
||
(crate::config::CommitFormat::Conventional, Language::Korean) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT_KO,
|
||
(crate::config::CommitFormat::Conventional, Language::Spanish) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ES,
|
||
(crate::config::CommitFormat::Conventional, Language::French) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT_FR,
|
||
(crate::config::CommitFormat::Conventional, Language::German) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT_DE,
|
||
(crate::config::CommitFormat::Conventional, _) => CONVENTIONAL_COMMIT_SYSTEM_PROMPT,
|
||
(crate::config::CommitFormat::Commitlint, Language::Chinese) => COMMITLINT_SYSTEM_PROMPT_ZH,
|
||
(crate::config::CommitFormat::Commitlint, Language::Japanese) => COMMITLINT_SYSTEM_PROMPT_JA,
|
||
(crate::config::CommitFormat::Commitlint, Language::Korean) => COMMITLINT_SYSTEM_PROMPT_KO,
|
||
(crate::config::CommitFormat::Commitlint, Language::Spanish) => COMMITLINT_SYSTEM_PROMPT_ES,
|
||
(crate::config::CommitFormat::Commitlint, Language::French) => COMMITLINT_SYSTEM_PROMPT_FR,
|
||
(crate::config::CommitFormat::Commitlint, Language::German) => COMMITLINT_SYSTEM_PROMPT_DE,
|
||
(crate::config::CommitFormat::Commitlint, _) => COMMITLINT_SYSTEM_PROMPT,
|
||
}
|
||
}
|
||
|
||
fn get_tag_system_prompt(language: Language) -> &'static str {
|
||
match language {
|
||
Language::Chinese => TAG_MESSAGE_SYSTEM_PROMPT_ZH,
|
||
Language::Japanese => TAG_MESSAGE_SYSTEM_PROMPT_JA,
|
||
Language::Korean => TAG_MESSAGE_SYSTEM_PROMPT_KO,
|
||
Language::Spanish => TAG_MESSAGE_SYSTEM_PROMPT_ES,
|
||
Language::French => TAG_MESSAGE_SYSTEM_PROMPT_FR,
|
||
Language::German => TAG_MESSAGE_SYSTEM_PROMPT_DE,
|
||
_ => TAG_MESSAGE_SYSTEM_PROMPT,
|
||
}
|
||
}
|
||
|
||
fn get_changelog_system_prompt(language: Language) -> &'static str {
|
||
match language {
|
||
Language::Chinese => CHANGELOG_SYSTEM_PROMPT_ZH,
|
||
Language::Japanese => CHANGELOG_SYSTEM_PROMPT_JA,
|
||
Language::Korean => CHANGELOG_SYSTEM_PROMPT_KO,
|
||
Language::Spanish => CHANGELOG_SYSTEM_PROMPT_ES,
|
||
Language::French => CHANGELOG_SYSTEM_PROMPT_FR,
|
||
Language::German => CHANGELOG_SYSTEM_PROMPT_DE,
|
||
_ => CHANGELOG_SYSTEM_PROMPT,
|
||
}
|
||
}
|
||
|
||
// System prompts for LLM
|
||
|
||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates conventional commit messages.
|
||
|
||
Analyze the git diff provided and generate a commit message following the Conventional Commits specification.
|
||
|
||
Format: <type>[optional scope]: <description>
|
||
|
||
Types:
|
||
- feat: A new feature
|
||
- fix: A bug fix
|
||
- docs: Documentation only changes
|
||
- style: Changes that don't affect code meaning (formatting, semicolons, etc.)
|
||
- refactor: Code change that neither fixes a bug nor adds a feature
|
||
- perf: Code change that improves performance
|
||
- test: Adding or correcting tests
|
||
- build: Changes to build system or dependencies
|
||
- ci: Changes to CI configuration
|
||
- chore: Other changes that don't modify src or test files
|
||
- revert: Reverts a previous commit
|
||
|
||
Rules:
|
||
1. Use lowercase for type and scope
|
||
2. Keep description under 100 characters
|
||
3. Use imperative mood ("add" not "added")
|
||
4. Don't capitalize first letter
|
||
5. No period at the end
|
||
6. Include scope if the change is specific to a module/component
|
||
|
||
Output ONLY the commit message, nothing else.
|
||
"#;
|
||
|
||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成符合 Conventional Commits 规范的提交消息的助手。
|
||
|
||
分析提供的 git diff,并生成符合 Conventional Commits 规范的提交消息。
|
||
|
||
格式: <type>[可选作用域]: <描述>
|
||
|
||
类型:
|
||
- feat: 新功能
|
||
- fix: 修复错误
|
||
- docs: 仅文档更改
|
||
- style: 不影响代码含义的更改(格式化、分号等)
|
||
- refactor: 既不修复错误也不添加功能的代码更改
|
||
- perf: 提高性能的代码更改
|
||
- test: 添加或更正测试
|
||
- build: 更改构建系统或依赖项
|
||
- ci: 更改 CI 配置
|
||
- chore: 其他不修改 src 或测试文件的更改
|
||
- revert: 撤销之前的提交
|
||
|
||
规则:
|
||
1. 类型和小写使用小写
|
||
2. 描述保持在 100 个字符以内
|
||
3. 使用祈使语气("添加"而不是"已添加")
|
||
4. 不要大写首字母
|
||
5. 结尾不要句号
|
||
6. 如果更改特定于模块/组件,请包含作用域
|
||
|
||
仅输出提交消息,不要输出其他内容。
|
||
"#;
|
||
|
||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_JA: &str = r#"あなたはConventional Commits仕様に従ったコミットメッセージを生成するアシスタントです。
|
||
|
||
提供されたgit diffを分析し、Conventional Commits仕様に従ったコミットメッセージを生成してください。
|
||
|
||
形式: <type>[オプションのスコープ]: <説明>
|
||
|
||
タイプ:
|
||
- feat: 新機能
|
||
- fix: バグ修正
|
||
- docs: ドキュメントのみの変更
|
||
- style: コードの意味に影響しない変更(フォーマット、セミコロンなど)
|
||
- refactor: バグ修正や機能追加を伴わないコード変更
|
||
- perf: パフォーマンスを向上させるコード変更
|
||
- test: テストの追加または修正
|
||
- build: ビルドシステムまたは依存関係の変更
|
||
- ci: CI設定の変更
|
||
- chore: srcやテストファイルを変更しないその他の変更
|
||
- revert: 以前のコミットを取り消す
|
||
|
||
ルール:
|
||
1. タイプとスコープは小文字を使用
|
||
2. 説明は100文字以内にする
|
||
3. 命令形を使用する("追加"ではなく"追加する")
|
||
4. 先頭を大文字にしない
|
||
5. 最後にピリオドを付けない
|
||
6. 変更がモジュール/コンポーネントに固有の場合はスコープを含める
|
||
|
||
コミットメッセージのみを出力し、それ以外は出力しないでください。
|
||
"#;
|
||
|
||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_KO: &str = r#"당신은 Conventional Commits 사양에 따른 커밋 메시지를 생성하는 도우미입니다.
|
||
|
||
제공된 git diff를 분석하고 Conventional Commits 사양에 따른 커밋 메시지를 생성하세요.
|
||
|
||
형식: <type>[선택적 범위]: <설명>
|
||
|
||
유형:
|
||
- feat: 새 기능
|
||
- fix: 버그 수정
|
||
- docs: 문서 변경만
|
||
- style: 코드 의미에 영향을 주지 않는 변경(서식, 세미콜론 등)
|
||
- refactor: 버그를 수정하거나 기능을 추가하지 않는 코드 변경
|
||
- perf: 성능을 향상시키는 코드 변경
|
||
- test: 테스트 추가 또는 수정
|
||
- build: 빌드 시스템 또는 종속성 변경
|
||
- ci: CI 구성 변경
|
||
- chore: src 또는 테스트 파일을 수정하지 않는 기타 변경
|
||
- revert: 이전 커밋 되돌리기
|
||
|
||
규칙:
|
||
1. 유형과 범위는 소문자 사용
|
||
2. 설명은 100자 이내로 유지
|
||
3. 명령형 사용("추가"가 아닌 "추가하다")
|
||
4. 첫 글자 대문자화하지 않음
|
||
5. 끝에 마침표 사용하지 않음
|
||
6. 변경 사항이 모듈/구성 요소에 특정한 경우 범위 포함
|
||
|
||
커밋 메시지만 출력하고 다른 내용은 출력하지 마세요.
|
||
"#;
|
||
|
||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de commit siguiendo la especificación Conventional Commits.
|
||
|
||
Analiza el diff de git proporcionado y genera un mensaje de commit siguiendo la especificación Conventional Commits.
|
||
|
||
Formato: <tipo>[alcance opcional]: <descripción>
|
||
|
||
Tipos:
|
||
- feat: Una nueva característica
|
||
- fix: Una corrección de error
|
||
- docs: Solo cambios en documentación
|
||
- style: Cambios que no afectan el significado del código (formato, punto y coma, etc.)
|
||
- refactor: Cambio de código que no corrige un error ni agrega una característica
|
||
- perf: Cambio de código que mejora el rendimiento
|
||
- test: Agregar o corregir pruebas
|
||
- build: Cambios en el sistema de construcción o dependencias
|
||
- ci: Cambios en la configuración de CI
|
||
- chore: Otros cambios que no modifican archivos src o de prueba
|
||
- revert: Revierte un commit anterior
|
||
|
||
Reglas:
|
||
1. Usa minúsculas para tipo y alcance
|
||
2. Mantén la descripción bajo 100 caracteres
|
||
3. Usa modo imperativo ("agregar" no "agregado")
|
||
4. No capitalices la primera letra
|
||
5. Sin punto al final
|
||
6. Incluye alcance si el cambio es específico de un módulo/componente
|
||
|
||
Genera SOLO el mensaje de commit, nada más.
|
||
"#;
|
||
|
||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages de commit suivant la spécification Conventional Commits.
|
||
|
||
Analysez le diff git fourni et générez un message de commit suivant la spécification Conventional Commits.
|
||
|
||
Format: <type>[portée optionnelle]: <description>
|
||
|
||
Types:
|
||
- feat: Une nouvelle fonctionnalité
|
||
- fix: Une correction de bug
|
||
- docs: Changements de documentation uniquement
|
||
- style: Changements qui n'affectent pas la signification du code (formatage, points-virgules, etc.)
|
||
- refactor: Changement de code qui ne corrige pas un bug ni n'ajoute une fonctionnalité
|
||
- perf: Changement de code qui améliore les performances
|
||
- test: Ajout ou correction de tests
|
||
- build: Changements du système de build ou des dépendances
|
||
- ci: Changements de la configuration CI
|
||
- chore: Autres changements qui ne modifient pas les fichiers src ou de test
|
||
- revert: Révertit un commit précédent
|
||
|
||
Règles:
|
||
1. Utilisez des minuscules pour le type et la portée
|
||
2. Gardez la description sous 100 caractères
|
||
3. Utilisez le mode impératif ("ajouter" non "ajouté")
|
||
4. Ne capitalisez pas la première lettre
|
||
5. Pas de point à la fin
|
||
6. Incluez la portée si le changement est spécifique à un module/composant
|
||
|
||
Générez SEULEMENT le message de commit, rien d'autre.
|
||
"#;
|
||
|
||
const CONVENTIONAL_COMMIT_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Commit-Nachrichten gemäß der Conventional Commits-Spezifikation generiert.
|
||
|
||
Analysieren Sie den bereitgestellten git diff und generieren Sie eine Commit-Nachricht gemäß der Conventional Commits-Spezifikation.
|
||
|
||
Format: <typ>[optionaler Bereich]: <beschreibung>
|
||
|
||
Typen:
|
||
- feat: Eine neue Funktion
|
||
- fix: Ein Bugfix
|
||
- docs: Nur Dokumentationsänderungen
|
||
- style: Änderungen, die die Code-Bedeutung nicht beeinflussen (Formatierung, Semikolons usw.)
|
||
- refactor: Code-Änderung, die weder einen Bug behebt noch eine Funktion hinzufügt
|
||
- perf: Code-Änderung, die die Leistung verbessert
|
||
- test: Hinzufügen oder Korrigieren von Tests
|
||
- build: Änderungen am Build-System oder Abhängigkeiten
|
||
- ci: Änderungen an der CI-Konfiguration
|
||
- chore: Andere Änderungen, die src- oder Testdateien nicht ändern
|
||
- revert: Setzt einen vorherigen Commit zurück
|
||
|
||
Regeln:
|
||
1. Verwenden Sie Kleinbuchstaben für Typ und Bereich
|
||
2. Halten Sie die Beschreibung unter 100 Zeichen
|
||
3. Verwenden Sie den Imperativ ("hinzufügen" nicht "hinzugefügt")
|
||
4. Großschreiben Sie den ersten Buchstaben nicht
|
||
5. Kein Punkt am Ende
|
||
6. Fügen Sie einen Bereich ein, wenn die Änderung spezifisch für ein Modul/Komponente ist
|
||
|
||
Geben Sie NUR die Commit-Nachricht aus, nichts anderes.
|
||
"#;
|
||
|
||
const COMMITLINT_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates commit messages following @commitlint/config-conventional.
|
||
|
||
Analyze the git diff and generate a commit message.
|
||
|
||
Format: <type>[optional scope]: <subject>
|
||
|
||
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||
|
||
Rules:
|
||
1. Subject should not start with uppercase
|
||
2. Subject should not end with period
|
||
3. Subject should be 4-100 characters
|
||
4. Use imperative mood
|
||
5. Be concise but descriptive
|
||
|
||
Output ONLY the commit message, nothing else.
|
||
"#;
|
||
|
||
const COMMITLINT_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成符合 @commitlint/config-conventional 规范的提交消息的助手。
|
||
|
||
分析 git diff 并生成提交消息。
|
||
|
||
格式: <type>[可选作用域]: <主题>
|
||
|
||
类型: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||
|
||
规则:
|
||
1. 主题不应以大写字母开头
|
||
2. 主题不应以句号结尾
|
||
3. 主题应为 4-100 个字符
|
||
4. 使用祈使语气
|
||
5. 简洁但描述性强
|
||
|
||
仅输出提交消息,不要输出其他内容。
|
||
"#;
|
||
|
||
const COMMITLINT_SYSTEM_PROMPT_JA: &str = r#"あなたは@commitlint/config-conventionalに従ったコミットメッセージを生成するアシスタントです。
|
||
|
||
git diffを分析し、コミットメッセージを生成してください。
|
||
|
||
形式: <type>[オプションのスコープ]: <件名>
|
||
|
||
タイプ: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||
|
||
ルール:
|
||
1. 件名は大文字で始めないでください
|
||
2. 件名はピリオドで終わらないでください
|
||
3. 件名は4-100文字である必要があります
|
||
4. 命令形を使用してください
|
||
5. 簡潔ですが説明的であること
|
||
|
||
コミットメッセージのみを出力し、それ以外は出力しないでください。
|
||
"#;
|
||
|
||
const COMMITLINT_SYSTEM_PROMPT_KO: &str = r#"당신은 @commitlint/config-conventional에 따른 커밋 메시지를 생성하는 도우미입니다.
|
||
|
||
git diff를 분석하고 커밋 메시지를 생성하세요.
|
||
|
||
형식: <type>[선택적 범위]: <제목>
|
||
|
||
유형: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||
|
||
규칙:
|
||
1. 제목은 대문자로 시작하지 않아야 합니다
|
||
2. 제목은 마침표로 끝나지 않아야 합니다
|
||
3. 제목은 4-100자여야 합니다
|
||
4. 명령형을 사용하세요
|
||
5. 간결하지만 설명적이어야 합니다
|
||
|
||
커밋 메시지만 출력하고 다른 내용은 출력하지 마세요.
|
||
"#;
|
||
|
||
const COMMITLINT_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de commit siguiendo @commitlint/config-conventional.
|
||
|
||
Analiza el diff de git y genera un mensaje de commit.
|
||
|
||
Formato: <tipo>[alcance opcional]: <asunto>
|
||
|
||
Tipos: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||
|
||
Reglas:
|
||
1. El asunto no debe comenzar con mayúscula
|
||
2. El asunto no debe terminar con punto
|
||
3. El asunto debe tener 4-100 caracteres
|
||
4. Usa modo imperativo
|
||
5. Sé conciso pero descriptivo
|
||
|
||
Genera SOLO el mensaje de commit, nada más.
|
||
"#;
|
||
|
||
const COMMITLINT_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages de commit suivant @commitlint/config-conventional.
|
||
|
||
Analysez le diff git et générez un message de commit.
|
||
|
||
Format: <type>[portée optionnelle]: <sujet>
|
||
|
||
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||
|
||
Règles:
|
||
1. Le sujet ne doit pas commencer par une majuscule
|
||
2. Le sujet ne doit pas se terminer par un point
|
||
3. Le sujet doit avoir 4-100 caractères
|
||
4. Utilisez le mode impératif
|
||
5. Soyez concis mais descriptif
|
||
|
||
Générez SEULEMENT le message de commit, rien d'autre.
|
||
"#;
|
||
|
||
const COMMITLINT_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Commit-Nachrichten gemäß @commitlint/config-conventional generiert.
|
||
|
||
Analysieren Sie den git diff und generieren Sie eine Commit-Nachricht.
|
||
|
||
Format: <typ>[optionaler Bereich]: <betreff>
|
||
|
||
Typen: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||
|
||
Regeln:
|
||
1. Der Betreff sollte nicht mit einem Großbuchstaben beginnen
|
||
2. Der Betreff sollte nicht mit einem Punkt enden
|
||
3. Der Betreff sollte 4-100 Zeichen haben
|
||
4. Verwenden Sie den Imperativ
|
||
5. Seien Sie prägnant aber beschreibend
|
||
|
||
Geben Sie NUR die Commit-Nachricht aus, nichts anderes.
|
||
"#;
|
||
|
||
const TAG_MESSAGE_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates git tag annotation messages.
|
||
|
||
Given a version number and a list of commits, generate a concise but informative tag message.
|
||
|
||
The message should:
|
||
1. Start with a brief summary of the release
|
||
2. Group changes by type (features, fixes, etc.)
|
||
3. Be suitable for a git annotated tag
|
||
|
||
Format:
|
||
<version> Release
|
||
|
||
Summary of changes...
|
||
|
||
Changes:
|
||
- Feature: description
|
||
- Fix: description
|
||
...
|
||
"#;
|
||
|
||
const TAG_MESSAGE_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成 git 标签注释消息的助手。
|
||
|
||
给定版本号和提交列表,生成简洁但信息丰富的标签消息。
|
||
|
||
消息应该:
|
||
1. 以发布的简要摘要开始
|
||
2. 按类型分组更改(功能、修复等)
|
||
3. 适合 git 标注标签
|
||
|
||
格式:
|
||
<version> 发布
|
||
|
||
更改摘要...
|
||
|
||
更改:
|
||
- 功能:描述
|
||
- 修复:描述
|
||
...
|
||
"#;
|
||
|
||
const TAG_MESSAGE_SYSTEM_PROMPT_JA: &str = r#"あなたはgitタグ注釈メッセージを生成するアシスタントです。
|
||
|
||
バージョン番号とコミットのリストを考慮して、簡潔ですが情報豊富なタグメッセージを生成してください。
|
||
|
||
メッセージは以下のようであるべきです:
|
||
1. リリースの簡単な要約から始める
|
||
2. タイプ別に変更をグループ化する(機能、修正など)
|
||
3. git注釈タグに適している
|
||
|
||
形式:
|
||
<version> リリース
|
||
|
||
変更の概要...
|
||
|
||
変更:
|
||
- 機能:説明
|
||
- 修正:説明
|
||
...
|
||
"#;
|
||
|
||
const TAG_MESSAGE_SYSTEM_PROMPT_KO: &str = r#"당신은 git 태그 주석 메시지를 생성하는 도우미입니다.
|
||
|
||
버전 번호와 커밋 목록을 고려하여 간결하지만 정보가 풍부한 태그 메시지를 생성하세요.
|
||
|
||
메시지는 다음과 같아야 합니다:
|
||
1. 릴리스의 간단한 요약으로 시작
|
||
2. 유형별로 변경 사항 그룹화(기능, 수정 등)
|
||
3. git 주석 태그에 적합
|
||
|
||
형식:
|
||
<version> 릴리스
|
||
|
||
변경 사항 요약...
|
||
|
||
변경 사항:
|
||
- 기능: 설명
|
||
- 수정: 설명
|
||
...
|
||
"#;
|
||
|
||
const TAG_MESSAGE_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera mensajes de anotación de etiquetas git.
|
||
|
||
Dado un número de versión y una lista de commits, genera un mensaje de etiqueta conciso pero informativo.
|
||
|
||
El mensaje debe:
|
||
1. Comenzar con un resumen breve de la versión
|
||
2. Agrupar cambios por tipo (características, correcciones, etc.)
|
||
3. Ser adecuado para una etiqueta git anotada
|
||
|
||
Formato:
|
||
<version> Versión
|
||
|
||
Resumen de cambios...
|
||
|
||
Cambios:
|
||
- Característica: descripción
|
||
- Corrección: descripción
|
||
...
|
||
"#;
|
||
|
||
const TAG_MESSAGE_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des messages d'annotation de balises git.
|
||
|
||
Étant donné un numéro de version et une liste de commits, générez un message de balise concis mais informatif.
|
||
|
||
Le message doit :
|
||
1. Commencer par un bref résumé de la version
|
||
2. Grouper les changements par type (fonctionnalités, corrections, etc.)
|
||
3. Être adapté à une balise git annotée
|
||
|
||
Format :
|
||
<version> Version
|
||
|
||
Résumé des changements...
|
||
|
||
Changements :
|
||
- Fonctionnalité : description
|
||
- Correction : description
|
||
...
|
||
"#;
|
||
|
||
const TAG_MESSAGE_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der git-Tag-Anmerkungsnachrichten generiert.
|
||
|
||
Gegeben eine Versionsnummer und eine Liste von Commits, generieren Sie eine prägnante aber informative Tag-Nachricht.
|
||
|
||
Die Nachricht sollte:
|
||
1. Mit einer kurzen Zusammenfassung der Version beginnen
|
||
2. Änderungen nach Typ gruppieren (Funktionen, Fixes, etc.)
|
||
3. Für ein git-annotiertes Tag geeignet sein
|
||
|
||
Format:
|
||
<version> Version
|
||
|
||
Zusammenfassung der Änderungen...
|
||
|
||
Änderungen:
|
||
- Funktion: Beschreibung
|
||
- Fix: Beschreibung
|
||
...
|
||
"#;
|
||
|
||
const CHANGELOG_SYSTEM_PROMPT: &str = r#"You are a helpful assistant that generates changelog entries.
|
||
|
||
Given a version and a list of commits, generate a well-formatted changelog section.
|
||
|
||
Group commits by:
|
||
- Features (feat)
|
||
- Bug Fixes (fix)
|
||
- Documentation (docs)
|
||
- Other Changes
|
||
|
||
Format in markdown with proper headings and bullet points.
|
||
"#;
|
||
|
||
const CHANGELOG_SYSTEM_PROMPT_ZH: &str = r#"你是一个生成变更日志条目的助手。
|
||
|
||
给定版本和提交列表,生成格式良好的变更日志部分。
|
||
|
||
按以下方式分组提交:
|
||
- 功能 (feat)
|
||
- 错误修复 (fix)
|
||
- 文档 (docs)
|
||
- 其他更改
|
||
|
||
使用适当的标题和项目符号以 markdown 格式输出。
|
||
"#;
|
||
|
||
const CHANGELOG_SYSTEM_PROMPT_JA: &str = r#"あなたは変更ログエントリを生成するアシスタントです。
|
||
|
||
バージョンとコミットのリストを考慮して、適切にフォーマットされた変更ログセクションを生成してください。
|
||
|
||
コミットを以下でグループ化してください:
|
||
- 機能 (feat)
|
||
- バグ修正 (fix)
|
||
- ドキュメント (docs)
|
||
- その他の変更
|
||
|
||
適切な見出しと箇条書きを使用してmarkdown形式でフォーマットしてください。
|
||
"#;
|
||
|
||
const CHANGELOG_SYSTEM_PROMPT_KO: &str = r#"당신은 변경 로그 항목을 생성하는 도우미입니다.
|
||
|
||
버전과 커밋 목록을 고려하여 잘 포맷된 변경 로그 섹션을 생성하세요.
|
||
|
||
다음으로 커밋을 그룹화하세요:
|
||
- 기능 (feat)
|
||
- 버그 수정 (fix)
|
||
- 문서 (docs)
|
||
- 기타 변경 사항
|
||
|
||
적절한 제목과 글머리 기호를 사용하여 markdown 형식으로 포맷하세요.
|
||
"#;
|
||
|
||
const CHANGELOG_SYSTEM_PROMPT_ES: &str = r#"Eres un asistente que genera entradas de registro de cambios.
|
||
|
||
Dada una versión y una lista de commits, genera una sección de registro de cambios bien formateada.
|
||
|
||
Agrupa los commits por:
|
||
- Características (feat)
|
||
- Correcciones de errores (fix)
|
||
- Documentación (docs)
|
||
- Otros cambios
|
||
|
||
Formatea en markdown con encabezados y viñetas apropiados.
|
||
"#;
|
||
|
||
const CHANGELOG_SYSTEM_PROMPT_FR: &str = r#"Vous êtes un assistant qui génère des entrées de journal des modifications.
|
||
|
||
Étant donné une version et une liste de commits, générez une section de journal des modifications bien formatée.
|
||
|
||
Groupez les commits par :
|
||
- Fonctionnalités (feat)
|
||
- Corrections de bugs (fix)
|
||
- Documentation (docs)
|
||
- Autres modifications
|
||
|
||
Formatez en markdown avec des en-têtes et des puces appropriés.
|
||
"#;
|
||
|
||
const CHANGELOG_SYSTEM_PROMPT_DE: &str = r#"Sie sind ein Assistent, der Changelog-Einträge generiert.
|
||
|
||
Gegeben eine Version und eine Liste von Commits, generieren Sie einen gut formatierten Changelog-Abschnitt.
|
||
|
||
Gruppieren Sie Commits nach:
|
||
- Funktionen (feat)
|
||
- Bugfixes (fix)
|
||
- Dokumentation (docs)
|
||
- Andere Änderungen
|
||
|
||
Formatieren Sie in Markdown mit geeigneten Überschriften und Aufzählungspunkten.
|
||
"#;
|