diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7ad219f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Byte-compiled files +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +venv/ +env/ +ENV/ +.venv/ +env-bak/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# System +.DS_Store +Thumbs.db + +# Logs +*.log + +# Environment files +.env +.env.local +.env.*.local + +# Docker +.dockerignore +Dockerfile +docker-compose.yml + +# Test files +pytest_cache/ +.coverage +.nox/ + +# Temporary files +*~ +*.tmp \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9b651b2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +# Clover AI Agent Dockerfile +FROM python:3.11-slim + +# Set working directory +WORKDIR /app + +# Copy requirements first (for better caching) +COPY requirements.txt . + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + gcc \ + && rm -rf /var/lib/apt/lists/* + +# Install Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application code +COPY . . + +# Create non-root user +RUN useradd --create-home --shell /bin/bash clover \ + && chown -R clover:clover /app +USER clover + +# Expose health check port (if needed) +EXPOSE 8080 + +# Health check endpoint +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD python3 health.py + +# Default command +CMD ["python3", "main.py"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d59db5f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3.8' + +services: + clover: + build: . + container_name: clover-ai + restart: unless-stopped + ports: + - "8080:8080" + volumes: + - .:/app + - ~/.clover:/home/clover/.clover + environment: + - PYTHONPATH=/app + - LOG_LEVEL=INFO + command: python3 main.py + healthcheck: + test: ["CMD", "python3", "health.py"] + interval: 30s + timeout: 10s + start_period: 5s + retries: 3 \ No newline at end of file diff --git a/health.py b/health.py new file mode 100644 index 0000000..4dfb595 --- /dev/null +++ b/health.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +""" +Health check endpoint for Clover service. +This script can be called directly to check the health status of the Clover service. +""" + +import json +import sys +import os +import datetime + +# Add the current directory to Python path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +def check_health(): + """Check the health status of the Clover service""" + + try: + # Import required modules + from config.settings import load_config + from tools.command_safety import get_command_status + from tools.resource_monitor import get_resource_status + + # Load configuration + config = load_config() + + # Check basic service status + service_status = { + "status": "healthy", + "service": "clover_ai", + "version": "1.0.0", + "config_loaded": True, + "timestamp": datetime.datetime.now().isoformat() + } + + # Check safety systems + try: + safety_status = get_command_status() + service_status["safety"] = { + "safety_available": safety_status.get("safety_available", False), + "violations": safety_status.get("safety", {}).get("violation_count", 0) + } + except Exception as e: + service_status["safety"] = {"error": str(e)} + + # Check resource usage + try: + resource_status = get_resource_status() + service_status["resources"] = { + "cpu_percent": resource_status.get("current_resources", {}).get("cpu_percent", 0), + "memory_mb": resource_status.get("current_resources", {}).get("memory_mb", 0), + "processes": resource_status.get("current_resources", {}).get("process_count", 0) + } + except Exception as e: + service_status["resources"] = {"error": str(e)} + + # Check if main components are accessible + try: + from models.model_manager import ModelManager + model_manager = ModelManager() + service_status["model_manager"] = { + "initialized": True, + "available_models": len(model_manager.get_available_models()) + } + except Exception as e: + service_status["model_manager"] = {"error": str(e)} + + return service_status + + except Exception as e: + error_status = { + "status": "unhealthy", + "error": str(e), + "timestamp": datetime.datetime.now().isoformat() + } + return error_status + +def main(): + """Main health check function""" + status = check_health() + + # Print JSON response + print(json.dumps(status, indent=2)) + + # Exit with appropriate code + if status.get("status") == "healthy": + sys.exit(0) + else: + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file