use crate::RuChatError;
use crate::chroma::ls::{ChromaLsArgs, chroma_ls};
use crate::chroma::query::{QueryArgs, query};
use crate::chroma::similarity::{SimilarityArgs, similarity_search};
use crate::embed::{EmbedArgs, embed};
use crate::ollama::ask::{AskArgs, ask};
use crate::ollama::chat::{ChatArgs, chat};
use crate::ollama::func::strukt::{FuncStructArgs, func_struct};
use crate::ollama::func::{FuncArgs, func};
use crate::ollama::model::ls::list;
use crate::ollama::model::pull::{PullArgs, pull};
use crate::ollama::model::rm::{RmArgs, remove};
use crate::ollama::pipe::{PipeArgs, pipe};
use clap::{Parser, Subcommand};
use ollama_rs::Ollama;
#[derive(Parser, Debug, PartialEq)]
pub struct Args {
#[clap(subcommand)]
pub command: Option<Commands>,
#[clap(short, long, default_value = "http://172.18.0.1:11434")]
pub(crate) server: String,
#[clap(short, long, default_value = "false")]
pub(crate) verbose: bool,
}
impl Args {
pub(crate) async fn handle_request(&self) -> Result<(), RuChatError> {
let default = Commands::Pipe(PipeArgs::default());
if self.verbose {
let command_line = std::env::args().collect::<Vec<String>>().join(" ");
println!("Command line: {}", command_line);
}
match self.command.as_ref().unwrap_or(&default) {
Commands::Ask(ask_args) => ask(self.init()?, ask_args).await?,
Commands::Pipe(pipe_args) => pipe(self.init()?, pipe_args).await?,
Commands::Chat(chat_args) => chat(self.init()?, chat_args).await?,
Commands::Ls => list(self).await?,
Commands::Rm(rm_args) => remove(self, rm_args).await?,
Commands::Pull(pull_args) => pull(self, pull_args).await?,
Commands::Func(func_args) => func(self.init()?, func_args).await?,
Commands::FuncStruct(func_args) => func_struct(self.init()?, func_args).await?,
Commands::Embed(embed_args) => embed(self.init()?, embed_args).await?,
Commands::Query(query_args) => query(self.init()?, query_args).await?,
Commands::Similarity(similarity_args) => similarity_search(similarity_args).await?,
Commands::ChromaLs(chroma_ls_args) => chroma_ls(chroma_ls_args).await?,
}
Ok(())
}
fn init(&self) -> Result<Ollama, RuChatError> {
if self.verbose {
println!("Connecting to Ollama server at {}", self.server);
}
self.server
.rsplit_once(':')
.and_then(|(host, port)| port.parse::<u16>().map(|p| Ollama::new(host, p)).ok())
.ok_or_else(|| RuChatError::ArgServerError(self.server.to_string()))
}
}
#[derive(Subcommand, Debug, Clone, PartialEq)]
pub enum Commands {
Ask(AskArgs),
Pipe(PipeArgs),
Chat(ChatArgs),
Ls,
Rm(RmArgs),
Pull(PullArgs),
Func(FuncArgs),
FuncStruct(FuncStructArgs),
Embed(EmbedArgs),
Query(QueryArgs),
Similarity(SimilarityArgs),
ChromaLs(ChromaLsArgs),
}
#[cfg(test)]
mod tests {
use super::*;
use clap::Parser;
#[test]
fn test_args_parsing() {
let args = Args::parse_from(&["test", "--server", "http://localhost:8080", "--verbose"]);
assert_eq!(args.server, "http://localhost:8080");
assert!(args.verbose);
}
#[test]
fn test_subcommand_parsing() {
let args = Args::parse_from(&["test", "ask"]);
match args.command {
Some(Commands::Ask(_)) => assert!(true),
_ => assert!(false, "Expected Ask subcommand"),
}
}
#[tokio::test]
async fn test_handle_request_default() {
let args = Args::parse_from(&["test", "-h"]);
let result = args.handle_request().await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_request_ask() {
let args = Args::parse_from(&["test", "ls"]);
let result = args.handle_request().await;
assert!(result.is_ok());
}
}