File size: 7,385 Bytes
4d264ff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#!/bin/bash

# HuggingFace deployment script for PuppyCompanion FastAPI
# Usage: ./deploy_hf.sh [--space-name SPACE_NAME]

set -e

# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'

log() {
    echo -e "${GREEN}[DEPLOY]${NC} $1"
}

warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

# Default configuration
SPACE_NAME="puppycompanion-v3"
APP_DIR="."
HF_USERNAME="JTh34"

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --space-name)
            SPACE_NAME="$2"
            shift 2
            ;;
        *)
            error "Unknown option: $1"
            exit 1
            ;;
    esac
done

# Ask for space name if not provided (with default)
if [ -z "$SPACE_NAME" ]; then
    read -p "HuggingFace space name [puppycompanion-v3]: " SPACE_NAME
    SPACE_NAME=${SPACE_NAME:-puppycompanion-v3}
fi

if [ -z "$SPACE_NAME" ]; then
    error "Space name required"
    exit 1
fi

# Check that the app directory exists
if [ ! -d "$APP_DIR" ]; then
    error "Application directory not found: $APP_DIR"
    exit 1
fi

cd "$APP_DIR"

log "Preparing deployment for FastAPI space: $HF_USERNAME/$SPACE_NAME"

# Pre-deployment checks
log "Pre-deployment checks..."

# Check required files for FastAPI application
REQUIRED_FILES=(
    "main.py"
    "Dockerfile"
    "README.MD"
    "all_books_preprocessed_chunks.json"
    "rag_system.py"
    "agent_workflow.py"
    "embedding_models.py"
    "books_config.json"
    "static/index.html"
)

for file in "${REQUIRED_FILES[@]}"; do
    if [ ! -f "$file" ]; then
        error "Missing required file: $file"
        exit 1
    fi
done

log "βœ… All required files found"

# Check that API keys are not in files
ENV_FILES=(".env" ".env.local" ".env.prod" ".env.development" ".env.staging")
for env_file in "${ENV_FILES[@]}"; do
    if [ -f "$env_file" ]; then
        if grep -q "sk-\|OPENAI_API_KEY\|TAVILY_API_KEY" "$env_file" 2>/dev/null; then
            warn "API keys detected in $env_file - file will be excluded from deployment"
            warn "Make sure to configure your secrets on HuggingFace Spaces"
        fi
    fi
done

