Gianpaolo Macario
commited on
Commit
·
e21102a
1
Parent(s):
d229ac5
feat: first shot at dockerizing app.py
Browse files- .dockerignore +16 -0
- Dockerfile +51 -0
- app.py +3 -1
- docker-compose.yaml +19 -0
- entrypoint.sh +12 -0
- env.example +3 -0
- flux.py +21 -3
.dockerignore
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.pyc
|
| 3 |
+
*.pyo
|
| 4 |
+
*.pyd
|
| 5 |
+
.Python
|
| 6 |
+
.env
|
| 7 |
+
.env.*
|
| 8 |
+
*.sqlite
|
| 9 |
+
*.db
|
| 10 |
+
output/
|
| 11 |
+
.git/
|
| 12 |
+
.gitignore
|
| 13 |
+
.dockerignore
|
| 14 |
+
Dockerfile
|
| 15 |
+
*.md
|
| 16 |
+
!README.md
|
Dockerfile
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Compile stage: install build dependencies
|
| 2 |
+
FROM python:3.12-slim AS builder
|
| 3 |
+
|
| 4 |
+
# Set working directory
|
| 5 |
+
WORKDIR /app
|
| 6 |
+
|
| 7 |
+
# Install build dependencies
|
| 8 |
+
RUN apt-get update && \
|
| 9 |
+
apt-get install -y --no-install-recommends \
|
| 10 |
+
build-essential \
|
| 11 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 12 |
+
|
| 13 |
+
# Install Python dependencies
|
| 14 |
+
COPY requirements.txt .
|
| 15 |
+
RUN python -m pip install --upgrade pip && \
|
| 16 |
+
python -m pip install --no-cache-dir wheel && \
|
| 17 |
+
pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
|
| 18 |
+
|
| 19 |
+
# Final stage: copy only necessary files
|
| 20 |
+
FROM python:3.12-slim
|
| 21 |
+
|
| 22 |
+
WORKDIR /app
|
| 23 |
+
|
| 24 |
+
# Copy wheels from builder stage
|
| 25 |
+
COPY --from=builder /app/wheels /wheels
|
| 26 |
+
|
| 27 |
+
# Install Python packages from wheels
|
| 28 |
+
RUN pip install --no-cache /wheels/*
|
| 29 |
+
|
| 30 |
+
# Copy application files
|
| 31 |
+
COPY app.py flux.py stablediffusion.py ./
|
| 32 |
+
COPY pyproject.toml README.md ./
|
| 33 |
+
|
| 34 |
+
# Create directories for temporary files
|
| 35 |
+
RUN mkdir -p /tmp/flux /tmp/flux2 && \
|
| 36 |
+
chmod 777 /tmp/flux /tmp/flux2
|
| 37 |
+
|
| 38 |
+
# Set environment variables
|
| 39 |
+
ENV PYTHONUNBUFFERED=1
|
| 40 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 41 |
+
ENV PYTHONPATH=/app
|
| 42 |
+
|
| 43 |
+
# Copy and set permissions for entrypoint script
|
| 44 |
+
COPY entrypoint.sh .
|
| 45 |
+
RUN chmod +x entrypoint.sh
|
| 46 |
+
|
| 47 |
+
# Expose the port that Gradio will run on
|
| 48 |
+
EXPOSE 7860
|
| 49 |
+
|
| 50 |
+
# Command to run the application
|
| 51 |
+
ENTRYPOINT ["./entrypoint.sh"]
|
app.py
CHANGED
|
@@ -236,6 +236,8 @@ with gr.Blocks() as demo:
|
|
| 236 |
demo.launch(
|
| 237 |
mcp_server=True,
|
| 238 |
share=True,
|
| 239 |
-
ssr_mode=False
|
|
|
|
|
|
|
| 240 |
|
| 241 |
# EOF
|
|
|
|
| 236 |
demo.launch(
|
| 237 |
mcp_server=True,
|
| 238 |
share=True,
|
| 239 |
+
ssr_mode=False,
|
| 240 |
+
server_name="0.0.0.0", # Listen on all interfaces
|
| 241 |
+
server_port=7860) # Use the port we exposed in Dockerfile
|
| 242 |
|
| 243 |
# EOF
|
docker-compose.yaml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: '3.8'
|
| 2 |
+
|
| 3 |
+
services:
|
| 4 |
+
simple-calculator:
|
| 5 |
+
build: .
|
| 6 |
+
ports:
|
| 7 |
+
- "7860:7860"
|
| 8 |
+
environment:
|
| 9 |
+
- PYTHONUNBUFFERED=1
|
| 10 |
+
# Add your Modal credentials here or use .env file
|
| 11 |
+
- MODAL_TOKEN_ID=${MODAL_TOKEN_ID:-}
|
| 12 |
+
- MODAL_TOKEN_SECRET=${MODAL_TOKEN_SECRET:-}
|
| 13 |
+
volumes:
|
| 14 |
+
# Mount the Modal config directory to persist credentials
|
| 15 |
+
- modal-config:/root/.modal
|
| 16 |
+
restart: unless-stopped
|
| 17 |
+
|
| 18 |
+
volumes:
|
| 19 |
+
modal-config: # Named volume for Modal configuration
|
entrypoint.sh
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Create Modal config directory
|
| 4 |
+
mkdir -p ~/.modal
|
| 5 |
+
|
| 6 |
+
# Write Modal token configuration if provided
|
| 7 |
+
if [ ! -z "$MODAL_TOKEN_ID" ] && [ ! -z "$MODAL_TOKEN_SECRET" ]; then
|
| 8 |
+
echo "{\"token_id\":\"$MODAL_TOKEN_ID\",\"token_secret\":\"$MODAL_TOKEN_SECRET\"}" > ~/.modal/config.json
|
| 9 |
+
fi
|
| 10 |
+
|
| 11 |
+
# Start the application
|
| 12 |
+
exec python app.py
|
env.example
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copy this file to .env and fill in your Modal credentials
|
| 2 |
+
MODAL_TOKEN_ID=your_modal_token_id_here
|
| 3 |
+
MODAL_TOKEN_SECRET=your_modal_token_secret_here
|
flux.py
CHANGED
|
@@ -2,13 +2,27 @@
|
|
| 2 |
#
|
| 3 |
# See https://modal.com/docs/examples/flux
|
| 4 |
|
| 5 |
-
|
| 6 |
-
|
| 7 |
import time
|
| 8 |
from io import BytesIO
|
| 9 |
from pathlib import Path
|
| 10 |
import modal
|
| 11 |
-
import modal.running_app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
# We’ll make use of the full CUDA toolkit in this example, so we’ll build our container image
|
| 14 |
# off of the nvidia/cuda base.
|
|
@@ -284,6 +298,10 @@ def generate_image2(prompt: str):
|
|
| 284 |
"""
|
| 285 |
|
| 286 |
print("DEBUG: generate_image2 called with prompt:", prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
|
| 288 |
if prompt is None or prompt.strip() == "A portrait of a handsome software developer":
|
| 289 |
print("DEBUG: Returning hardcoded image URL for default prompt")
|
|
|
|
| 2 |
#
|
| 3 |
# See https://modal.com/docs/examples/flux
|
| 4 |
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
import time
|
| 8 |
from io import BytesIO
|
| 9 |
from pathlib import Path
|
| 10 |
import modal
|
| 11 |
+
# import modal.running_app
|
| 12 |
+
|
| 13 |
+
# Check for Modal credentials
|
| 14 |
+
MODAL_TOKEN_ID = os.getenv('MODAL_TOKEN_ID')
|
| 15 |
+
MODAL_TOKEN_SECRET = os.getenv('MODAL_TOKEN_SECRET')
|
| 16 |
+
|
| 17 |
+
if not MODAL_TOKEN_ID or not MODAL_TOKEN_SECRET:
|
| 18 |
+
print("WARNING: Modal credentials not found. Image generation will return placeholder images.", file=sys.stderr)
|
| 19 |
+
MODAL_AVAILABLE = False
|
| 20 |
+
else:
|
| 21 |
+
try:
|
| 22 |
+
MODAL_AVAILABLE = True
|
| 23 |
+
except ImportError:
|
| 24 |
+
print("WARNING: Modal package not available. Image generation will return placeholder images.", file=sys.stderr)
|
| 25 |
+
MODAL_AVAILABLE = False
|
| 26 |
|
| 27 |
# We’ll make use of the full CUDA toolkit in this example, so we’ll build our container image
|
| 28 |
# off of the nvidia/cuda base.
|
|
|
|
| 298 |
"""
|
| 299 |
|
| 300 |
print("DEBUG: generate_image2 called with prompt:", prompt)
|
| 301 |
+
|
| 302 |
+
if not MODAL_AVAILABLE:
|
| 303 |
+
print("DEBUG: Modal not available, returning placeholder image")
|
| 304 |
+
return generate_image1(prompt)
|
| 305 |
|
| 306 |
if prompt is None or prompt.strip() == "A portrait of a handsome software developer":
|
| 307 |
print("DEBUG: Returning hardcoded image URL for default prompt")
|