Skip to content

Commit

Permalink
Add command to store and display previous search history in the datab…
Browse files Browse the repository at this point in the history
…ase (#36)

* Add SQLite, tabled, and terminal_size dependencies, and implement history command

* Add query parameter to history command

* Fix binding values in handle_history function

* Refactor history module and fix import order

* Add offset parameter to history command
  • Loading branch information
ykdy3951 authored Mar 6, 2024
1 parent 73da5bb commit 9a4ce48
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ serde_json = "1.0"
dirs = "5.0"
spinners = "4.1.1"
cli-clipboard = "0.4.0"
sqlite = "0.33.0"
tabled = "0.15.0"
terminal_size = "0.3.0"
104 changes: 104 additions & 0 deletions src/commands/history/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use clap::Args;
use sqlite::{Connection, State, Value};
use tabled::{
settings::{peaker::PriorityMax, Width},
Table, Tabled,
};

#[derive(Debug, Args)]
#[clap(name = "history", about = "Display the previous search history")]
pub struct History {
#[clap(short, long, default_value = "10")]
limit: i64,

#[clap(short, long, default_value = "0")]
offset: i64,

#[clap(short, long)]
query: Option<String>,
}

#[derive(Tabled)]
pub struct HistoryRow {
id: i64,
input: String,
output: String,
created_at: String,
}

pub async fn connect_history() -> Connection {
let home_dir = dirs::home_dir().unwrap();
let save_dir = home_dir.join(".cllm");
let db_path = save_dir.join(":memory:");

let connection = sqlite::open(db_path).unwrap();

connection
.execute(
"
CREATE TABLE IF NOT EXISTS history (
id INTEGER PRIMARY KEY,
input TEXT NOT NULL,
output TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
",
)
.unwrap();

connection
}

pub async fn insert_history(
input: String,
output: String,
) -> Result<(), Box<dyn std::error::Error>> {
let connection = connect_history().await;

let query = "INSERT INTO history (input, output) VALUES (:input, :output)";
let mut statement = connection.prepare(query).unwrap();
statement.bind_iter::<_, (_, Value)>([(":input", input.into()), (":output", output.into())])?;

statement.next().unwrap();

Ok(())
}

pub async fn handle_history(history: History) -> Result<(), Box<dyn std::error::Error>> {
let limit = history.limit;
let condition = format!("%{}%", history.query.unwrap_or("".to_string())).to_string();

let connection = connect_history().await;
let mut rows: Vec<HistoryRow> = Vec::new();

let query =
"SELECT * FROM history WHERE input LIKE :query ORDER BY created_at DESC LIMIT :limit OFFSET :offset";
let mut statement = connection.prepare(query).unwrap();
statement.bind_iter::<_, (_, Value)>([
(":query", condition.into()),
(":limit", limit.to_string().into()),
(":offset", history.offset.to_string().into()),
])?;

while let Ok(State::Row) = statement.next() {
let id: i64 = statement.read(0)?;
let input: String = statement.read(1)?;
let output: String = statement.read(2)?;
let created_at: String = statement.read(3)?;

rows.push(HistoryRow {
id,
input,
output,
created_at,
});
}

let terminal_size::Width(width) = terminal_size::terminal_size().unwrap().0;
let mut table = Table::new(rows);
table.with(Width::wrap(width as usize).priority::<PriorityMax>());

println!("{}", table);

Ok(())
}
3 changes: 3 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod history;
mod search;
mod set;

Expand All @@ -7,11 +8,13 @@ use clap::Subcommand;
pub enum Commands {
Search(search::Search),
Set(set::Set),
History(history::History),
}

pub async fn handle_command(command: Commands) -> Result<(), Box<dyn std::error::Error>> {
match command {
Commands::Search(search) => search::handle_search(search).await,
Commands::Set(set) => set::handle_set(set).await,
Commands::History(history) => history::handle_history(history).await,
}
}
5 changes: 4 additions & 1 deletion src/commands/search/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::history::insert_history;
use clap::Parser;
use cli_clipboard::{ClipboardContext, ClipboardProvider};
use llm_chain::{
Expand All @@ -11,6 +12,7 @@ use llm_chain::{
use llm_chain_openai::chatgpt::Model;
use spinners::{Spinner, Spinners};
use std::env;

#[derive(Debug, Parser)]
#[clap(name = "search", about = "Search a command from the LLM model")]
pub struct Search {
Expand Down Expand Up @@ -71,7 +73,7 @@ pub async fn handle_search(search: Search) -> Result<(), Box<dyn std::error::Err
let step = Step::for_prompt_template(prompt!(
user: "task : {{query}}"
));
let parameters = parameters!().with("query", search.qeury);
let parameters = parameters!().with("query", search.qeury.clone());
let res = chain.send_message(step, &parameters, &exec).await?;
let res = res.to_immediate().await?.as_content().to_chat().to_string();
let res = res.split("Assistant: ").collect::<Vec<&str>>()[1]
Expand All @@ -81,6 +83,7 @@ pub async fn handle_search(search: Search) -> Result<(), Box<dyn std::error::Err

let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
ctx.set_contents(res.clone().to_string()).unwrap();
insert_history(search.qeury, res.clone()).await?;

spinner.stop_and_persist(
"✔",
Expand Down

0 comments on commit 9a4ce48

Please sign in to comment.