new crate that uses openai to summarize git diffs

This commit is contained in:
extrawurst 2023-12-15 19:28:11 +01:00
parent 7b7c5c4131
commit 51d8f96348
8 changed files with 271 additions and 1 deletions

100
Cargo.lock generated
View file

@ -725,6 +725,16 @@ dependencies = [
"thiserror",
]
[[package]]
name = "git2-summarize"
version = "0.1.0"
dependencies = [
"git2",
"log",
"openai-api-rs",
"thiserror",
]
[[package]]
name = "git2-testing"
version = "0.1.0"
@ -1056,6 +1066,21 @@ dependencies = [
"adler",
]
[[package]]
name = "minreq"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb3371dfc7b772c540da1380123674a8e20583aca99907087d990ca58cf44203"
dependencies = [
"log",
"once_cell",
"rustls",
"rustls-webpki",
"serde",
"serde_json",
"webpki-roots",
]
[[package]]
name = "mio"
version = "0.8.5"
@ -1142,6 +1167,17 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "openai-api-rs"
version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ead8e910b541f342b445ab68dd52ae24d695abaf781aee2ae933a77ac29ea5de"
dependencies = [
"minreq",
"serde",
"serde_json",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
@ -1382,6 +1418,20 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "ring"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e"
dependencies = [
"cc",
"getrandom",
"libc",
"spin",
"untrusted",
"windows-sys 0.48.0",
]
[[package]]
name = "ron"
version = "0.8.0"
@ -1413,6 +1463,28 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "rustls"
version = "0.21.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
"ring",
"rustls-webpki",
"sct",
]
[[package]]
name = "rustls-webpki"
version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "ryu"
version = "1.0.14"
@ -1447,6 +1519,16 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]]
name = "sct"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "serde"
version = "1.0.156"
@ -1579,6 +1661,12 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "strsim"
version = "0.10.0"
@ -1783,6 +1871,12 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
version = "2.5.0"
@ -1882,6 +1976,12 @@ version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "webpki-roots"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10"
[[package]]
name = "which"
version = "4.4.0"

View file

@ -69,7 +69,7 @@ trace-libgit = ["asyncgit/trace-libgit"]
vendor-openssl = ["asyncgit/vendor-openssl"]
[workspace]
members = ["asyncgit", "filetreelist", "git2-hooks", "git2-testing", "scopetime"]
members = ["asyncgit", "filetreelist", "git2-hooks", "git2-summarize", "git2-testing", "scopetime"]
[profile.release]
lto = true

19
git2-summarize/Cargo.toml Normal file
View file

@ -0,0 +1,19 @@
[package]
name = "git2-summarize"
version = "0.1.0"
authors = ["extrawurst <mail@rusticorn.com>"]
edition = "2021"
description = "use openai gpt to summarize git2 diffs"
homepage = "https://github.com/extrawurst/gitui"
repository = "https://github.com/extrawurst/gitui"
documentation = "https://docs.rs/git2-summarize/"
readme = "README.md"
license = "MIT"
categories = ["development-tools"]
keywords = ["git"]
[dependencies]
git2 = ">=0.17"
log = "0.4"
thiserror = "1.0"
openai-api-rs = "2.1"

1
git2-summarize/LICENSE.md Symbolic link
View file

@ -0,0 +1 @@
../LICENSE.md

3
git2-summarize/README.md Normal file
View file

@ -0,0 +1,3 @@
# git2-summarize
this uses open ai chat-gpt to summarize a git diff

View file

