bin/aia in aia-0.0.2 vs bin/aia in aia-0.0.3

- old
+ new

@@ -1,272 +1,7 @@ #!/usr/bin/env ruby -# encoding: utf-8 -# frozen_string_literal: true -# warn_indent: true -########################################################## -### -## File: aia -## Desc: AI Assistant -## Use generative AI with saved parameterized prompts -## By: Dewayne VanHoozer (dvanhoozer@gmail.com) -## -## This program makes use of the gem word_wrap's -## CLI tool: ww -## -## brew install fzf mods the_silver_searcher ripgrep -# -# TODO: refactor with a goal to isolate the search_proc and mods functionality -# TODO: consider a config file. -# TODO: remove use of CLI Helper. -# TODO: consider --no-log -# +# aia -require 'pathname' -HOME = Pathname.new( ENV['HOME'] ) -PROMPTS_DIR = Pathname.new(ENV['PROMPTS_DIR'] || (HOME + ".prompts_dir")) +require_relative '../lib/aia' -require 'prompt_manager' -require 'prompt_manager/storage/file_system_adapter' - -PromptManager::Prompt.storage_adapter = - PromptManager::Storage::FileSystemAdapter.config do |config| - config.prompts_dir = PROMPTS_DIR - config.prompt_extension = '.txt' # default - config.params_extension = '.json' # default - # config.search_proc = nil # default - end.new - - - -require 'amazing_print' -require 'readline' # TODO: or reline ?? -require 'word_wrap' -require 'word_wrap/core_ext' - -require 'debug_me' -include DebugMe - -require 'cli_helper' -include CliHelper - -MODS_MODEL = ENV['MODS_MODEL'] || 'gpt-4-1106-preview' - -AI_CLI_PROGRAM = "mods" -ai_default_opts = "-m #{MODS_MODEL} --no-limit -f" -ai_options = ai_default_opts.dup - -extra_inx = ARGV.index('--') - -if extra_inx - ai_options += " " + ARGV[extra_inx+1..].join(' ') - ARGV.pop(ARGV.size - extra_inx) -end - -AI_COMMAND = "#{AI_CLI_PROGRAM} #{ai_options} " -EDITOR = ENV['EDITOR'] -PROMPT_LOG = PROMPTS_DIR + "_prompts.log" - -# PROMPT_EXTNAME = ".txt" -# DEFAULTS_EXTNAME = ".json" - -# SEARCH_COMMAND = "ag -l" -# KEYWORD_REGEX = /(\[[A-Z _|]+\])/ - - -configatron.version = '1.2.0' - -AI_CLI_PROGRAM_HELP = `#{AI_CLI_PROGRAM} --help` - -HELP = <<EOHELP -AI Assistant (aia) -================== - -The AI cli program being used is: #{AI_CLI_PROGRAM} - -The defaul options to #{AI_CLI_PROGRAM} are: - "#{ai_default_opts}" - -You can pass additional CLI options to #{AI_CLI_PROGRAM} like this: - "#{my_name} my options -- options for #{AI_CLI_PROGRAM}" - -EOHELP - -cli_helper("Use generative AI with saved parameterized prompts") do |o| - o.bool '-f', '--fuzzy', 'Allow fuzzy matching', default: false - o.path '-o', '--output', 'The output file', default: Pathname.pwd + "temp.md" -end - - -AG_COMMAND = "ag --file-search-regex '\.txt$' e" # searching for the letter "e" -CD_COMMAND = "cd #{PROMPTS_DIR}" -FIND_COMMAND = "find . -name '*.txt'" - -FZF_OPTIONS = [ - "--tabstop=2", # 2 soaces for a tab - "--header='Prompt contents below'", - "--header-first", - "--prompt='Search term: '", - '--delimiter :', - "--preview 'ww {1}'", # ww comes from the word_wrap gem - "--preview-window=down:50%:wrap" -].join(' ') - -FZF_OPTIONS += " --exact" unless fuzzy? - -FZF_COMMAND = "#{CD_COMMAND} ; #{FIND_COMMAND} | fzf #{FZF_OPTIONS}" -AG_FZF_COMMAND = "#{CD_COMMAND} ; #{AG_COMMAND} | fzf #{FZF_OPTIONS}" - -# use `ag` to build a list of text lines from each prompt -# use `fzf` to search through that list to select a prompt file - -def ag_fzf = `#{AG_FZF_COMMAND}`.split(':')&.first&.strip&.gsub('.txt','') - - - -# The prompt_id is always the first argument -if configatron.arguments.empty? - show_usage - exit -end - - -def process_arguments - prompt_id = configatron.arguments.shift - - if prompt_id.include?('.') - error "Invalid prompt_id: #{configatron.prompt_id}" - else - configatron.input_files = [] - configatron.arguments.each do |arg| - file_path = Pathname.new(arg) - if file_path.exist? - configatron.input_files << file_path - else - error "File does not exist: #{file_path}" - end - end - end - - prompt_id # may be invalid -end - -configatron.prompt_id = process_arguments - -abort_if_errors - -###################################################### -# Local methods - -def replace_keywords - defaults = configatron.prompt.parameters - - configatron.prompt.keywords.each do |kw| - defaults[kw] = keyword_value(kw, defaults[kw]) - end - - configatron.prompt.parameters = defaults - configatron.prompt.save -end - - -def keyword_value(kw, default) - label = "Default: " - puts "#{kw} ..." - print label - puts default.wrap.split("\n").join("\n"+" "*label.length) - a_string = Readline.readline("\n-=> ", false) - puts - a_string.empty? ? default : a_string -end - - -def log(prompt, answer) - f = File.open(PROMPT_LOG, "ab") - - f.write <<~EOS - ======================================= - == #{Time.now} - == #{prompt.path} - - PROMPT: #{prompt} - - RESULT: - #{answer} - - EOS -end - - -def search_for_a_matching_prompt - found_prompt_ids = PromptManager::Prompt.search( - configatron.prompt_id - ) - if found_prompt_ids.size > 1 - puts <<~EOS - - Search Results - ============== - - The following prompt IDs have the search term '#{configatron.prompt_id}' - #{found_prompt_ids.join(', ').wrap} - - EOS - exit - else - configatron.prompt_id = found_prompt_ids.first - configatron.prompt = PromptManager::Prompt.get(id: configatron.prompt_id) - end -end - -###################################################### -# Main - -at_exit do - puts - puts "Done." - puts -end - -ap configatron.to_h if debug? - - -begin - configatron.prompt = PromptManager::Prompt.get(id: configatron.prompt_id) -rescue ArgumentError - search_for_a_matching_prompt -end - - -puts -puts "PROMPT:" -puts configatron.prompt.text.wrap -puts - -unless configatron.prompt.keywords.empty? - replace_keywords - configatron.prompt.build - configatron.prompt.save -end - -command = AI_COMMAND + configatron.prompt.to_s - -configatron.input_files.each do |input_file| - command += " < #{input_file}" -end - -print "\n\n" if verbose? && !keywords.empty? - -if verbose? - puts "="*42 - puts command - puts "="*42 - print "\n\n" -end - -result = `#{command}` - -configatron.output.write result - -log configatron.prompt, result - - -__END__ +# Create an instance of the Main class and run the program +AIA::Main.new.call