From 024c651a13f8611e8654fe025e1a36354a4a15de Mon Sep 17 00:00:00 2001 From: FANGAreNotGnu Date: Mon, 11 Nov 2024 07:32:56 +0000 Subject: [PATCH] add interactive configuration tool --- tools/configure_llms.py | 164 +++++++++++++++++++++ tools/configure_llms.sh | 315 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 479 insertions(+) create mode 100644 tools/configure_llms.py create mode 100644 tools/configure_llms.sh diff --git a/tools/configure_llms.py b/tools/configure_llms.py new file mode 100644 index 0000000..2218dda --- /dev/null +++ b/tools/configure_llms.py @@ -0,0 +1,164 @@ +import os +import sys +import json +import getpass +from pathlib import Path +import configparser +from typing import Dict, Optional + +class LLMConfigManager: + def __init__(self): + self.config_dir = Path.home() / '.llm_config' + self.config_file = self.config_dir / 'config.ini' + self.providers = ['aws_bedrock', 'openai'] + self.ensure_config_directory() + + def ensure_config_directory(self): + """Create configuration directory if it doesn't exist""" + self.config_dir.mkdir(exist_ok=True) + + def load_current_config(self) -> configparser.ConfigParser: + """Load existing configuration or create new one""" + config = configparser.ConfigParser() + if self.config_file.exists(): + config.read(self.config_file) + return config + + def save_config(self, config: configparser.ConfigParser): + """Save configuration to file""" + with open(self.config_file, 'w') as f: + config.write(f) + + def set_environment_variables(self, config: configparser.ConfigParser): + """Set environment variables based on configuration""" + if 'aws_bedrock' in config: + os.environ['BEDROCK_API_KEY'] = config['aws_bedrock']['bedrock_api_key'] + os.environ['AWS_DEFAULT_REGION'] = config['aws_bedrock']['aws_region'] + os.environ['AWS_ACCESS_KEY_ID'] = config['aws_bedrock']['aws_access_key_id'] + os.environ['AWS_SECRET_ACCESS_KEY'] = config['aws_bedrock']['aws_secret_access_key'] + + if 'openai' in config: + os.environ['OPENAI_API_KEY'] = config['openai']['api_key'] + + def configure_aws_bedrock(self) -> Dict[str, str]: + """Interactive configuration for AWS Bedrock""" + print("\n=== AWS Bedrock Configuration ===") + config = { + 'bedrock_api_key': getpass.getpass('Enter Bedrock API Key: '), + 'aws_region': input('Enter AWS Region (e.g., us-east-1): '), + 'aws_access_key_id': input('Enter AWS Access Key ID: '), + 'aws_secret_access_key': getpass.getpass('Enter AWS Secret Access Key: ') + } + return config + + def configure_openai(self) -> Dict[str, str]: + """Interactive configuration for OpenAI""" + print("\n=== OpenAI Configuration ===") + config = { + 'api_key': getpass.getpass('Enter OpenAI API Key (starts with sk-): ') + } + return config + + def validate_aws_config(self, config: Dict[str, str]) -> bool: + """Basic validation for AWS configuration""" + if not all(config.values()): + return False + if not config['aws_region'].startswith('us-') and not config['aws_region'].startswith('eu-'): + return False + if not config['bedrock_api_key'].strip(): + return False + return True + + def validate_openai_config(self, config: Dict[str, str]) -> bool: + """Basic validation for OpenAI configuration""" + return bool(config['api_key'] and config['api_key'].startswith('sk-')) + + def run_interactive_setup(self): + """Run the interactive configuration process""" + print("Welcome to the LLM Configuration Tool!") + print("\nAvailable LLM Providers:") + for idx, provider in enumerate(self.providers, 1): + print(f"{idx}. {provider}") + + while True: + try: + choice = int(input("\nSelect provider (1-2): ")) + if choice not in [1, 2]: + raise ValueError + break + except ValueError: + print("Please enter a valid number (1-2)") + + config = self.load_current_config() + + if choice == 1: # AWS Bedrock + aws_config = self.configure_aws_bedrock() + if not self.validate_aws_config(aws_config): + print("Error: Invalid AWS configuration. Please check your inputs.") + return + + if 'aws_bedrock' not in config: + config.add_section('aws_bedrock') + for key, value in aws_config.items(): + config['aws_bedrock'][key] = value + + else: # OpenAI + openai_config = self.configure_openai() + if not self.validate_openai_config(openai_config): + print("Error: Invalid OpenAI API key format. Key should start with 'sk-'") + return + + if 'openai' not in config: + config.add_section('openai') + for key, value in openai_config.items(): + config['openai'][key] = value + + self.save_config(config) + self.set_environment_variables(config) + print("\nConfiguration saved successfully!") + print(f"Configuration file location: {self.config_file}") + + def show_current_config(self): + """Display current configuration (with masked sensitive data)""" + if not self.config_file.exists(): + print("No configuration file found.") + return + + config = self.load_current_config() + print("\nCurrent Configuration:") + print("=====================") + + for section in config.sections(): + print(f"\n[{section}]") + for key, value in config[section].items(): + if 'key' in key.lower() or 'secret' in key.lower(): + masked_value = value[:4] + '****' + value[-4:] + print(f"{key}: {masked_value}") + else: + print(f"{key}: {value}") + +def main(): + config_manager = LLMConfigManager() + + while True: + print("\nLLM Configuration Tool") + print("1. Configure LLM Provider") + print("2. Show Current Configuration") + print("3. Exit") + + try: + choice = int(input("\nSelect an option (1-3): ")) + if choice == 1: + config_manager.run_interactive_setup() + elif choice == 2: + config_manager.show_current_config() + elif choice == 3: + print("Goodbye!") + break + else: + print("Please enter a valid option (1-3)") + except ValueError: + print("Please enter a valid number") + +if __name__ == "__main__": + main() diff --git a/tools/configure_llms.sh b/tools/configure_llms.sh new file mode 100644 index 0000000..f7fd8e5 --- /dev/null +++ b/tools/configure_llms.sh @@ -0,0 +1,315 @@ +#!/bin/bash + +# Check if the script is being sourced +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + echo "This script must be sourced. Please run:" + echo "source ${0}" + exit 1 +fi + +# Colors for better readability +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +# Configuration file path +CONFIG_FILE="$HOME/.llm_config" + +# Function to print colored messages +print_color() { + local color=$1 + local message=$2 + echo -e "${color}${message}${NC}" +} + +# Function to print section header +print_header() { + local message=$1 + echo + print_color "$BLUE" "=== $message ===" + echo +} + +# Function to validate AWS region +validate_aws_region() { + local region=$1 + # List of valid AWS regions + local valid_regions=("us-east-1" "us-east-2" "us-west-1" "us-west-2" "eu-west-1" "eu-central-1" "ap-southeast-1" "ap-southeast-2" "ap-northeast-1") + + for valid_region in "${valid_regions[@]}"; do + if [ "$region" == "$valid_region" ]; then + return 0 + fi + done + return 1 +} + +# Function to validate API keys +validate_api_key() { + local key=$1 + local type=$2 + + case $type in + "bedrock") + [[ $key =~ ^[0-9]{4}[0-9.]+$ ]] && return 0 ;; + "openai") + [[ $key =~ ^sk-[A-Za-z0-9]+$ ]] && return 0 ;; + *) + return 1 ;; + esac + return 1 +} + +# Function to read existing configuration into temporary variables +read_existing_config() { + # Declare temporary variables + declare -g tmp_BEDROCK_API_KEY="" + declare -g tmp_AWS_DEFAULT_REGION="" + declare -g tmp_AWS_ACCESS_KEY_ID="" + declare -g tmp_AWS_SECRET_ACCESS_KEY="" + declare -g tmp_OPENAI_API_KEY="" + + if [ -f "$CONFIG_FILE" ]; then + while IFS='=' read -r key value; do + if [ -n "$key" ] && [ -n "$value" ]; then + case "$key" in + "BEDROCK_API_KEY") tmp_BEDROCK_API_KEY="$value" ;; + "AWS_DEFAULT_REGION") tmp_AWS_DEFAULT_REGION="$value" ;; + "AWS_ACCESS_KEY_ID") tmp_AWS_ACCESS_KEY_ID="$value" ;; + "AWS_SECRET_ACCESS_KEY") tmp_AWS_SECRET_ACCESS_KEY="$value" ;; + "OPENAI_API_KEY") tmp_OPENAI_API_KEY="$value" ;; + esac + fi + done < "$CONFIG_FILE" + fi +} + +# Function to save configuration and export variables +save_configuration() { + local provider=$1 + + # Create or truncate the config file + > "$CONFIG_FILE" + + if [ "$provider" == "bedrock" ]; then + # Update Bedrock variables + tmp_BEDROCK_API_KEY="$BEDROCK_API_KEY" + tmp_AWS_DEFAULT_REGION="$AWS_DEFAULT_REGION" + tmp_AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" + tmp_AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" + else + # Update OpenAI variable + tmp_OPENAI_API_KEY="$OPENAI_API_KEY" + fi + + # Save all configurations + if [ -n "$tmp_BEDROCK_API_KEY" ]; then + cat << EOF >> "$CONFIG_FILE" +BEDROCK_API_KEY=$tmp_BEDROCK_API_KEY +AWS_DEFAULT_REGION=$tmp_AWS_DEFAULT_REGION +AWS_ACCESS_KEY_ID=$tmp_AWS_ACCESS_KEY_ID +AWS_SECRET_ACCESS_KEY=$tmp_AWS_SECRET_ACCESS_KEY +EOF + fi + + if [ -n "$tmp_OPENAI_API_KEY" ]; then + echo "OPENAI_API_KEY=$tmp_OPENAI_API_KEY" >> "$CONFIG_FILE" + fi + + # Export all variables + if [ -n "$tmp_BEDROCK_API_KEY" ]; then + export BEDROCK_API_KEY="$tmp_BEDROCK_API_KEY" + export AWS_DEFAULT_REGION="$tmp_AWS_DEFAULT_REGION" + export AWS_ACCESS_KEY_ID="$tmp_AWS_ACCESS_KEY_ID" + export AWS_SECRET_ACCESS_KEY="$tmp_AWS_SECRET_ACCESS_KEY" + fi + + if [ -n "$tmp_OPENAI_API_KEY" ]; then + export OPENAI_API_KEY="$tmp_OPENAI_API_KEY" + fi + + # Set proper permissions + chmod 600 "$CONFIG_FILE" + + print_color "$GREEN" "Configuration saved to $CONFIG_FILE" + print_color "$GREEN" "Variables have been exported in the current session" +} + +# Function to check and backup existing configuration +check_existing_config() { + if [ -f "$CONFIG_FILE" ]; then + print_color "$BLUE" "Existing configuration found. Creating backup..." + cp "$CONFIG_FILE" "${CONFIG_FILE}.backup" + print_color "$GREEN" "Backup created at ${CONFIG_FILE}.backup" + fi +} + +# Function to display current configuration file +display_config() { + if [ ! -f "$CONFIG_FILE" ]; then + print_color "$YELLOW" "No configuration file found at $CONFIG_FILE" + return + fi + + read_existing_config + + print_header "Current Configuration File" + + print_color "$GREEN" "AWS Bedrock Configuration:" + if [ -n "$tmp_BEDROCK_API_KEY" ]; then + echo "BEDROCK_API_KEY=${tmp_BEDROCK_API_KEY}" + echo "AWS_DEFAULT_REGION=${tmp_AWS_DEFAULT_REGION}" + echo "AWS_ACCESS_KEY_ID=${tmp_AWS_ACCESS_KEY_ID}" + echo "AWS_SECRET_ACCESS_KEY=********" + else + print_color "$YELLOW" "Bedrock is not configured" + fi + + echo + print_color "$GREEN" "OpenAI Configuration:" + if [ -n "$tmp_OPENAI_API_KEY" ]; then + echo "OPENAI_API_KEY=${tmp_OPENAI_API_KEY}" + else + print_color "$YELLOW" "OpenAI is not configured" + fi + echo +} + +# Function to display current environment variables +display_env_vars() { + print_header "Current Environment Variables" + + print_color "$GREEN" "AWS Bedrock Environment Variables:" + echo "BEDROCK_API_KEY=${BEDROCK_API_KEY:-(not set)}" + echo "AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-(not set)}" + echo "AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-(not set)}" + if [ -n "$AWS_SECRET_ACCESS_KEY" ]; then + echo "AWS_SECRET_ACCESS_KEY=********" + else + echo "AWS_SECRET_ACCESS_KEY=(not set)" + fi + + echo + print_color "$GREEN" "OpenAI Environment Variables:" + echo "OPENAI_API_KEY=${OPENAI_API_KEY:-(not set)}" + echo + + # Compare configuration with environment variables + if [ -f "$CONFIG_FILE" ]; then + read_existing_config + + local has_mismatch=false + + if [ -n "$tmp_BEDROCK_API_KEY" ] && [ "$tmp_BEDROCK_API_KEY" != "$BEDROCK_API_KEY" ]; then + has_mismatch=true + fi + if [ -n "$tmp_AWS_DEFAULT_REGION" ] && [ "$tmp_AWS_DEFAULT_REGION" != "$AWS_DEFAULT_REGION" ]; then + has_mismatch=true + fi + if [ -n "$tmp_AWS_ACCESS_KEY_ID" ] && [ "$tmp_AWS_ACCESS_KEY_ID" != "$AWS_ACCESS_KEY_ID" ]; then + has_mismatch=true + fi + if [ -n "$tmp_AWS_SECRET_ACCESS_KEY" ] && [ "$tmp_AWS_SECRET_ACCESS_KEY" != "$AWS_SECRET_ACCESS_KEY" ]; then + has_mismatch=true + fi + if [ -n "$tmp_OPENAI_API_KEY" ] && [ "$tmp_OPENAI_API_KEY" != "$OPENAI_API_KEY" ]; then + has_mismatch=true + fi + + if [ "$has_mismatch" = true ]; then + print_color "$YELLOW" "Warning: Some environment variables don't match the configuration file." + print_color "$YELLOW" "Run 'source $CONFIG_FILE' to sync them." + fi + fi +} + +# Function to configure providers +configure_provider() { + print_color "$GREEN" "Select your LLM provider to configure:" + echo "1) AWS Bedrock" + echo "2) OpenAI" + read -p "Enter your choice (1/2): " provider_choice + + case $provider_choice in + 1) + print_color "$BLUE" "\nConfiguring AWS Bedrock..." + + while true; do + read -p "Enter your Bedrock API Key (starts with 4509): " BEDROCK_API_KEY + if validate_api_key "$BEDROCK_API_KEY" "bedrock"; then + break + fi + print_color "$RED" "Invalid Bedrock API Key format. Please try again." + done + + while true; do + read -p "Enter your AWS region (e.g., us-east-1): " AWS_DEFAULT_REGION + if validate_aws_region "$AWS_DEFAULT_REGION"; then + break + fi + print_color "$RED" "Invalid AWS region. Please enter a valid region." + done + + read -p "Enter your AWS Access Key ID: " AWS_ACCESS_KEY_ID + read -s -p "Enter your AWS Secret Access Key: " AWS_SECRET_ACCESS_KEY + echo + + save_configuration "bedrock" + ;; + + 2) + print_color "$BLUE" "\nConfiguring OpenAI..." + + while true; do + read -p "Enter your OpenAI API Key (starts with sk-): " OPENAI_API_KEY + if validate_api_key "$OPENAI_API_KEY" "openai"; then + break + fi + print_color "$RED" "Invalid OpenAI API Key format. Please try again." + done + + print_color "$RED" "Note: Free-tier OpenAI accounts may be subject to rate limits." + print_color "$RED" "We recommend using a paid OpenAI API key for seamless functionality." + + save_configuration "openai" + ;; + + *) + print_color "$RED" "Invalid choice. Exiting." + return 1 + ;; + esac + + print_color "$GREEN" "\nConfiguration complete!" + display_config +} + +# Main script +clear +print_color "$BLUE" "=== LLM Configuration Tool ===" +echo +print_color "$GREEN" "Select an option:" +echo "1) Configure LLM providers" +echo "2) View current configuration file" +echo "3) View current environment variables" +read -p "Enter your choice (1/2/3): " main_choice + +case $main_choice in + 1) + check_existing_config + read_existing_config + configure_provider + ;; + 2) + display_config + ;; + 3) + display_env_vars + ;; + *) + print_color "$RED" "Invalid choice. Exiting." + return 1 + ;; +esac