diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..97a4aa5
@@ -0,0 +1,84 @@
+mod openai;
+
+use openai::{Message, Role};
+
+use std::collections::HashMap;
+use std::fmt::{Error, format};
+use std::process::Command;
+use colored::Colorize;
+use reqwest::{Request, RequestBuilder};
+use serde::{Serialize, Deserialize};
+
+const SYSTEM_MSG: &str = "NICE MAN";
+const MODEL: &str = "gpt-3.5-turbo";
+
+fn main() {
+ println!();
+ let diff = match git_diff() {
+ Ok(diff) => diff,
+ Err(e) => {
+ println!("{}", e);
+ return;
+ }
+ };
+ // println!("{}", diff);
+
+ let mut messages = Vec::new();
+ messages.push(Message::system(SYSTEM_MSG));
+ messages.push(Message::user(diff));
+
+ let json = serde_json::to_string(&messages).unwrap();
+
+ let client = reqwest::blocking::Client::new();
+ let res = client
+ .get("https://api.openai.com/v1/chat/completions")
+ .header("Content-Type", "application/json")
+ .header("Authorization", format!("Bearer {}", 123))
+ .body(json)
+ .send();
+
+ match res {
+ Ok(res) => {
+ match res.status() {
+ reqwest::StatusCode::OK => {
+ let body = res.text().unwrap();
+ let resp = serde_json::from_str::<openai::Response>(&body).unwrap();
+ println!("This used {} token, costing you ~{}$", format!("{}", resp.usage.total_tokens).green(), format!("{}", cost(resp.usage.total_tokens)).green());
+ for choice in resp.choices {
+ println!("{}", choice.message.content);
+ }
+ }
+ _ => {
+ let e = res.text().unwrap();
+ let error = serde_json::from_str::<openai::ErrorRoot>(&e).unwrap().error;
+ println!("{}", error);
+ return;
+ }
+ }
+ }
+ Err(e) => {
+ println!("{}", e);
+ return;
+ }
+ }
+}
+
+fn git_diff() -> Result<String, String> {
+ let diff = Command::new("git")
+ .arg("diff")
+ .arg("--staged")
+ .arg("--minimal")
+ .arg("-U2")
+ .output()
+ .expect("failed to execute git diff");
+ match diff.status.success() {
+ true => Ok(String::from_utf8_lossy(&diff.stdout).to_string()),
+ false => Err(String::from_utf8_lossy(&diff.stderr).to_string()),
+ }
+}
+
+const PRICE: f64 = 0.002;
+
+fn cost(token: i64) -> f64 {
+ token as f64 * (PRICE / 1000.0)
+}
\ No newline at end of file
diff --git a/src/openai.rs b/src/openai.rs
new file mode 100644
index 0000000..24caddb
@@ -0,0 +1,85 @@
+use std::fmt;
+use colored::Colorize;
+use serde::{Serialize, Deserialize};
+use serde_json::Value;
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "lowercase")]
+pub enum Role {
+ System,
+ User,
+ Assistant,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Message {
+ pub role: Role,
+ pub content: String,
+}
+
+impl Message {
+ pub fn system<S: Into<String>>(content: S) -> Message {
+ Message {
+ role: Role::System,
+ content: content.into(),
+ }
+ }
+ pub fn user<S: Into<String>>(content: S) -> Message {
+ Message {
+ role: Role::User,
+ content: content.into(),
+ }
+ }
+ pub fn assistant<S: Into<String>>(content: S) -> Message {
+ Message {
+ role: Role::Assistant,
+ content: content.into(),
+ }
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct ErrorRoot {
+ pub error: Error,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct Error {
+ pub message: String,
+ #[serde(rename = "type")]
+ pub type_field: String,
+ pub param: Value,
+ pub code: String,
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{} ({}): {:?}", self.type_field.red(), self.code, self.message)
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Response {
+ pub id: String,
+ pub object: String,
+ pub created: i64,
+ pub model: String,
+ pub choices: Vec<Choice>,
+ pub usage: Usage,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Choice {
+ pub index: i64,
+ pub finish_reason: String,
+ pub message: Message,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Usage {
+ pub prompt_tokens: i64,
+ pub completion_tokens: i64,
+ pub total_tokens: i64,
+}