Auditoria completa y plan de implementacion TZZR

- ARCHITECTURE.md: Estado real de 23 repos
- IMPLEMENTATION_PLAN.md: 7 fases de implementacion
- PHASES/: Scripts detallados para cada fase

Resultado de auditoria:
- 5 repos implementados
- 4 repos parciales
- 14 repos solo documentacion
This commit is contained in:
ARCHITECT
2025-12-24 08:59:14 +00:00
parent 1638a8cf85
commit 73ae91d337
7 changed files with 2089 additions and 2 deletions

316
PHASES/FASE_0_LIMPIEZA.md Normal file
View File

@@ -0,0 +1,316 @@
# FASE 0: LIMPIEZA Y CONSOLIDACIÓN
**Complejidad:** Simple
**Duración estimada:** 1 día
---
## OBJETIVO
Eliminar confusión, actualizar documentación obsoleta, sincronizar estado real con documentación.
---
## PREREQUISITOS
- Acceso SSH a ARCHITECT
- Token de escritura Gitea: `ac5a604b9aac5cee81192a656fc918f9efa3834b`
---
## PASO 0.1: Limpiar repo architect
### Acción
Eliminar carpetas obsoletas que causan confusión.
### Script
```bash
#!/bin/bash
# 0.1-limpiar-architect.sh
set -e
WORK_DIR="/tmp/cleanup-architect"
SSH_KEY="/home/orchestrator/.ssh/tzzr"
echo "=== Limpiando repo architect ==="
# Clonar
rm -rf $WORK_DIR
mkdir -p $WORK_DIR
cd $WORK_DIR
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222 -o StrictHostKeyChecking=no" \
git clone ssh://git@localhost:2222/tzzr/architect.git
cd architect
# Eliminar carpetas obsoletas
rm -rf app-v2 orchestrator-setup orchestrator-v3 local
# Commit
git add -A
git commit -m "Limpieza: eliminar carpetas obsoletas (app-v2, orchestrator-*, local)"
# Push
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222" git push origin main
echo "=== Completado ==="
```
### Verificación
```bash
curl -s "http://localhost:3000/api/v1/repos/tzzr/architect/contents" \
-H "Authorization: token 5ca10e5b71d41f9b22f12d0f96bfc2e6de5c2c7f" | jq -r '.[].name'
# No debe aparecer: app-v2, orchestrator-setup, orchestrator-v3, local
```
### Rollback
```bash
# Git revert del último commit
cd $WORK_DIR/architect
git revert HEAD --no-edit
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222" git push origin main
```
---
## PASO 0.2: Actualizar referencias NocoDB
### Acción
Buscar y reemplazar referencias a NocoDB por Directus en todos los repos.
### Script
```bash
#!/bin/bash
# 0.2-actualizar-nocodb.sh
set -e
WORK_DIR="/tmp/cleanup-nocodb"
SSH_KEY="/home/orchestrator/.ssh/tzzr"
TOKEN="5ca10e5b71d41f9b22f12d0f96bfc2e6de5c2c7f"
# Repos a revisar
REPOS="deck corp hst system contratos-comunes"
rm -rf $WORK_DIR
mkdir -p $WORK_DIR
cd $WORK_DIR
for repo in $REPOS; do
echo "=== Procesando $repo ==="
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222 -o StrictHostKeyChecking=no" \
git clone ssh://git@localhost:2222/tzzr/$repo.git
cd $repo
# Buscar y reemplazar
find . -name "*.md" -type f -exec grep -l "NocoDB" {} \; | while read file; do
echo " Actualizando: $file"
sed -i 's/NocoDB/Directus/g' "$file"
sed -i 's/nocodb/directus/g' "$file"
done
# Si hay cambios, commit
if [[ -n $(git status --porcelain) ]]; then
git add -A
git commit -m "Actualizar referencias: NocoDB -> Directus (migración completada)"
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222" git push origin main
echo " Cambios pusheados"
else
echo " Sin cambios"
fi
cd ..
done
echo "=== Completado ==="
```
### Verificación
```bash
# No debe encontrar NocoDB en ningún README actual
for repo in deck corp hst system contratos-comunes; do
result=$(curl -s "http://localhost:3000/api/v1/repos/tzzr/$repo/raw/README.md" \
-H "Authorization: token 5ca10e5b71d41f9b22f12d0f96bfc2e6de5c2c7f" | grep -i nocodb || echo "")
if [[ -n "$result" ]]; then
echo "WARN: NocoDB encontrado en $repo"
else
echo "OK: $repo limpio"
fi
done
```
---
## PASO 0.3: Sincronizar READMEs con realidad
### Acción
Añadir badges de estado a cada repo indicando si está IMPLEMENTADO, PARCIAL, o PLANIFICADO.
### Ejemplo de Badge
```markdown
<!-- Al inicio de cada README -->
![Estado](https://img.shields.io/badge/Estado-PLANIFICADO-yellow)
```
### Script
```bash
#!/bin/bash
# 0.3-sincronizar-estados.sh
# Definición de estados
declare -A ESTADOS
ESTADOS[clara]="IMPLEMENTADO"
ESTADOS[hst]="IMPLEMENTADO"
ESTADOS[packet]="IMPLEMENTADO"
ESTADOS[orchestrator]="IMPLEMENTADO"
ESTADOS[context]="IMPLEMENTADO"
ESTADOS[grace]="PARCIAL"
ESTADOS[penny]="PARCIAL"
ESTADOS[the-factory]="PARCIAL"
ESTADOS[deck]="PARCIAL"
ESTADOS[alfred]="PLANIFICADO"
ESTADOS[jared]="PLANIFICADO"
ESTADOS[margaret]="PLANIFICADO"
ESTADOS[mason]="PLANIFICADO"
ESTADOS[feldman]="PLANIFICADO"
ESTADOS[sentinel]="PLANIFICADO"
ESTADOS[vision-builder]="PLANIFICADO"
ESTADOS[locker]="PLANIFICADO"
ESTADOS[mind-link]="PLANIFICADO"
# Colores de badge
declare -A COLORES
COLORES[IMPLEMENTADO]="green"
COLORES[PARCIAL]="orange"
COLORES[PLANIFICADO]="yellow"
SSH_KEY="/home/orchestrator/.ssh/tzzr"
WORK_DIR="/tmp/sync-estados"
rm -rf $WORK_DIR
mkdir -p $WORK_DIR
cd $WORK_DIR
for repo in "${!ESTADOS[@]}"; do
estado="${ESTADOS[$repo]}"
color="${COLORES[$estado]}"
badge="![Estado](https://img.shields.io/badge/Estado-${estado}-${color})"
echo "=== $repo: $estado ==="
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222 -o StrictHostKeyChecking=no" \
git clone ssh://git@localhost:2222/tzzr/$repo.git 2>/dev/null
cd $repo
# Verificar si README tiene badge
if grep -q "img.shields.io/badge/Estado" README.md 2>/dev/null; then
# Actualizar badge existente
sed -i "s|!\[Estado\](https://img.shields.io/badge/Estado-[^)]*)|${badge}|g" README.md
else
# Añadir badge al inicio
if [[ -f README.md ]]; then
echo -e "${badge}\n\n$(cat README.md)" > README.md
fi
fi
if [[ -n $(git status --porcelain) ]]; then
git add README.md
git commit -m "Añadir badge de estado: $estado"
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222" git push origin main
fi
cd ..
done
```
---
## PASO 0.4: Decidir sobre mind-link
### Opciones
1. **Eliminar repo** - Si no se va a implementar
2. **Marcar como ABANDONADO** - Si puede implementarse en el futuro
3. **Implementar básico** - Si es prioritario
### Recomendación
Marcar como ABANDONADO por ahora, implementar después de FASE 4.
### Script (opción 2)
```bash
#!/bin/bash
# 0.4-archivar-mind-link.sh
SSH_KEY="/home/orchestrator/.ssh/tzzr"
WORK_DIR="/tmp/mind-link-archive"
rm -rf $WORK_DIR
mkdir -p $WORK_DIR
cd $WORK_DIR
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222 -o StrictHostKeyChecking=no" \
git clone ssh://git@localhost:2222/tzzr/mind-link.git
cd mind-link
# Actualizar README
cat > README.md << 'EOF'
![Estado](https://img.shields.io/badge/Estado-ABANDONADO-red)
# MIND LINK
> **NOTA:** Este repo está temporalmente archivado. Se implementará después de completar el pipeline principal (FASE 4).
## Concepto Original
Interfaz para conectar ideas y conceptos. Visualización de relaciones entre elementos.
## Funciones Planificadas
- Conexión de conceptos
- Grafos de conocimiento
- Navegación visual
- Búsqueda semántica
---
*Archivado: 2025-12-24*
EOF
# Eliminar carpetas vacías
rm -rf src docs
git add -A
git commit -m "Archivar temporalmente: implementar post-FASE 4"
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222" git push origin main
```
---
## CHECKLIST FINAL FASE 0
- [ ] 0.1 - Carpetas obsoletas eliminadas de architect
- [ ] 0.2 - Referencias a NocoDB actualizadas
- [ ] 0.3 - Badges de estado en todos los READMEs
- [ ] 0.4 - mind-link archivado
- [ ] Todos los cambios pusheados a Gitea
- [ ] Sin errores en los repos
---
## SIGUIENTE FASE
Continuar con [FASE_1_PIPELINE_MINIMO.md](FASE_1_PIPELINE_MINIMO.md)