@ -0,0 +1,49 @@
diff --git a/git2-hooks/src/lib.rs b/git2-hooks/src/lib.rs
index 0cf5ac8..042ac87 100644
--- a/git2-hooks/src/lib.rs
+++ b/git2-hooks/src/lib.rs
@@ -27,6 +27,7 @@ use git2::Repository;
pub const HOOK_POST_COMMIT: &str = "post-commit";
pub const HOOK_PRE_COMMIT: &str = "pre-commit";
pub const HOOK_COMMIT_MSG: &str = "commit-msg";
+pub const HOOK_PRE_PUSH: &str = "pre-push";
const HOOK_COMMIT_MSG_TEMP_FILE: &str = "COMMIT_EDITMSG";
@@ -152,6 +153,36 @@ pub fn hooks_post_commit(
hook.run_hook(&[])
}
+/// see [`hooks_pre_push`]
+pub enum PrePushHookLocalRef<'a> {
+ Delete,
+ Ref {
+ local_ref: &'a str,
+ local_obj_name: &'a str,
+ },
+}
+
+/// see https://git-scm.com/docs/githooks#_pre_push
+///
+/// # Arguments
+///
+/// * `remote_obj_name` - pass `None` if foreign ref not yet exists
+pub fn hooks_pre_push(
+ repo: &Repository,
+ other_paths: Option<&[&str]>,
+ local_ref: PrePushHookLocalRef,
+ remote_ref: &str,
+ remote_obj_name: Option<&str>,
+) -> Result<HookResult> {
+ let hook = HookPaths::new(repo, other_paths, HOOK_PRE_PUSH)?;
+
+ if !hook.found() {
+ return Ok(HookResult::NoHookFound);
+ }
+
+ hook.run_hook(&[])
+}
+
#[cfg(test)]
mod tests {
use super::*;

View file

@ -0,0 +1,13 @@
use std::env;
fn main() {
let diff = include_str!("simple.diff");
let summary = git2_summarize::git_diff_summarize_old(
&env::var("OPENAI_API_KEY").unwrap(),
diff,
)
.unwrap();
println!("{summary}");
}

85
git2-summarize/src/lib.rs Normal file
View file

@ -0,0 +1,85 @@
//! Uses Open API GPT-3 to summarize unified git diffs
use openai_api_rs::v1::{
api::Client,
chat_completion::{self, ChatCompletionRequest},
common::GPT3_5_TURBO,
completion::{self, CompletionRequest},
};
/// Uses old GPT3_TEXT_DAVINCI_003 model to generate message
///
/// # Arguments
///
/// * `api_key` - open api key
/// * `diff` - expects a diff formatted as a unified diff
pub fn git_diff_summarize_old(
api_key: &str,
diff: &str,
) -> Result<String, String> {
let client = Client::new(api_key.to_string());
let req = CompletionRequest::new(
completion::GPT3_TEXT_DAVINCI_003.to_string(),
format!("Generate a Git commit message based on the following summary: {}\n\nCommit message: ",diff),
)
.max_tokens(500)
.temperature(0.5)
.n(1);
let result = client.completion(req).map_err(|e| e.message)?;
Ok(result
.choices
.get(0)
.ok_or_else(|| String::from("choises empty"))?
.text
.clone())
}
/// Uses GPT3_5_TURBO model to generate message using chat completion API
///
/// # Arguments
///
/// * `api_key` - open api key
/// * `diff` - expects a diff formatted as a unified diff
pub fn git_diff_summarize(
api_key: &str,
diff: &str,
line_length: usize,
) -> Result<String, String> {
let client = Client::new(api_key.to_string());
let prompt = format!(
r#"You are a smart git commit message creator software.
Now you are going to create a git commit message.
The commit messages you generate aim to explain why the changes were introduced.
Write a one-sentence message no longer than {line_length} characters, followed by two newline characters.
Create a commit message for these changes:\n{}
"#,
diff
);
let req = ChatCompletionRequest::new(
GPT3_5_TURBO.to_string(),
vec![chat_completion::ChatCompletionMessage {
role: chat_completion::MessageRole::system,
content: prompt,
name: None,
function_call: None,
}],
)
.max_tokens(200);
let result =
client.chat_completion(req).map_err(|e| e.message)?;
Ok(result
.choices
.get(0)
.ok_or_else(|| String::from("response.choises empty"))?
.message
.content
.as_ref()
.ok_or_else(|| String::from("choise[0].message empty"))?
.clone())
}