Compare commits

..
Author SHA1 Message Date
hermes ec4eff61ab feat: estilo editorial de la IA configurable (editorial-style.php)
La IA del plugin 'AI' redacta segun el estilo del pack: editorial-style.php
(tono, normas, prohibidos, max chars de titulares) se copia a wp-content y un
mu-plugin lo inyecta en las instrucciones de sistema via wpai_system_instruction
(scp: wpai_title_generation_system_instruction para el cap de caracteres).
Editas el fichero, re-ejecutas deploy y la IA cambia de estilo.
2026-09-13 00:10:55 +02:00
hermes dbbac84b0d feat: pack wordpress con IA nativa de WP 7.1 — fuera Open WebUI
- Eliminado el servicio openwebui del pack wordpress (no estaba integrado
  con WP; el chat IA vive ahora dentro del editor de WordPress).
- Plugins IA oficiales preinstalados y configurados en el arranque:
  'AI' (AI Experiments) + 'AI Provider for Ollama' (connector), host
  http://ollama:11434 (red interna del compose, sin puerto publicado).
- Autoconfig via contenedor oficial wordpress:cli (--volumes-from):
  espera a core is-installed, instala plugins y setea el option. Si WP
  aun no esta instalado, aviso y re-ejecucion tras el asistente.
- CPU cap dinamico en hermes/openclaw (min 6, nproc) y OLLAMA_CPUS
  parametrizado en compose (6.0 default) — evita fallo en hosts de 4 cores.
- .gitignore raiz (**/.env, *.gguf, override GPU).
- GATE A PASS: subagente independiente (5 findings aplicados: EAP 5.1,
  .gitignore, fallo autoconfig visible, red vacia, indentacion).
- E2E verificado en VPS: plugins activos + option host + provider
  responde /v1/chat/completions del modelo local.