# Check for PDF files that should not be deployed
if ls data/*.pdf >/dev/null 2>&1; then
    warn "PDF files detected in data/ directory"
    warn "These will be excluded from deployment for security"
fi

# Validate chunks file size
if [ -f "all_books_preprocessed_chunks.json" ]; then
    FILE_SIZE=$(stat -f%z "all_books_preprocessed_chunks.json" 2>/dev/null || stat -c%s "all_books_preprocessed_chunks.json" 2>/dev/null)
    FILE_SIZE_MB=$((FILE_SIZE / 1024 / 1024))
    log "Chunks file size: ${FILE_SIZE_MB}MB"
    if [ $FILE_SIZE_MB -gt 100 ]; then
        warn "Large chunks file detected (${FILE_SIZE_MB}MB)"
        warn "This may cause slower deployment and startup times"
    fi
fi

# Create requirements.txt from pyproject.toml if needed and requirements.txt doesn't exist
if [ ! -f "requirements.txt" ] && [ -f "pyproject.toml" ]; then
    log "Generating requirements.txt from pyproject.toml..."
    if command -v pip-compile &> /dev/null; then
        pip-compile pyproject.toml
    else
        warn "pip-compile not found. Basic requirements.txt generation..."
        # Basic extraction of dependencies from pyproject.toml
        if command -v python &> /dev/null; then
            python -c "
import tomllib
with open('pyproject.toml', 'rb') as f:
    data = tomllib.load(f)
deps = data.get('project', {}).get('dependencies', [])
with open('requirements.txt', 'w') as f:
    for dep in deps:
        f.write(dep + '\n')
" 2>/dev/null || {
                warn "Could not generate requirements.txt automatically"
                warn "Please create the requirements.txt file manually"
                exit 1
            }
        fi
    fi
elif [ -f "requirements.txt" ]; then
    log "βœ… requirements.txt found"
fi

# Validate Dockerfile for FastAPI
if grep -q "main.py" Dockerfile && grep -q "7860" Dockerfile; then
    log "βœ… Dockerfile configured for FastAPI"
else
    warn "Dockerfile may not be properly configured for FastAPI deployment"
fi

# Check SSH connection to HuggingFace
log "Checking HuggingFace SSH connection..."
if ! ssh -T git@hf.co -o ConnectTimeout=10 -o BatchMode=yes 2>/dev/null; then
    warn "SSH connection to HuggingFace failed"
    info "Check your SSH configuration or use: ssh-keygen -t ed25519 -C 'your_email@example.com'"
    info "Then add the public key to your HuggingFace profile"
    
    # Fallback to HTTPS if available
    if command -v huggingface-cli &> /dev/null && huggingface-cli whoami &> /dev/null; then
        warn "Using HTTPS as fallback..."
        USE_SSH=false
    else
        error "No authentication method available"
        exit 1
    fi
else
    log "βœ… HuggingFace SSH connection OK"
    USE_SSH=true
fi

# Create the space if it does not exist (requires huggingface-cli)
if command -v huggingface-cli &> /dev/null; then
    log "Creating/updating HuggingFace space..."
    huggingface-cli repo create "$SPACE_NAME" --type space --space_sdk docker 2>/dev/null || true
else
    warn "huggingface-cli not available, make sure the space exists"
fi

# Clone or update the repo
TEMP_DIR="/tmp/hf_deploy_$$"
log "Cloning repository..."

if [ "$USE_SSH" = true ]; then
    # Use SSH
    git clone "git@hf.co:spaces/$HF_USERNAME/$SPACE_NAME" "$TEMP_DIR" || {
        error "SSH clone failed. Check username and space name."
        exit 1
    }
else
    # Use HTTPS
    git clone "https://huggingface.co/spaces/$HF_USERNAME/$SPACE_NAME" "$TEMP_DIR" || {
        error "HTTPS clone failed. Check username and space name."
        exit 1
    }
fi

# Copy files with FastAPI-specific exclusions
log "Copying FastAPI application files..."
rsync -av \
    --exclude='.git' \
    --exclude='venv_*' \
    --exclude='.env*' \
    --exclude='__pycache__' \
    --exclude='.chainlit' \
    --exclude='*.pdf' \
    --exclude='*.PDF' \
    --exclude='data/*.pdf' \
    --exclude='data/*.PDF' \
    --exclude='.DS_Store' \
    --exclude='*.log' \
    --exclude='qdrant_storage' \
    --exclude='deploy_hf.sh' \
    --exclude='.gitattributes' \
    --exclude='uv.lock' \
    --exclude='document_loader_preproc.py' \
    ./ "$TEMP_DIR/"

# Go to temp directory
cd "$TEMP_DIR"

# Configure Git if needed
git config user.email "action@github.com" || true
git config user.name "Deploy Script" || true

# Verify critical files are present
log "Verifying deployment files..."
CRITICAL_FILES=("main.py" "Dockerfile" "all_books_preprocessed_chunks.json")
for file in "${CRITICAL_FILES[@]}"; do
    if [ ! -f "$file" ]; then
        error "Critical file missing after copy: $file"
        exit 1
    fi
done

log "βœ… All critical files verified"

# Add and commit
log "Committing changes..."
git add .
git commit -m "Deploy PuppyCompanion FastAPI $(date '+%Y-%m-%d %H:%M:%S')" || {
    warn "No changes detected"
}

# Push to HuggingFace
log "Pushing to HuggingFace..."
git push

# Clean up
cd - > /dev/null
rm -rf "$TEMP_DIR"

log "πŸš€ FastAPI deployment completed successfully!"
info "Your app will be available at: https://huggingface.co/spaces/$HF_USERNAME/$SPACE_NAME"
info "Deployment may take a few minutes to build and start..."
info "Check the logs on HuggingFace Spaces for any issues"