diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3e21b20..0000000 --- a/.gitignore +++ /dev/null @@ -1,61 +0,0 @@ -# Models & Large Files -.ollama/ -models/ -*.safetensors -*.gguf -*.bin -*.pth - -# Workspace -workspace/ -uploads/ -backups/ - -# Python -__pycache__/ -*.pyc -*.pyo -*.egg-info/ -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -.venv/ -venv/ -ENV/ - -# IDE -.vscode/ -.idea/ -*.swp -*.swo -*~ -.DS_Store - -# Environment -.env -.env.local -.env.*.local - -# Logs -logs/ -*.log - -# Temporary -*.tmp -*.cache -.pytest_cache/ -.coverage - -# OS -.DS_Store -Thumbs.db \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 79ace9c..0000000 --- a/Makefile +++ /dev/null @@ -1,89 +0,0 @@ -.PHONY: help install update monitor health-check backup clean reinstall logs - -help: - @echo "LLM Server - Comandos disponibles:" - @echo "" - @echo " make install - Instalar todo desde cero (requiere sudo)" - @echo " make update - Actualizar código y dependencias" - @echo " make monitor - Ver monitoreo en tiempo real" - @echo " make health-check - Verificar estado del sistema" - @echo " make backup - Hacer backup de configuración" - @echo " make logs - Ver logs de servicios" - @echo " make status - Ver estado de servicios" - @echo " make start - Iniciar servicios" - @echo " make stop - Detener servicios" - @echo " make restart - Reiniciar servicios" - @echo " make clean - Limpiar archivos temporales" - @echo " make reinstall - Reinstalar (redownload modelos)" - -install: - @echo "Instalando LLM Server..." - sudo bash scripts/install.sh - -install-quick: - @echo "Instalación rápida (sin modelos)..." - sudo bash scripts/install.sh --quick - -install-gpu-only: - @echo "Instalando solo GPU drivers..." - sudo bash scripts/install.sh --gpu-only - -update: - bash scripts/update.sh - -monitor: - bash scripts/monitor.sh - -health-check: - bash scripts/health-check.sh - -backup: - bash scripts/backup.sh - -logs: - @echo "Logs de Ollama:" - sudo journalctl -u ollama -f - -logs-api: - @echo "Logs de API:" - sudo journalctl -u llm-api -f - -status: - @echo "Ollama:" - @sudo systemctl status ollama --no-pager - @echo "" - @echo "LLM API:" - @sudo systemctl status llm-api --no-pager - -start: - sudo systemctl start ollama llm-api - @echo "✅ Servicios iniciados" - -stop: - sudo systemctl stop ollama llm-api - @echo "✅ Servicios detenidos" - -restart: - sudo systemctl restart ollama llm-api - @echo "✅ Servicios reiniciados" - -clean: - rm -rf __pycache__ .pytest_cache .venv venv - find . -type f -name "*.pyc" -delete - @echo "✅ Limpiado" - -reinstall: - @echo "Reinstalando LLM Server..." - sudo bash scripts/install.sh --gpu-only - make update - @echo "✅ Reinstalación completada" - -info: - @echo "========== INFORMACIÓN DEL SERVIDOR ==========" - @echo "Hostname: $$(hostname)" - @echo "IP: $$(hostname -I)" - @echo "SO: $$(lsb_release -d | cut -f2)" - @echo "CPU: $$(lscpu | grep 'Model name' | cut -d: -f2)" - @echo "RAM: $$(free -h | awk 'NR==2 {print $$2}')" - @echo "GPU: $$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null || echo 'No disponible')" - @echo "==============================================" \ No newline at end of file diff --git a/agent.py b/agent.py deleted file mode 100644 index 6beb3fa..0000000 --- a/agent.py +++ /dev/null @@ -1,316 +0,0 @@ -""" -Code Agent - Handles file operations, code execution, and testing -""" - -import os -import json -import requests -import subprocess -import webbrowser -import time -from pathlib import Path -from datetime import datetime -from typing import Dict, Any -from dotenv import load_dotenv - -load_dotenv() - -# ============================================================================ -# CONFIGURATION -# ============================================================================ - -LLM_SERVER = os.getenv("LLM_SERVER_URL", "http://localhost:8000") -OLLAMA_URL = os.getenv("OLLAMA_URL", "http://localhost:11434") -LLM_FAST = os.getenv("LLM_FAST_MODEL", "phi") -LLM_POWER = os.getenv("LLM_POWER_MODEL", "deepseek-coder:33b") - -# ============================================================================ -# CODE AGENT CLASS -# ============================================================================ - -class CodeAgent: - """Agent that modifies files, executes code, and tests in browser""" - - def __init__(self, work_dir: str = "./workspace"): - self.work_dir = Path(work_dir) - self.work_dir.mkdir(exist_ok=True) - print(f"📁 Workspace: {self.work_dir.absolute()}") - - # ======================================================================== - # FILE OPERATIONS - # ======================================================================== - - def read_file(self, file_path: str) -> str: - """Read file from workspace""" - file = self.work_dir / file_path - - if not file.exists(): - return f"❌ File not found: {file_path}" - - try: - with open(file, 'r', encoding='utf-8') as f: - content = f.read() - print(f"✅ Read: {file_path} ({len(content)} bytes)") - return content - except Exception as e: - return f"❌ Error reading {file_path}: {e}" - - def write_file(self, file_path: str, content: str) -> str: - """Write/modify file in workspace""" - file = self.work_dir / file_path - file.parent.mkdir(parents=True, exist_ok=True) - - try: - with open(file, 'w', encoding='utf-8') as f: - f.write(content) - print(f"✅ Wrote: {file_path}") - return f"File saved: {file_path}" - except Exception as e: - return f"❌ Error writing {file_path}: {e}" - - def delete_file(self, file_path: str) -> str: - """Delete file from workspace""" - file = self.work_dir / file_path - - if not file.exists(): - return f"❌ File not found: {file_path}" - - try: - file.unlink() - return f"✅ Deleted: {file_path}" - except Exception as e: - return f"❌ Error deleting {file_path}: {e}" - - def list_files(self) -> str: - """List all files in workspace""" - files = list(self.work_dir.rglob("*")) - file_list = "\n".join([ - f" {f.relative_to(self.work_dir)}" - for f in files if f.is_file() - ]) - return f"📁 Files in workspace:\n{file_list}" if file_list else "📁 No files" - - # ======================================================================== - # CODE EXECUTION - # ======================================================================== - - def execute_python(self, code: str, file_name: str = "exec.py") -> str: - """Execute Python code""" - script_path = self.work_dir / file_name - - try: - # Save script - with open(script_path, 'w', encoding='utf-8') as f: - f.write(code) - - # Execute - result = subprocess.run( - ["python3", str(script_path)], - capture_output=True, - text=True, - timeout=30, - cwd=self.work_dir - ) - - output = result.stdout + result.stderr - print(f"🐍 Python executed: {file_name}") - return output[:1000] # Limit output - - except subprocess.TimeoutExpired: - return "❌ Timeout: Script took more than 30 seconds" - except Exception as e: - return f"❌ Error: {e}" - - def execute_node(self, code: str, file_name: str = "exec.js") -> str: - """Execute Node.js code""" - script_path = self.work_dir / file_name - - try: - with open(script_path, 'w', encoding='utf-8') as f: - f.write(code) - - result = subprocess.run( - ["node", str(script_path)], - capture_output=True, - text=True, - timeout=30, - cwd=self.work_dir - ) - - output = result.stdout + result.stderr - print(f"📟 Node.js executed: {file_name}") - return output[:1000] - - except FileNotFoundError: - return "❌ Node.js not installed" - except Exception as e: - return f"❌ Error: {e}" - - def execute_shell(self, command: str) -> str: - """Execute shell command (whitelist safe commands only)""" - allowed_commands = [ - 'ls', 'pwd', 'mkdir', 'rm', 'cp', 'mv', - 'cat', 'grep', 'find', 'du', 'df', - 'git', 'npm', 'pip', 'python' - ] - - cmd_name = command.split()[0] if command else "" - if cmd_name not in allowed_commands: - return f"❌ Command not allowed: {cmd_name}" - - try: - result = subprocess.run( - command.split(), - capture_output=True, - text=True, - timeout=30, - cwd=self.work_dir - ) - output = result.stdout + result.stderr - return output[:500] - except Exception as e: - return f"❌ Error: {e}" - - # ======================================================================== - # TESTING & BROWSER - # ======================================================================== - - def test_html(self, html_file: str) -> str: - """Open HTML file in browser for testing""" - file_path = self.work_dir / html_file - - if not file_path.exists(): - return f"❌ File not found: {html_file}" - - try: - url = f"file:///{file_path.absolute()}".replace("\\", "/") - webbrowser.open(url) - print(f"🌐 Opened in browser: {html_file}") - return f"✅ HTML opened: {html_file}" - except Exception as e: - return f"❌ Error: {e}" - - def open_browser(self, url: str) -> str: - """Open URL in browser""" - try: - webbrowser.open(url) - return f"✅ Browser opened: {url}" - except Exception as e: - return f"❌ Error: {e}" - - # ======================================================================== - # GIT OPERATIONS - # ======================================================================== - - def git_commit(self, message: str = None) -> str: - """Auto-commit changes""" - try: - if not message: - message = f"Auto-commit from agent - {datetime.now().isoformat()}" - - # Git add - result = subprocess.run( - ['git', 'add', '.'], - cwd=self.work_dir, - capture_output=True, - text=True - ) - - if result.returncode != 0: - return f"❌ Git add failed: {result.stderr}" - - # Git commit - result = subprocess.run( - ['git', 'commit', '-m', message], - cwd=self.work_dir, - capture_output=True, - text=True - ) - - if result.returncode != 0: - return f"ℹ️ Nothing to commit" - - return f"✅ Committed: {message}" - except Exception as e: - return f"❌ Error: {e}" - - def git_push(self) -> str: - """Push to remote repository""" - try: - result = subprocess.run( - ['git', 'push'], - cwd=self.work_dir, - capture_output=True, - text=True, - timeout=30 - ) - - if result.returncode == 0: - return "✅ Pushed to remote" - else: - return f"❌ Push failed: {result.stderr}" - except Exception as e: - return f"❌ Error: {e}" - - # ======================================================================== - # LLM INTERACTION - # ======================================================================== - - def call_llm(self, prompt: str, model: str = "phi") -> str: - """Call LLM server""" - try: - response = requests.post( - f"{OLLAMA_URL}/api/generate", - json={ - "model": model, - "prompt": prompt, - "stream": False - }, - timeout=300 - ) - - if response.status_code == 200: - return response.json()["response"] - else: - return f"❌ LLM Error: {response.status_code}" - - except requests.exceptions.ConnectionError: - return f"❌ Cannot connect to {OLLAMA_URL}" - except Exception as e: - return f"❌ Error: {e}" - -# ============================================================================ -# GET AGENT TOOLS -# ============================================================================ - -def get_agent_tools(agent: CodeAgent) -> Dict[str, Any]: - """Return dictionary of available tools""" - return { - "read_file": agent.read_file, - "write_file": agent.write_file, - "delete_file": agent.delete_file, - "execute_python": agent.execute_python, - "execute_node": agent.execute_node, - "execute_shell": agent.execute_shell, - "test_html": agent.test_html, - "open_browser": agent.open_browser, - "git_commit": agent.git_commit, - "git_push": agent.git_push, - "list_files": agent.list_files, - "call_llm": agent.call_llm, - } - -# ============================================================================ -# MAIN (for testing) -# ============================================================================ - -if __name__ == "__main__": - agent = CodeAgent() - - # Test - print("\n🧪 Testing Agent...") - print(agent.list_files()) - - # Create test file - agent.write_file("test.txt", "Hello from agent!") - print(agent.read_file("test.txt")) \ No newline at end of file diff --git a/backend.py b/backend.py deleted file mode 100644 index ddb2132..0000000 --- a/backend.py +++ /dev/null @@ -1,247 +0,0 @@ -from fastapi import FastAPI, File, UploadFile, Form, HTTPException -from fastapi.responses import StreamingResponse, JSONResponse -from fastapi.staticfiles import StaticFiles -from fastapi.cors import CORSMiddleware -import aiofiles -import base64 -import requests -import json -import os -from pathlib import Path -from dotenv import load_dotenv -import asyncio -import io -from PIL import Image -import uuid - -load_dotenv() - -app = FastAPI(title="Code Agent Chat") - -# CORS para que el frontend acceda -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# Config -LLM_SERVER = os.getenv("LLM_SERVER_URL", "http://localhost:8000") -UPLOAD_DIR = Path("./uploads") -WORKSPACE_DIR = Path("./workspace") -UPLOAD_DIR.mkdir(exist_ok=True) -WORKSPACE_DIR.mkdir(exist_ok=True) - -# Importar agent -from agent import CodeAgent, get_agent_tools - -agent = CodeAgent(work_dir=str(WORKSPACE_DIR)) - -# ============================================================================ -# ENDPOINTS -# ============================================================================ - -@app.get("/api/health") -async def health(): - """Verificar que el servidor está vivo""" - return {"status": "ok", "workspace": str(WORKSPACE_DIR.absolute())} - -@app.get("/api/files") -async def list_files(): - """Listar archivos en workspace""" - files = [] - for f in WORKSPACE_DIR.rglob("*"): - if f.is_file(): - files.append({ - "name": str(f.relative_to(WORKSPACE_DIR)), - "size": f.stat().st_size, - "type": f.suffix - }) - return {"files": files} - -@app.get("/api/file/{file_path:path}") -async def read_file(file_path: str): - """Leer contenido de archivo""" - file = WORKSPACE_DIR / file_path - - if not file.exists(): - raise HTTPException(status_code=404, detail="Archivo no encontrado") - - try: - with open(file, 'r') as f: - content = f.read() - return {"content": content, "name": file_path} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/api/chat") -async def chat( - message: str = Form(...), - image: UploadFile = File(None), - model: str = Form("phi") -): - """ - Endpoint principal de chat - - message: tu prompt - - image: imagen adjunta (opcional) - - model: "phi" (rápido) o "deepseek-coder:33b" (potente) - """ - - # Procesar imagen si hay - image_data = None - image_base64 = None - - if image: - try: - contents = await image.read() - image_base64 = base64.b64encode(contents).decode() - - # Guardar imagen - image_path = UPLOAD_DIR / f"{uuid.uuid4()}.png" - with open(image_path, 'wb') as f: - f.write(contents) - - image_data = f"[Imagen adjunta: {image.filename}]" - print(f"📸 Imagen procesada: {image.filename}") - - except Exception as e: - raise HTTPException(status_code=400, detail=f"Error procesando imagen: {e}") - - # Construir prompt para el LLM - full_prompt = f""" -{message} - -{f"Contexto de imagen: {image_data}" if image_data else ""} - -Tienes acceso a estas herramientas: -- read_file(file_path): Leer archivo -- write_file(file_path, content): Escribir archivo -- execute_python(code): Ejecutar Python -- execute_node(code): Ejecutar Node.js -- test_html(file_name): Servir y testear HTML -- open_browser(url): Abrir navegador -- list_files(): Listar archivos - -Responde en JSON con tu pensamiento y la acción a ejecutar. -Ejemplo: -{{"thought": "Voy a leer el archivo", "action": "read_file", "args": {{"file_path": "app.js"}}}} -""" - - # Llamar LLM - try: - response = requests.post( - f"{LLM_SERVER}/code", - json={ - "message": full_prompt, - "model": model - }, - timeout=300, - stream=False - ) - - if response.status_code != 200: - raise HTTPException( - status_code=response.status_code, - detail=response.text - ) - - llm_response = response.json()["response"] - - # Parsear JSON y ejecutar acción - result = process_agent_response(llm_response) - - return { - "message": message, - "image": image.filename if image else None, - "model": model, - "llm_response": llm_response, - "action_result": result, - "image_base64": image_base64 - } - - except requests.exceptions.ConnectionError: - raise HTTPException( - status_code=503, - detail=f"No se puede conectar a LLM Server: {LLM_SERVER}" - ) - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/api/chat-stream") -async def chat_stream( - message: str = Form(...), - image: UploadFile = File(None), - model: str = Form("phi") -): - """Versión streaming (respuestas en tiempo real)""" - - image_data = None - if image: - contents = await image.read() - image_path = UPLOAD_DIR / f"{uuid.uuid4()}.png" - with open(image_path, 'wb') as f: - f.write(contents) - image_data = f"[Imagen: {image.filename}]" - - full_prompt = f"{message}\n{image_data if image_data else ''}" - - async def generate(): - try: - # Streaming desde LLM - response = requests.post( - f"{LLM_SERVER}/code", - json={ - "message": full_prompt, - "model": model - }, - timeout=300, - stream=True - ) - - for line in response.iter_lines(): - if line: - yield line + b'\n' - - except Exception as e: - yield json.dumps({"error": str(e)}).encode() + b'\n' - - return StreamingResponse(generate(), media_type="text/event-stream") - -def process_agent_response(response: str) -> dict: - """Parsear respuesta del LLM y ejecutar acción""" - tools = get_agent_tools(agent) - - try: - # Extraer JSON - json_start = response.find('{') - json_end = response.rfind('}') + 1 - json_str = response[json_start:json_end] - action = json.loads(json_str) - except: - return {"error": "No se pudo parsear la respuesta", "raw": response[:200]} - - action_name = action.get("action") or action.get("tool") - args = action.get("args", {}) - - if action_name not in tools: - return {"error": f"Acción desconocida: {action_name}"} - - try: - result = tools[action_name](**args) - return {"success": True, "action": action_name, "result": result} - except Exception as e: - return {"error": f"Error ejecutando {action_name}: {str(e)}"} - -# ============================================================================ -# SERVIR STATIC FILES (UI Frontend) -# ============================================================================ - -app.mount("/", StaticFiles(directory="static", html=True), name="static") - -if __name__ == "__main__": - import uvicorn - print(f"🚀 Backend en http://localhost:5000") - print(f"📁 Workspace: {WORKSPACE_DIR.absolute()}") - uvicorn.run(app, host="0.0.0.0", port=5000) \ No newline at end of file diff --git a/config/server.json b/config/server.json deleted file mode 100644 index 6c42982..0000000 --- a/config/server.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "server": { - "host": "0.0.0.0", - "api_port": 8000, - "web_port": 5000, - "workers": 4, - "debug": false, - "environment": "production" - }, - "models": { - "fast": { - "name": "phi", - "description": "Phi 2.7B - Rápido", - "vram_required_gb": 2, - "tokens_per_second": 50 - }, - "power": { - "name": "deepseek-coder:33b", - "description": "DeepSeek 33B - Potente", - "vram_required_gb": 18, - "tokens_per_second": 6 - } - }, - "gpu": { - "memory_fraction": 0.9, - "max_batch_size": 8, - "enable_cuda": true, - "device_id": 0 - }, - "logging": { - "level": "INFO", - "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s", - "log_dir": "./logs", - "max_file_size_mb": 10, - "backup_count": 10 - }, - "database": { - "type": "sqlite", - "path": "./data/llm_history.db", - "enable_history": true - }, - "security": { - "enable_rate_limit": true, - "rate_limit_requests": 100, - "rate_limit_period_seconds": 60, - "require_api_key": false, - "allowed_origins": ["*"] - }, - "workspace": { - "path": "./workspace", - "max_file_size_mb": 100, - "allowed_extensions": [".py", ".js", ".html", ".css", ".json", ".txt", ".md"] - }, - "api_endpoints": { - "health": "/api/health", - "models": "/api/models", - "chat": "/api/chat", - "files": "/api/files", - "metrics": "/api/metrics" - }, - "ollama": { - "host": "localhost", - "port": 11434, - "timeout_seconds": 300, - "auto_download_models": true - }, - "features": { - "enable_git_commit": true, - "enable_code_execution": true, - "enable_file_operations": true, - "enable_browser_testing": true, - "enable_metrics": true - } -} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e2fc263..0000000 --- a/requirements.txt +++ /dev/null @@ -1,22 +0,0 @@ -# API & Web Framework -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -python-multipart==0.0.6 -aiofiles==23.2.1 - -# LLM & AI -langchain==0.1.0 -requests==2.31.0 - -# Data Processing -pillow==10.1.0 -pydantic==2.5.0 - -# Configuration -python-dotenv==1.0.0 - -# Development (opcional) -pytest==7.4.3 -pytest-asyncio==0.21.1 -black==23.12.0 -flake8==6.1.0 \ No newline at end of file diff --git a/scripts/backup.sh b/scripts/backup.sh deleted file mode 100644 index 8444fde..0000000 --- a/scripts/backup.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -################################################################################ -# BACKUP SCRIPT -# Realiza backup de modelos y configuración -################################################################################ - -set -e - -RED='\033[0;31m' -GREEN='\033[0;32m' -BLUE='\033[0;34m' -NC='\033[0m' - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -BACKUP_DIR="$PROJECT_DIR/backups" -TIMESTAMP=$(date +%Y%m%d_%H%M%S) - -log() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $@"; } -log_success() { echo -e "${GREEN}✅ $@${NC}"; } - -log "Iniciando backup..." - -mkdir -p "$BACKUP_DIR" - -# Backup configuración -log "Haciendo backup de configuración..." -tar -czf "$BACKUP_DIR/config_$TIMESTAMP.tar.gz" \ - -C "$PROJECT_DIR" \ - config/ \ - .env \ - requirements.txt \ - 2>/dev/null || true - -# Backup modelos (OPCIONAL - muy grandes) -read -p "¿Hacer backup de modelos Ollama? (y/n - muy grande, ~20GB): " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - log "Haciendo backup de modelos (esto tardará)..." - tar -czf "$BACKUP_DIR/models_$TIMESTAMP.tar.gz" \ - /home/charle/.ollama/models \ - 2>/dev/null || true -fi - -# Backup workspace -log "Haciendo backup de workspace..." -tar -czf "$BACKUP_DIR/workspace_$TIMESTAMP.tar.gz" \ - -C "$PROJECT_DIR" \ - workspace/ \ - 2>/dev/null || true - -log_success "Backups completados en: $BACKUP_DIR" -ls -lh "$BACKUP_DIR" \ No newline at end of file diff --git a/scripts/health-check.sh b/scripts/health-check.sh deleted file mode 100644 index 2641387..0000000 --- a/scripts/health-check.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash - -################################################################################ -# HEALTH CHECK SCRIPT -# Verifica que todo funcione correctamente -################################################################################ - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -FAILURES=0 - -check() { - local name=$1 - local cmd=$2 - local expected=$3 - - echo -n "Verificando $name... " - - if eval "$cmd" &>/dev/null; then - echo -e "${GREEN}✅${NC}" - return 0 - else - echo -e "${RED}❌${NC}" - ((FAILURES++)) - return 1 - fi -} - -echo -e "${BLUE}========================================${NC}" -echo -e "${BLUE} LLM SERVER HEALTH CHECK${NC}" -echo -e "${BLUE}========================================${NC}\n" - -# Sistema -echo -e "${YELLOW}Sistema:${NC}" -check "Ubuntu 22.04" "grep -q '22.04' /etc/os-release" -check "Internet" "ping -c 1 8.8.8.8" - -# Drivers & GPU -echo -e "\n${YELLOW}GPU & Drivers:${NC}" -check "NVIDIA Driver" "command -v nvidia-smi" -check "CUDA 12.3" "command -v nvcc" -check "RTX 3090" "nvidia-smi | grep -q 'RTX 3090'" -check "cuDNN" "ldconfig -p | grep -q cudnn" - -# Software -echo -e "\n${YELLOW}Software:${NC}" -check "Python 3.11" "python3.11 --version" -check "Docker" "command -v docker" -check "Git" "command -v git" - -# Services -echo -e "\n${YELLOW}Servicios:${NC}" -check "Ollama service" "sudo systemctl is-active ollama" -check "API service" "sudo systemctl is-active llm-api" - -# Conectividad -echo -e "\n${YELLOW}API Connectivity:${NC}" -check "Ollama API" "curl -s http://localhost:11434/api/tags" -check "FastAPI" "curl -s http://localhost:8000/health" - -# Modelos -echo -e "\n${YELLOW}Modelos Ollama:${NC}" -check "Phi disponible" "curl -s http://localhost:11434/api/tags | grep -q 'phi'" -check "DeepSeek disponible" "curl -s http://localhost:11434/api/tags | grep -q 'deepseek'" - -# Disk Space -echo -e "\n${YELLOW}Espacio en Disco:${NC}" -root_usage=$(df / | awk 'NR==2 {print int($5)}') -if [ "$root_usage" -lt 90 ]; then - echo -e "Uso de disco (root): ${GREEN}${root_usage}%${NC}" -else - echo -e "Uso de disco (root): ${RED}${root_usage}%${NC}" - ((FAILURES++)) -fi - -# Summary -echo -e "\n${BLUE}========================================${NC}" -if [ "$FAILURES" -eq 0 ]; then - echo -e "${GREEN}✅ TODOS LOS CHECKS PASARON${NC}" - exit 0 -else - echo -e "${RED}❌ $FAILURES CHECKS FALLARON${NC}" - exit 1 -fi \ No newline at end of file diff --git a/scripts/install.sh b/scripts/install.sh deleted file mode 100644 index 08f8ce8..0000000 --- a/scripts/install.sh +++ /dev/null @@ -1,534 +0,0 @@ -#!/bin/bash - -################################################################################ -# LLM SERVER DEPLOYMENT SCRIPT -# Ubuntu 22.04 LTS + ASUS H510M + RTX 3090 -# -# Uso: bash scripts/install.sh [--quick] [--gpu-only] -# -# Opciones: -# --quick Salta verificaciones lentas -# --gpu-only Solo instala GPU drivers (para re-install) -################################################################################ - -set -e # Exit si hay error - -# Colores -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Variables -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -WORKSPACE_DIR="$PROJECT_DIR/workspace" -VENV_DIR="$PROJECT_DIR/venv" -LOG_FILE="$PROJECT_DIR/logs/install.log" - -# Crear directorio de logs -mkdir -p "$PROJECT_DIR/logs" - -# Function: Log con timestamp -log() { - local level=$1 - shift - local message="$@" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - echo -e "${BLUE}[$timestamp]${NC} ${level}: ${message}" | tee -a "$LOG_FILE" -} - -# Function: Log success -log_success() { - echo -e "${GREEN}✅ $@${NC}" | tee -a "$LOG_FILE" -} - -# Function: Log error -log_error() { - echo -e "${RED}❌ $@${NC}" | tee -a "$LOG_FILE" -} - -# Function: Log warning -log_warning() { - echo -e "${YELLOW}⚠️ $@${NC}" | tee -a "$LOG_FILE" -} - -# Function: Check command exists -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -# Function: Check if running as root -check_root() { - if [[ $EUID -ne 0 ]]; then - log_error "Este script debe ejecutarse con sudo" - exit 1 - fi -} - -################################################################################ -# MAIN INSTALLATION -################################################################################ - -main() { - local quick_mode=false - local gpu_only=false - - # Parse arguments - while [[ $# -gt 0 ]]; do - case $1 in - --quick) - quick_mode=true - shift - ;; - --gpu-only) - gpu_only=true - shift - ;; - *) - log_error "Opción desconocida: $1" - usage - exit 1 - ;; - esac - done - - log "LOG" "==========================================" - log "LOG" "LLM Server Installation" - log "LOG" "==========================================" - log "LOG" "Project Dir: $PROJECT_DIR" - log "LOG" "Workspace: $WORKSPACE_DIR" - log "LOG" "Quick Mode: $quick_mode" - log "LOG" "GPU Only: $gpu_only" - log "LOG" "==========================================" - - # Checks iniciales - check_root - check_os - check_hardware - - if [ "$gpu_only" = false ]; then - install_dependencies - install_docker - fi - - install_nvidia_drivers - install_cuda_toolkit - install_ollama - setup_python_venv - create_services - - if [ "$quick_mode" = false ]; then - download_models - fi - - setup_directories - generate_config - - log_success "==========================================" - log_success "✨ INSTALACIÓN COMPLETADA" - log_success "==========================================" - print_next_steps -} - -################################################################################ -# FUNCIONES AUXILIARES -################################################################################ - -check_os() { - log "LOG" "Verificando Sistema Operativo..." - - if [ ! -f /etc/os-release ]; then - log_error "No se pudo detectar el SO" - exit 1 - fi - - . /etc/os-release - if [[ "$ID" != "ubuntu" ]]; then - log_error "Este script solo soporta Ubuntu" - exit 1 - fi - - if [[ "$VERSION_ID" != "22.04" ]]; then - log_warning "Se recomienda Ubuntu 22.04, detectado: $VERSION_ID" - fi - - log_success "Ubuntu $VERSION_ID detectado" -} - -check_hardware() { - log "LOG" "Verificando Hardware..." - - # Check GPU - if ! command_exists nvidia-smi; then - log_warning "nvidia-smi no disponible aún (se instalará)" - else - gpu_info=$(nvidia-smi --query-gpu=name,memory.total --format=csv,noheader) - log_success "GPU detectada: $gpu_info" - fi - - # Check CPU - cpu_count=$(nproc) - log_success "CPU: $cpu_count cores" - - # Check RAM - ram_gb=$(free -h | awk '/^Mem:/ {print $2}') - log_success "RAM: $ram_gb" - - # Check Disk - disk_info=$(df -h / | awk 'NR==2 {print $2}') - log_success "Disco: $disk_info disponible" -} - -install_dependencies() { - log "LOG" "Instalando dependencias del sistema..." - - apt update - apt install -y \ - build-essential \ - git \ - wget \ - curl \ - htop \ - nano \ - openssh-server \ - python3.11 \ - python3.11-venv \ - python3.11-dev \ - pkg-config \ - libssl-dev \ - libffi-dev - - log_success "Dependencias instaladas" -} - -install_docker() { - log "LOG" "Instalando Docker..." - - if command_exists docker; then - log_success "Docker ya está instalado" - return - fi - - curl -fsSL https://get.docker.com -o /tmp/get-docker.sh - sh /tmp/get-docker.sh - - # Agregar usuario al grupo docker - if id "charle" &>/dev/null; then - usermod -aG docker charle - log_success "Usuario 'charle' agregado al grupo docker" - fi - - systemctl start docker - systemctl enable docker - - log_success "Docker instalado" -} - -install_nvidia_drivers() { - log "LOG" "Instalando NVIDIA Drivers..." - - if command_exists nvidia-smi; then - current_driver=$(nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -1) - log_success "Driver NVIDIA $current_driver ya instalado" - return - fi - - # Agregar repositorio NVIDIA - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A4B469963BF863CC 2>&1 | grep -v "Warning" || true - - add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/ /" 2>&1 | grep -v "already" || true - - apt update - apt install -y cuda-drivers - - log_success "NVIDIA Drivers instalados" - - log_warning "Se recomienda reiniciar: sudo reboot" -} - -install_cuda_toolkit() { - log "LOG" "Instalando CUDA Toolkit 12.3..." - - if [ -d "/usr/local/cuda-12.3" ]; then - log_success "CUDA 12.3 ya está instalado" - return - fi - - log "LOG" "Descargando CUDA 12.3.0..." - cd /tmp - wget -q https://developer.download.nvidia.com/compute/cuda/12.3.0/local_installers/cuda_12.3.0_545.23.06_linux.run \ - -O cuda_12.3.0_545.23.06_linux.run - - log "LOG" "Instalando CUDA (esto puede tardar 10-15 minutos)..." - chmod +x cuda_12.3.0_545.23.06_linux.run - ./cuda_12.3.0_545.23.06_linux.run --silent --driver=false --toolkit - - # Configurar PATH - if ! grep -q "cuda-12.3" /root/.bashrc; then - cat >> /root/.bashrc << 'EOF' - -# CUDA 12.3 -export PATH=/usr/local/cuda-12.3/bin:$PATH -export LD_LIBRARY_PATH=/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH -EOF - fi - - source /root/.bashrc - - # Verificar - if command_exists nvcc; then - cuda_version=$(nvcc --version | grep "release" | awk '{print $5}') - log_success "CUDA $cuda_version instalado" - fi - - # Install cuDNN - log "LOG" "Instalando cuDNN..." - apt install -y libcudnn8 - - log_success "CUDA Toolkit instalado" -} - -install_ollama() { - log "LOG" "Instalando Ollama..." - - if command_exists ollama; then - log_success "Ollama ya está instalado" - else - curl https://ollama.ai/install.sh | sh - log_success "Ollama instalado" - fi - - # Configurar servicio systemd - log "LOG" "Configurando servicio Ollama..." - - mkdir -p /etc/systemd/system - - cat > /etc/systemd/system/ollama.service << 'EOF' -[Unit] -Description=Ollama -After=network-online.target - -[Service] -ExecStart=/usr/local/bin/ollama serve -User=charle -Group=charle -Restart=always -RestartSec=3 -Environment="OLLAMA_HOST=0.0.0.0:11434" -Environment="OLLAMA_MODELS=/home/charle/.ollama/models" -Environment="OLLAMA_NUM_GPU=1" - -[Install] -WantedBy=default.target -EOF - - systemctl daemon-reload - systemctl enable ollama - systemctl restart ollama - - sleep 2 - - if systemctl is-active --quiet ollama; then - log_success "Servicio Ollama activo" - else - log_error "Error iniciando Ollama" - fi -} - -setup_python_venv() { - log "LOG" "Creando Python Virtual Environment..." - - if [ -d "$VENV_DIR" ]; then - log_success "VEnv ya existe" - return - fi - - python3.11 -m venv "$VENV_DIR" - - source "$VENV_DIR/bin/activate" - - pip install --upgrade pip setuptools wheel - - pip install \ - fastapi \ - uvicorn \ - python-multipart \ - aiofiles \ - pillow \ - python-dotenv \ - requests \ - langchain \ - pydantic - - log_success "Python VEnv configurado" -} - -create_services() { - log "LOG" "Creando systemd services..." - - # API Service - cat > /etc/systemd/system/llm-api.service << EOF -[Unit] -Description=LLM API Server -After=network.target ollama.service - -[Service] -Type=simple -User=charle -WorkingDirectory=$PROJECT_DIR -Environment="PATH=$VENV_DIR/bin" -Environment="OLLAMA_URL=http://localhost:11434" -ExecStart=$VENV_DIR/bin/python $PROJECT_DIR/backend.py -Restart=always -RestartSec=10 - -[Install] -WantedBy=multi-user.target -EOF - - systemctl daemon-reload - systemctl enable llm-api - - log_success "Systemd services creados" -} - -download_models() { - log "LOG" "Descargando modelos (esto puede tardar 20-30 minutos)..." - log_warning "Esto es OPCIONAL. Presiona Ctrl+C para cancelar." - - sleep 5 - - source "$VENV_DIR/bin/activate" - - # Esperar a que Ollama esté listo - for i in {1..30}; do - if curl -s http://localhost:11434/api/tags > /dev/null; then - log_success "Ollama está listo" - break - fi - log "LOG" "Esperando Ollama... ($i/30)" - sleep 2 - done - - log "LOG" "Descargando Phi..." - ollama pull phi:latest - - log "LOG" "Descargando DeepSeek Coder 33B..." - ollama pull deepseek-coder:33b - - log_success "Modelos descargados" -} - -setup_directories() { - log "LOG" "Creando directorios..." - - mkdir -p "$WORKSPACE_DIR" - mkdir -p "$PROJECT_DIR/uploads" - mkdir -p "$PROJECT_DIR/logs" - - # Cambiar permisos - chown -R charle:charle "$PROJECT_DIR" - chmod -R 755 "$PROJECT_DIR" - - log_success "Directorios creados" -} - -generate_config() { - log "LOG" "Generando archivos de configuración..." - - # .env file - if [ ! -f "$PROJECT_DIR/.env" ]; then - cat > "$PROJECT_DIR/.env" << EOF -# LLM Server Configuration -LLM_SERVER_URL=http://localhost:8000 -LLM_FAST_MODEL=phi -LLM_POWER_MODEL=deepseek-coder:33b -OLLAMA_URL=http://localhost:11434 -WORKSPACE_DIR=$WORKSPACE_DIR - -# Server -HOST=0.0.0.0 -API_PORT=8000 -WEB_PORT=5000 - -# Logging -LOG_LEVEL=INFO -EOF - log_success ".env creado" - fi - - # Config JSON - if [ ! -f "$PROJECT_DIR/config/server.json" ]; then - mkdir -p "$PROJECT_DIR/config" - cat > "$PROJECT_DIR/config/server.json" << 'EOF' -{ - "server": { - "host": "0.0.0.0", - "api_port": 8000, - "web_port": 5000, - "workers": 4 - }, - "models": { - "fast": "phi", - "power": "deepseek-coder:33b" - }, - "gpu": { - "memory_fraction": 0.9, - "max_batch_size": 8 - }, - "logging": { - "level": "INFO", - "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" - } -} -EOF - log_success "config/server.json creado" - fi -} - -print_next_steps() { - cat << EOF - -${BLUE}=========================================${NC} -${GREEN}✨ PRÓXIMOS PASOS:${NC} -${BLUE}=========================================${NC} - -1. ${YELLOW}Verificar instalación:${NC} - sudo systemctl status ollama - sudo systemctl status llm-api - -2. ${YELLOW}Ver logs:${NC} - sudo journalctl -u ollama -f - sudo journalctl -u llm-api -f - -3. ${YELLOW}Iniciar servicios:${NC} - sudo systemctl start ollama - sudo systemctl start llm-api - -4. ${YELLOW}Acceder a la API:${NC} - curl http://localhost:8000/health - -5. ${YELLOW}Descargar modelos (si no se descargaron):${NC} - source $VENV_DIR/bin/activate - ollama pull phi:latest - ollama pull deepseek-coder:33b - -6. ${YELLOW}Ver estado en tiempo real:${NC} - watch -n 1 nvidia-smi - -${BLUE}=========================================${NC} -${GREEN}📁 Archivos importantes:${NC} -${BLUE}=========================================${NC} - Config: $PROJECT_DIR/config/server.json - .env: $PROJECT_DIR/.env - Logs: $PROJECT_DIR/logs/ - Workspace: $WORKSPACE_DIR/ - -${BLUE}=========================================${NC} -EOF -} - -# Ejecutar main -main "$@" \ No newline at end of file diff --git a/scripts/monitor.sh b/scripts/monitor.sh deleted file mode 100644 index 86b9606..0000000 --- a/scripts/monitor.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash - -################################################################################ -# MONITOR SCRIPT -# Monitorea servicios y hardware en tiempo real -################################################################################ - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -clear_screen() { - clear -} - -print_header() { - echo -e "${BLUE}=================================================${NC}" - echo -e "${BLUE} LLM SERVER MONITOR - $(date '+%Y-%m-%d %H:%M:%S')${NC}" - echo -e "${BLUE}=================================================${NC}" -} - -print_section() { - echo -e "\n${YELLOW}>>> $1${NC}" -} - -check_service() { - local service=$1 - if sudo systemctl is-active --quiet "$service"; then - echo -e "${GREEN}✅ $service - ACTIVO${NC}" - sudo systemctl status "$service" --no-pager | grep -E "(Active|ExecStart)" | sed 's/^/ /' - else - echo -e "${RED}❌ $service - INACTIVO${NC}" - fi -} - -get_ip() { - hostname -I | awk '{print $1}' -} - -main() { - while true; do - clear_screen - print_header - - # System Info - print_section "SISTEMA" - echo "Hostname: $(hostname)" - echo "IP: $(get_ip)" - echo "Uptime: $(uptime -p)" - echo "Usuarios conectados: $(who | wc -l)" - - # CPU & RAM - print_section "CPU & MEMORIA" - free -h | awk 'NR==1 {print ""; print $0} NR==2 {print $0}' - echo "" - top -bn1 | head -3 | tail -1 - - # Disk - print_section "DISCO" - df -h / | awk 'NR==2 {printf "Root: %s used / %s total (%.1f%%)\n", $3, $2, ($3/$2)*100}' - - # GPU - print_section "GPU - NVIDIA RTX 3090" - nvidia-smi --query-gpu=index,name,driver_version,memory.used,memory.total,temperature.gpu,utilization.gpu \ - --format=csv,noheader | while read line; do - echo " $line" - done - - # Services - print_section "SERVICIOS" - check_service "ollama" - echo "" - check_service "llm-api" - - # Network - print_section "RED" - echo "API (port 8000): $(curl -s http://localhost:8000/health | jq '.' 2>/dev/null || echo 'NO RESPONDE')" - echo "Ollama (port 11434): $(curl -s http://localhost:11434/api/tags | jq '.models | length' 2>/dev/null || echo '0') modelos" - - # Logs recientes - print_section "ÚLTIMOS ERRORES (últimas 5 líneas)" - echo "Ollama:" - sudo journalctl -u ollama -n 3 --no-pager | sed 's/^/ /' - echo "" - echo "API:" - sudo journalctl -u llm-api -n 3 --no-pager | sed 's/^/ /' - - # Footer - echo "" - echo -e "${BLUE}=================================================${NC}" - echo "Presiona Ctrl+C para salir | Se actualiza cada 10 segundos" - echo -e "${BLUE}=================================================${NC}" - - sleep 10 - done -} - -main \ No newline at end of file diff --git a/scripts/update.sh b/scripts/update.sh deleted file mode 100644 index d8531e9..0000000 --- a/scripts/update.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -################################################################################ -# UPDATE SCRIPT -# Actualiza código, modelos y dependencias -################################################################################ - -set -e - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -VENV_DIR="$PROJECT_DIR/venv" - -log() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $@"; } -log_success() { echo -e "${GREEN}✅ $@${NC}"; } -log_error() { echo -e "${RED}❌ $@${NC}"; exit 1; } - -log "Actualizando LLM Server..." - -# Pull latest from git -log "Descargando cambios de git..." -cd "$PROJECT_DIR" -git pull origin main || log "Git pull completado con warnings" - -# Update Python dependencies -log "Actualizando dependencias Python..." -source "$VENV_DIR/bin/activate" -pip install --upgrade pip -pip install -r requirements.txt --upgrade - -# Update Ollama models (opcional) -read -p "¿Actualizar modelos Ollama? (y/n): " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - log "Actualizando Phi..." - ollama pull phi:latest - - log "Actualizando DeepSeek..." - ollama pull deepseek-coder:33b -fi - -# Restart services -log "Reiniciando servicios..." -sudo systemctl restart ollama -sudo systemctl restart llm-api - -log_success "Actualización completada" \ No newline at end of file diff --git a/static/index.html b/static/index.html deleted file mode 100644 index 6776450..0000000 --- a/static/index.html +++ /dev/null @@ -1,549 +0,0 @@ - - -
- - -