From d3bf2670e6701e3728325e93fba9cd3a1ec4af6e Mon Sep 17 00:00:00 2001 From: Ruslan Date: Mon, 18 Nov 2024 13:20:19 +0200 Subject: [PATCH] READY : Continue work on assistant (#1489) * Refactor table formatting * Partial refactoring * Filter columns * Improve commands --- module/move/assistant/src/actions/openai.rs | 26 ++++- .../src/actions/openai_assistants_list.rs | 33 +++--- .../src/actions/openai_files_list.rs | 33 +++--- .../assistant/src/actions/openai_runs_list.rs | 35 +++--- module/move/assistant/src/bin/main.rs | 2 +- module/move/assistant/src/commands.rs | 30 ++++++ .../src/commands/openai_assistants.rs | 12 +-- .../src/commands/openai_assistants_list.rs | 5 +- .../assistant/src/commands/openai_files.rs | 12 +-- .../src/commands/openai_files_list.rs | 5 +- .../assistant/src/commands/openai_runs.rs | 14 +-- .../src/commands/openai_runs_list.rs | 5 +- module/move/assistant/src/lib.rs | 1 + module/move/assistant/src/util.rs | 10 ++ .../move/assistant/src/util/display_table.rs | 101 ++++++++++++++++++ 15 files changed, 238 insertions(+), 86 deletions(-) create mode 100644 module/move/assistant/src/util.rs create mode 100644 module/move/assistant/src/util/display_table.rs diff --git a/module/move/assistant/src/actions/openai.rs b/module/move/assistant/src/actions/openai.rs index 82053c4d47..da8be32030 100644 --- a/module/move/assistant/src/actions/openai.rs +++ b/module/move/assistant/src/actions/openai.rs @@ -13,6 +13,8 @@ mod private use crate::*; use ser::DisplayFromStr; + use commands::TableConfig; + /// Collective enum for errors in OpenAI actions. #[ ser::serde_as ] #[ derive( Debug, Error, AsRefStr, ser::Serialize ) ] @@ -26,12 +28,31 @@ mod private #[ from ] #[ serde_as( as = "DisplayFromStr" ) ] openai_api_rs::v1::error::APIError - ) + ), + + /// User chosen a mix of table styles instead of a single one. + /// E.g.: both `--as-table` and `--as-records` were set, however only one style must be chosen + #[ error( "Select only one table style: either `--as-table`, `--as-records`, or `--columns`" ) ] + WrongTableStyle, } /// Shorthand for `Result` in OpenAI actions. pub type Result< T > = core::result::Result< T, Error >; + /// Check the CLI arguments for table style. + /// There are 3 arguments: `--as-table`, `--as-records`, `--columns`. Only one argument + /// should be active a time. + pub fn check_table_style( table_config: &TableConfig ) -> Result< () > + { + if table_config.as_table && ( table_config.as_records || table_config.columns ) + || table_config.as_records && ( table_config.as_table || table_config.columns ) + || table_config.columns && ( table_config.as_records || table_config.as_table ) + { + return Err( Error::WrongTableStyle ) + } + + Ok( () ) + } } crate::mod_interface! @@ -39,6 +60,7 @@ crate::mod_interface! own use { Error, - Result + Result, + check_table_style, }; } \ No newline at end of file diff --git a/module/move/assistant/src/actions/openai_assistants_list.rs b/module/move/assistant/src/actions/openai_assistants_list.rs index 9859761c3b..2326ac2a6a 100644 --- a/module/move/assistant/src/actions/openai_assistants_list.rs +++ b/module/move/assistant/src/actions/openai_assistants_list.rs @@ -7,24 +7,24 @@ mod private use std::fmt; - use format_tools:: - { - AsTable, - TableFormatter, - output_format, - }; + use format_tools::AsTable; use crate::*; use client::Client; + use debug::AssistantObjectWrap; - use actions::openai::Result; + + use actions::openai::{ Result, check_table_style }; + + use commands::TableConfig; + use util::display_table::display_tabular_data; /// Report for `openai assistants list`. #[ derive( Debug ) ] pub struct ListReport { - /// Show records as separate tables. - pub show_records_as_tables : bool, + /// Configure table formatting. + pub table_config : TableConfig, /// OpenAI assistants. pub assistants: Vec< AssistantObjectWrap > @@ -38,14 +38,7 @@ mod private f : &mut fmt::Formatter< '_ > ) -> fmt::Result { - if self.show_records_as_tables - { - writeln!(f, "{}", AsTable::new( &self.assistants ).table_to_string_with_format( &output_format::Records::default() ) ) - } - else - { - writeln!(f, "{}", AsTable::new( &self.assistants ).table_to_string_with_format( &output_format::Table::default() ) ) - } + display_tabular_data( &AsTable::new( &self.assistants ), f, &self.table_config ) } } @@ -53,12 +46,14 @@ mod private pub async fn action ( client : &Client, - show_records_as_tables : bool, + table_config : TableConfig, ) -> Result < ListReport > { + check_table_style( &table_config )?; + let response = client.list_assistant( None, None, None, None ).await?; let assistants = response.data.into_iter().map( AssistantObjectWrap ).collect(); - Ok( ListReport { show_records_as_tables, assistants } ) + Ok( ListReport { table_config, assistants } ) } } diff --git a/module/move/assistant/src/actions/openai_files_list.rs b/module/move/assistant/src/actions/openai_files_list.rs index 8a3f371a92..12f6ab7bd0 100644 --- a/module/move/assistant/src/actions/openai_files_list.rs +++ b/module/move/assistant/src/actions/openai_files_list.rs @@ -7,24 +7,24 @@ mod private use std::fmt; - use format_tools:: - { - AsTable, - TableFormatter, - output_format, - }; + use format_tools::AsTable; use crate::*; use client::Client; + use debug::FileDataWrap; - use actions::openai::Result; + + use actions::openai::{ Result, check_table_style }; + + use commands::TableConfig; + use util::display_table::display_tabular_data; /// Report for `openai files list`. #[ derive( Debug ) ] pub struct ListReport { - /// Show records as separate tables. - pub show_records_as_tables : bool, + /// Configure table formatting. + pub table_config : TableConfig, /// Files in OpenAI. pub files : Vec< FileDataWrap > @@ -38,14 +38,7 @@ mod private f : &mut fmt::Formatter< '_ > ) -> fmt::Result { - if self.show_records_as_tables - { - writeln!(f, "{}", AsTable::new( &self.files ).table_to_string_with_format( &output_format::Records::default() ) ) - } - else - { - writeln!(f, "{}", AsTable::new( &self.files ).table_to_string_with_format( &output_format::Table::default() ) ) - } + display_tabular_data( &AsTable::new( &self.files ), f, &self.table_config ) } } @@ -53,12 +46,14 @@ mod private pub async fn action ( client : &Client, - show_records_as_tables : bool, + table_config : TableConfig, ) -> Result < ListReport > { + check_table_style( &table_config )?; + let response = client.file_list().await?; let files = response.data.into_iter().map( FileDataWrap ).collect(); - Ok( ListReport { show_records_as_tables, files } ) + Ok( ListReport { table_config, files } ) } } diff --git a/module/move/assistant/src/actions/openai_runs_list.rs b/module/move/assistant/src/actions/openai_runs_list.rs index 631b6ed4cb..d5bf8098c6 100644 --- a/module/move/assistant/src/actions/openai_runs_list.rs +++ b/module/move/assistant/src/actions/openai_runs_list.rs @@ -7,27 +7,27 @@ mod private use std::fmt; - use format_tools:: - { - AsTable, - TableFormatter, - output_format, - }; + use format_tools::AsTable; use crate::*; use client::Client; + use debug::RunObjectWrap; - use actions::openai::Result; + + use actions::openai::{ Result, check_table_style }; + + use commands::TableConfig; + use util::display_table::display_tabular_data; /// Report for `openai runs list`. #[ derive( Debug ) ] pub struct ListReport { - /// Show records as separate tables. - pub show_records_as_tables : bool, + /// Configure table formatting. + pub table_config : TableConfig, /// Current OpenAI runs. - pub runs : Vec< RunObjectWrap > + pub runs : Vec< RunObjectWrap >, } impl fmt::Display for ListReport @@ -38,14 +38,7 @@ mod private f : &mut fmt::Formatter< '_ > ) -> fmt::Result { - if self.show_records_as_tables - { - writeln!(f, "{}", AsTable::new( &self.runs ).table_to_string_with_format( &output_format::Records::default() ) ) - } - else - { - writeln!(f, "{}", AsTable::new( &self.runs ).table_to_string_with_format( &output_format::Table::default() ) ) - } + display_tabular_data( &AsTable::new( &self.runs ), f, &self.table_config ) } } @@ -54,12 +47,14 @@ mod private ( client : &Client, thread_id : String, - show_records_as_tables : bool, + table_config : TableConfig, ) -> Result < ListReport > { + check_table_style( &table_config )?; + let response = client.list_run( thread_id, None, None, None, None ).await?; let runs = response.data.into_iter().map( RunObjectWrap ).collect(); - Ok( ListReport { show_records_as_tables, runs } ) + Ok( ListReport { table_config, runs } ) } } diff --git a/module/move/assistant/src/bin/main.rs b/module/move/assistant/src/bin/main.rs index adeeaf150f..419030d03b 100644 --- a/module/move/assistant/src/bin/main.rs +++ b/module/move/assistant/src/bin/main.rs @@ -26,7 +26,7 @@ async fn main() -> Result< (), Box< dyn Error > > let secret = Secret::load()?; - let client = client::client( &secret )?; + let client = client( &secret )?; let cli = Cli::parse(); diff --git a/module/move/assistant/src/commands.rs b/module/move/assistant/src/commands.rs index 7a8f56c76c..7f54ec320b 100644 --- a/module/move/assistant/src/commands.rs +++ b/module/move/assistant/src/commands.rs @@ -29,6 +29,35 @@ mod private OpenAi( openai::Command ), } + // const DEFAULT_MAX_TABLE_WIDTH: usize = 130; + // Commented out as not yet implemented in `format_tools`. + + /// Common collection of arguments for formatting tabular data. + #[ derive( Debug, Parser ) ] + pub struct TableConfig + { + /// Limit table widht. + // #[ arg( long, default_value_t = DEFAULT_MAX_TABLE_WIDTH ) ] + // pub max_table_width : usize, + // Commented out as not yet implemented in `format_tools`. + + /// Show tabular data as an ordinary table. + #[ arg( long ) ] + pub as_table : bool, + + /// Show each record of a tabular data as a separate table. + #[ arg( long ) ] + pub as_records : bool, + + /// Show only keys (columns) of tabular data. + #[ arg( long ) ] + pub columns : bool, + + /// Filter columns of tabular data. + #[ arg( long, value_delimiter( ',' ) ) ] + pub filter_columns : Vec< String >, + } + } crate::mod_interface! @@ -45,5 +74,6 @@ crate::mod_interface! { Cli, CliCommand, + TableConfig, }; } diff --git a/module/move/assistant/src/commands/openai_assistants.rs b/module/move/assistant/src/commands/openai_assistants.rs index 66e2d057e8..0d941c94ba 100644 --- a/module/move/assistant/src/commands/openai_assistants.rs +++ b/module/move/assistant/src/commands/openai_assistants.rs @@ -9,7 +9,7 @@ mod private use crate::*; use client::Client; - use commands::openai_assistants_list; + use commands::{ openai_assistants_list, TableConfig }; /// OpenAI assistants. #[ derive ( Debug, Subcommand ) ] @@ -18,9 +18,9 @@ mod private /// List OpenAI assistants. List { - /// Show records as separate tables. - #[ arg( long, default_value_t = false ) ] - show_records_as_tables : bool + /// Configure table formatting. + #[ clap( flatten ) ] + table_config : TableConfig, }, } @@ -33,9 +33,9 @@ mod private { match command { - Command::List{ show_records_as_tables } => + Command::List{ table_config } => { - openai_assistants_list::command( client, show_records_as_tables ).await; + openai_assistants_list::command( client, table_config ).await; } } } diff --git a/module/move/assistant/src/commands/openai_assistants_list.rs b/module/move/assistant/src/commands/openai_assistants_list.rs index 95e1ffb62c..6ce7a80ac4 100644 --- a/module/move/assistant/src/commands/openai_assistants_list.rs +++ b/module/move/assistant/src/commands/openai_assistants_list.rs @@ -8,15 +8,16 @@ mod private use crate::*; use client::Client; use actions; + use commands::TableConfig; /// List OpenAI assistants command. pub async fn command ( client : &Client, - show_records_as_tables : bool, + table_config : TableConfig, ) { - let result = actions::openai_assistants_list::action( client, show_records_as_tables ).await; + let result = actions::openai_assistants_list::action( client, table_config ).await; match result { diff --git a/module/move/assistant/src/commands/openai_files.rs b/module/move/assistant/src/commands/openai_files.rs index 33e18fea0a..ea72a42ad1 100644 --- a/module/move/assistant/src/commands/openai_files.rs +++ b/module/move/assistant/src/commands/openai_files.rs @@ -9,7 +9,7 @@ mod private use crate::*; use client::Client; - use commands::openai_files_list; + use commands::{ openai_files_list, TableConfig }; /// OpenAI files. #[ derive ( Debug, Subcommand ) ] @@ -18,9 +18,9 @@ mod private /// List OpenAI files. List { - /// Show records as separate tables. - #[ arg( long, default_value_t = false ) ] - show_records_as_tables : bool + /// Configure table formatting. + #[ clap( flatten ) ] + table_config : TableConfig, }, } @@ -33,9 +33,9 @@ mod private { match command { - Command::List{ show_records_as_tables } => + Command::List{ table_config } => { - openai_files_list::command( client, show_records_as_tables ).await; + openai_files_list::command( client, table_config ).await; } } } diff --git a/module/move/assistant/src/commands/openai_files_list.rs b/module/move/assistant/src/commands/openai_files_list.rs index 04bc83c0c4..6225b9faf2 100644 --- a/module/move/assistant/src/commands/openai_files_list.rs +++ b/module/move/assistant/src/commands/openai_files_list.rs @@ -8,15 +8,16 @@ mod private use crate::*; use client::Client; use actions; + use commands::TableConfig; /// List files in your OpenAI API. pub async fn command ( client : &Client, - show_records_as_tables : bool, + table_config : TableConfig, ) { - let result = actions::openai_files_list::action( client, show_records_as_tables ).await; + let result = actions::openai_files_list::action( client, table_config ).await; match result { diff --git a/module/move/assistant/src/commands/openai_runs.rs b/module/move/assistant/src/commands/openai_runs.rs index e5e183b33e..2cf7812000 100644 --- a/module/move/assistant/src/commands/openai_runs.rs +++ b/module/move/assistant/src/commands/openai_runs.rs @@ -9,7 +9,7 @@ mod private use crate::*; use client::Client; - use commands::openai_runs_list; + use commands::{ openai_runs_list, TableConfig }; /// OpenAI runs. #[ derive ( Debug, Subcommand ) ] @@ -21,10 +21,10 @@ mod private /// Thread ID. thread_id : String, - /// Show records as separate tables. - #[ arg( long, default_value_t = false ) ] - show_records_as_tables : bool - }, + /// Configure table formatting. + #[ clap( flatten ) ] + table_config : TableConfig, + } } /// Execute OpenAI commands related to runs. @@ -36,9 +36,9 @@ mod private { match command { - Command::List { thread_id, show_records_as_tables } => + Command::List { thread_id, table_config } => { - openai_runs_list::command( client, thread_id, show_records_as_tables ).await; + openai_runs_list::command( client, thread_id, table_config ).await; } } } diff --git a/module/move/assistant/src/commands/openai_runs_list.rs b/module/move/assistant/src/commands/openai_runs_list.rs index 928e0b473a..6d08d64ed3 100644 --- a/module/move/assistant/src/commands/openai_runs_list.rs +++ b/module/move/assistant/src/commands/openai_runs_list.rs @@ -8,16 +8,17 @@ mod private use crate::*; use client::Client; use actions; + use commands::TableConfig; /// List runs in the thread in OpenAI API. pub async fn command ( client : &Client, thread_id : String, - show_records_as_tables : bool, + table_config : TableConfig, ) { - let result = actions::openai_runs_list::action( client, thread_id, show_records_as_tables ).await; + let result = actions::openai_runs_list::action( client, thread_id, table_config ).await; match result { diff --git a/module/move/assistant/src/lib.rs b/module/move/assistant/src/lib.rs index c064213715..5a33e41692 100644 --- a/module/move/assistant/src/lib.rs +++ b/module/move/assistant/src/lib.rs @@ -32,6 +32,7 @@ crate::mod_interface! layer commands; layer actions; layer secret; + layer util; exposed use ::reflect_tools:: { diff --git a/module/move/assistant/src/util.rs b/module/move/assistant/src/util.rs new file mode 100644 index 0000000000..7e34c0fd16 --- /dev/null +++ b/module/move/assistant/src/util.rs @@ -0,0 +1,10 @@ +//! +//! Collection of utility functions for this crate. +//! + +mod private {} + +crate::mod_interface! +{ + layer display_table; +} \ No newline at end of file diff --git a/module/move/assistant/src/util/display_table.rs b/module/move/assistant/src/util/display_table.rs new file mode 100644 index 0000000000..edced5fbdd --- /dev/null +++ b/module/move/assistant/src/util/display_table.rs @@ -0,0 +1,101 @@ +//! +//! Function for displaying tabular data according to `TableConfig`. +//! + +mod private +{ + + use std::fmt; + + use format_tools:: + { + TableFormatter, + output_format, + print, + TableOutputFormat, + }; + + use crate::*; + use commands::{ TableConfig }; + + /// Function for displaying tabular data according to `TableConfig`. + pub fn display_tabular_data<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + table_config : &'a TableConfig, + ) -> fmt::Result + { + if table_config.as_table + { + display_table( data, f, &table_config.filter_columns ) + } + else if table_config.as_records + { + display_records( data, f, &table_config.filter_columns ) + } + else if table_config.columns + { + display_columns( data, f, &table_config.filter_columns ) + } + else + { + display_table( data, f, &table_config.filter_columns ) + } + } + + fn display_table<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + filter_columns : &'a Vec< String >, + ) -> fmt::Result + { + display_data( data, f, filter_columns, output_format::Table::default() ) + } + + fn display_records<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + filter_columns : &'a Vec< String >, + ) -> fmt::Result + { + display_data( data, f, filter_columns, output_format::Records::default() ) + } + + fn display_columns<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + filter_columns : &'a Vec< String >, + ) -> fmt::Result + { + display_data( data, f, filter_columns, output_format::Keys::default() ) + } + + fn display_data<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + filter_columns : &'a Vec< String >, + format : impl TableOutputFormat, + ) -> fmt::Result + { + let mut printer = print::Printer::with_format( &format ); + let binding = | title : &str | + { + filter_columns.is_empty() || filter_columns.iter().any( |c| c.as_str() == title ) + }; + printer.filter_col = &binding; + + let mut context = print::Context::new( f, printer ); + TableFormatter::fmt( data, &mut context ) + } + +} + +crate::mod_interface! +{ + own use display_tabular_data; +} \ No newline at end of file