Spaces:
Sleeping
Sleeping
Commit ·
f44fecc
1
Parent(s): 09343ea
feat: migrate to uv and add daggr workflow
Browse files- .gitignore +14 -0
- MIGRATION_UV_DAGGR.md +223 -0
- README.md +55 -0
- app_daggr.py +205 -0
- git_error.txt +66 -0
- install.ps1 +83 -0
- install.sh +79 -0
- pyproject.toml +23 -0
- requirements.txt +2 -1
- uv.lock +0 -0
.gitignore
CHANGED
|
@@ -2,22 +2,28 @@
|
|
| 2 |
.venv/
|
| 3 |
venv/
|
| 4 |
env/
|
|
|
|
| 5 |
|
| 6 |
# Variables de entorno
|
| 7 |
.env
|
| 8 |
.env.local
|
|
|
|
| 9 |
|
| 10 |
# Python
|
| 11 |
__pycache__/
|
| 12 |
*.py[cod]
|
| 13 |
*$py.class
|
| 14 |
*.so
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
# IDE
|
| 17 |
.idea/
|
| 18 |
.vscode/
|
| 19 |
*.swp
|
| 20 |
*.swo
|
|
|
|
| 21 |
|
| 22 |
# OS
|
| 23 |
.DS_Store
|
|
@@ -26,5 +32,13 @@ Thumbs.db
|
|
| 26 |
# Modal
|
| 27 |
.modal/
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
# Artifacts
|
| 30 |
*.log
|
|
|
|
|
|
|
|
|
| 2 |
.venv/
|
| 3 |
venv/
|
| 4 |
env/
|
| 5 |
+
__pypackages__/
|
| 6 |
|
| 7 |
# Variables de entorno
|
| 8 |
.env
|
| 9 |
.env.local
|
| 10 |
+
.env*.local
|
| 11 |
|
| 12 |
# Python
|
| 13 |
__pycache__/
|
| 14 |
*.py[cod]
|
| 15 |
*$py.class
|
| 16 |
*.so
|
| 17 |
+
*.egg-info/
|
| 18 |
+
dist/
|
| 19 |
+
build/
|
| 20 |
|
| 21 |
# IDE
|
| 22 |
.idea/
|
| 23 |
.vscode/
|
| 24 |
*.swp
|
| 25 |
*.swo
|
| 26 |
+
*.sublime-*
|
| 27 |
|
| 28 |
# OS
|
| 29 |
.DS_Store
|
|
|
|
| 32 |
# Modal
|
| 33 |
.modal/
|
| 34 |
|
| 35 |
+
# UV
|
| 36 |
+
.uv-cache/
|
| 37 |
+
|
| 38 |
+
# Daggr
|
| 39 |
+
daggr_cache/
|
| 40 |
+
|
| 41 |
# Artifacts
|
| 42 |
*.log
|
| 43 |
+
.gradio_cached_examples/
|
| 44 |
+
.gradio_servables/
|
MIGRATION_UV_DAGGR.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Migración a UV y Daggr - Acuarela Portrait
|
| 2 |
+
|
| 3 |
+
Este documento explica cómo migrar tu proyecto a **UV** y integrar **Daggr**.
|
| 4 |
+
|
| 5 |
+
## ¿Qué es UV?
|
| 6 |
+
|
| 7 |
+
**UV** es un gestor de paquetes ultra-rápido para Python, escrito en Rust. Reemplaza `pip` y `venv` con una herramienta mucho más eficiente.
|
| 8 |
+
|
| 9 |
+
**Ventajas:**
|
| 10 |
+
- ⚡ 100x más rápido que pip
|
| 11 |
+
- 🔒 Resolución de dependencias deterministica
|
| 12 |
+
- 📦 Integración con `pyproject.toml`
|
| 13 |
+
- 🔄 Manejo automático de virtual environments
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## ¿Qué es Daggr?
|
| 18 |
+
|
| 19 |
+
**Daggr** es una librería de Hugging Face para crear workflows de IA de forma visual en Python.
|
| 20 |
+
|
| 21 |
+
**Características:**
|
| 22 |
+
- 🔗 Encadena aplicaciones Gradio, modelos y funciones Python
|
| 23 |
+
- 👀 Inspecciona outputs intermedios visualmente
|
| 24 |
+
- ⏪ Vuelve a ejecutar pasos individuales sin rerun de todo el pipeline
|
| 25 |
+
- 💾 Persiste estado automáticamente
|
| 26 |
+
- 🎨 Genera un canvas visual automáticamente
|
| 27 |
+
|
| 28 |
+
**Es ideal para tu proyecto porque:**
|
| 29 |
+
- Ya tienes un pipeline secuencial (Captioning → Generation)
|
| 30 |
+
- Permite ver qué salida genera cada paso
|
| 31 |
+
- Facilita debugging de pipelines complejos
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## Instalación de UV
|
| 36 |
+
|
| 37 |
+
### Windows:
|
| 38 |
+
```powershell
|
| 39 |
+
# Opción 1: Con pip (si ya tienes Python)
|
| 40 |
+
pip install uv
|
| 41 |
+
|
| 42 |
+
# Opción 2: Con winget (si tienes Windows Package Manager)
|
| 43 |
+
winget install astral-sh.uv
|
| 44 |
+
|
| 45 |
+
# Opción 3: Script instalador oficial
|
| 46 |
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
### Verificar instalación:
|
| 50 |
+
```powershell
|
| 51 |
+
uv --version
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
---
|
| 55 |
+
|
| 56 |
+
## Migración del Proyecto
|
| 57 |
+
|
| 58 |
+
### 1. **Ya creé `pyproject.toml`**
|
| 59 |
+
|
| 60 |
+
Tu proyecto ahora tiene un `pyproject.toml` que reemplaza `requirements.txt` y contiene:
|
| 61 |
+
- Metadata del proyecto
|
| 62 |
+
- Dependencias principales (incluyendo `daggr`)
|
| 63 |
+
- Configuración de UV
|
| 64 |
+
|
| 65 |
+
### 2. **Crear y activar virtual environment con UV**
|
| 66 |
+
|
| 67 |
+
```powershell
|
| 68 |
+
# Crear venv
|
| 69 |
+
uv venv
|
| 70 |
+
|
| 71 |
+
# Activar (Windows)
|
| 72 |
+
.venv\Scripts\Activate.ps1
|
| 73 |
+
|
| 74 |
+
# O en cmd:
|
| 75 |
+
.venv\Scripts\activate.bat
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
### 3. **Instalar dependencias**
|
| 79 |
+
|
| 80 |
+
```powershell
|
| 81 |
+
# Opción A: Instalar todas (recomendado)
|
| 82 |
+
uv pip install -e ".[dev]"
|
| 83 |
+
|
| 84 |
+
# Opción B: Solo lo esencial
|
| 85 |
+
uv sync
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
### 4. **Modal setup (igual que antes)**
|
| 89 |
+
|
| 90 |
+
```powershell
|
| 91 |
+
# Instalar Modal si no está incluido
|
| 92 |
+
uv pip install modal
|
| 93 |
+
|
| 94 |
+
# Login en Modal
|
| 95 |
+
modal token new
|
| 96 |
+
|
| 97 |
+
# Deploy backend
|
| 98 |
+
modal deploy modal_backend.py
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
---
|
| 102 |
+
|
| 103 |
+
## Uso: 3 Opciones
|
| 104 |
+
|
| 105 |
+
### **Opción 1: Mantener app.py actual (sin Daggr)**
|
| 106 |
+
|
| 107 |
+
Simplemente usa uv en lugar de pip:
|
| 108 |
+
|
| 109 |
+
```powershell
|
| 110 |
+
uv pip install -r requirements.txt # También funciona con UV
|
| 111 |
+
# O mejor:
|
| 112 |
+
uv sync
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
Luego:
|
| 116 |
+
```powershell
|
| 117 |
+
gradio app.py
|
| 118 |
+
```
|
| 119 |
+
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
### **Opción 2: Usar Daggr (app_daggr.py)**
|
| 123 |
+
|
| 124 |
+
He creado `app_daggr.py` que refactoriza tu app para usar Daggr.
|
| 125 |
+
|
| 126 |
+
**Ventajas:**
|
| 127 |
+
- ✅ Visualización automática del workflow
|
| 128 |
+
- ✅ Inspecciona output de cada paso
|
| 129 |
+
- ✅ Vuelve a ejecutar pasos individuales
|
| 130 |
+
- ✅ Debug más fácil
|
| 131 |
+
|
| 132 |
+
**Uso:**
|
| 133 |
+
|
| 134 |
+
```powershell
|
| 135 |
+
# Primero, asegúrate que Modal está deployado
|
| 136 |
+
modal deploy modal_backend.py
|
| 137 |
+
|
| 138 |
+
# Luego ejecuta:
|
| 139 |
+
python app_daggr.py
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
Se abrirá en `http://localhost:7860` con:
|
| 143 |
+
- **Node 1**: Image Converter
|
| 144 |
+
- **Node 2**: Image Analysis (Caption generation)
|
| 145 |
+
- **Node 3**: Artistic Prompt Engineering
|
| 146 |
+
- **Node 4**: Watercolor Generation
|
| 147 |
+
|
| 148 |
+
Cada nodo muestra su output y puedes reejecutar pasos individuales.
|
| 149 |
+
|
| 150 |
+
---
|
| 151 |
+
|
| 152 |
+
### **Opción 3: Migración Gradual**
|
| 153 |
+
|
| 154 |
+
Mantén `app.py` y agrega Daggr como una capa adicional:
|
| 155 |
+
|
| 156 |
+
```python
|
| 157 |
+
from daggr import GradioNode, Graph
|
| 158 |
+
|
| 159 |
+
# Tu app.py desplegado en Hugging Face Spaces
|
| 160 |
+
acuarela_space = GradioNode(
|
| 161 |
+
"your-username/acuarela-portrait",
|
| 162 |
+
api_name="/predict",
|
| 163 |
+
inputs={"image": gr.Image()},
|
| 164 |
+
outputs={"image": gr.Image(), "text": gr.Textbox()},
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
# Puedes encadenarlo con otros nodos...
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## Comparativa: pip vs UV
|
| 173 |
+
|
| 174 |
+
| Operación | pip | uv |
|
| 175 |
+
|-----------|-----|-----|
|
| 176 |
+
| Instalar paquete | `pip install package` | `uv pip install package` |
|
| 177 |
+
| Requirements | `pip install -r req.txt` | `uv sync` o `uv pip install -r req.txt` |
|
| 178 |
+
| Crear venv | `python -m venv .venv` | `uv venv` |
|
| 179 |
+
| Velocidad | 📊 Baseline | 📊📊📊📊📊 ~100x más rápido |
|
| 180 |
+
|
| 181 |
+
---
|
| 182 |
+
|
| 183 |
+
## Próximos Pasos
|
| 184 |
+
|
| 185 |
+
1. **Instala UV** (si no lo has hecho)
|
| 186 |
+
2. **Activa el venv con UV**:
|
| 187 |
+
```powershell
|
| 188 |
+
uv venv
|
| 189 |
+
.venv\Scripts\Activate.ps1
|
| 190 |
+
```
|
| 191 |
+
3. **Instala dependencias**:
|
| 192 |
+
```powershell
|
| 193 |
+
uv sync
|
| 194 |
+
```
|
| 195 |
+
4. **Elige tu enfoque**:
|
| 196 |
+
- ✅ **Opción 1**: Mantén `app.py` (cambio mínimo)
|
| 197 |
+
- ✅ **Opción 2**: Usa `app_daggr.py` (máxima visibilidad)
|
| 198 |
+
- ✅ **Opción 3**: Refactoriza gradualmente
|
| 199 |
+
|
| 200 |
+
5. **Deploy Modal**:
|
| 201 |
+
```powershell
|
| 202 |
+
modal deploy modal_backend.py
|
| 203 |
+
```
|
| 204 |
+
|
| 205 |
+
6. **Ejecuta**:
|
| 206 |
+
```powershell
|
| 207 |
+
python app.py # Opción 1
|
| 208 |
+
# o
|
| 209 |
+
python app_daggr.py # Opción 2
|
| 210 |
+
```
|
| 211 |
+
|
| 212 |
+
---
|
| 213 |
+
|
| 214 |
+
## Recursos
|
| 215 |
+
|
| 216 |
+
- 📍 [Documentación UV](https://docs.astral.sh/uv/)
|
| 217 |
+
- 📍 [Documentación Daggr](https://github.com/gradio-app/daggr)
|
| 218 |
+
- 📍 [Blog Daggr en HF](https://huggingface.co/blog/daggr)
|
| 219 |
+
- 📍 [Modal Docs](https://modal.com/docs)
|
| 220 |
+
|
| 221 |
+
---
|
| 222 |
+
|
| 223 |
+
**¿Preguntas?** Revisa los ejemplos en `app_daggr.py` o la documentación oficial.
|
README.md
CHANGED
|
@@ -120,6 +120,44 @@ Hugging Face Space --> Modal Backend
|
|
| 120 |
|
| 121 |
## Instalación Local
|
| 122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
```bash
|
| 124 |
# 1. Clonar repositorio
|
| 125 |
git clone <repo-url>
|
|
@@ -143,6 +181,23 @@ modal deploy modal_backend.py
|
|
| 143 |
python app.py
|
| 144 |
```
|
| 145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
---
|
| 147 |
|
| 148 |
## Costos Estimados
|
|
|
|
| 120 |
|
| 121 |
## Instalación Local
|
| 122 |
|
| 123 |
+
### Opción A: Con UV (⚡ Recomendado - 100x más rápido)
|
| 124 |
+
|
| 125 |
+
```bash
|
| 126 |
+
# 1. Instalar UV (Windows/Mac/Linux)
|
| 127 |
+
pip install uv
|
| 128 |
+
|
| 129 |
+
# 2. Clonar repositorio
|
| 130 |
+
git clone <repo-url>
|
| 131 |
+
cd AcuarelaPortraits
|
| 132 |
+
|
| 133 |
+
# 3. Crear entorno virtual con UV
|
| 134 |
+
uv venv
|
| 135 |
+
|
| 136 |
+
# 4. Activar (Windows)
|
| 137 |
+
.venv\Scripts\Activate.ps1
|
| 138 |
+
# O en cmd: .venv\Scripts\activate.bat
|
| 139 |
+
# Linux/Mac: source .venv/bin/activate
|
| 140 |
+
|
| 141 |
+
# 5. Instalar dependencias
|
| 142 |
+
uv sync
|
| 143 |
+
# O: uv pip install -e ".[dev]"
|
| 144 |
+
|
| 145 |
+
# 6. Autenticarse en Modal
|
| 146 |
+
modal token new
|
| 147 |
+
|
| 148 |
+
# 7. Desplegar backend en Modal
|
| 149 |
+
modal deploy modal_backend.py
|
| 150 |
+
|
| 151 |
+
# 8. Ejecutar aplicación (elige una opción)
|
| 152 |
+
# - App original:
|
| 153 |
+
python app.py
|
| 154 |
+
|
| 155 |
+
# - App con Daggr (visualización del workflow):
|
| 156 |
+
python app_daggr.py
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
### Opción B: Con pip (Tradicional)
|
| 160 |
+
|
| 161 |
```bash
|
| 162 |
# 1. Clonar repositorio
|
| 163 |
git clone <repo-url>
|
|
|
|
| 181 |
python app.py
|
| 182 |
```
|
| 183 |
|
| 184 |
+
### 🆕 Integración con Daggr
|
| 185 |
+
|
| 186 |
+
Este proyecto ahora incluye **Daggr**, una herramienta de Hugging Face para visualizar y debuggear pipelines de IA.
|
| 187 |
+
|
| 188 |
+
**Características:**
|
| 189 |
+
- 👀 Inspecciona el output de cada paso del pipeline
|
| 190 |
+
- ⏪ Vuelve a ejecutar pasos individuales sin re-ejecutar todo
|
| 191 |
+
- 📊 Canvas visual automático del workflow
|
| 192 |
+
- 💾 Persiste estado automáticamente
|
| 193 |
+
|
| 194 |
+
Para usar Daggr:
|
| 195 |
+
```bash
|
| 196 |
+
python app_daggr.py
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
Ve a `MIGRATION_UV_DAGGR.md` para más detalles.
|
| 200 |
+
|
| 201 |
---
|
| 202 |
|
| 203 |
## Costos Estimados
|
app_daggr.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Acuarela Portrait Generator - Refactored with Daggr
|
| 3 |
+
|
| 4 |
+
This version uses Daggr to create a visual workflow that:
|
| 5 |
+
- Chains the Image Captioning and Image Generation steps
|
| 6 |
+
- Provides visual inspection of intermediate steps
|
| 7 |
+
- Allows rerunning individual steps without re-executing the entire pipeline
|
| 8 |
+
- Automatically generates a visual canvas
|
| 9 |
+
|
| 10 |
+
To use this, ensure Modal backend is running:
|
| 11 |
+
$ modal deploy modal_backend.py
|
| 12 |
+
|
| 13 |
+
Then run:
|
| 14 |
+
$ python app_daggr.py
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
import os
|
| 18 |
+
import io
|
| 19 |
+
import modal
|
| 20 |
+
import gradio as gr
|
| 21 |
+
from PIL import Image
|
| 22 |
+
import uuid
|
| 23 |
+
from dotenv import load_dotenv
|
| 24 |
+
|
| 25 |
+
# Import Daggr components
|
| 26 |
+
from daggr import FnNode, GradioNode, InferenceNode, Graph
|
| 27 |
+
|
| 28 |
+
load_dotenv()
|
| 29 |
+
|
| 30 |
+
# --- Modal Setup ---
|
| 31 |
+
try:
|
| 32 |
+
ImageCaptioner = modal.Cls.from_name("acuarela-portrait", "ImageCaptioner")
|
| 33 |
+
ImageGenerator = modal.Cls.from_name("acuarela-portrait", "ImageGenerator")
|
| 34 |
+
MODAL_AVAILABLE = True
|
| 35 |
+
print("✅ Modal backend conectado correctamente")
|
| 36 |
+
except modal.exception.NotFoundError:
|
| 37 |
+
print("⚠️ Modal backend no desplegado. Ejecuta: modal deploy modal_backend.py")
|
| 38 |
+
MODAL_AVAILABLE = False
|
| 39 |
+
except Exception as e:
|
| 40 |
+
print(f"❌ Error conectando con Modal: {e}")
|
| 41 |
+
MODAL_AVAILABLE = False
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# --- Function Nodes ---
|
| 45 |
+
|
| 46 |
+
def convert_image_to_bytes(image) -> bytes:
|
| 47 |
+
"""Convert PIL Image to bytes for Modal processing"""
|
| 48 |
+
if image is None:
|
| 49 |
+
return None
|
| 50 |
+
img_byte_arr = io.BytesIO()
|
| 51 |
+
image.save(img_byte_arr, format='PNG')
|
| 52 |
+
return img_byte_arr.getvalue()
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def generate_caption(img_bytes: bytes) -> str:
|
| 56 |
+
"""
|
| 57 |
+
Step 1: Generate image caption using Modal
|
| 58 |
+
"""
|
| 59 |
+
if not MODAL_AVAILABLE or img_bytes is None:
|
| 60 |
+
raise ValueError("Modal not available or image is None")
|
| 61 |
+
|
| 62 |
+
try:
|
| 63 |
+
captioner = ImageCaptioner()
|
| 64 |
+
caption = captioner.caption.remote(img_bytes)
|
| 65 |
+
if not caption:
|
| 66 |
+
raise ValueError("Could not generate image caption")
|
| 67 |
+
return caption
|
| 68 |
+
except Exception as e:
|
| 69 |
+
raise ValueError(f"Caption generation failed: {str(e)}")
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def create_artistic_prompt(caption: str) -> str:
|
| 73 |
+
"""
|
| 74 |
+
Step 2: Engineer prompt with artistic style
|
| 75 |
+
"""
|
| 76 |
+
prompt = (
|
| 77 |
+
f"digital watercolor illustration of {caption}. "
|
| 78 |
+
"semi-realistic style, clean defined outlines, solid light blue pastel background, "
|
| 79 |
+
"soft shading, vibrant clothing colors, elegant look, "
|
| 80 |
+
"smooth gradients, high quality digital art, masterpiece, character design"
|
| 81 |
+
)
|
| 82 |
+
return prompt
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def generate_watercolor_image(img_bytes: bytes, prompt: str) -> Image.Image:
|
| 86 |
+
"""
|
| 87 |
+
Step 3: Generate watercolor image using Modal SDXL
|
| 88 |
+
"""
|
| 89 |
+
if not MODAL_AVAILABLE or img_bytes is None:
|
| 90 |
+
raise ValueError("Modal not available or image is None")
|
| 91 |
+
|
| 92 |
+
try:
|
| 93 |
+
negative_prompt = (
|
| 94 |
+
"photorealistic, 3d render, photograph, complex background, "
|
| 95 |
+
"white background, dark background, messy sketch, blurry, "
|
| 96 |
+
"distorted face, ugly, bad anatomy, text, watermark, signature, "
|
| 97 |
+
"over-saturated, high contrast, gloomy"
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
generator = ImageGenerator()
|
| 101 |
+
result_bytes = generator.generate.remote(img_bytes, prompt, negative_prompt, strength=0.65)
|
| 102 |
+
result_image = Image.open(io.BytesIO(result_bytes))
|
| 103 |
+
return result_image
|
| 104 |
+
except Exception as e:
|
| 105 |
+
raise ValueError(f"Image generation failed: {str(e)}")
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# --- Daggr Workflow Definition ---
|
| 109 |
+
|
| 110 |
+
def create_workflow():
|
| 111 |
+
"""
|
| 112 |
+
Create the Daggr workflow graph
|
| 113 |
+
"""
|
| 114 |
+
|
| 115 |
+
# Node 1: Image Input (implicit - handled by Gradio interface)
|
| 116 |
+
# Node 2: Convert image to bytes
|
| 117 |
+
converter = FnNode(
|
| 118 |
+
fn=convert_image_to_bytes,
|
| 119 |
+
name="Image Converter",
|
| 120 |
+
inputs={
|
| 121 |
+
"image": gr.Image(label="Upload your photo", type="pil"),
|
| 122 |
+
},
|
| 123 |
+
outputs={
|
| 124 |
+
"return": gr.Textbox(visible=False), # Hidden - intermediate step
|
| 125 |
+
},
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
# Node 3: Generate caption
|
| 129 |
+
captioner = FnNode(
|
| 130 |
+
fn=generate_caption,
|
| 131 |
+
name="Image Analysis (BLIP Caption)",
|
| 132 |
+
inputs={
|
| 133 |
+
"img_bytes": converter.return_,
|
| 134 |
+
},
|
| 135 |
+
outputs={
|
| 136 |
+
"return": gr.Textbox(label="Generated Caption"),
|
| 137 |
+
},
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
# Node 4: Create artistic prompt
|
| 141 |
+
prompt_engineer = FnNode(
|
| 142 |
+
fn=create_artistic_prompt,
|
| 143 |
+
name="Artistic Prompt Engineering",
|
| 144 |
+
inputs={
|
| 145 |
+
"caption": captioner.return_,
|
| 146 |
+
},
|
| 147 |
+
outputs={
|
| 148 |
+
"return": gr.Textbox(label="Artistic Prompt", lines=3),
|
| 149 |
+
},
|
| 150 |
+
)
|
| 151 |
+
|
| 152 |
+
# Node 5: Generate watercolor image
|
| 153 |
+
image_generator = FnNode(
|
| 154 |
+
fn=generate_watercolor_image,
|
| 155 |
+
name="Watercolor Generation (SDXL)",
|
| 156 |
+
inputs={
|
| 157 |
+
"img_bytes": converter.return_,
|
| 158 |
+
"prompt": prompt_engineer.return_,
|
| 159 |
+
},
|
| 160 |
+
outputs={
|
| 161 |
+
"return": gr.Image(label="Watercolor Portrait"),
|
| 162 |
+
},
|
| 163 |
+
)
|
| 164 |
+
|
| 165 |
+
# Create the graph
|
| 166 |
+
graph = Graph(
|
| 167 |
+
name="🎨 Acuarela Portrait Generator - Daggr Workflow",
|
| 168 |
+
nodes=[converter, captioner, prompt_engineer, image_generator],
|
| 169 |
+
description="Transform your photos into watercolor artworks using AI. "
|
| 170 |
+
"Each step is visualized and can be rerun independently!",
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
return graph
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
# --- Alternative: Hybrid approach (Original app with Daggr integration) ---
|
| 177 |
+
|
| 178 |
+
def create_hybrid_workflow():
|
| 179 |
+
"""
|
| 180 |
+
Alternative: Keep the original Gradio app but add visual inspection with Daggr
|
| 181 |
+
This version uses GradioNode to reference the existing app
|
| 182 |
+
"""
|
| 183 |
+
|
| 184 |
+
# If you have deployed your existing app.py as a Gradio Space, reference it:
|
| 185 |
+
# my_space = GradioNode(
|
| 186 |
+
# "your-username/acuarela-portrait",
|
| 187 |
+
# api_name="/predict",
|
| 188 |
+
# inputs={"image": gr.Image()},
|
| 189 |
+
# outputs={"image": gr.Image(), "text": gr.Textbox()},
|
| 190 |
+
# )
|
| 191 |
+
|
| 192 |
+
pass
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
# --- Launch ---
|
| 196 |
+
|
| 197 |
+
if __name__ == "__main__":
|
| 198 |
+
if MODAL_AVAILABLE:
|
| 199 |
+
print("\n🚀 Launching Daggr workflow...")
|
| 200 |
+
workflow = create_workflow()
|
| 201 |
+
workflow.launch(share=False)
|
| 202 |
+
else:
|
| 203 |
+
print("\n❌ Modal backend not available.")
|
| 204 |
+
print("First, deploy the backend with: modal deploy modal_backend.py")
|
| 205 |
+
print("Then run this script again.")
|
git_error.txt
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
git : remote: [31m--
|
| 2 |
+
---------------------
|
| 3 |
+
---------------------
|
| 4 |
+
---------------------
|
| 5 |
+
--------[0m
|
| 6 |
+
En línea: 1
|
| 7 |
+
Carácter: 1
|
| 8 |
+
+ git push origin
|
| 9 |
+
main 2>&1 | Out-File
|
| 10 |
+
-FilePath
|
| 11 |
+
git_error.txt
|
| 12 |
+
-Encodin ...
|
| 13 |
+
+ ~~~~~~~~~~~~~~~~~~~
|
| 14 |
+
~~~~~~
|
| 15 |
+
+ CategoryInfo
|
| 16 |
+
: NotSpe
|
| 17 |
+
cified: (remote:
|
| 18 |
+
[31m--...---[
|
| 19 |
+
0m :Strin
|
| 20 |
+
g) [], RemoteExc
|
| 21 |
+
eption
|
| 22 |
+
+ FullyQualified
|
| 23 |
+
ErrorId : Native
|
| 24 |
+
CommandError
|
| 25 |
+
|
| 26 |
+
remote: [31mYour
|
| 27 |
+
push was rejected
|
| 28 |
+
because it contains
|
| 29 |
+
binary files.[0m
|
| 30 |
+
|
| 31 |
+
remote: [31mPlease
|
| 32 |
+
use https://huggingfa
|
| 33 |
+
ce.co/docs/hub/xet
|
| 34 |
+
to store binary
|
| 35 |
+
files.[0m
|
| 36 |
+
remote: [31mSee
|
| 37 |
+
also: https://hugging
|
| 38 |
+
face.co/docs/hub/xet/
|
| 39 |
+
using-xet-storage#git
|
| 40 |
+
[0m
|
| 41 |
+
remote: [31m[0m
|
| 42 |
+
|
| 43 |
+
remote:
|
| 44 |
+
[31mOffending
|
| 45 |
+
files:[0m
|
| 46 |
+
remote: [31m -
|
| 47 |
+
example.png (ref:
|
| 48 |
+
refs/heads/main)[0m
|
| 49 |
+
|
| 50 |
+
remote: [31m--------
|
| 51 |
+
---------------------
|
| 52 |
+
---------------------
|
| 53 |
+
---------------------
|
| 54 |
+
--[0m
|
| 55 |
+
To https://huggingfac
|
| 56 |
+
e.co/spaces/Alexramsa
|
| 57 |
+
l/AcuarelaPortraits
|
| 58 |
+
! [remote rejected]
|
| 59 |
+
main -> main
|
| 60 |
+
(pre-receive hook
|
| 61 |
+
declined)
|
| 62 |
+
error: failed to
|
| 63 |
+
push some refs to 'ht
|
| 64 |
+
tps://huggingface.co/
|
| 65 |
+
spaces/Alexramsal/Acu
|
| 66 |
+
arelaPortraits'
|
install.ps1
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Acuarela Portrait - Quick Setup Script
|
| 2 |
+
# Este script automatiza la instalación con UV para Windows
|
| 3 |
+
|
| 4 |
+
param(
|
| 5 |
+
[switch]$SkipPython = $false,
|
| 6 |
+
[switch]$SkipModal = $false
|
| 7 |
+
)
|
| 8 |
+
|
| 9 |
+
Write-Host "🎨 Acuarela Portrait - Instalación con UV" -ForegroundColor Cyan
|
| 10 |
+
Write-Host "============================================`n" -ForegroundColor Cyan
|
| 11 |
+
|
| 12 |
+
# Check Python
|
| 13 |
+
Write-Host "1️⃣ Verificando Python..." -ForegroundColor Yellow
|
| 14 |
+
$pythonVersion = python --version 2>&1
|
| 15 |
+
if ($LASTEXITCODE -eq 0) {
|
| 16 |
+
Write-Host "✅ Python encontrado: $pythonVersion" -ForegroundColor Green
|
| 17 |
+
} else {
|
| 18 |
+
Write-Host "❌ Python no encontrado. Instálalo desde https://python.org" -ForegroundColor Red
|
| 19 |
+
exit 1
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
# Check/Install UV
|
| 23 |
+
Write-Host "`n2️⃣ Verificando UV..." -ForegroundColor Yellow
|
| 24 |
+
$uvVersion = uv --version 2>&1
|
| 25 |
+
if ($LASTEXITCODE -eq 0) {
|
| 26 |
+
Write-Host "✅ UV encontrado: $uvVersion" -ForegroundColor Green
|
| 27 |
+
} else {
|
| 28 |
+
Write-Host "⚠️ UV no encontrado. Instalando..." -ForegroundColor Yellow
|
| 29 |
+
pip install uv
|
| 30 |
+
$uvVersion = uv --version 2>&1
|
| 31 |
+
Write-Host "✅ UV instalado: $uvVersion" -ForegroundColor Green
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
# Create venv
|
| 35 |
+
Write-Host "`n3️⃣ Creando entorno virtual..." -ForegroundColor Yellow
|
| 36 |
+
if (Test-Path ".venv") {
|
| 37 |
+
Write-Host "✅ Entorno virtual ya existe" -ForegroundColor Green
|
| 38 |
+
} else {
|
| 39 |
+
uv venv
|
| 40 |
+
Write-Host "✅ Entorno virtual creado" -ForegroundColor Green
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
# Activate venv
|
| 44 |
+
Write-Host "`n4️⃣ Activando entorno virtual..." -ForegroundColor Yellow
|
| 45 |
+
& ".\.venv\Scripts\Activate.ps1"
|
| 46 |
+
Write-Host "✅ Entorno virtual activado" -ForegroundColor Green
|
| 47 |
+
|
| 48 |
+
# Install dependencies
|
| 49 |
+
Write-Host "`n5️⃣ Instalando dependencias..." -ForegroundColor Yellow
|
| 50 |
+
uv sync
|
| 51 |
+
if ($LASTEXITCODE -eq 0) {
|
| 52 |
+
Write-Host "✅ Dependencias instaladas" -ForegroundColor Green
|
| 53 |
+
} else {
|
| 54 |
+
Write-Host "❌ Error instalando dependencias" -ForegroundColor Red
|
| 55 |
+
exit 1
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
# Modal setup
|
| 59 |
+
if (-not $SkipModal) {
|
| 60 |
+
Write-Host "`n6️⃣ Configurando Modal..." -ForegroundColor Yellow
|
| 61 |
+
Write-Host "Necesitas obtener tu token de Modal en: https://modal.com/settings/tokens" -ForegroundColor Cyan
|
| 62 |
+
$continue = Read-Host "¿Continuar con configuración de Modal? (y/n)"
|
| 63 |
+
|
| 64 |
+
if ($continue -eq "y") {
|
| 65 |
+
modal token new
|
| 66 |
+
Write-Host "✅ Modal configurado" -ForegroundColor Green
|
| 67 |
+
|
| 68 |
+
Write-Host "`n7️⃣ Deployando backend Modal..." -ForegroundColor Yellow
|
| 69 |
+
modal deploy modal_backend.py
|
| 70 |
+
Write-Host "✅ Backend deployado" -ForegroundColor Green
|
| 71 |
+
} else {
|
| 72 |
+
Write-Host "⚠️ Modal no configurado. Hazlo manualmente con: modal token new" -ForegroundColor Yellow
|
| 73 |
+
}
|
| 74 |
+
} else {
|
| 75 |
+
Write-Host "`n6️⃣ Skipping Modal setup (use -SkipModal flag)" -ForegroundColor Yellow
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
Write-Host "`n✨ ¡Instalación completada!" -ForegroundColor Green
|
| 79 |
+
Write-Host "`n🚀 Para ejecutar la aplicación:" -ForegroundColor Cyan
|
| 80 |
+
Write-Host " Opción 1: python app.py" -ForegroundColor White
|
| 81 |
+
Write-Host " Opción 2: python app_daggr.py (con visualización del workflow)" -ForegroundColor White
|
| 82 |
+
|
| 83 |
+
Write-Host "`n📚 Para más información: lee MIGRATION_UV_DAGGR.md" -ForegroundColor Cyan
|
install.sh
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Acuarela Portrait - Quick Setup Script
|
| 3 |
+
# Este script automatiza la instalación con UV para Linux/Mac
|
| 4 |
+
|
| 5 |
+
set -e
|
| 6 |
+
|
| 7 |
+
# Colors
|
| 8 |
+
RED='\033[0;31m'
|
| 9 |
+
GREEN='\033[0;32m'
|
| 10 |
+
YELLOW='\033[1;33m'
|
| 11 |
+
CYAN='\033[0;36m'
|
| 12 |
+
NC='\033[0m' # No Color
|
| 13 |
+
|
| 14 |
+
echo -e "${CYAN}🎨 Acuarela Portrait - Instalación con UV${NC}"
|
| 15 |
+
echo -e "${CYAN}============================================\n${NC}"
|
| 16 |
+
|
| 17 |
+
# Check Python
|
| 18 |
+
echo -e "${YELLOW}1️⃣ Verificando Python...${NC}"
|
| 19 |
+
if command -v python3 &> /dev/null; then
|
| 20 |
+
PYTHON_VERSION=$(python3 --version)
|
| 21 |
+
echo -e "${GREEN}✅ Python encontrado: $PYTHON_VERSION${NC}"
|
| 22 |
+
else
|
| 23 |
+
echo -e "${RED}❌ Python no encontrado. Instálalo desde https://python.org${NC}"
|
| 24 |
+
exit 1
|
| 25 |
+
fi
|
| 26 |
+
|
| 27 |
+
# Check/Install UV
|
| 28 |
+
echo -e "\n${YELLOW}2️⃣ Verificando UV...${NC}"
|
| 29 |
+
if command -v uv &> /dev/null; then
|
| 30 |
+
UV_VERSION=$(uv --version)
|
| 31 |
+
echo -e "${GREEN}✅ UV encontrado: $UV_VERSION${NC}"
|
| 32 |
+
else
|
| 33 |
+
echo -e "${YELLOW}⚠️ UV no encontrado. Instalando...${NC}"
|
| 34 |
+
pip install uv
|
| 35 |
+
UV_VERSION=$(uv --version)
|
| 36 |
+
echo -e "${GREEN}✅ UV instalado: $UV_VERSION${NC}"
|
| 37 |
+
fi
|
| 38 |
+
|
| 39 |
+
# Create venv
|
| 40 |
+
echo -e "\n${YELLOW}3️⃣ Creando entorno virtual...${NC}"
|
| 41 |
+
if [ -d ".venv" ]; then
|
| 42 |
+
echo -e "${GREEN}✅ Entorno virtual ya existe${NC}"
|
| 43 |
+
else
|
| 44 |
+
uv venv
|
| 45 |
+
echo -e "${GREEN}✅ Entorno virtual creado${NC}"
|
| 46 |
+
fi
|
| 47 |
+
|
| 48 |
+
# Activate venv
|
| 49 |
+
echo -e "\n${YELLOW}4️⃣ Activando entorno virtual...${NC}"
|
| 50 |
+
source .venv/bin/activate
|
| 51 |
+
echo -e "${GREEN}✅ Entorno virtual activado${NC}"
|
| 52 |
+
|
| 53 |
+
# Install dependencies
|
| 54 |
+
echo -e "\n${YELLOW}5️⃣ Instalando dependencias...${NC}"
|
| 55 |
+
uv sync
|
| 56 |
+
echo -e "${GREEN}✅ Dependencias instaladas${NC}"
|
| 57 |
+
|
| 58 |
+
# Modal setup
|
| 59 |
+
echo -e "\n${YELLOW}6️⃣ Configurando Modal...${NC}"
|
| 60 |
+
echo -e "${CYAN}Necesitas obtener tu token de Modal en: https://modal.com/settings/tokens${NC}"
|
| 61 |
+
read -p "¿Continuar con configuración de Modal? (y/n) " -n 1 -r
|
| 62 |
+
echo
|
| 63 |
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
| 64 |
+
modal token new
|
| 65 |
+
echo -e "${GREEN}✅ Modal configurado${NC}"
|
| 66 |
+
|
| 67 |
+
echo -e "\n${YELLOW}7️⃣ Deployando backend Modal...${NC}"
|
| 68 |
+
modal deploy modal_backend.py
|
| 69 |
+
echo -e "${GREEN}✅ Backend deployado${NC}"
|
| 70 |
+
else
|
| 71 |
+
echo -e "${YELLOW}⚠️ Modal no configurado. Hazlo manualmente con: modal token new${NC}"
|
| 72 |
+
fi
|
| 73 |
+
|
| 74 |
+
echo -e "\n${GREEN}✨ ¡Instalación completada!${NC}"
|
| 75 |
+
echo -e "\n${CYAN}🚀 Para ejecutar la aplicación:${NC}"
|
| 76 |
+
echo -e " Opción 1: python app.py"
|
| 77 |
+
echo -e " Opción 2: python app_daggr.py (con visualización del workflow)"
|
| 78 |
+
|
| 79 |
+
echo -e "\n${CYAN}📚 Para más información: lee MIGRATION_UV_DAGGR.md${NC}"
|
pyproject.toml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "acuarela-portrait"
|
| 3 |
+
version = "3.0.0"
|
| 4 |
+
description = "Watercolor Portrait Generator with AI - Combines GIT Image Captioning and SDXL Image Generation"
|
| 5 |
+
readme = "README.md"
|
| 6 |
+
license = {text = "MIT"}
|
| 7 |
+
requires-python = ">=3.11"
|
| 8 |
+
dependencies = [
|
| 9 |
+
"gradio==4.19.2",
|
| 10 |
+
"huggingface_hub==0.20.3",
|
| 11 |
+
"modal",
|
| 12 |
+
"typer",
|
| 13 |
+
"pillow",
|
| 14 |
+
"python-dotenv",
|
| 15 |
+
"daggr",
|
| 16 |
+
]
|
| 17 |
+
|
| 18 |
+
[project.optional-dependencies]
|
| 19 |
+
dev = [
|
| 20 |
+
"pytest>=7.0",
|
| 21 |
+
"black>=23.0",
|
| 22 |
+
"ruff>=0.1.0",
|
| 23 |
+
]
|
requirements.txt
CHANGED
|
@@ -2,4 +2,5 @@ gradio==4.19.2
|
|
| 2 |
huggingface_hub==0.20.3
|
| 3 |
modal
|
| 4 |
pillow
|
| 5 |
-
python-dotenv
|
|
|
|
|
|
| 2 |
huggingface_hub==0.20.3
|
| 3 |
modal
|
| 4 |
pillow
|
| 5 |
+
python-dotenv
|
| 6 |
+
daggr
|
uv.lock
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|