mirror of
https://github.com/mindverse/Second-Me.git
synced 2026-07-17 05:08:25 +00:00
* feat:remove conda from setup * cool. more code about removing conda & env * optimize script * add python check * optimize setup * optimize setup * add warning info * optimize check * add node check & npm check * add cmake install suggestion * add poetry suggestion * add python command check * add python tools * add poetry * add graphrag poetry install command optimization * active poetry shell * fix duplicated log * avoid poetry multipul active * add sqlite3 check * optimize sqlite3 setup suggestion * optimize * add gitignore * reverse compose detect
659 lines
20 KiB
Bash
Executable file
659 lines
20 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# Import utility scripts
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
source "$SCRIPT_DIR/utils/logging.sh"
|
|
source "$SCRIPT_DIR/utils/os_detection.sh"
|
|
source "$SCRIPT_DIR/utils/install_config.sh"
|
|
source "$SCRIPT_DIR/utils/python_tools.sh"
|
|
|
|
# Version
|
|
VERSION="1.0.0"
|
|
|
|
# Total number of stages
|
|
TOTAL_STAGES=6
|
|
CURRENT_STAGE=0
|
|
STAGE_NAME=""
|
|
|
|
# Trap ctrl-c and call cleanup
|
|
trap cleanup INT
|
|
|
|
# Cleanup function to restore terminal settings
|
|
cleanup() {
|
|
echo -e "\n${YELLOW}Setup interrupted.${NC}"
|
|
exit 1
|
|
}
|
|
|
|
# Display title and logo
|
|
display_header() {
|
|
local title="$1"
|
|
|
|
echo ""
|
|
echo -e "${CYAN}"
|
|
echo ' ███████╗███████╗ ██████╗ ██████╗ ███╗ ██╗██████╗ ███╗ ███╗███████╗'
|
|
echo ' ██╔════╝██╔════╝██╔════╝██╔═══██╗████╗ ██║██╔══██╗ ████╗ ████║██╔════╝'
|
|
echo ' ███████╗█████╗ ██║ ██║ ██║██╔██╗ ██║██║ ██║█████╗██╔████╔██║█████╗ '
|
|
echo ' ╚════██║██╔══╝ ██║ ██║ ██║██║╚██╗██║██║ ██║╚════╝██║╚██╔╝██║██╔══╝ '
|
|
echo ' ███████║███████╗╚██████╗╚██████╔╝██║ ╚████║██████╔╝ ██║ ╚═╝ ██║███████╗'
|
|
echo ' ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝╚══════╝'
|
|
echo -e "${NC}"
|
|
echo -e "${BOLD}Second-Me Setup Script v${VERSION}${NC}"
|
|
echo -e "${GRAY}$(date)${NC}\n"
|
|
|
|
if [ -n "$title" ]; then
|
|
echo -e "${CYAN}====== $title ======${NC}"
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
# Display stage start
|
|
display_stage() {
|
|
local stage_num=$1
|
|
local stage_name=$2
|
|
CURRENT_STAGE=$stage_num
|
|
STAGE_NAME=$stage_name
|
|
|
|
echo ""
|
|
echo -e "${CYAN}====== Stage $stage_num/$TOTAL_STAGES: $stage_name ======${NC}"
|
|
echo ""
|
|
}
|
|
|
|
# Setup and configure package managers (npm)
|
|
check_npm() {
|
|
log_step "Checking npm installation..."
|
|
|
|
# Check if npm is already installed
|
|
if ! command -v npm &>/dev/null; then
|
|
log_error "npm not found - please install npm manually"
|
|
|
|
# Get system identification and show installation recommendations
|
|
local system_id=$(get_system_id)
|
|
get_npm_recommendation "$system_id"
|
|
|
|
return 1
|
|
fi
|
|
|
|
log_success "npm check passed"
|
|
return 0
|
|
}
|
|
|
|
# Check Node.js installation
|
|
check_node() {
|
|
log_step "Checking Node.js installation..."
|
|
|
|
local node_cmd=""
|
|
|
|
# Check for node command
|
|
if command -v node &>/dev/null; then
|
|
node_cmd="node"
|
|
# Also check for nodejs command as it's used on some Linux distributions
|
|
elif command -v nodejs &>/dev/null; then
|
|
node_cmd="nodejs"
|
|
else
|
|
log_error "Node.js is not installed, please install Node.js manually"
|
|
|
|
# Get system identification and show installation recommendations
|
|
local system_id=$(get_system_id)
|
|
get_node_recommendation "$system_id"
|
|
|
|
return 1
|
|
fi
|
|
|
|
# Check version (if needed)
|
|
local version=$($node_cmd --version 2>&1 | sed 's/v//')
|
|
log_success "Node.js check passed, using $node_cmd version $version"
|
|
return 0
|
|
}
|
|
|
|
# Check if command exists
|
|
check_command() {
|
|
if ! command -v $1 &> /dev/null; then
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Helper function to install dependencies
|
|
install_python_dependency() {
|
|
# Install Python packages using Poetry
|
|
log_step "Installing Python packages using Poetry"
|
|
|
|
# Check if pyproject.toml exists
|
|
if [ ! -f "pyproject.toml" ]; then
|
|
log_error "Missing pyproject.toml file"
|
|
return 1
|
|
fi
|
|
|
|
# Update lockfile and install dependencies
|
|
log_info "Updating Poetry lockfile..."
|
|
if ! poetry lock --no-cache; then
|
|
log_error "Failed to update Poetry lockfile"
|
|
return 1
|
|
fi
|
|
|
|
# Install dependencies
|
|
log_info "Using Poetry to install dependencies..."
|
|
if ! poetry install --no-root --no-interaction; then
|
|
log_error "Failed to install dependencies using Poetry"
|
|
return 1
|
|
fi
|
|
|
|
# Verify key packages are installed using Poetry's own environment
|
|
log_info "Verifying key packages using Poetry environment..."
|
|
local required_packages=("flask" "chromadb" "langchain")
|
|
for pkg in "${required_packages[@]}"; do
|
|
if ! poetry run python -c "import $pkg" 2>/dev/null; then
|
|
log_error "Package '$pkg' is not installed correctly in Poetry environment"
|
|
return 1
|
|
else
|
|
log_info "Package '$pkg' is installed correctly in Poetry environment"
|
|
fi
|
|
done
|
|
|
|
# Get and save the Poetry environment path
|
|
local poetry_env_path=$(poetry env info -p 2>/dev/null)
|
|
if [ -n "$poetry_env_path" ]; then
|
|
log_info "Poetry virtual environment is located at: $poetry_env_path"
|
|
# Create an activation script for convenience
|
|
create_poetry_activate_script "$poetry_env_path"
|
|
fi
|
|
|
|
log_success "Python environment setup completed"
|
|
log_info "------------------------------------------------------------------------------"
|
|
log_info "To use this Python environment, you can:"
|
|
log_info "1. Run 'poetry shell' to open a new shell with the virtual environment activated"
|
|
log_info "2. Run 'source .poetry-venv/activate' to activate the environment in your current shell"
|
|
log_info "3. Use 'poetry run python script.py' to run a single command without activating the environment"
|
|
log_info "------------------------------------------------------------------------------"
|
|
return 0
|
|
}
|
|
|
|
# Create a convenient activation script for the Poetry environment
|
|
create_poetry_activate_script() {
|
|
local env_path="$1"
|
|
local activate_dir=".poetry-venv"
|
|
local activate_script="$activate_dir/activate"
|
|
|
|
# Create directory if it doesn't exist
|
|
mkdir -p "$activate_dir"
|
|
|
|
# Create activation script
|
|
cat > "$activate_script" << EOF
|
|
#!/bin/bash
|
|
# Activation script for Poetry virtual environment
|
|
|
|
# Source the actual virtual environment activate script
|
|
source "$env_path/bin/activate"
|
|
|
|
# Print confirmation message
|
|
echo "Poetry virtual environment activated: $env_path"
|
|
echo "Use 'deactivate' command to exit this environment"
|
|
EOF
|
|
|
|
# Make script executable
|
|
chmod +x "$activate_script"
|
|
log_info "Created Poetry environment activation script at: $activate_script"
|
|
}
|
|
|
|
install_graphrag() {
|
|
log_step "Installing graphrag"
|
|
|
|
# Check the current graphrag version in Poetry environment
|
|
log_step "Checking graphrag version in Poetry environment"
|
|
GRAPHRAG_VERSION=$(poetry run pip show graphrag 2>/dev/null | grep "Version:" | cut -d " " -f2)
|
|
GRAPHRAG_TARGET="1.2.1.dev27"
|
|
GRAPHRAG_LOCAL_PATH="dependencies/graphrag-${GRAPHRAG_TARGET}.tar.gz"
|
|
|
|
if [ "$GRAPHRAG_VERSION" != "$GRAPHRAG_TARGET" ]; then
|
|
log_info "Installing correct version of graphrag in Poetry environment..."
|
|
if [ -f "$GRAPHRAG_LOCAL_PATH" ]; then
|
|
log_info "Installing graphrag from local file using Poetry..."
|
|
if ! poetry run pip install --force-reinstall "$GRAPHRAG_LOCAL_PATH"; then
|
|
log_error "Failed to install graphrag from local file"
|
|
return 1
|
|
fi
|
|
else
|
|
log_error "Local graphrag package not found at: $GRAPHRAG_LOCAL_PATH"
|
|
log_error "Please ensure the graphrag package exists in the dependencies directory"
|
|
return 1
|
|
fi
|
|
log_success "Graphrag installed successfully"
|
|
else
|
|
log_success "Graphrag version is correct, skipping installation"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Build llama.cpp
|
|
build_llama() {
|
|
log_section "BUILDING LLAMA.CPP"
|
|
|
|
LLAMA_LOCAL_ZIP="dependencies/llama.cpp.zip"
|
|
|
|
# Check if llama.cpp directory exists
|
|
if [ ! -d "llama.cpp" ]; then
|
|
log_info "Setting up llama.cpp..."
|
|
|
|
if [ -f "$LLAMA_LOCAL_ZIP" ]; then
|
|
log_info "Using local llama.cpp archive..."
|
|
if ! unzip -q "$LLAMA_LOCAL_ZIP"; then
|
|
log_error "Failed to extract local llama.cpp archive"
|
|
return 1
|
|
fi
|
|
else
|
|
log_error "Local llama.cpp archive not found at: $LLAMA_LOCAL_ZIP"
|
|
log_error "Please ensure the llama.cpp.zip file exists in the dependencies directory"
|
|
return 1
|
|
fi
|
|
else
|
|
log_info "Found existing llama.cpp directory"
|
|
fi
|
|
|
|
# Check if llama.cpp has been successfully compiled
|
|
if [ -f "llama.cpp/build/bin/llama-server" ]; then
|
|
log_info "Found existing llama-server build"
|
|
# Check if executable file can be run and get version info
|
|
if version_output=$(./llama.cpp/build/bin/llama-server --version 2>&1) && [[ $version_output == version:* ]]; then
|
|
log_success "Existing llama-server build is working properly (${version_output}), skipping compilation"
|
|
return 0
|
|
else
|
|
log_warning "Existing build seems broken or incompatible, will recompile..."
|
|
fi
|
|
fi
|
|
|
|
# Enter llama.cpp directory and build
|
|
cd llama.cpp
|
|
|
|
# Clean previous build
|
|
if [ -d "build" ]; then
|
|
log_info "Cleaning previous build..."
|
|
rm -rf build
|
|
fi
|
|
|
|
# Create and enter build directory
|
|
log_info "Creating build directory..."
|
|
mkdir -p build && cd build
|
|
|
|
# Configure CMake
|
|
log_info "Configuring CMake..."
|
|
if ! cmake ..; then
|
|
log_error "CMake configuration failed"
|
|
cd ../..
|
|
return 1
|
|
fi
|
|
|
|
# Build project
|
|
log_info "Building project..."
|
|
if ! cmake --build . --config Release; then
|
|
log_error "Build failed"
|
|
cd ../..
|
|
return 1
|
|
fi
|
|
|
|
# Check build result
|
|
if [ ! -f "bin/llama-server" ]; then
|
|
log_error "Build failed: llama-server executable not found"
|
|
log_error "Expected at: bin/llama-server"
|
|
cd ../..
|
|
return 1
|
|
fi
|
|
|
|
log_success "Found llama-server at: bin/llama-server"
|
|
cd ../..
|
|
log_section "LLAMA.CPP BUILD COMPLETE"
|
|
}
|
|
|
|
# Set up frontend environment
|
|
build_frontend() {
|
|
log_section "SETTING UP FRONTEND"
|
|
|
|
FRONTEND_DIR="lpm_frontend"
|
|
|
|
# Enter frontend directory
|
|
cd "$FRONTEND_DIR" || {
|
|
log_error "Failed to enter frontend directory: $FRONTEND_DIR"
|
|
log_error "Please ensure the directory exists and you have permission to access it."
|
|
return 1
|
|
}
|
|
|
|
# Check if dependencies have been installed
|
|
if [ -d "node_modules" ]; then
|
|
log_info "Found existing node_modules, checking for updates..."
|
|
if [ -f "package-lock.json" ]; then
|
|
log_info "Using existing package-lock.json..."
|
|
# Run npm install even if package-lock.json exists to ensure dependencies are complete
|
|
log_info "Running npm install to ensure dependencies are complete..."
|
|
if ! npm install; then
|
|
log_error "Failed to install frontend dependencies with existing package-lock.json"
|
|
log_error "Try removing node_modules directory and package-lock.json, then run setup again"
|
|
cd ..
|
|
return 1
|
|
fi
|
|
else
|
|
log_info "Installing dependencies..."
|
|
if ! npm install; then
|
|
log_error "Failed to install frontend dependencies"
|
|
log_error "Check your npm configuration and network connection"
|
|
log_error "You can try running 'npm install' manually in the $FRONTEND_DIR directory"
|
|
cd ..
|
|
return 1
|
|
fi
|
|
fi
|
|
else
|
|
log_info "Installing dependencies..."
|
|
if ! npm install; then
|
|
log_error "Failed to install frontend dependencies"
|
|
log_error "Check your npm configuration and network connection"
|
|
log_error "You can try running 'npm install' manually in the $FRONTEND_DIR directory"
|
|
cd ..
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Verify that the installation was successful
|
|
if [ ! -d "node_modules" ]; then
|
|
log_error "node_modules directory not found after npm install"
|
|
log_error "Frontend dependencies installation failed"
|
|
cd ..
|
|
return 1
|
|
fi
|
|
|
|
log_success "Frontend dependencies installed successfully"
|
|
cd ..
|
|
log_section "FRONTEND SETUP COMPLETE"
|
|
}
|
|
|
|
# Show help information
|
|
show_help() {
|
|
echo -e "${BOLD}Second-Me Setup Script v${VERSION}${NC}"
|
|
echo -e "Usage: $0 [options] [command]"
|
|
echo
|
|
echo -e "Commands:"
|
|
echo -e " python\t\tSetup Python environment only"
|
|
echo -e " llama\t\t\tBuild llama.cpp only"
|
|
echo -e " frontend\t\tSetup frontend project only"
|
|
echo -e " (no command)\t\tPerform full installation"
|
|
echo
|
|
echo -e "Options:"
|
|
echo -e " --help\t\tShow this help information"
|
|
echo -e " --require-confirmation\tRequire confirmation when warnings are present"
|
|
echo
|
|
echo -e "Examples:"
|
|
echo -e " $0 \t\t\tPerform full installation"
|
|
echo -e " $0 python\t\tSetup Python environment only"
|
|
echo -e " $0 --require-confirmation\tRequire confirmation when warnings are present"
|
|
echo
|
|
echo -e "For a complete list of all available commands, run:"
|
|
echo -e " make help"
|
|
}
|
|
|
|
# Check system requirements
|
|
check_system_requirements() {
|
|
log_step "Checking system requirements"
|
|
|
|
# Detect system type
|
|
local system_type=$(uname -s)
|
|
log_info "Detected system type: $system_type"
|
|
|
|
# Only check macOS version if on Mac
|
|
if [[ "$system_type" == "Darwin" ]]; then
|
|
local macos_version=$(sw_vers -productVersion)
|
|
log_info "Detected macOS version: $macos_version"
|
|
|
|
local major_version=$(echo "$macos_version" | cut -d. -f1)
|
|
if [[ "$major_version" -lt 14 ]]; then
|
|
log_error "This script requires macOS 14 (Sonoma) or later. Your version: $macos_version"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
log_success "System requirements check passed"
|
|
return 0
|
|
}
|
|
|
|
# Check required configuration files
|
|
check_config_files() {
|
|
log_step "Checking necessary configuration files"
|
|
|
|
# Check for .env file
|
|
if [[ ! -f ".env" ]]; then
|
|
log_error "Missing .env file"
|
|
return 1
|
|
fi
|
|
|
|
log_success "All necessary configuration files are present"
|
|
return 0
|
|
}
|
|
|
|
# Check directory permissions
|
|
check_directory_permissions() {
|
|
log_step "Checking directory permissions"
|
|
local errors=0
|
|
local directories=("." "./scripts" "./run" "./logs")
|
|
|
|
for dir in "${directories[@]}"; do
|
|
if [[ ! -w "$dir" ]]; then
|
|
log_error "Directory without write permission: $dir"
|
|
errors=$((errors + 1))
|
|
fi
|
|
done
|
|
|
|
if [[ $errors -eq 0 ]]; then
|
|
log_success "Directory permissions check passed"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Check for potential conflicts
|
|
check_potential_conflicts() {
|
|
log_info "Checking for potential conflicts"
|
|
|
|
# System requirements check
|
|
if ! check_system_requirements; then
|
|
log_error "System requirements check failed"
|
|
exit 1
|
|
fi
|
|
|
|
# Configuration files check
|
|
if ! check_config_files; then
|
|
log_error "Configuration files check failed"
|
|
exit 1
|
|
fi
|
|
|
|
# Directory permissions check
|
|
if ! check_directory_permissions; then
|
|
log_error "Directory permissions check failed"
|
|
exit 1
|
|
fi
|
|
|
|
if ! check_python; then
|
|
log_error "python check failed, please install python first"
|
|
exit 1
|
|
fi
|
|
|
|
if ! check_node; then
|
|
log_error "Node.js check failed"
|
|
exit 1
|
|
fi
|
|
|
|
if ! check_npm; then
|
|
log_error "npm check failed"
|
|
exit 1
|
|
fi
|
|
|
|
if ! check_cmake; then
|
|
log_error "cmake check and installation failed"
|
|
exit 1
|
|
fi
|
|
|
|
if ! check_poetry; then
|
|
log_error "poetry check failed, please install poetry first"
|
|
exit 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
check_python() {
|
|
log_step "Checking for python installation"
|
|
|
|
# Get the appropriate Python command
|
|
local python_cmd=$(get_python_command)
|
|
|
|
if [ -z "$python_cmd" ]; then
|
|
log_error "python is not installed, please install python manually"
|
|
|
|
# Get system identification and show installation recommendations
|
|
local system_id=$(get_system_id)
|
|
get_python_recommendation "$system_id"
|
|
|
|
return 1
|
|
fi
|
|
|
|
# version > 3.12
|
|
local version=$($python_cmd --version 2>&1 | cut -d ' ' -f 2)
|
|
if [[ "$version" < "3.12" ]]; then
|
|
log_error "python version $version is not supported, please install python 3.12 or higher"
|
|
return 1
|
|
fi
|
|
|
|
log_success "python check passed, using $python_cmd version $version"
|
|
return 0
|
|
}
|
|
|
|
check_poetry() {
|
|
log_step "Checking for poetry installation"
|
|
|
|
if ! command -v poetry &>/dev/null; then
|
|
log_error "poetry is not installed, please install poetry manually"
|
|
|
|
# Get system identification and show installation recommendations
|
|
local system_id=$(get_system_id)
|
|
get_poetry_recommendation "$system_id"
|
|
|
|
return 1
|
|
fi
|
|
|
|
log_success "poetry check passed"
|
|
return 0
|
|
}
|
|
|
|
# Check and install cmake if not present
|
|
check_cmake() {
|
|
log_step "Checking for cmake installation"
|
|
|
|
if ! command -v cmake &>/dev/null; then
|
|
log_warning "cmake is not installed, please install cmake manually"
|
|
|
|
# Get system identification and show installation recommendations
|
|
local system_id=$(get_system_id)
|
|
get_cmake_recommendation "$system_id"
|
|
|
|
return 1
|
|
fi
|
|
|
|
log_success "cmake check passed"
|
|
return 0
|
|
}
|
|
|
|
# Check if SQLite is installed and available
|
|
check_sqlite() {
|
|
log_step "Checking SQLite"
|
|
|
|
if ! check_command "sqlite3"; then
|
|
log_warning "SQLite3 is not installed or not in your PATH"
|
|
|
|
log_error "Please install SQLite before continuing, database operations require this dependency"
|
|
|
|
# Get system identification and show installation recommendations
|
|
local system_id=$(get_system_id)
|
|
get_sqlite_recommendation "$system_id"
|
|
|
|
return 1
|
|
fi
|
|
|
|
# SQLite is installed
|
|
local version=$(sqlite3 --version | awk '{print $1}')
|
|
log_success "SQLite check passed, version $version"
|
|
return 0
|
|
}
|
|
|
|
# Parse command line arguments
|
|
parse_args() {
|
|
REQUIRE_CONFIRMATION=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--require-confirmation)
|
|
REQUIRE_CONFIRMATION=true
|
|
shift
|
|
;;
|
|
python|llama|frontend)
|
|
COMPONENT="$1"
|
|
shift
|
|
;;
|
|
*)
|
|
log_error "Unknown argument: $1"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
|
|
# Main function
|
|
main() {
|
|
# Display welcome message
|
|
display_header "Second-Me Complete Installation"
|
|
|
|
# Parse command line arguments
|
|
parse_args "$@"
|
|
|
|
# All pre-installation checks
|
|
log_section "Running pre-installation checks"
|
|
|
|
# 1. Basic tools check (most fundamental)
|
|
if ! check_potential_conflicts; then
|
|
log_error "Basic tools check failed"
|
|
exit 1
|
|
fi
|
|
|
|
# Check SQLite installation
|
|
if ! check_sqlite; then
|
|
log_error "SQLite check failed"
|
|
exit 1
|
|
fi
|
|
|
|
# Start installation process
|
|
log_section "Starting installation"
|
|
|
|
if ! install_python_dependency; then
|
|
log_error "Failed to install python dependencies"
|
|
exit 1
|
|
fi
|
|
|
|
if ! install_graphrag; then
|
|
log_error "Failed to install graphrag"
|
|
exit 1
|
|
fi
|
|
|
|
# 3. Build llama.cpp
|
|
if ! build_llama; then
|
|
exit 1
|
|
fi
|
|
|
|
# 4. Build frontend
|
|
if ! build_frontend; then
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Installation complete!"
|
|
return 0
|
|
}
|
|
|
|
# Start execution
|
|
main "$@"
|