View File

@@ -0,0 +1,419 @@
# FASE 1: PIPELINE MÍNIMO VIABLE
**Complejidad:** Media
**Duración estimada:** 2-3 días
**Prioridad:** CRÍTICA
---
## OBJETIVO
Establecer el flujo: PACKET → CLARA → PostgreSQL + R2
Esto permite que la app móvil envíe contenido y se almacene correctamente.
---
## PREREQUISITOS
- [x] FASE 0 completada
- [x] SSH acceso a DECK (72.62.1.113)
- [x] R2 bucket 'deck' accesible
- [x] PostgreSQL en DECK funcionando
- [x] HST funcionando (tags)
---
## PASO 1.1: Crear tablas de CLARA en DECK
### Conectar a DECK
```bash
ssh -i /home/orchestrator/.ssh/tzzr root@72.62.1.113
```
### Ejecutar SQL
```bash
sudo -u postgres psql -d tzzr << 'EOF'
-- Tabla principal de log
CREATE TABLE IF NOT EXISTS clara_log (
id BIGSERIAL PRIMARY KEY,
h_instancia VARCHAR(64) NOT NULL,
h_entrada VARCHAR(64) NOT NULL,
contenedor JSONB NOT NULL,
r2_paths JSONB DEFAULT '{}',
estado VARCHAR(20) DEFAULT 'recibido',
procesado_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
CONSTRAINT clara_log_h_entrada_unique UNIQUE (h_entrada)
);
-- Índices para búsqueda eficiente
CREATE INDEX IF NOT EXISTS idx_clara_h_instancia ON clara_log(h_instancia);
CREATE INDEX IF NOT EXISTS idx_clara_estado ON clara_log(estado);
CREATE INDEX IF NOT EXISTS idx_clara_created ON clara_log(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_clara_contenedor ON clara_log USING gin(contenedor);
-- Comentarios
COMMENT ON TABLE clara_log IS 'Log inmutable de entrada - recibe contenedores de PACKET';
COMMENT ON COLUMN clara_log.h_instancia IS 'Hash SHA-256 que identifica la instancia DECK';
COMMENT ON COLUMN clara_log.h_entrada IS 'Hash SHA-256 único del contenedor';
COMMENT ON COLUMN clara_log.contenedor IS 'Contenedor completo en formato JSON (S-CONTRACT)';
COMMENT ON COLUMN clara_log.r2_paths IS 'Rutas de archivos subidos a R2';
COMMENT ON COLUMN clara_log.estado IS 'Estado: recibido, en_mason, en_feldman, consolidado';
-- Verificar
SELECT 'Tabla clara_log creada correctamente' AS resultado;
\dt clara_log
\d clara_log
EOF
```
### Verificación
```bash
sudo -u postgres psql -d tzzr -c "SELECT COUNT(*) FROM clara_log;"
# Debe retornar 0 (tabla vacía)
```
### Rollback
```sql
DROP TABLE IF EXISTS clara_log CASCADE;
```
---
## PASO 1.2: Generar h_instancia para DECK
### Concepto
h_instancia es un hash SHA-256 único que identifica esta instancia de DECK.
### Generar
```bash
# En DECK
SEED="deck-personal-$(hostname)-$(date +%s)"
H_INSTANCIA=$(echo -n "$SEED" | sha256sum | cut -d' ' -f1)
echo "H_INSTANCIA=$H_INSTANCIA"
# Guardar en archivo de configuración
echo "H_INSTANCIA=$H_INSTANCIA" >> /opt/clara/.env
```
### Verificación
El hash debe tener 64 caracteres hexadecimales.
---
## PASO 1.3: Desplegar CLARA como Docker
### Crear estructura en DECK
```bash
ssh -i /home/orchestrator/.ssh/tzzr root@72.62.1.113 << 'REMOTE'
mkdir -p /opt/clara
cd /opt/clara
# Clonar repo
git clone http://localhost:3000/tzzr/clara.git .
# Crear .env
cat > .env << 'EOF'
# Generado automáticamente
H_INSTANCIA=<PEGAR_HASH_GENERADO>
# PostgreSQL
DB_HOST=172.17.0.1
DB_PORT=5432
DB_NAME=tzzr
DB_USER=deck
DB_PASSWORD=<PASSWORD_DECK>
# Cloudflare R2
R2_ENDPOINT=https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com
R2_ACCESS_KEY=ecddc771824c3cb3417d9451780db3d2
R2_SECRET_KEY=c8138e2597100ffb7dd1477ad722c0214f86097cd968752aea3cfcea5d54dbac
R2_BUCKET=deck
# Puerto
PORT=5051
EOF
# Construir y levantar
docker-compose up -d --build
# Verificar
docker-compose logs --tail=20
REMOTE
```
### docker-compose.yml actualizado
```yaml
version: '3.8'
services:
clara:
build: .
container_name: clara
ports:
- "5051:5051"
env_file:
- .env
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5051/health"]
interval: 30s
timeout: 10s
retries: 3
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
default:
external:
name: deck_network
```
### Dockerfile
```dockerfile
FROM python:3.11-slim
WORKDIR /app
# Dependencias del sistema
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
# Dependencias Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Código
COPY app.py .
# Puerto
EXPOSE 5051
# Ejecutar
CMD ["python", "app.py"]
```
### Verificación
```bash
# Desde DECK
curl http://localhost:5051/health
# Debe retornar: {"service": "clara", "status": "ok", ...}
# Desde ARCHITECT
curl http://72.62.1.113:5051/health
```
---
## PASO 1.4: Configurar Caddy para /ingest
### Editar Caddyfile en DECK
```bash
ssh -i /home/orchestrator/.ssh/tzzr root@72.62.1.113 << 'REMOTE'
# Añadir a Caddyfile existente
cat >> /etc/caddy/Caddyfile << 'EOF'
# CLARA - API de ingesta
clara.tzzrdeck.me {
reverse_proxy localhost:5051
}
# También en el dominio principal
tzzrdeck.me {
handle /ingest* {
reverse_proxy localhost:5051
}
# ... resto de configuración
}
EOF
# Recargar Caddy
systemctl reload caddy
REMOTE
```
### Verificación
```bash
# HTTPS (si DNS configurado)
curl https://clara.tzzrdeck.me/health
# O directamente
curl http://72.62.1.113:5051/health
```
---
## PASO 1.5: Probar ingesta completa
### Test desde curl
```bash
# Definir variables
H_INSTANCIA="<hash_de_paso_1.2>"
TEST_HASH=$(echo -n "test-$(date +%s)" | sha256sum | cut -d' ' -f1)
# Enviar contenedor de prueba
curl -X POST http://72.62.1.113:5051/ingest \
-H "Content-Type: application/json" \
-H "X-Auth-Key: $H_INSTANCIA" \
-d '{
"id": "'$TEST_HASH'",
"archivo_hash": "'$TEST_HASH'",
"origen": {
"app": "curl-test",
"version": "1.0",
"timestamp_captura": "'$(date -Iseconds)'"
},
"contenido": {
"titulo": "Test de ingesta",
"descripcion": "Contenedor de prueba desde curl"
},
"etiquetas": []
}'
```
### Respuestas esperadas
```json
// Éxito
{"ok": true, "id": 1, "h_entrada": "abc123..."}
// Duplicado
{"error": "hash_exists"}
// Sin auth
{"error": "unauthorized"}
```
### Verificar en PostgreSQL
```bash
ssh -i /home/orchestrator/.ssh/tzzr root@72.62.1.113 \
"sudo -u postgres psql -d tzzr -c 'SELECT id, h_entrada, estado, created_at FROM clara_log ORDER BY id DESC LIMIT 5;'"
```
---
## PASO 1.6: Probar subida a R2
### Test con archivo
```bash
# Crear archivo de prueba
echo "Contenido de prueba" > /tmp/test.txt
TEST_DATA=$(base64 /tmp/test.txt)
TEST_HASH=$(echo -n "test-file-$(date +%s)" | sha256sum | cut -d' ' -f1)
curl -X POST http://72.62.1.113:5051/ingest \
-H "Content-Type: application/json" \
-H "X-Auth-Key: $H_INSTANCIA" \
-d '{
"id": "'$TEST_HASH'",
"archivo_hash": "'$TEST_HASH'",
"origen": {
"app": "curl-test",
"version": "1.0"
},
"archivos": [{
"nombre": "test.txt",
"tipo": "text/plain",
"data": "'$TEST_DATA'"
}]
}'
```
### Verificar en R2
```bash
# Usando AWS CLI configurado para R2
aws s3 ls s3://deck/ --endpoint-url https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com
```
---
## CHECKLIST FINAL FASE 1
- [ ] 1.1 - Tabla clara_log creada en DECK PostgreSQL
- [ ] 1.2 - h_instancia generado y guardado
- [ ] 1.3 - CLARA corriendo en Docker
- [ ] 1.4 - Caddy configurado (opcional)
- [ ] 1.5 - Test de ingesta exitoso
- [ ] 1.6 - Archivo subido a R2
- [ ] Health check responde correctamente
- [ ] Logs sin errores
---
## MÉTRICAS DE ÉXITO
| Métrica | Valor Esperado |
|---------|----------------|
| /health responde | < 100ms |
| /ingest (sin archivo) | < 500ms |
| /ingest (con archivo) | < 2s |
| Registros en clara_log | > 0 |
| Archivos en R2/deck | > 0 |
---
## TROUBLESHOOTING
### CLARA no arranca
```bash
docker logs clara
# Verificar variables de entorno
docker exec clara env | grep -E "DB_|R2_"
```
### No conecta a PostgreSQL
```bash
# Verificar red
docker exec clara ping -c1 172.17.0.1
# Verificar puerto
docker exec clara nc -zv 172.17.0.1 5432
```
### Error R2
```bash
# Verificar credenciales
docker exec clara python -c "
import boto3
s3 = boto3.client('s3',
endpoint_url='https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com',
aws_access_key_id='ecddc771824c3cb3417d9451780db3d2',
aws_secret_access_key='c8138e2597100ffb7dd1477ad722c0214f86097cd968752aea3cfcea5d54dbac'
)
print(s3.list_buckets())
"
```
---
## SIGUIENTE FASE
Continuar con [FASE_2_PROCESAMIENTO_IA.md](FASE_2_PROCESAMIENTO_IA.md)