2026-09-12 23:48:19 +02:00
hermes 9438b75c9f fix: limite de CPU 6.0 para ollama (#25)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 23:07:46 +02:00
hermes 5030770bc2 fix: think=false en Open WebUI (el SYSTEM /no_think no basta) (#24)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 23:06:35 +02:00
hermes c68fe80484 fix: desactivar el thinking de Qwen3 (SYSTEM /no_think) (#23)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 22:38:19 +02:00
hermes fb3c3fdb67 feat: remove.ps1 / remove.sh para desinstalar cada pack (#22)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 22:25:07 +02:00
hermes fc5747d3cd feat: precalentar el modelo al terminar el deploy (#21)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 22:15:21 +02:00
hermes 6adbd966a0 feat: modelo por defecto qwen3:4b (llama3.2 3B enredaba con las tools) (#20)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 22:05:33 +02:00
hermes 51258f6889 fix: sin loops de tool-calls en el chat (#19)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:54:15 +02:00
hermes 1e5b301000 feat: feedback del down/rm inicial (#18)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:48:31 +02:00
hermes a7d3e9373a fix: skip de la descarga si el modelo ya esta en el volumen (#17)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:44:35 +02:00
hermes fbf567f942 feat: deteccion de GPU NVIDIA y aceleracion automatica (#16)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:33:43 +02:00
hermes 6f052cf738 fix: limite de RAM 6G para ollama (#15)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:32:12 +02:00
hermes 938ca2b268 fix: mensaje del wait-loop de Ollama (no duplicaba el del modelo) (#14)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:27:30 +02:00
hermes 6e311050e5 fix: down/rm ANTES de detectar puertos (#13)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:22:56 +02:00
hermes ebc420656a fix: progreso del download GGUF y 1 solo mensaje de modelo (#12)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:21:23 +02:00
hermes e39fabd31c fix: num_ctx 16384 en el modelo (el 4096 da 400 en Open WebUI) (#11)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:19:29 +02:00
hermes 350d55c434 feat: modelo via HF primero, registry de Ollama como ultimo recurso (#10)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:11:02 +02:00
hermes 99e0eebc29 feat: 2o mirror de HF (unsloth) en el fallback del modelo (#9)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:05:06 +02:00
hermes a7609f56b0 feat: fallback del modelo via HuggingFace si el registry falla (#8)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 21:04:18 +02:00
hermes 539cd4d181 feat: pull del modelo respeta HTTPS_PROXY (#7)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 20:58:59 +02:00
hermes 912105f16f feat: down/rm de runs previos antes del up (#6)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 20:55:43 +02:00
hermes 8bd5bbf366 fix: IP del modo VPS via interfaz de la ruta por defecto (#5)
Co-authored-by: Hermes Agent <hermes@d0a1.es>
2026-09-12 20:49:29 +02:00
23 changed files with 667 additions and 125 deletions

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
# .env files (contraseñas generadas en deploy) — nunca al repo
**/.env
!**/.env.example
# Overrides GPU generados en runtime
docker-compose.gpu.yml
# Modelos descargados temporalmente
*.gguf
+74 -12
View File
@@ -80,6 +80,23 @@ if ($TotalRamGb -lt 3.5) {
} }
Ok "RAM: $TotalRamGb GB" Ok "RAM: $TotalRamGb GB"
# --- Tumbar deploy previo (antes de detectar puertos) -----------------------
cmd /c docker rm -f d0a1-hermes-ollama '>' NUL '2>&1'
Info 'Deploy previo detenido (rm; volumen con el modelo intacto).'
# --- GPU NVIDIA? (si hay, Ollama la usa y va 5-10x mas rapido) ---------------
$HasGpu = $false
if (Get-Command nvidia-smi -ErrorAction SilentlyContinue) {
$GpuInfo = & nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>$null
if ($LASTEXITCODE -eq 0 -and $GpuInfo) {
$HasGpu = $true
$GpuName = ($GpuInfo -split ',')[0].Trim()
Info "GPU NVIDIA detectada: $GpuName (aceleracion activada)"
}
}
if (-not $HasGpu) {
Warn 'Sin GPU NVIDIA: modo CPU (~10-20 tokens/s). Con una GPU NVIDIA va 5-10x mas rapido.'
}
# --- Auto-detect Ollama port ------------------------------------------------ # --- Auto-detect Ollama port ------------------------------------------------
$OllamaPort = Find-FreePort 11434 $OllamaPort = Find-FreePort 11434
@@ -98,7 +115,10 @@ Write-Host ''
Warn '[1/3] Arrancando Ollama (IA local)...' Warn '[1/3] Arrancando Ollama (IA local)...'
$running = docker ps --format '{{.Names}}' | Select-String -Quiet 'd0a1-hermes-ollama' $running = docker ps --format '{{.Names}}' | Select-String -Quiet 'd0a1-hermes-ollama'
if (-not $running) { if (-not $running) {
docker run -d --name d0a1-hermes-ollama ` $GpuArgs = @()
if ($HasGpu) { $GpuArgs = @('--gpus', 'all') }
$CpuCap = [Math]::Min(6, [int]$env:NUMBER_OF_PROCESSORS)
docker run -d --name d0a1-hermes-ollama --memory 6g --cpus $CpuCap @GpuArgs `
-p "${OllamaPort}:11434" ` -p "${OllamaPort}:11434" `
-v d0a1_hermes_ollama:/root/.ollama ` -v d0a1_hermes_ollama:/root/.ollama `
-e OLLAMA_HOST=0.0.0.0 ` -e OLLAMA_HOST=0.0.0.0 `
@@ -120,21 +140,63 @@ while ($true) {
exit 1 exit 1
} }
} }
Warn ' Descargando modelo (llama3.2:3b, ~2 GB)...' Warn ' Descargando modelo (qwen3:4b, ~2.5 GB)...'
$PullOk = $false # Si el usuario define $env:HTTPS_PROXY, Ollama lo usa para el pull (doc oficial):
foreach ($Attempt in 1..3) { $ProxyEnv = @()
if ($Attempt -gt 1) { Warn "Reintento $Attempt de 3..." } if ($env:HTTPS_PROXY) { $ProxyEnv = @('-e', "HTTPS_PROXY=$env:HTTPS_PROXY", '-e', "HTTP_PROXY=$env:HTTP_PROXY") }
docker exec d0a1-hermes-ollama ollama pull llama3.2:3b # --- Modelo ya presente? (volumen persistente: no re-descargar) ------------
if ($LASTEXITCODE -eq 0) { $PullOk = $true; break } $ModelList = docker exec d0a1-hermes-ollama ollama list 2>$null
Warn 'Descarga interrumpida (red). Reintentando en 5 s...' if ("$ModelList" -match 'qwen3:4b') {
Start-Sleep -Seconds 5 Info 'Modelo qwen3:4b ya descargado (volumen intacto). Omitiendo descarga.'
cmd /c docker exec d0a1-hermes-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf' '>' NUL '2>&1'
} else {
# --- Modelo: HF primero (CDN propio, rapido) y registry de Ollama como ultimo recurso ---
$Gguf = Join-Path $ScriptDir 'qwen3-4b-q4.gguf'
$HfUrls = @(
'https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf',
'https://huggingface.co/unsloth/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf'
)
Info 'Descargando modelo de IA (qwen3:4b, ~2.5 GB)...'
foreach ($Url in $HfUrls) {
curl.exe -# -L --retry 3 --max-time 1800 -o "$Gguf" $Url
if ($LASTEXITCODE -eq 0 -and (Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) { break }
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
if ($Url -ne $HfUrls[-1]) { Warn 'Mirror no accesible, probando el siguiente...' }
}
if ((Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) {
Info 'Importando modelo en Ollama...'
docker cp "$Gguf" d0a1-hermes-ollama:/root/.ollama/import.gguf
docker exec d0a1-hermes-ollama sh -c 'printf "FROM /root/.ollama/import.gguf\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
$CreateOk = ($LASTEXITCODE -eq 0)
docker exec d0a1-hermes-ollama rm -f /root/.ollama/import.gguf | Out-Null
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
$PullOk = $CreateOk
if (-not $CreateOk) { Err 'Fallo al importar el modelo desde el GGUF.' }
} else {
# Ultimo recurso: pull directo (1 intento, ya sin esperar 3 rondas)
Warn 'HuggingFace no accesible. Probando el registry de Ollama (ultimo recurso)...'
docker exec @ProxyEnv d0a1-hermes-ollama ollama pull qwen3:4b
if ($LASTEXITCODE -eq 0) {
$PullOk = $true
# Contexto ampliado (el default 4096 da 400 en Open WebUI con prompts largos)
docker exec d0a1-hermes-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
}
} }
if (-not $PullOk) { if (-not $PullOk) {
Err 'Fallo la descarga del modelo tras 3 intentos.' Err 'No se pudo descargar el modelo (ni HuggingFace ni registry).'
Write-Host ' Revisa tu red (VPN/proxy) y reintenta a mano:' if (-not $env:HTTPS_PROXY) {
Write-Host ' docker exec d0a1-hermes-ollama ollama pull llama3.2:3b' Write-Host ' Tu red bloquea ambos. Si tienes proxy/VPN:'
Write-Host ' $env:HTTPS_PROXY = "http://127.0.0.1:7890" # (puerto de tu proxy)'
Write-Host ' .\deploy.ps1 vps'
}
exit 1 exit 1
} }
}
# --- Precalentar el modelo (load ya, no en el primer mensaje) ---------------
Warn ' Precargando el modelo en memoria...'
cmd /c docker exec d0a1-hermes-ollama sh -c 'ollama run qwen3:4b ""' '>' NUL '2>&1'
Ok "Ollama corriendo en http://localhost:${OllamaPort}" Ok "Ollama corriendo en http://localhost:${OllamaPort}"
# --- 2. Instalar Hermes Agent ------------------------------------------------ # --- 2. Instalar Hermes Agent ------------------------------------------------
+5 -3
View File
@@ -92,10 +92,12 @@ echo ""
# ── 1. Arrancar Ollama (Docker) ────────────── # ── 1. Arrancar Ollama (Docker) ──────────────
echo -e "${YELLOW}[1/3]${NC} Arrancando Ollama (IA local)..." echo -e "${YELLOW}[1/3]${NC} Arrancando Ollama (IA local)..."
if ! docker ps --format '{{.Names}}' | grep -q d0a1-hermes-ollama; then if ! docker ps --format '{{.Names}}' | grep -q d0a1-hermes-ollama; then
CPU_CAP=$(( $(nproc) > 6 ? 6 : $(nproc) ))
docker run -d --name d0a1-hermes-ollama \ docker run -d --name d0a1-hermes-ollama \
-p "${OLLAMA_PORT}:11434" \ -p "${{OLLAMA_PORT}}:11434" \
-v d0a1_hermes_ollama:/root/.ollama \ -v d0a1_hermes_ollama:/root/.ollama \
-e OLLAMA_HOST=0.0.0.0 \ -e OLLAMA_HOST=0.0.0.0 \
--memory 6g --cpus "$CPU_CAP" \
--restart unless-stopped \ --restart unless-stopped \
ollama/ollama:0.33.3 ollama/ollama:0.33.3
fi fi
@@ -112,8 +114,8 @@ until docker exec d0a1-hermes-ollama ollama ps &>/dev/null; do
exit 1 exit 1
fi fi
done done
echo -e "${YELLOW} Descargando modelo (llama3.2:3b, ~2 GB)...${NC}" echo -e "${YELLOW} Descargando modelo (qwen3:4b, ~2.5 GB)...${NC}"
docker exec d0a1-hermes-ollama ollama pull llama3.2:3b docker exec d0a1-hermes-ollama ollama pull qwen3:4b
echo -e "${GREEN}✓${NC} Ollama corriendo en http://localhost:${OLLAMA_PORT}" echo -e "${GREEN}✓${NC} Ollama corriendo en http://localhost:${OLLAMA_PORT}"
# ── 2. Instalar Hermes Agent ──────────────── # ── 2. Instalar Hermes Agent ────────────────
+16
View File
@@ -0,0 +1,16 @@
# ============================================================
# d0a1 pack - Hermes (Windows) - DESINSTALAR
# Elimina el contenedor y el volumen (datos + modelo).
# ============================================================
$ErrorActionPreference = 'Stop'
function Info($m) { Write-Host ">>> $m" }
Info 'Borrando contenedor y volumen...'
cmd /c docker rm -f d0a1-hermes-ollama '>' NUL '2>&1'
cmd /c docker volume rm d0a1_hermes_ollama '>' NUL '2>&1'
Write-Host ''
Info 'Eliminado TODO: contenedor + volumen (incluido el modelo IA).'
Write-Host ''
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
# d0a1 pack - Hermes (Linux) - DESINSTALAR
docker rm -f d0a1-hermes-ollama >/dev/null 2>&1 || true
docker volume rm d0a1_hermes_ollama >/dev/null 2>&1 || true
echo ">>> Eliminado TODO: contenedor + volumen (incluido el modelo IA)."
+74 -12
View File
@@ -80,6 +80,23 @@ if ($TotalRamGb -lt 3.5) {
} }
Ok "RAM: $TotalRamGb GB" Ok "RAM: $TotalRamGb GB"
# --- Tumbar deploy previo (antes de detectar puertos) -----------------------
cmd /c docker rm -f d0a1-openclaw-ollama '>' NUL '2>&1'
Info 'Deploy previo detenido (rm; volumen con el modelo intacto).'
# --- GPU NVIDIA? (si hay, Ollama la usa y va 5-10x mas rapido) ---------------
$HasGpu = $false
if (Get-Command nvidia-smi -ErrorAction SilentlyContinue) {
$GpuInfo = & nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>$null
if ($LASTEXITCODE -eq 0 -and $GpuInfo) {
$HasGpu = $true
$GpuName = ($GpuInfo -split ',')[0].Trim()
Info "GPU NVIDIA detectada: $GpuName (aceleracion activada)"
}
}
if (-not $HasGpu) {
Warn 'Sin GPU NVIDIA: modo CPU (~10-20 tokens/s). Con una GPU NVIDIA va 5-10x mas rapido.'
}
# --- Auto-detect Ollama port ------------------------------------------------ # --- Auto-detect Ollama port ------------------------------------------------
$OllamaPort = Find-FreePort 11434 $OllamaPort = Find-FreePort 11434
@@ -98,7 +115,10 @@ Write-Host ''
Warn '[1/3] Arrancando Ollama (IA local)...' Warn '[1/3] Arrancando Ollama (IA local)...'
$running = docker ps --format '{{.Names}}' | Select-String -Quiet 'd0a1-openclaw-ollama' $running = docker ps --format '{{.Names}}' | Select-String -Quiet 'd0a1-openclaw-ollama'
if (-not $running) { if (-not $running) {
docker run -d --name d0a1-openclaw-ollama ` $GpuArgs = @()
if ($HasGpu) { $GpuArgs = @('--gpus', 'all') }
$CpuCap = [Math]::Min(6, [int]$env:NUMBER_OF_PROCESSORS)
docker run -d --name d0a1-openclaw-ollama --memory 6g --cpus $CpuCap @GpuArgs `
-p "${OllamaPort}:11434" ` -p "${OllamaPort}:11434" `
-v d0a1_openclaw_ollama:/root/.ollama ` -v d0a1_openclaw_ollama:/root/.ollama `
-e OLLAMA_HOST=0.0.0.0 ` -e OLLAMA_HOST=0.0.0.0 `
@@ -120,21 +140,63 @@ while ($true) {
exit 1 exit 1
} }
} }
Warn ' Descargando modelo (llama3.2:3b, ~2 GB)...' Warn ' Descargando modelo (qwen3:4b, ~2.5 GB)...'
$PullOk = $false # Si el usuario define $env:HTTPS_PROXY, Ollama lo usa para el pull (doc oficial):
foreach ($Attempt in 1..3) { $ProxyEnv = @()
if ($Attempt -gt 1) { Warn "Reintento $Attempt de 3..." } if ($env:HTTPS_PROXY) { $ProxyEnv = @('-e', "HTTPS_PROXY=$env:HTTPS_PROXY", '-e', "HTTP_PROXY=$env:HTTP_PROXY") }
docker exec d0a1-openclaw-ollama ollama pull llama3.2:3b # --- Modelo ya presente? (volumen persistente: no re-descargar) ------------
if ($LASTEXITCODE -eq 0) { $PullOk = $true; break } $ModelList = docker exec d0a1-openclaw-ollama ollama list 2>$null
Warn 'Descarga interrumpida (red). Reintentando en 5 s...' if ("$ModelList" -match 'qwen3:4b') {
Start-Sleep -Seconds 5 Info 'Modelo qwen3:4b ya descargado (volumen intacto). Omitiendo descarga.'
cmd /c docker exec d0a1-openclaw-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf' '>' NUL '2>&1'
} else {
# --- Modelo: HF primero (CDN propio, rapido) y registry de Ollama como ultimo recurso ---
$Gguf = Join-Path $ScriptDir 'qwen3-4b-q4.gguf'
$HfUrls = @(
'https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf',
'https://huggingface.co/unsloth/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf'
)
Info 'Descargando modelo de IA (qwen3:4b, ~2.5 GB)...'
foreach ($Url in $HfUrls) {
curl.exe -# -L --retry 3 --max-time 1800 -o "$Gguf" $Url
if ($LASTEXITCODE -eq 0 -and (Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) { break }
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
if ($Url -ne $HfUrls[-1]) { Warn 'Mirror no accesible, probando el siguiente...' }
}
if ((Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) {
Info 'Importando modelo en Ollama...'
docker cp "$Gguf" d0a1-openclaw-ollama:/root/.ollama/import.gguf
docker exec d0a1-openclaw-ollama sh -c 'printf "FROM /root/.ollama/import.gguf\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
$CreateOk = ($LASTEXITCODE -eq 0)
docker exec d0a1-openclaw-ollama rm -f /root/.ollama/import.gguf | Out-Null
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
$PullOk = $CreateOk
if (-not $CreateOk) { Err 'Fallo al importar el modelo desde el GGUF.' }
} else {
# Ultimo recurso: pull directo (1 intento, ya sin esperar 3 rondas)
Warn 'HuggingFace no accesible. Probando el registry de Ollama (ultimo recurso)...'
docker exec @ProxyEnv d0a1-openclaw-ollama ollama pull qwen3:4b
if ($LASTEXITCODE -eq 0) {
$PullOk = $true
# Contexto ampliado (el default 4096 da 400 en Open WebUI con prompts largos)
docker exec d0a1-openclaw-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
}
} }
if (-not $PullOk) { if (-not $PullOk) {
Err 'Fallo la descarga del modelo tras 3 intentos.' Err 'No se pudo descargar el modelo (ni HuggingFace ni registry).'
Write-Host ' Revisa tu red (VPN/proxy) y reintenta a mano:' if (-not $env:HTTPS_PROXY) {
Write-Host ' docker exec d0a1-openclaw-ollama ollama pull llama3.2:3b' Write-Host ' Tu red bloquea ambos. Si tienes proxy/VPN:'
Write-Host ' $env:HTTPS_PROXY = "http://127.0.0.1:7890" # (puerto de tu proxy)'
Write-Host ' .\deploy.ps1 vps'
}
exit 1 exit 1
} }
}
# --- Precalentar el modelo (load ya, no en el primer mensaje) ---------------
Warn ' Precargando el modelo en memoria...'
cmd /c docker exec d0a1-openclaw-ollama sh -c 'ollama run qwen3:4b ""' '>' NUL '2>&1'
Ok "Ollama corriendo en http://localhost:${OllamaPort}" Ok "Ollama corriendo en http://localhost:${OllamaPort}"
# --- 2. Instalar OpenClaw ----------------------------------------------------- # --- 2. Instalar OpenClaw -----------------------------------------------------
+5 -3
View File
@@ -92,10 +92,12 @@ echo ""
# ── 1. Arrancar Ollama (Docker) ────────────── # ── 1. Arrancar Ollama (Docker) ──────────────
echo -e "${YELLOW}[1/3]${NC} Arrancando Ollama (IA local)..." echo -e "${YELLOW}[1/3]${NC} Arrancando Ollama (IA local)..."
if ! docker ps --format '{{.Names}}' | grep -q d0a1-openclaw-ollama; then if ! docker ps --format '{{.Names}}' | grep -q d0a1-openclaw-ollama; then
CPU_CAP=$(( $(nproc) > 6 ? 6 : $(nproc) ))
docker run -d --name d0a1-openclaw-ollama \ docker run -d --name d0a1-openclaw-ollama \
-p "${OLLAMA_PORT}:11434" \ -p "${{OLLAMA_PORT}}:11434" \
-v d0a1_openclaw_ollama:/root/.ollama \ -v d0a1_openclaw_ollama:/root/.ollama \
-e OLLAMA_HOST=0.0.0.0 \ -e OLLAMA_HOST=0.0.0.0 \
--memory 6g --cpus "$CPU_CAP" \
--restart unless-stopped \ --restart unless-stopped \
ollama/ollama:0.33.3 ollama/ollama:0.33.3
fi fi
@@ -112,8 +114,8 @@ until docker exec d0a1-openclaw-ollama ollama ps &>/dev/null; do
exit 1 exit 1
fi fi
done done
echo -e "${YELLOW} Descargando modelo (llama3.2:3b, ~2 GB)...${NC}" echo -e "${YELLOW} Descargando modelo (qwen3:4b, ~2.5 GB)...${NC}"
docker exec d0a1-openclaw-ollama ollama pull llama3.2:3b docker exec d0a1-openclaw-ollama ollama pull qwen3:4b
echo -e "${GREEN}✓${NC} Ollama corriendo en http://localhost:${OLLAMA_PORT}" echo -e "${GREEN}✓${NC} Ollama corriendo en http://localhost:${OLLAMA_PORT}"
# ── 2. Instalar OpenClaw ───────────────────── # ── 2. Instalar OpenClaw ─────────────────────
+16
View File
@@ -0,0 +1,16 @@
# ============================================================
# d0a1 pack - OpenClaw (Windows) - DESINSTALAR
# Elimina el contenedor y el volumen (datos + modelo).
# ============================================================
$ErrorActionPreference = 'Stop'
function Info($m) { Write-Host ">>> $m" }
Info 'Borrando contenedor y volumen...'
cmd /c docker rm -f d0a1-openclaw-ollama '>' NUL '2>&1'
cmd /c docker volume rm d0a1_openclaw_ollama '>' NUL '2>&1'
Write-Host ''
Info 'Eliminado TODO: contenedor + volumen (incluido el modelo IA).'
Write-Host ''
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
# d0a1 pack - OpenClaw (Linux) - DESINSTALAR
docker rm -f d0a1-openclaw-ollama >/dev/null 2>&1 || true
docker volume rm d0a1_openclaw_ollama >/dev/null 2>&1 || true
echo ">>> Eliminado TODO: contenedor + volumen (incluido el modelo IA)."
+1 -1
View File
@@ -33,7 +33,7 @@ Solo pagas el servidor. La IA es tuya.
## Modelos ## Modelos
El modelo por defecto es `llama3.2:3b` (2 GB, corre en 4 GB RAM). El modelo por defecto es `qwen3:4b` (2 GB, corre en 4 GB RAM).
```bash ```bash
docker exec d0a1-ollama ollama pull qwen3:4b # Mejor en español + razonamiento (4 GB RAM) docker exec d0a1-ollama ollama pull qwen3:4b # Mejor en español + razonamiento (4 GB RAM)
+80 -13
View File
@@ -86,6 +86,25 @@ if ($TotalRamGb -lt 3.5) {
} }
Ok "RAM: $TotalRamGb GB" Ok "RAM: $TotalRamGb GB"
# --- Tumbar deploy previo (antes de detectar puertos) ----------------------
# Mantiene los volumenes (el modelo ya descargado no se re-descarga) y libera
# los puertos para que Find-FreePort vea el estado REAL tras el down.
cmd /c docker compose -f $ComposeFile down '>' NUL '2>&1'
Info 'Deploy previo detenido (down; volumenes con el modelo intactos).'
# --- GPU NVIDIA? (si hay, Ollama la usa y va 5-10x mas rapido) ---------------
$HasGpu = $false
if (Get-Command nvidia-smi -ErrorAction SilentlyContinue) {
$GpuInfo = & nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>$null
if ($LASTEXITCODE -eq 0 -and $GpuInfo) {
$HasGpu = $true
$GpuName = ($GpuInfo -split ',')[0].Trim()
Info "GPU NVIDIA detectada: $GpuName (aceleracion activada)"
}
}
if (-not $HasGpu) {
Warn 'Sin GPU NVIDIA: modo CPU (~10-20 tokens/s). Con una GPU NVIDIA va 5-10x mas rapido.'
}
# --- Auto-detect ports ---------------------------------------------------- # --- Auto-detect ports ----------------------------------------------------
$OllamaPort = Find-FreePort 11434 $OllamaPort = Find-FreePort 11434
$WebUiPort = Find-FreePort 3000 $WebUiPort = Find-FreePort 3000
@@ -119,11 +138,17 @@ Write-Host ''
Warn 'Descargando contenedores (2-3 min la primera vez)...' Warn 'Descargando contenedores (2-3 min la primera vez)...'
$env:OLLAMA_PORT = "$OllamaPort" $env:OLLAMA_PORT = "$OllamaPort"
$env:WEBUI_PORT = "$WebUiPort" $env:WEBUI_PORT = "$WebUiPort"
docker compose -f $ComposeFile up -d $ComposeArgs = @('-f', $ComposeFile)
if ($HasGpu) {
$OverrideFile = Join-Path $ScriptDir 'docker-compose.gpu.yml'
Set-Content -Path $OverrideFile -Value "services:`r`n ollama:`r`n gpus: all`r`n"
$ComposeArgs += @('-f', $OverrideFile)
}
docker compose @ComposeArgs up -d
if ($LASTEXITCODE -ne 0) { Err "docker compose up fallo (exit $LASTEXITCODE)."; exit 1 } if ($LASTEXITCODE -ne 0) { Err "docker compose up fallo (exit $LASTEXITCODE)."; exit 1 }
# --- Pull model ------------------------------------------------------------- # --- Pull model -------------------------------------------------------------
Warn 'Descargando modelo de IA (llama3.2:3b, ~2 GB)...' Info 'Esperando a que Ollama arranque...'
$MaxWait = 60; $Waited = 0 $MaxWait = 60; $Waited = 0
while ($true) { while ($true) {
# Descarte de stderr via cmd /c (ver nota de PS 5.1 / PS #4002 arriba) # Descarte de stderr via cmd /c (ver nota de PS 5.1 / PS #4002 arriba)
@@ -136,20 +161,62 @@ while ($true) {
exit 1 exit 1
} }
} }
$PullOk = $false # Si el usuario define $env:HTTPS_PROXY, Ollama lo usa para el pull (doc oficial):
foreach ($Attempt in 1..3) { $ProxyEnv = @()
if ($Attempt -gt 1) { Warn "Reintento $Attempt de 3..." } if ($env:HTTPS_PROXY) { $ProxyEnv = @('-e', "HTTPS_PROXY=$env:HTTPS_PROXY", '-e', "HTTP_PROXY=$env:HTTP_PROXY") }
docker exec d0a1-ollama ollama pull llama3.2:3b # --- Modelo ya presente? (volumen persistente: no re-descargar) ------------
if ($LASTEXITCODE -eq 0) { $PullOk = $true; break } $ModelList = docker exec d0a1-ollama ollama list 2>$null
Warn 'Descarga interrumpida (red). Reintentando en 5 s...' if ("$ModelList" -match 'qwen3:4b') {
Start-Sleep -Seconds 5 Info 'Modelo qwen3:4b ya descargado (volumen intacto). Omitiendo descarga.'
cmd /c docker exec d0a1-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf' '>' NUL '2>&1'
} else {
# --- Modelo: HF primero (CDN propio, rapido) y registry de Ollama como ultimo recurso ---
$Gguf = Join-Path $ScriptDir 'qwen3-4b-q4.gguf'
$HfUrls = @(
'https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf',
'https://huggingface.co/unsloth/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf'
)
Info 'Descargando modelo de IA (qwen3:4b, ~2.5 GB)...'
foreach ($Url in $HfUrls) {
curl.exe -# -L --retry 3 --max-time 1800 -o "$Gguf" $Url
if ($LASTEXITCODE -eq 0 -and (Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) { break }
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
if ($Url -ne $HfUrls[-1]) { Warn 'Mirror no accesible, probando el siguiente...' }
}
if ((Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) {
Info 'Importando modelo en Ollama...'
docker cp "$Gguf" d0a1-ollama:/root/.ollama/import.gguf
docker exec d0a1-ollama sh -c 'printf "FROM /root/.ollama/import.gguf\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
$CreateOk = ($LASTEXITCODE -eq 0)
docker exec d0a1-ollama rm -f /root/.ollama/import.gguf | Out-Null
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
$PullOk = $CreateOk
if (-not $CreateOk) { Err 'Fallo al importar el modelo desde el GGUF.' }
} else {
# Ultimo recurso: pull directo (1 intento, ya sin esperar 3 rondas)
Warn 'HuggingFace no accesible. Probando el registry de Ollama (ultimo recurso)...'
docker exec @ProxyEnv d0a1-ollama ollama pull qwen3:4b
if ($LASTEXITCODE -eq 0) {
$PullOk = $true
# Contexto ampliado (el default 4096 da 400 en Open WebUI con prompts largos)
docker exec d0a1-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
}
} }
if (-not $PullOk) { if (-not $PullOk) {
Err 'Fallo la descarga del modelo tras 3 intentos.' Err 'No se pudo descargar el modelo (ni HuggingFace ni registry).'
Write-Host ' Revisa tu red (VPN/proxy) y reintenta a mano:' if (-not $env:HTTPS_PROXY) {
Write-Host ' docker exec d0a1-ollama ollama pull llama3.2:3b' Write-Host ' Tu red bloquea ambos. Si tienes proxy/VPN:'
Write-Host ' $env:HTTPS_PROXY = "http://127.0.0.1:7890" # (puerto de tu proxy)'
Write-Host ' .\deploy.ps1 vps'
}
exit 1 exit 1
} }
}
# --- Precalentar el modelo (load a GPU/RAM ya, no en el primer mensaje) -----
Info 'Precargando el modelo en memoria...'
cmd /c docker exec d0a1-ollama sh -c 'ollama run qwen3:4b ""' '>' NUL '2>&1'
# --- Done ------------------------------------------------------------------- # --- Done -------------------------------------------------------------------
Write-Host '' Write-Host ''
@@ -162,7 +229,7 @@ if ($Mode -eq 'local') {
} }
Write-Host '' Write-Host ''
Write-Host " ${Bold}Modelos alternativos:${NC}" Write-Host " ${Bold}Modelos alternativos:${NC}"
Write-Host ' docker exec d0a1-ollama ollama pull qwen3:4b # Mejor en espanol + razonamiento (4 GB RAM)' Write-Host ' docker exec d0a1-ollama ollama pull llama3.2:3b # Mas ligero (2 GB RAM)'
Write-Host ' docker exec d0a1-ollama ollama pull qwen3:8b # Mas calidad (6 GB RAM)' Write-Host ' docker exec d0a1-ollama ollama pull qwen3:8b # Mas calidad (6 GB RAM)'
Write-Host '' Write-Host ''
Write-Host " ${Bold}Parar:${NC} .\deploy.ps1 stop" Write-Host " ${Bold}Parar:${NC} .\deploy.ps1 stop"
+3 -3
View File
@@ -105,7 +105,7 @@ echo -e "${YELLOW}Descargando contenedores (2-3 min la primera vez)...${NC}"
docker compose -f "$COMPOSE_FILE" up -d docker compose -f "$COMPOSE_FILE" up -d
# ── Pull model ─────────────────────────────── # ── Pull model ───────────────────────────────
echo -e "${YELLOW}Descargando modelo de IA (llama3.2:3b, ~2 GB)...${NC}" echo -e "${YELLOW}Descargando modelo de IA (qwen3:4b, ~2.5 GB)...${NC}"
MAX_WAIT=60 MAX_WAIT=60
WAITED=0 WAITED=0
until docker exec d0a1-ollama ollama ps &>/dev/null; do until docker exec d0a1-ollama ollama ps &>/dev/null; do
@@ -116,7 +116,7 @@ until docker exec d0a1-ollama ollama ps &>/dev/null; do
exit 1 exit 1
fi fi
done done
docker exec d0a1-ollama ollama pull llama3.2:3b docker exec d0a1-ollama ollama pull qwen3:4b
# ── Done ──────────────────────────────────── # ── Done ────────────────────────────────────
echo "" echo ""
@@ -129,7 +129,7 @@ else
fi fi
echo "" echo ""
echo -e " ${BOLD}Modelos alternativos:${NC}" echo -e " ${BOLD}Modelos alternativos:${NC}"
echo " docker exec d0a1-ollama ollama pull qwen3:4b # Mejor en español + razonamiento (4 GB RAM)" echo " docker exec d0a1-ollama ollama pull llama3.2:3b # Más ligero (2 GB RAM)"
echo " docker exec d0a1-ollama ollama pull qwen3:8b # Más calidad (6 GB RAM)" echo " docker exec d0a1-ollama ollama pull qwen3:8b # Más calidad (6 GB RAM)"
echo "" echo ""
echo -e " ${BOLD}Parar:${NC} ./deploy.sh stop" echo -e " ${BOLD}Parar:${NC} ./deploy.sh stop"
+9 -2
View File
@@ -6,7 +6,7 @@
# #
# Requisitos: Docker + 4 GB RAM mínimo # Requisitos: Docker + 4 GB RAM mínimo
# Incluye: Ollama (IA local) + Open WebUI (interfaz web) # Incluye: Ollama (IA local) + Open WebUI (interfaz web)
# Modelo por defecto: llama3.2:3b (~2 GB, corre en 4 GB RAM) # Modelo por defecto: qwen3:4b (~2.5 GB, corre en 4 GB RAM)
services: services:
ollama: ollama:
container_name: d0a1-ollama container_name: d0a1-ollama
@@ -18,7 +18,7 @@ services:
- ollama_data:/root/.ollama - ollama_data:/root/.ollama
environment: environment:
OLLAMA_HOST: "0.0.0.0" OLLAMA_HOST: "0.0.0.0"
OLLAMA_KEEP_ALIVE: "5m" OLLAMA_KEEP_ALIVE: "-1"
OLLAMA_NUM_PARALLEL: "1" OLLAMA_NUM_PARALLEL: "1"
healthcheck: healthcheck:
test: ["CMD", "ollama", "ps"] test: ["CMD", "ollama", "ps"]
@@ -26,6 +26,11 @@ services:
timeout: 5s timeout: 5s
retries: 10 retries: 10
start_period: 30s start_period: 30s
deploy:
resources:
limits:
memory: 6G
cpus: "${OLLAMA_CPUS:-6.0}"
openwebui: openwebui:
container_name: d0a1-openwebui container_name: d0a1-openwebui
@@ -43,6 +48,8 @@ services:
ENABLE_SIGNUP: "true" ENABLE_SIGNUP: "true"
ENABLE_WEB_SEARCH: "false" ENABLE_WEB_SEARCH: "false"
ENABLE_DIRECT_CONNECTIONS: "false" ENABLE_DIRECT_CONNECTIONS: "false"
CHAT_RESPONSE_MAX_TOOL_CALL_ITERATIONS: "1"
DEFAULT_MODEL_PARAMS: '{"function_calling": "legacy", "think": false}'
depends_on: depends_on:
ollama: ollama:
condition: service_healthy condition: service_healthy
+24
View File
@@ -0,0 +1,24 @@
# ============================================================
# d0a1 pack - Open WebUI (Windows) - DESINSTALAR
# Elimina contenedores, red y volumenes (datos + modelo).
# ============================================================
$ErrorActionPreference = 'Stop'
$ScriptDir = $PSScriptRoot
if (-not $ScriptDir) { $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path }
$ComposeFile = Join-Path $ScriptDir 'docker-compose.yml'
function Info($m) { Write-Host ">>> $m" }
function Err($m) { Write-Host "!!! $m"; exit 1 }
# Sin confirmacion: este pack no guarda datos sensibles (solo chat + modelo).
Info 'Deteniendo y borrando contenedores...'
cmd /c docker compose -f "$ComposeFile" down -v --remove-orphans '>' NUL '2>&1'
if ($LASTEXITCODE -ne 0) { Err 'Fallo el compose down (docker no arrancado?)' }
Write-Host ''
Info 'Eliminado TODO:'
Write-Host ' - Contenedores y red'
Write-Host ' - Volumenes (incluido el modelo IA)'
Write-Host ''
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# d0a1 pack - Open WebUI (Linux) - DESINSTALAR
set -e
cd "$(cd "$(dirname "$0")" && pwd)"
echo ">>> Deteniendo y borrando contenedores..."
docker compose -f docker-compose.yml down -v --remove-orphans >/dev/null 2>&1 || { echo "!!! Fallo el compose down"; exit 1; }
echo ""
echo ">>> Eliminado TODO: contenedores, red y volumenes (incluido el modelo IA)."
+8 -7
View File
@@ -1,10 +1,10 @@
# WordPress + IA — WP con IA local # WordPress + IA — WP con IA local
Tu WordPress con IA local conectada. Genera borradores, modera comentarios y chatea con tu sitio. Tu WordPress con IA local conectada. Titulares, extractos y moderación de comentarios con IA, dentro del propio editor.
## Qué es ## Qué es
WordPress corriendo en tu servidor con Ollama (IA local) y Open WebUI conectados. Instala el plugin AI Agent Bridge para generar contenido y moderar comentarios con IA local, sin API de terceros. WordPress corriendo en tu servidor con Ollama (IA local) conectado de serie: los plugins **AI** y **AI Provider for Ollama** se instalan y configuran solos durante el deploy. Genera títulos, extractos y alt text desde el editor de WordPress con tu propio modelo (qwen3:4b), sin API de terceros ni cuotas.
## Prueba local (gratis, 1 comando) ## Prueba local (gratis, 1 comando)
@@ -13,9 +13,8 @@ WordPress corriendo en tu servidor con Ollama (IA local) y Open WebUI conectados
``` ```
- WordPress: http://localhost:8080 - WordPress: http://localhost:8080
- IA (chat): http://localhost:3000
Sigue el asistente de instalación de WordPress (2 minutos), luego instala el plugin AI Agent Bridge desde el panel. Sigue el asistente de instalación de WordPress (2 minutos). Al terminar, ejecuta `./deploy.sh` otra vez y los plugins de IA quedan activados y conectados.
## Despliega en VPS ## Despliega en VPS
@@ -33,13 +32,14 @@ Solo pagas el servidor. WordPress y la IA son tuyos.
- Docker instalado - Docker instalado
- 6 GB RAM mínimo - 6 GB RAM mínimo
- GPU NVIDIA recomendada (detección automática)
## Qué incluye ## Qué incluye
- WordPress 7.0 + PHP 8.4 - WordPress 7.1 + PHP 8.4
- MariaDB 11.8 - MariaDB 11.8
- Ollama (IA local, modelo llama3.2:3b por defecto) - Ollama (IA local, modelo qwen3:4b por defecto)
- Open WebUI (interfaz de chat) - Plugins IA preconfigurados: AI (funciones en el editor) + AI Provider for Ollama
## Comandos ## Comandos
@@ -47,4 +47,5 @@ Solo pagas el servidor. WordPress y la IA son tuyos.
./deploy.sh local # Arrancar en local ./deploy.sh local # Arrancar en local
./deploy.sh vps # Arrancar en VPS ./deploy.sh vps # Arrancar en VPS
./deploy.sh stop # Parar todo ./deploy.sh stop # Parar todo
./remove.sh # Desinstalar todo (contenedores + datos)
``` ```
+155 -27
View File
@@ -119,16 +119,31 @@ if (-not (Test-Path $EnvFile)) {
Info "Contrasenas generadas en $EnvFile" Info "Contrasenas generadas en $EnvFile"
} }
# --- GPU NVIDIA? (si hay, Ollama la usa y va 5-10x mas rapido) ---------------
$HasGpu = $false
if (Get-Command nvidia-smi -ErrorAction SilentlyContinue) {
$GpuInfo = & nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>$null
if ($LASTEXITCODE -eq 0 -and $GpuInfo) {
$HasGpu = $true
$GpuName = ($GpuInfo -split ',')[0].Trim()
Info "GPU NVIDIA detectada: $GpuName (aceleracion activada)"
}
}
if (-not $HasGpu) {
Warn 'Sin GPU NVIDIA: modo CPU (~10-20 tokens/s). Con una GPU NVIDIA va 5-10x mas rapido.'
}
# --- Auto-detect ports ---------------------------------------------------- # --- Auto-detect ports ----------------------------------------------------
$OllamaPort = Find-FreePort 11434 # --- Tumbar deploy previo (antes de detectar puertos) ----------------------
cmd /c docker compose -f $ComposeFile down '>' NUL '2>&1'
Info 'Deploy previo detenido (down; volumenes con el modelo intactos).'
$OllamaPort = $null # Ollama ya no publica puerto: solo lo usa WP por la red interna
$WpPort = Find-FreePort 8080 $WpPort = Find-FreePort 8080
$WebUiPort = Find-FreePort 3000
# --- Mode info ------------------------------------------------------------ # --- Mode info ------------------------------------------------------------
if ($Mode -eq 'local') { if ($Mode -eq 'local') {
Warn 'Modo: local (tu ordenador)' Warn 'Modo: local (tu ordenador)'
Write-Host " WordPress: ${Cyan}http://localhost:${WpPort}${NC}" Write-Host " WordPress: ${Cyan}http://localhost:${WpPort}${NC}"
Write-Host " IA (chat): ${Cyan}http://localhost:${WebUiPort}${NC}"
} else { } else {
Warn 'Modo: VPS (accesible desde fuera)' Warn 'Modo: VPS (accesible desde fuera)'
# IP real de LAN: la de la interfaz con la ruta por defecto (evita # IP real de LAN: la de la interfaz con la ruta por defecto (evita
@@ -140,28 +155,30 @@ if ($Mode -eq 'local') {
Select-Object -First 1).IPAddress Select-Object -First 1).IPAddress
if (-not $Ip) { $Ip = 'TU_IP' } if (-not $Ip) { $Ip = 'TU_IP' }
Write-Host " WordPress: ${Cyan}http://${Ip}:${WpPort}${NC}" Write-Host " WordPress: ${Cyan}http://${Ip}:${WpPort}${NC}"
Write-Host " IA (chat): ${Cyan}http://${Ip}:${WebUiPort}${NC}"
Write-Host '' Write-Host ''
Write-Host " ${Bold}¿No tienes VPS?${NC} Consigue uno con descuento:" Write-Host " ${Bold}¿No tienes VPS?${NC} Consigue uno con descuento:"
Write-Host " ${Cyan}https://d0a1.es/go/vultr/${NC} - Vultr" Write-Host " ${Cyan}https://d0a1.es/go/vultr/${NC} - Vultr"
Write-Host " ${Cyan}https://d0a1.es/go/digitalocean/${NC} - DigitalOcean (`$200 credit)" Write-Host " ${Cyan}https://d0a1.es/go/digitalocean/${NC} - DigitalOcean (`$200 credit)"
} }
if ($OllamaPort -ne 11434) { Warn "Puerto 11434 ocupado, usando $OllamaPort" } if ($WpPort -ne 8080) { Warn "Puerto 8080 ocupado, usando $WpPort" }
if ($WpPort -ne 8080) { Warn "Puerto 8080 ocupado, usando $WpPort" }
if ($WebUiPort -ne 3000) { Warn "Puerto 3000 ocupado, usando $WebUiPort" }
Write-Host '' Write-Host ''
# --- Deploy ---------------------------------------------------------------- # --- Deploy ----------------------------------------------------------------
Warn 'Descargando contenedores (3-5 min la primera vez)...' Warn 'Descargando contenedores (3-5 min la primera vez)...'
$env:OLLAMA_PORT = "$OllamaPort" cmd /c docker compose -f $ComposeFile down '>' NUL '2>&1'
$env:WP_PORT = "$WpPort" $env:WP_PORT = "$WpPort"
$env:WEBUI_PORT = "$WebUiPort" $ComposeArgs = @('-f', $ComposeFile)
docker compose -f $ComposeFile up -d if ($HasGpu) {
$OverrideFile = Join-Path $ScriptDir 'docker-compose.gpu.yml'
Set-Content -Path $OverrideFile -Value "services:`r`n ollama:`r`n gpus: all`r`n"
$ComposeArgs += @('-f', $OverrideFile)
}
docker compose @ComposeArgs up -d
if ($LASTEXITCODE -ne 0) { Err "docker compose up fallo (exit $LASTEXITCODE)."; exit 1 } if ($LASTEXITCODE -ne 0) { Err "docker compose up fallo (exit $LASTEXITCODE)."; exit 1 }
# --- Pull model ------------------------------------------------------------- # --- Pull model -------------------------------------------------------------
Warn 'Descargando modelo de IA (llama3.2:3b, ~2 GB)...' Info 'Esperando a que Ollama arranque...'
$MaxWait = 60; $Waited = 0 $MaxWait = 60; $Waited = 0
while ($true) { while ($true) {
# Descarte de stderr via cmd /c (ver nota de PS 5.1 / PS #4002 arriba) # Descarte de stderr via cmd /c (ver nota de PS 5.1 / PS #4002 arriba)
@@ -174,37 +191,148 @@ while ($true) {
exit 1 exit 1
} }
} }
$PullOk = $false # Si el usuario define $env:HTTPS_PROXY, Ollama lo usa para el pull (doc oficial):
foreach ($Attempt in 1..3) { $ProxyEnv = @()
if ($Attempt -gt 1) { Warn "Reintento $Attempt de 3..." } if ($env:HTTPS_PROXY) { $ProxyEnv = @('-e', "HTTPS_PROXY=$env:HTTPS_PROXY", '-e', "HTTP_PROXY=$env:HTTP_PROXY") }
docker exec d0a1-wp-ollama ollama pull llama3.2:3b # --- Modelo ya presente? (volumen persistente: no re-descargar) ------------
if ($LASTEXITCODE -eq 0) { $PullOk = $true; break } $ModelList = docker exec d0a1-wp-ollama ollama list 2>$null
Warn 'Descarga interrumpida (red). Reintentando en 5 s...' if ("$ModelList" -match 'qwen3:4b') {
Start-Sleep -Seconds 5 Info 'Modelo qwen3:4b ya descargado (volumen intacto). Omitiendo descarga.'
cmd /c docker exec d0a1-wp-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf' '>' NUL '2>&1'
} else {
# --- Modelo: HF primero (CDN propio, rapido) y registry de Ollama como ultimo recurso ---
$Gguf = Join-Path $ScriptDir 'qwen3-4b-q4.gguf'
$HfUrls = @(
'https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf',
'https://huggingface.co/unsloth/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf'
)
Info 'Descargando modelo de IA (qwen3:4b, ~2.5 GB)...'
foreach ($Url in $HfUrls) {
curl.exe -# -L --retry 3 --max-time 1800 -o "$Gguf" $Url
if ($LASTEXITCODE -eq 0 -and (Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) { break }
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
if ($Url -ne $HfUrls[-1]) { Warn 'Mirror no accesible, probando el siguiente...' }
}
if ((Test-Path $Gguf) -and (Get-Item $Gguf).Length -gt 2400000000) {
Info 'Importando modelo en Ollama...'
docker cp "$Gguf" d0a1-wp-ollama:/root/.ollama/import.gguf
docker exec d0a1-wp-ollama sh -c 'printf "FROM /root/.ollama/import.gguf\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
$CreateOk = ($LASTEXITCODE -eq 0)
docker exec d0a1-wp-ollama rm -f /root/.ollama/import.gguf | Out-Null
Remove-Item "$Gguf" -Force -ErrorAction SilentlyContinue
$PullOk = $CreateOk
if (-not $CreateOk) { Err 'Fallo al importar el modelo desde el GGUF.' }
} else {
# Ultimo recurso: pull directo (1 intento, ya sin esperar 3 rondas)
Warn 'HuggingFace no accesible. Probando el registry de Ollama (ultimo recurso)...'
docker exec @ProxyEnv d0a1-wp-ollama ollama pull qwen3:4b
if ($LASTEXITCODE -eq 0) {
$PullOk = $true
# Contexto ampliado (el default 4096 da 400 en Open WebUI con prompts largos)
docker exec d0a1-wp-ollama sh -c 'printf "FROM qwen3:4b\\nPARAMETER num_ctx 16384\\nSYSTEM /no_think\\n" > /tmp/mf && ollama create qwen3:4b -f /tmp/mf'
}
} }
if (-not $PullOk) { if (-not $PullOk) {
Err 'Fallo la descarga del modelo tras 3 intentos.' Err 'No se pudo descargar el modelo (ni HuggingFace ni registry).'
Write-Host ' Revisa tu red (VPN/proxy) y reintenta a mano:' if (-not $env:HTTPS_PROXY) {
Write-Host ' docker exec d0a1-wp-ollama ollama pull llama3.2:3b' Write-Host ' Tu red bloquea ambos. Si tienes proxy/VPN:'
Write-Host ' $env:HTTPS_PROXY = "http://127.0.0.1:7890" # (puerto de tu proxy)'
Write-Host ' .\deploy.ps1 vps'
}
exit 1 exit 1
} }
}
# --- Precalentar el modelo (load a GPU/RAM ya, no en el primer mensaje) -----
Info 'Precargando el modelo en memoria...'
cmd /c docker exec d0a1-wp-ollama sh -c 'ollama run qwen3:4b ""' '>' NUL '2>&1'
# --- Done ------------------------------------------------------------------- # --- Done -------------------------------------------------------------------
Write-Host '' Write-Host ''
Info 'Listo! Tu WordPress con IA esta corriendo.' Info 'Listo! Tu WordPress con IA esta corriendo.'
Write-Host ''
# --- Auto-config WordPress: plugins IA + conexion a Ollama -------------------
# EAP=Continue: los 2>$null sobre nativos con EAP=Stop provocan NativeCommandError
# terminante (PS #4002, ver nota arriba). El bloque nuevo maneja errores por rc.
$PrevEap = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
# El contenedor wordpress:7.1 no trae WP-CLI; usar el contenedor wordpress:cli.
Info 'Configurando los plugins de IA en WordPress (1-2 min la primera vez)...'
cmd /c "docker pull wordpress:cli >NUL 2>&1"
# Red real del compose (el nombre depende del directorio, no es fijo):
$WpNet = docker inspect d0a1-wp --format '{{range $k,$_ := .NetworkSettings.Networks}}{{$k}}{{end}}' 2>$null
if (-not $WpNet) {
Warn 'No se detecto la red del compose (d0a1-wp no corre). Saltando autoconfig.'
$ErrorActionPreference = $PrevEap
exit 1
}
$EnvFileContent = Get-Content $EnvFile -ErrorAction SilentlyContinue
$WpDbPass = ($EnvFileContent | Where-Object { $_ -like 'MYSQL_PASSWORD=*' }) -replace '^MYSQL_PASSWORD=', '' | Select-Object -First 1
if (-not $WpDbPass) { $WpDbPass = 'change-me-to-a-strong-password' }
function Invoke-WpCli {
# docker run con --volumes-from (mismo patron env que usa el compose).
$ArgsList = @('run', '--rm', '--network', $WpNet, '--volumes-from', 'd0a1-wp',
'--env', "WORDPRESS_DB_HOST=db:3306",
'--env', 'WORDPRESS_DB_NAME=wordpress',
'--env', 'WORDPRESS_DB_USER=wordpress',
'--env', "WORDPRESS_DB_PASSWORD=$WpDbPass",
'wordpress:cli') + $Args + @('--allow-root')
& docker @ArgsList 2>$null
return $LASTEXITCODE
}
# Esperar a que WP este instalado (asistente del navegador opcional: si el
# usuario aun no instalo WP, la autoconfig se salta y puede repetir deploy).
$WpReady = $false
for ($i = 0; $i -lt 15; $i++) {
if ((Invoke-WpCli 'core' 'is-installed') -eq 0) { $WpReady = $true; break }
Start-Sleep -Seconds 4
}
if ($WpReady) {
$Rc = Invoke-WpCli 'plugin' 'install' 'ai' 'ai-provider-for-ollama' '--activate'
if ($Rc -eq 0) {
$Rc = Invoke-WpCli 'option' 'update' 'ai_provider_for_ollama_settings' '{"host":"http://ollama:11434"}' '--format=json'
}
if ($Rc -eq 0) {
Ok 'Plugins de IA activados y conectados a Ollama (IA local)'
} else {
Warn 'No se pudo auto-configurar. Re-ejecuta .\deploy.ps1 tras el asistente de WordPress.'
}
# Estilo editorial: copiar al wp-content (editable: editorial-style.php del pack)
# e instalar el mu-plugin que lo inyecta en las instrucciones de la IA.
$StyleRc = 1
cmd /c "docker exec d0a1-wp mkdir -p /var/www/html/wp-content/mu-plugins >NUL 2>&1"
if ($LASTEXITCODE -eq 0) {
docker cp (Join-Path $ScriptDir 'editorial-style.php') d0a1-wp:/var/www/html/wp-content/editorial-style.php 2>$null
if ($LASTEXITCODE -eq 0) {
docker cp (Join-Path $ScriptDir 'mu-plugin-d0a1-editorial.php') d0a1-wp:/var/www/html/wp-content/mu-plugins/d0a1-editorial.php 2>$null
$StyleRc = $LASTEXITCODE
}
}
if ($StyleRc -eq 0) {
Ok 'Estilo editorial activo (edita editorial-style.php y re-ejecuta para cambiarlo)'
}
} else {
Warn 'WordPress aun no esta instalado. Tras el asistente del navegador,'
Warn 'vuelve a ejecutar .\deploy.ps1 y los plugins de IA se configuran solos.'
}
$ErrorActionPreference = $PrevEap
Write-Host '' Write-Host ''
if ($Mode -eq 'local') { if ($Mode -eq 'local') {
Write-Host " ${Bold}WordPress:${NC} ${Cyan}http://localhost:${WpPort}${NC}" Write-Host " ${Bold}WordPress:${NC} ${Cyan}http://localhost:${WpPort}${NC}"
Write-Host " ${Bold}IA (chat):${NC} ${Cyan}http://localhost:${WebUiPort}${NC}"
} else { } else {
Write-Host " ${Bold}WordPress:${NC} ${Cyan}http://${Ip}:${WpPort}${NC}" Write-Host " ${Bold}WordPress:${NC} ${Cyan}http://${Ip}:${WpPort}${NC}"
Write-Host " ${Bold}IA (chat):${NC} ${Cyan}http://${Ip}:${WebUiPort}${NC}"
} }
Write-Host '' Write-Host ''
Write-Host " ${Bold}Configurar WordPress:${NC}" Write-Host " ${Bold}IA integrada en el editor:${NC} titulos sugeridos, extractos, alt text"
Write-Host ' 1. Abre la URL de WordPress en tu navegador' Write-Host ' y moderacion de comentarios con tu modelo local (qwen3:4b).'
Write-Host ' 2. Sigue el asistente de instalacion (2 minutos)' Write-Host " Configuracion en ${Bold}Ajustes - Connectors${NC} dentro de WordPress."
Write-Host " 3. Instala el plugin 'AI Agent Bridge' desde el panel"
Write-Host '' Write-Host ''
Write-Host " ${Bold}Parar:${NC} .\deploy.ps1 stop" Write-Host " ${Bold}Parar:${NC} .\deploy.ps1 stop"
Write-Host " ${Bold}¿Quieres mas?${NC} ${Cyan}https://d0a1.es/packs/${NC}" Write-Host " ${Bold}¿Quieres mas?${NC} ${Cyan}https://d0a1.es/packs/${NC}"
+59 -18
View File
@@ -84,20 +84,16 @@ find_free_port() {
return 1 return 1
} }
export OLLAMA_PORT=$(find_free_port 11434)
export WP_PORT=$(find_free_port 8080) export WP_PORT=$(find_free_port 8080)
export WEBUI_PORT=$(find_free_port 3000)
# ── Mode info ─────────────────────────────── # ── Mode info ───────────────────────────────
if [ "$MODE" = "local" ]; then if [ "$MODE" = "local" ]; then
echo -e "${YELLOW}Modo:${NC} local (tu ordenador)" echo -e "${YELLOW}Modo:${NC} local (tu ordenador)"
echo -e " WordPress: ${CYAN}http://localhost:${WP_PORT}${NC}" echo -e " WordPress: ${CYAN}http://localhost:${WP_PORT}${NC}"
echo -e " IA (chat): ${CYAN}http://localhost:${WEBUI_PORT}${NC}"
elif [ "$MODE" = "vps" ]; then elif [ "$MODE" = "vps" ]; then
IP=$(hostname -I 2>/dev/null | awk '{print $1}' || echo 'TU_IP') IP=$(hostname -I 2>/dev/null | awk '{print $1}' || echo 'TU_IP')
echo -e "${YELLOW}Modo:${NC} VPS (accesible desde fuera)" echo -e "${YELLOW}Modo:${NC} VPS (accesible desde fuera)"
echo -e " WordPress: ${CYAN}http://${IP}:${WP_PORT}${NC}" echo -e " WordPress: ${CYAN}http://${IP}:${WP_PORT}${NC}"
echo -e " IA (chat): ${CYAN}http://${IP}:${WEBUI_PORT}${NC}"
echo "" echo ""
echo -e " ${BOLD}¿No tienes VPS?${NC} Consigue uno con descuento:" echo -e " ${BOLD}¿No tienes VPS?${NC} Consigue uno con descuento:"
echo -e " ${CYAN}https://d0a1.es/go/vultr/${NC} — Vultr" echo -e " ${CYAN}https://d0a1.es/go/vultr/${NC} — Vultr"
@@ -108,15 +104,9 @@ else
exit 1 exit 1
fi fi
if [ "$OLLAMA_PORT" != "11434" ]; then
echo -e "${YELLOW}⚠ Puerto 11434 ocupado, usando ${OLLAMA_PORT}${NC}"
fi
if [ "$WP_PORT" != "8080" ]; then if [ "$WP_PORT" != "8080" ]; then
echo -e "${YELLOW}⚠ Puerto 8080 ocupado, usando ${WP_PORT}${NC}" echo -e "${YELLOW}⚠ Puerto 8080 ocupado, usando ${WP_PORT}${NC}"
fi fi
if [ "$WEBUI_PORT" != "3000" ]; then
echo -e "${YELLOW}⚠ Puerto 3000 ocupado, usando ${WEBUI_PORT}${NC}"
fi
echo "" echo ""
# ── Deploy ────────────────────────────────── # ── Deploy ──────────────────────────────────
@@ -124,7 +114,7 @@ echo -e "${YELLOW}Descargando contenedores (3-5 min la primera vez)...${NC}"
docker compose -f "$COMPOSE_FILE" up -d docker compose -f "$COMPOSE_FILE" up -d
# ── Pull model ─────────────────────────────── # ── Pull model ───────────────────────────────
echo -e "${YELLOW}Descargando modelo de IA (llama3.2:3b, ~2 GB)...${NC}" echo -e "${YELLOW}Descargando modelo de IA (qwen3:4b, ~2.5 GB)...${NC}"
MAX_WAIT=60 MAX_WAIT=60
WAITED=0 WAITED=0
until docker exec d0a1-wp-ollama ollama ps &>/dev/null; do until docker exec d0a1-wp-ollama ollama ps &>/dev/null; do
@@ -135,24 +125,75 @@ until docker exec d0a1-wp-ollama ollama ps &>/dev/null; do
exit 1 exit 1
fi fi
done done
docker exec d0a1-wp-ollama ollama pull llama3.2:3b docker exec d0a1-wp-ollama ollama pull qwen3:4b
# ── Done ──────────────────────────────────── # ── Done ────────────────────────────────────
echo "" echo ""
echo -e "${BOLD}${GREEN}¡Listo! Tu WordPress con IA está corriendo.${NC}" echo -e "${BOLD}${GREEN}¡Listo! Tu WordPress con IA está corriendo.${NC}"
echo ""
# ── Auto-config WordPress (plugins IA + conexión a Ollama) ──
# El contenedor wordpress:7.1 no trae WP-CLI; usar el contenedor wordpress:cli.
echo -e "${YELLOW}Configurando los plugins de IA en WordPress (1-2 min la primera vez)...${NC}"
docker pull wordpress:cli >/dev/null 2>&1
# Red real del compose (el nombre depende del directorio, no es fijo):
WP_NET=$(docker inspect d0a1-wp --format '{{range $k,$_ := .NetworkSettings.Networks}}{{$k}}{{end}}' 2>/dev/null)
if [ -z "$WP_NET" ]; then
echo -e "${YELLOW}⚠ No se detecto la red del compose (d0a1-wp no corre). Saltando autoconfig.${NC}"
exit 1
fi
WP_DB_PASS=$(grep '^MYSQL_PASSWORD=' "$SCRIPT_DIR/.env" | cut -d= -f2)
wpcli() {
docker run --rm --network "$WP_NET" --volumes-from d0a1-wp \
--env WORDPRESS_DB_HOST=db:3306 \
--env WORDPRESS_DB_NAME=wordpress \
--env WORDPRESS_DB_USER=wordpress \
--env WORDPRESS_DB_PASSWORD="$WP_DB_PASS" \
wordpress:cli "$@" --allow-root
}
# Esperar a que WP esté instalado (el asistente del navegador es opcional:
# si el usuario aun no instalo WP, la autoconfig se salta y se puede repetir
# re-ejecutando deploy.sh).
WP_READY=0
for i in $(seq 1 15); do
if wpcli core is-installed >/dev/null 2>&1; then
WP_READY=1
break
fi
sleep 4
done
if [ "$WP_READY" = "1" ]; then
wpcli plugin install ai ai-provider-for-ollama --activate >/dev/null 2>&1 \
&& wpcli option update ai_provider_for_ollama_settings \
'{"host":"http://ollama:11434"}' --format=json >/dev/null 2>&1 \
&& echo -e "${GREEN}✓${NC} Plugins de IA activados y conectados a Ollama (IA local)" \
|| echo -e "${YELLOW}⚠ No se pudo auto-configurar. Re-ejecuta ./deploy.sh tras el asistente de WordPress.${NC}"
# Estilo editorial: copiar al wp-content (editable: editorial-style.php del pack)
# e instalar el mu-plugin que lo inyecta en las instrucciones de la IA.
if docker cp "$SCRIPT_DIR/editorial-style.php" d0a1-wp:/var/www/html/wp-content/editorial-style.php >/dev/null 2>&1 \
&& docker exec d0a1-wp mkdir -p /var/www/html/wp-content/mu-plugins \
&& docker cp "$SCRIPT_DIR/mu-plugin-d0a1-editorial.php" \
d0a1-wp:/var/www/html/wp-content/mu-plugins/d0a1-editorial.php >/dev/null 2>&1; then
echo -e "${GREEN}✓${NC} Estilo editorial activo (edita editorial-style.php y re-ejecuta para cambiarlo)"
fi
else
echo -e "${YELLOW}⚠ WordPress aun no está instalado. Tras el asistente del navegador,"
echo -e " vuelve a ejecutar ./deploy.sh y los plugins de IA se configuran solos.${NC}"
fi
echo "" echo ""
if [ "$MODE" = "local" ]; then if [ "$MODE" = "local" ]; then
echo -e " ${BOLD}WordPress:${NC} ${CYAN}http://localhost:${WP_PORT}${NC}" echo -e " ${BOLD}WordPress:${NC} ${CYAN}http://localhost:${WP_PORT}${NC}"
echo -e " ${BOLD}IA (chat):${NC} ${CYAN}http://localhost:${WEBUI_PORT}${NC}"
else else
echo -e " ${BOLD}WordPress:${NC} ${CYAN}http://${IP}:${WP_PORT}${NC}" echo -e " ${BOLD}WordPress:${NC} ${CYAN}http://${IP}:${WP_PORT}${NC}"
echo -e " ${BOLD}IA (chat):${NC} ${CYAN}http://${IP}:${WEBUI_PORT}${NC}"
fi fi
echo "" echo ""
echo -e " ${BOLD}Configurar WordPress:${NC}" echo -e " ${BOLD}IA integrada en el editor:${NC} títulos sugeridos, extractos, alt text"
echo " 1. Abre la URL de WordPress en tu navegador" echo -e " y moderación de comentarios con tu modelo local (qwen3:4b)."
echo " 2. Sigue el asistente de instalación (2 minutos)" echo -e " Configuración en ${BOLD}Ajustes → Connectors${NC} dentro de WordPress."
echo " 3. Instala el plugin 'AI Agent Bridge' desde el panel"
echo "" echo ""
echo -e " ${BOLD}Parar:${NC} ./deploy.sh stop" echo -e " ${BOLD}Parar:${NC} ./deploy.sh stop"
echo -e " ${BOLD}¿Quieres más?${NC} ${CYAN}https://d0a1.es/packs/${NC}" echo -e " ${BOLD}¿Quieres más?${NC} ${CYAN}https://d0a1.es/packs/${NC}"
+7 -24
View File
@@ -5,7 +5,7 @@
# VPS: ./deploy.sh vps → http://TU_IP:8080 # VPS: ./deploy.sh vps → http://TU_IP:8080
# #
# Requisitos: Docker + 6 GB RAM mínimo # Requisitos: Docker + 6 GB RAM mínimo
# Incluye: WordPress + MariaDB + Ollama + Open WebUI # Incluye: WordPress + MariaDB + Ollama (IA local) + plugins IA (AI + AI Provider for Ollama)
services: services:
db: db:
container_name: d0a1-wp-db container_name: d0a1-wp-db
@@ -46,40 +46,25 @@ services:
container_name: d0a1-wp-ollama container_name: d0a1-wp-ollama
image: ollama/ollama:0.33.3 image: ollama/ollama:0.33.3
restart: unless-stopped restart: unless-stopped
ports: # Sin publicar puerto: solo lo usa WordPress (red interna del compose).
- "127.0.0.1:${OLLAMA_PORT:-11434}:11434" expose:
- "11434"
volumes: volumes:
- ollama_data:/root/.ollama - ollama_data:/root/.ollama
environment: environment:
OLLAMA_HOST: "0.0.0.0" OLLAMA_HOST: "0.0.0.0"
OLLAMA_KEEP_ALIVE: "5m" OLLAMA_KEEP_ALIVE: "-1"
healthcheck: healthcheck:
test: ["CMD", "ollama", "ps"] test: ["CMD", "ollama", "ps"]
interval: 15s interval: 15s
timeout: 5s timeout: 5s
retries: 10 retries: 10
start_period: 30s start_period: 30s
openwebui:
container_name: d0a1-wp-openwebui
image: ghcr.io/open-webui/open-webui:0.11.3
restart: unless-stopped
ports:
- "${WEBUI_PORT:-3000}:8080"
volumes:
- openwebui_data:/app/backend/data
environment:
OLLAMA_BASE_URL: "http://ollama:11434"
WEBUI_NAME: "d0a1"
WEBUI_AUTH: "false"
DEFAULT_LOCALE: "es"
depends_on:
ollama:
condition: service_healthy
deploy: deploy:
resources: resources:
limits: limits:
memory: 2G memory: 6G
cpus: "${OLLAMA_CPUS:-6.0}"
volumes: volumes:
wp_db: wp_db:
@@ -88,5 +73,3 @@ volumes:
driver: local driver: local
ollama_data: ollama_data:
driver: local driver: local
openwebui_data:
driver: local
+20
View File
@@ -0,0 +1,20 @@
<?php
/**
* Estilo editorial de d0a1 para la IA local (WordPress "AI" plugin).
* EDITA AQUI y re-ejecuta deploy para aplicarlo. La IA redacta segun esto.
*/
return array(
'estilo' => 'Directo, claro y cercano. Sin humo. Espanol de Espana (tu, no usted). Frases cortas.',
'reglas' => array(
'Spanish (Spain) siempre, salvo que el contenido fuente este en otro idioma.',
'Nada de relleno: cada frase aporta un dato, un beneficio o un paso.',
'Precios en euros (EUR).',
'Voz activa. Verbo al principio cuando sea natural.',
),
'prohibido' => array(
'Emojis, hashtags ni llamadas a la accion genericas.',
'Superlativos vacios ("increible", "revolucionario").',
'Markdown ni comillas envolviendo el resultado.',
),
'titulares_max_chars' => 60,
);
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* Plugin Name: d0a1 — Instrucciones editoriales IA (mu-plugin)
* Description: Inyecta el estilo editorial (editorial-style.php del pack) en las instrucciones de sistema del plugin "AI".
*/
if ( ! defined( 'ABSPATH' ) ) { exit; }
function d0a1_editorial_style() {
$file = WP_CONTENT_DIR . '/editorial-style.php';
if ( ! file_exists( $file ) ) { return null; }
$s = include $file;
return is_array( $s ) ? $s : null;
}
function d0a1_editorial_block() {
$s = d0a1_editorial_style();
if ( ! $s ) { return ''; }
$out = "\n\nESTILO EDITORIAL DEL SITIO (prioridad sobre instrucciones anteriores):\n";
if ( ! empty( $s['estilo'] ) ) { $out .= 'Tono: ' . $s['estilo'] . "\n"; }
if ( ! empty( $s['reglas'] ) ) {
$out .= "Normas:\n";
foreach ( $s['reglas'] as $r ) { $out .= '- ' . $r . "\n"; }
}
if ( ! empty( $s['prohibido'] ) ) {
$out .= "Prohibido:\n";
foreach ( $s['prohibido'] as $p ) { $out .= '- ' . $p . "\n"; }
}
return $out;
}
// Global: todas las funciones IA del plugin (titulos, extractos, alt text, moderacion...).
add_filter( 'wpai_system_instruction', function ( $instruction ) {
return $instruction . d0a1_editorial_block();
}, 10, 1 );
// Afinar titulares: max chars configurable en editorial-style.php.
add_filter( 'wpai_title_generation_system_instruction', function ( $instruction ) {
$s = d0a1_editorial_style();
if ( $s && ! empty( $s['titulares_max_chars'] ) && $s['titulares_max_chars'] !== 80 ) {
$instruction = preg_replace( '/Be no more than \d+ characters/', 'Be no more than ' . (int) $s['titulares_max_chars'] . ' characters', $instruction );
}
return $instruction;
}, 10, 1 );
+28
View File
@@ -0,0 +1,28 @@
# ============================================================
# d0a1 pack - WordPress + IA (Windows) - DESINSTALAR
# Elimina contenedores, red y volumenes (datos + modelo).
# ============================================================
$ErrorActionPreference = 'Stop'
$ScriptDir = $PSScriptRoot
if (-not $ScriptDir) { $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path }
$ComposeFile = Join-Path $ScriptDir 'docker-compose.yml'
function Info($m) { Write-Host ">>> $m" }
function Err($m) { Write-Host "!!! $m"; exit 1 }
Write-Host ''
Write-Host '>>> ATENCION: esto borra TAMBIEN la base de datos y el contenido de WordPress.'
$Resp = Read-Host 'Continuar? [y/N]'
if ($Resp -notmatch '^[Yy]') { Write-Host 'Cancelado.'; exit 0 }
Write-Host ''
Info 'Deteniendo y borrando contenedores...'
cmd /c docker compose -f "$ComposeFile" down -v --remove-orphans '>' NUL '2>&1'
if ($LASTEXITCODE -ne 0) { Err 'Fallo el compose down (docker no arrancado?)' }
Write-Host ''
Info 'Eliminado TODO:'
Write-Host ' - Contenedores y red'
Write-Host ' - Volumenes (incluido el modelo IA)'
Write-Host ''
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# d0a1 pack - WordPress + IA (Linux) - DESINSTALAR
set -e
cd "$(cd "$(dirname "$0")" && pwd)"
read -r -p ">>> ATENCION: borra TAMBIEN la BD de WordPress. Continuar? [y/N] " r
case "$r" in [yY]*) ;; *) echo Cancelado.; exit 0;; esac
echo ""
echo ">>> Deteniendo y borrando contenedores..."
docker compose -f docker-compose.yml down -v --remove-orphans >/dev/null 2>&1 || { echo "!!! Fallo el compose down"; exit 1; }
echo ""
echo ">>> Eliminado TODO: contenedores, red y volumenes (incluido el modelo IA)."