From 7c677b60c261e8ce21f59f9f4379c2bb6a0a6b44 Mon Sep 17 00:00:00 2001 From: Jade Wibbels Date: Fri, 3 Jan 2025 16:44:07 -0700 Subject: [PATCH 1/2] chatbot --- module2/chatbot/.env | 0 module2/chatbot/Cargo.toml | 11 +++++ module2/chatbot/Makefile | 38 +++++++++++++++++ module2/chatbot/src/chatbot.rs | 76 ++++++++++++++++++++++++++++++++++ module2/chatbot/src/lib.rs | 1 + module2/chatbot/src/main.rs | 20 +++++++++ 6 files changed, 146 insertions(+) create mode 100644 module2/chatbot/.env create mode 100644 module2/chatbot/Cargo.toml create mode 100644 module2/chatbot/Makefile create mode 100644 module2/chatbot/src/chatbot.rs create mode 100644 module2/chatbot/src/lib.rs create mode 100644 module2/chatbot/src/main.rs diff --git a/module2/chatbot/.env b/module2/chatbot/.env new file mode 100644 index 0000000..e69de29 diff --git a/module2/chatbot/Cargo.toml b/module2/chatbot/Cargo.toml new file mode 100644 index 0000000..24c5560 --- /dev/null +++ b/module2/chatbot/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "chatbot" +version = "0.1.0" +edition = "2021" + +[dependencies] +reqwest = {version = "0.11.3", features = ["json"]} +tokio = {version = "1.9.0", features = ["full"]} +serde = {version = "1.0.118", features = ["derive"]} +serde_json = "1.0.60" +dotenv = "0.15.0" diff --git a/module2/chatbot/Makefile b/module2/chatbot/Makefile new file mode 100644 index 0000000..4daa6f8 --- /dev/null +++ b/module2/chatbot/Makefile @@ -0,0 +1,38 @@ +SHELL := /bin/bash +.PHONY: help + +help: + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +clean: ## Clean the project using cargo + cargo clean + +build: ## Build the project using cargo + cargo build + +run: ## Run the project using cargo + cargo run + +test: ## Run the tests using cargo + cargo test + +lint: ## Run the linter using cargo + @rustup component add clippy 2> /dev/null + cargo clippy + +format: ## Format the code using cargo + @rustup component add rustfmt 2> /dev/null + cargo fmt + +release: + cargo build --release + +all: format lint test run + +bump: ## Bump the version of the project + @echo "Current version is $(shell cargo pkgid | cut -d# -f2)" + @read -p "Enter the new version: " version; \ + updated_version=$$(cargo pkgid | cut -d# -f2 | sed "s/$(shell cargo pkgid | cut -d# -f2)/$$version/"); \ + sed -i -E "s/^version = .*/version = \"$$updated_version\"/" Cargo.toml + @echo "Version bumped to $$(cargo pkgid | cut -d# -f2)" + rm Cargo.toml-e \ No newline at end of file diff --git a/module2/chatbot/src/chatbot.rs b/module2/chatbot/src/chatbot.rs new file mode 100644 index 0000000..95255dd --- /dev/null +++ b/module2/chatbot/src/chatbot.rs @@ -0,0 +1,76 @@ +use reqwest::{header, Client}; +use serde_json::json; +use serde_json::Value; +use std::io; +use std::io::Write; + +pub async fn run_chat_loop( + client: &Client, + api_key: &str, + url: &str, +) -> Result<(), reqwest::Error> { + let mut conversation: String = String::from("The following is a conversation with an AI Assistant:"); + loop { + print!("Human: "); + io::stdout().flush().unwrap(); + + let user_input: String = read_user_input(); + + if user_input.to_lowercase() == "exit" || user_input.to_lowercase() == "quit" { + break; + } + + conversation.push_str("Human: "); + conversation.push_str(&user_input); + conversation.push_str("AI: "); + + let json: Value = json!({ + "model": "gpt-3.5-turbo-instruct", + "prompt": conversation, + "max_tokens": 150, + "temperature": 0.5, + "top_p": 1.0, + "frequency_penalty": 0.0, + "presence_penalty": 0.0, + "stop": ["Human:", "AI:"] + }); + + let body: Value = call_api(client, api_key, url, json).await?; + print!("{}", body); + let ai_response: &str = get_ai_response(&body); + + print!("AI: {}", ai_response); + + conversation.push_str(ai_response); + conversation.push_str("\n"); + } + Ok(()) +} + +pub async fn call_api( + client: &Client, + api_key: &str, + url: &str, + json: Value, +) -> Result { + let response: reqwest::Response = client + .post(url) + .header(header::CONTENT_TYPE, "application/json") + .header(header::AUTHORIZATION, format!("Bearer {}", api_key)) + .json(&json) + .send() + .await?; + + let body: Value = response.json().await?; + Ok(body) +} + +pub fn get_ai_response(body: &Value) -> &str { + body["choices"][0]["text"].as_str().unwrap().trim() +} + +pub fn read_user_input() -> String { + let mut user_input: String = String::new(); + io::stdin().read_line(&mut user_input).unwrap(); + user_input.trim().to_string() +} \ No newline at end of file diff --git a/module2/chatbot/src/lib.rs b/module2/chatbot/src/lib.rs new file mode 100644 index 0000000..e5781ac --- /dev/null +++ b/module2/chatbot/src/lib.rs @@ -0,0 +1 @@ +pub mod chatbot; \ No newline at end of file diff --git a/module2/chatbot/src/main.rs b/module2/chatbot/src/main.rs new file mode 100644 index 0000000..977c604 --- /dev/null +++ b/module2/chatbot/src/main.rs @@ -0,0 +1,20 @@ +use chatbot::chatbot::run_chat_loop; +use reqwest::Client; + +use dotenv::dotenv; +use std::env; + +#[tokio::main] +async fn main() -> Result<(), reqwest::Error> { + // Load the .env file + dotenv().ok(); + let client = Client::new(); + + // use env variable OPENAI_API_KEY + let api_key: String = env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY must be set"); + let url: &str = "https://api.openai.com/v1/completions"; + + run_chat_loop(&client, &api_key, url).await?; + + Ok(()) +} From 436aa66b6f3ba7c55cabc59a0271fe5e2354fcab Mon Sep 17 00:00:00 2001 From: Jade Wibbels Date: Fri, 3 Jan 2025 16:47:21 -0700 Subject: [PATCH 2/2] added comment in dotenv file --- module2/chatbot/.env | 1 + 1 file changed, 1 insertion(+) diff --git a/module2/chatbot/.env b/module2/chatbot/.env index e69de29..6719b33 100644 --- a/module2/chatbot/.env +++ b/module2/chatbot/.env @@ -0,0 +1 @@ +# To run locally, add an OPENAI_API_KEY variable here with a valid API key \ No newline at end of file