View File

@@ -0,0 +1,430 @@
# FASE 2: PROCESAMIENTO IA
**Complejidad:** Compleja
**Duración estimada:** 3-5 días
**Prioridad:** ALTA
---
## OBJETIVO
Desplegar GRACE en RunPod para procesamiento de:
- ASR (Speech-to-Text)
- OCR (Imágenes a texto)
- TTS (Text-to-Speech)
- Embeddings (Vectorización semántica)
- Face Detection
- Avatar Generation
---
## PREREQUISITOS
- [x] FASE 1 completada
- [ ] Cuenta RunPod con créditos
- [ ] API Key de RunPod
- [ ] Docker Hub o registro privado para imágenes
---
## PASO 2.1: Preparar imagen Docker para RunPod
### Estructura del handler
El archivo `grace/runpod/handler.py` ya está implementado y soporta:
| Módulo | Modelo | VRAM |
|--------|--------|------|
| ASR_ENGINE | Faster Whisper Large V3 | ~4GB |
| OCR_CORE | GOT-OCR 2.0 | ~8GB |
| TTS | XTTS-v2 | ~4GB |
| FACE_VECTOR | InsightFace Buffalo L | ~2GB |
| EMBEDDINGS | BGE-Large | ~2GB |
| AVATAR_GEN | SDXL Base 1.0 | ~8GB |
### Dockerfile optimizado
```dockerfile
# grace/runpod/Dockerfile
FROM runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04
WORKDIR /app
# Variables de entorno
ENV PYTHONUNBUFFERED=1
ENV TRANSFORMERS_CACHE=/app/models
ENV HF_HOME=/app/models
# Dependencias del sistema
RUN apt-get update && apt-get install -y \
ffmpeg \
libsm6 \
libxext6 \
libgl1-mesa-glx \
&& rm -rf /var/lib/apt/lists/*
# Dependencias Python base
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Precargar modelos para reducir cold start
RUN python -c "from faster_whisper import WhisperModel; WhisperModel('large-v3', device='cpu', compute_type='int8')"
RUN python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('BAAI/bge-large-en-v1.5')"
# Código del handler
COPY handler.py .
# Iniciar handler de RunPod
CMD ["python", "-u", "handler.py"]
```
### requirements.txt
```
runpod>=1.3.0
torch>=2.1.0
transformers>=4.36.0
faster-whisper>=0.10.0
TTS>=0.22.0
sentence-transformers>=2.2.2
insightface>=0.7.3
onnxruntime-gpu>=1.16.0
diffusers>=0.24.0
accelerate>=0.25.0
safetensors>=0.4.0
Pillow>=10.0.0
opencv-python-headless>=4.8.0
numpy>=1.24.0
boto3>=1.34.0
```
---
## PASO 2.2: Construir y subir imagen
### Opción A: Docker Hub
```bash
# En máquina con Docker
cd grace/runpod
# Construir
docker build -t tzzr/grace-gpu:v1.0 .
# Login a Docker Hub
docker login
# Subir
docker push tzzr/grace-gpu:v1.0
```
### Opción B: RunPod Registry
```bash
# Usar la CLI de RunPod
runpodctl build --name grace-gpu --tag v1.0 .
```
---
## PASO 2.3: Crear template en RunPod
### Via Dashboard
1. Ir a RunPod → Templates → Create Template
2. Configurar:
- **Name**: GRACE-GPU
- **Container Image**: tzzr/grace-gpu:v1.0
- **Container Disk**: 50GB
- **Volume Disk**: 100GB (para modelos)
- **Volume Mount Path**: /app/models
- **Expose HTTP Ports**: 8000
- **Expose TCP Ports**: (vacío)
### Via API
```bash
RUNPOD_API_KEY="<tu_api_key>"
curl -X POST "https://api.runpod.io/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUNPOD_API_KEY" \
-d '{
"query": "mutation { saveTemplate(input: { name: \"GRACE-GPU\", imageName: \"tzzr/grace-gpu:v1.0\", dockerArgs: \"\", containerDiskInGb: 50, volumeInGb: 100, volumeMountPath: \"/app/models\", ports: \"8000/http\", isServerless: true }) { id name } }"
}'
```
---
## PASO 2.4: Crear endpoint serverless
### Via Dashboard
1. Ir a Serverless → Create Endpoint
2. Configurar:
- **Name**: GRACE-Endpoint
- **Template**: GRACE-GPU
- **GPU Type**: RTX 4090 (24GB VRAM)
- **Min Workers**: 0
- **Max Workers**: 3
- **Idle Timeout**: 5 segundos
- **Flash Boot**: Enabled
### Configuración recomendada por módulo
| Módulo | GPU Mínima | GPU Recomendada |
|--------|------------|-----------------|
| ASR_ENGINE | RTX 3080 (10GB) | RTX 4090 (24GB) |
| OCR_CORE | RTX 3090 (24GB) | RTX 4090 (24GB) |
| TTS | RTX 3080 (10GB) | RTX 4090 (24GB) |
| FACE_VECTOR | RTX 3060 (8GB) | RTX 4090 (24GB) |
| EMBEDDINGS | RTX 3060 (8GB) | RTX 4090 (24GB) |
| AVATAR_GEN | RTX 3090 (24GB) | RTX 4090 (24GB) |
---
## PASO 2.5: Probar endpoint
### Test ASR_ENGINE
```bash
ENDPOINT_ID="<tu_endpoint_id>"
RUNPOD_API_KEY="<tu_api_key>"
# Crear audio de prueba (o usar uno existente)
# ffmpeg -f lavfi -i "sine=frequency=440:duration=3" -ar 16000 test.wav
# Codificar en base64
AUDIO_B64=$(base64 -w0 test.wav)
# Enviar request
curl -X POST "https://api.runpod.ai/v2/${ENDPOINT_ID}/runsync" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUNPOD_API_KEY" \
-d '{
"input": {
"contract_version": "2.1",
"profile": "LITE",
"envelope": {
"trace_id": "test-asr-001"
},
"routing": {
"module": "ASR_ENGINE"
},
"payload": {
"type": "audio",
"encoding": "base64",
"content": "'$AUDIO_B64'"
},
"context": {
"lang": "es"
}
}
}'
```
### Respuesta esperada
```json
{
"id": "...",
"status": "COMPLETED",
"output": {
"contract_version": "2.1",
"status": {"code": "SUCCESS"},
"result": {
"schema": "asr_output_v1",
"data": {
"text": "...",
"language_detected": "es",
"duration_seconds": 3.0,
"segments": [...]
}
},
"quality": {
"confidence": 0.95
}
}
}
```
### Test OCR_CORE
```bash
# Imagen de prueba
IMAGE_B64=$(base64 -w0 test_image.png)
curl -X POST "https://api.runpod.ai/v2/${ENDPOINT_ID}/runsync" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUNPOD_API_KEY" \
-d '{
"input": {
"contract_version": "2.1",
"routing": {"module": "OCR_CORE"},
"payload": {
"type": "image",
"encoding": "base64",
"content": "'$IMAGE_B64'"
}
}
}'
```
---
## PASO 2.6: Documentar endpoint
### Guardar en credentials
```bash
# En ARCHITECT, actualizar repo credentials
cd /tmp && rm -rf credentials
GIT_SSH_COMMAND="ssh -i /home/orchestrator/.ssh/tzzr -p 2222" \
git clone ssh://git@localhost:2222/tzzr/credentials.git
cd credentials
cat >> inventario/08-gpu-runpod.md << 'EOF'
## GRACE Endpoint (Actualizado 2025-12-24)
| Parámetro | Valor |
|-----------|-------|
| Endpoint ID | <endpoint_id> |
| Template | GRACE-GPU v1.0 |
| GPU | RTX 4090 |
| Max Workers | 3 |
| Idle Timeout | 5s |
### Módulos disponibles
- ASR_ENGINE (Whisper Large V3)
- OCR_CORE (GOT-OCR 2.0)
- TTS (XTTS-v2)
- FACE_VECTOR (InsightFace)
- EMBEDDINGS (BGE-Large)
- AVATAR_GEN (SDXL)
### Ejemplo de uso
```bash
curl -X POST "https://api.runpod.ai/v2/${ENDPOINT_ID}/runsync" \
-H "Authorization: Bearer ${RUNPOD_API_KEY}" \
-d '{"input": {...}}'
```
EOF
git add -A
git commit -m "Documentar GRACE endpoint RunPod"
GIT_SSH_COMMAND="ssh -i /home/orchestrator/.ssh/tzzr -p 2222" git push origin main
```
---
## PASO 2.7: Integrar con DECK
### Crear cliente GRACE en DECK
```python
# /opt/deck/grace_client.py
import os
import base64
import requests
from typing import Dict, Any, Optional
class GraceClient:
def __init__(self):
self.endpoint_id = os.getenv("GRACE_ENDPOINT_ID")
self.api_key = os.getenv("RUNPOD_API_KEY")
self.base_url = f"https://api.runpod.ai/v2/{self.endpoint_id}"
def call(self, module: str, content: bytes, context: Dict = None) -> Dict[str, Any]:
"""Llamar a módulo GRACE"""
payload = {
"input": {
"contract_version": "2.1",
"routing": {"module": module},
"payload": {
"type": self._get_type(module),
"encoding": "base64",
"content": base64.b64encode(content).decode()
},
"context": context or {}
}
}
response = requests.post(
f"{self.base_url}/runsync",
headers={"Authorization": f"Bearer {self.api_key}"},
json=payload,
timeout=120
)
return response.json()
def _get_type(self, module: str) -> str:
types = {
"ASR_ENGINE": "audio",
"OCR_CORE": "image",
"TTS": "text",
"FACE_VECTOR": "image",
"EMBEDDINGS": "text",
"AVATAR_GEN": "text"
}
return types.get(module, "binary")
def transcribe(self, audio_bytes: bytes, lang: str = "es") -> str:
"""Convenience method para ASR"""
result = self.call("ASR_ENGINE", audio_bytes, {"lang": lang})
return result.get("output", {}).get("result", {}).get("data", {}).get("text", "")
def ocr(self, image_bytes: bytes) -> str:
"""Convenience method para OCR"""
result = self.call("OCR_CORE", image_bytes)
return result.get("output", {}).get("result", {}).get("data", {}).get("text", "")
def embed(self, text: str) -> list:
"""Convenience method para embeddings"""
result = self.call("EMBEDDINGS", text.encode(), {})
return result.get("output", {}).get("result", {}).get("data", {}).get("vector", [])
```
---
## CHECKLIST FINAL FASE 2
- [ ] 2.1 - Dockerfile preparado
- [ ] 2.2 - Imagen subida a registro
- [ ] 2.3 - Template creado en RunPod
- [ ] 2.4 - Endpoint serverless configurado
- [ ] 2.5 - Tests exitosos (ASR, OCR, etc.)
- [ ] 2.6 - Credenciales documentadas
- [ ] 2.7 - Cliente integrado en DECK
---
## MÉTRICAS DE ÉXITO
| Métrica | Valor Esperado |
|---------|----------------|
| Cold start | < 60s |
| Warm ASR (30s audio) | < 10s |
| Warm OCR (imagen) | < 5s |
| Disponibilidad | > 99% |
---
## COSTOS ESTIMADOS
| Uso | GPU | Costo/hora | Estimado mensual |
|-----|-----|------------|------------------|
| Bajo (10 req/día) | RTX 4090 | $0.69 | ~$5-10 |
| Medio (100 req/día) | RTX 4090 | $0.69 | ~$30-50 |
| Alto (1000 req/día) | RTX 4090 | $0.69 | ~$100-200 |
---
## SIGUIENTE FASE
Continuar con [FASE_3_FLUJO_EMPRESARIAL.md](FASE_3_FLUJO_EMPRESARIAL.md)

View File

@@ -0,0 +1,259 @@
# FASE 3: FLUJO EMPRESARIAL
**Complejidad:** Media
**Duración estimada:** 1-2 días
**Prioridad:** MEDIA
---
## OBJETIVO
Desplegar MARGARET en CORP (clon de CLARA para servidor empresarial).
---
## PREREQUISITOS
- [x] FASE 1 completada (CLARA funcionando)
- [ ] SSH acceso a CORP (92.112.181.188)
- [ ] PostgreSQL en CORP accesible
- [ ] R2 bucket 'corp' accesible
---
## PASO 3.1: Crear repo margaret con código
MARGARET es esencialmente CLARA con:
- Diferente h_instancia
- Bucket R2 'corp' en lugar de 'deck'
- Tabla margaret_log en lugar de clara_log
- Campos adicionales para empresas (opcional)
### Script
```bash
#!/bin/bash
# Crear MARGARET como fork de CLARA
SSH_KEY="/home/orchestrator/.ssh/tzzr"
WORK_DIR="/tmp/create-margaret"
rm -rf $WORK_DIR
mkdir -p $WORK_DIR
cd $WORK_DIR
# Clonar CLARA
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222" \
git clone ssh://git@localhost:2222/tzzr/clara.git margaret
cd margaret
# Renombrar referencias
find . -type f -name "*.py" -exec sed -i 's/clara/margaret/g' {} \;
find . -type f -name "*.py" -exec sed -i 's/CLARA/MARGARET/g' {} \;
find . -type f -name "*.md" -exec sed -i 's/clara/margaret/g' {} \;
find . -type f -name "*.md" -exec sed -i 's/CLARA/MARGARET/g' {} \;
find . -type f -name "*.md" -exec sed -i 's/DECK/CORP/g' {} \;
# Actualizar docker-compose.yml
sed -i 's/5051/5052/g' docker-compose.yml
sed -i 's/deck/corp/g' docker-compose.yml
# Actualizar README
cat > README.md << 'EOF'
![Estado](https://img.shields.io/badge/Estado-IMPLEMENTADO-green)
# MARGARET
**Log de entrada CORP - Sistema TZZR**
Clon de CLARA para servidor empresarial. Recibe contenedores de PACKET y los almacena en PostgreSQL + R2.
## Diferencias con CLARA
| Aspecto | CLARA | MARGARET |
|---------|-------|----------|
| Servidor | DECK | CORP |
| Puerto | 5051 | 5052 |
| Bucket R2 | deck | corp |
| Tabla | clara_log | margaret_log |
## Despliegue
```bash
cd /opt/margaret
cp .env.example .env
# Editar .env con credenciales
docker-compose up -d
```
## API
Idéntica a CLARA:
- `POST /ingest` - Recibir contenedor
- `GET /query/{h_entrada}` - Consultar por hash
- `GET /list` - Listar entradas
- `GET /health` - Health check
EOF
# Cambiar origen remoto
git remote set-url origin ssh://git@localhost:2222/tzzr/margaret.git
# Crear nuevo historial
rm -rf .git
git init
git add -A
git commit -m "MARGARET: fork de CLARA para CORP"
# Push (asumiendo que el repo ya existe vacío)
GIT_SSH_COMMAND="ssh -i $SSH_KEY -p 2222" git push -u origin main --force
```
---
## PASO 3.2: Crear tablas en CORP PostgreSQL
### Conectar a CORP
```bash
ssh -i /home/orchestrator/.ssh/tzzr root@92.112.181.188
```
### Crear base de datos si no existe
```bash
sudo -u postgres psql << 'EOF'
CREATE DATABASE corp;
CREATE USER margaret WITH PASSWORD 'margaret_secure_2024';
GRANT ALL PRIVILEGES ON DATABASE corp TO margaret;
EOF
```
### Crear tabla
```bash
sudo -u postgres psql -d corp << 'EOF'
CREATE TABLE IF NOT EXISTS margaret_log (
id BIGSERIAL PRIMARY KEY,
h_instancia VARCHAR(64) NOT NULL,
h_entrada VARCHAR(64) NOT NULL,
contenedor JSONB NOT NULL,
r2_paths JSONB DEFAULT '{}',
estado VARCHAR(20) DEFAULT 'recibido',
-- Campos adicionales para empresas
empresa_id VARCHAR(64),
proyecto_id VARCHAR(64),
aprobado_por VARCHAR(100),
procesado_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
CONSTRAINT margaret_log_h_entrada_unique UNIQUE (h_entrada)
);
CREATE INDEX idx_margaret_h_instancia ON margaret_log(h_instancia);
CREATE INDEX idx_margaret_empresa ON margaret_log(empresa_id);
CREATE INDEX idx_margaret_proyecto ON margaret_log(proyecto_id);
CREATE INDEX idx_margaret_created ON margaret_log(created_at DESC);
COMMENT ON TABLE margaret_log IS 'Log de entrada CORP - contenedores empresariales';
EOF
```
---
## PASO 3.3: Desplegar MARGARET
### En CORP
```bash
ssh -i /home/orchestrator/.ssh/tzzr root@92.112.181.188 << 'REMOTE'
mkdir -p /opt/margaret
cd /opt/margaret
# Clonar repo
git clone http://69.62.126.110:3000/tzzr/margaret.git .
# Generar h_instancia único para CORP
SEED="corp-enterprise-$(hostname)-$(date +%s)"
H_INSTANCIA=$(echo -n "$SEED" | sha256sum | cut -d' ' -f1)
# Crear .env
cat > .env << EOF
H_INSTANCIA=$H_INSTANCIA
# PostgreSQL
DB_HOST=localhost
DB_PORT=5432
DB_NAME=corp
DB_USER=margaret
DB_PASSWORD=margaret_secure_2024
# R2
R2_ENDPOINT=https://7dedae6030f5554d99d37e98a5232996.r2.cloudflarestorage.com
R2_ACCESS_KEY=ecddc771824c3cb3417d9451780db3d2
R2_SECRET_KEY=c8138e2597100ffb7dd1477ad722c0214f86097cd968752aea3cfcea5d54dbac
R2_BUCKET=corp
PORT=5052
EOF
# Construir y levantar
docker-compose up -d --build
REMOTE
```
---
## PASO 3.4: Configurar Caddy en CORP
```bash
ssh -i /home/orchestrator/.ssh/tzzr root@92.112.181.188 << 'REMOTE'
cat >> /etc/caddy/Caddyfile << 'EOF'
margaret.tzzrcorp.me {
reverse_proxy localhost:5052
}
EOF
systemctl reload caddy
REMOTE
```
---
## PASO 3.5: Probar ingesta
```bash
H_INSTANCIA="<hash_generado_en_corp>"
curl -X POST http://92.112.181.188:5052/ingest \
-H "Content-Type: application/json" \
-H "X-Auth-Key: $H_INSTANCIA" \
-d '{
"id": "test-corp-001",
"archivo_hash": "test-corp-hash-001",
"origen": {"app": "test"},
"empresa_id": "empresa-001",
"proyecto_id": "proyecto-alpha"
}'
```
---
## CHECKLIST FINAL FASE 3
- [ ] 3.1 - Repo margaret creado con código
- [ ] 3.2 - Tabla margaret_log creada
- [ ] 3.3 - MARGARET corriendo en Docker
- [ ] 3.4 - Caddy configurado
- [ ] 3.5 - Test de ingesta exitoso
---
## SIGUIENTE FASE
Continuar con [FASE_4_PIPELINE_COMPLETO.md](FASE_4_PIPELINE_COMPLETO.md)