markitdown / start.sh
free-apis-collection's picture
Deploy 7de0c2ab99518aefca3cce1496d6b74cae82705f
d77da37 verified
Raw History Blame Contribute Delete
4.58 kB
#!/usr/bin/env bash
# ChatCsv&Pdf-Backend β€” HF Space entrypoint.
# Loads the single `ENV_FILE` secret (verbatim copy of `.env`) into the
# environment, then starts uvicorn. Same pattern as the reference
# huggingface-service start.sh, simplified for this app.
set -euo pipefail
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
# Track pre-existing process env (HF Space Secrets injected by the platform
# take precedence over ENV_FILE entries with the same name).
declare -A _ENV_FROM_PROCESS
for _k in $(compgen -e); do _ENV_FROM_PROCESS["$_k"]=1; done
# Parse a multi-line KEY=VALUE document (ENV_FILE secret value) and export
# each entry. Handles CRLF, blank lines, '#' comments, 'export ' prefixes,
# surrounding quotes, and values containing '=' (split on first '=' only).
# Never logs values β€” names only.
load_env_document() {
local content="$1" line key val
local _ok=0 _skip=0 _fail=0
if [[ "$content" != *$'\n'* && "$content" == *'\n'* ]]; then
log "ENV_FILE: no real newlines found β€” expanding literal \\n sequences"
content="${content//\\n/$'\n'}"
fi
while IFS= read -r line || [ -n "$line" ]; do
line="${line%$'\r'}"
key="${line#"${line%%[![:space:]]*}"}"
[ -n "$key" ] || continue
case "$key" in '#'*) continue ;; esac
if [[ "$key" == 'export '* ]]; then
key="${key#export }"
key="${key#"${key%%[![:space:]]*}"}"
fi
case "$key" in
*=*) val="${key#*=}"; key="${key%%=*}" ;;
*) log "ENV FAIL: malformed line, no '=' found: ${line:0:40}"; _fail=$((_fail+1)); continue ;;
esac
key="${key%"${key##*[![:space:]]}"}"
if ! [[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then
log "ENV FAIL: invalid variable name '${key:0:40}'"; _fail=$((_fail+1)); continue
fi
val="${val#"${val%%[![:space:]]*}"}"
val="${val%"${val##*[![:space:]]}"}"
case "$val" in
\"*\") val="${val#\"}"; val="${val%\"}" ;;
\'*\') val="${val#\'}"; val="${val%\'}" ;;
esac
if [ -n "${_ENV_FROM_PROCESS[$key]:-}" ]; then
log "ENV SKIP: $key (already set in process environment β€” keeping existing value)"
_skip=$((_skip+1))
elif export "$key=$val" 2>/dev/null; then
log "ENV OK: $key"; _ok=$((_ok+1))
else
log "ENV FAIL: $key (could not export)"; _fail=$((_fail+1))
fi
done <<< "$content"
log "ENV_FILE load summary: $_ok loaded, $_skip skipped, $_fail failed, $((_ok+_skip+_fail)) total"
}
if [ -n "${ENV_FILE:-}" ]; then
log "ENV_FILE secret detected (${#ENV_FILE} chars) β€” loading embedded environment"
load_env_document "$ENV_FILE"
else
log "ENV_FILE secret not set β€” falling back to .env files (local dev) / platform env (HF Secrets)"
[ -f ".env" ] && log ".env file present β€” pydantic-settings will load it" || log "no .env file β€” using process environment"
fi
_crit_missing=""
for _v in APPLICATION_MAIN_BACKEND_AUTH_TOKEN REDIS_URL PINECONE_API_KEYS; do
[ -n "${!_v:-}" ] || _crit_missing="$_crit_missing $_v"
done
if [ -n "$_crit_missing" ]; then
log "WARNING: keys not set:$_crit_missing (app still boots; /chat degrades without Pinecone/Redis)"
else
log "Critical keys: all present"
fi
unset _crit_missing _v
log "=== Starting up ==="
log "Python: $(python --version 2>&1)"
log "Working dir: $(pwd)"
mkdir -p "${STORAGE_DIR:-/app/storage}" /app/storage
log "Storage directories: OK"
python -c "import fastapi, uvicorn, httpx, pydantic" 2>/dev/null \
&& log "Core dependencies: OK" \
|| { log "ERROR: missing core dependencies (fastapi/uvicorn/httpx/pydantic)"; exit 1; }
HOST="${HOST:-0.0.0.0}"
PORT="${PORT:-7860}"
log "Self-ping: SELF_PING_ENABLED=${SELF_PING_ENABLED:-true} SELF_PING_URL=${SELF_PING_URL:-'(derived from SPACE_ID)'} interval=${SELF_PING_INTERVAL:-600}s"
_cron_base="${FRONTEND_BASE_URL:-'(missing)'}"
_cron_secret_state="missing"; [ -n "${CRON_SECRET:-}" ] && _cron_secret_state="set"
_cron_v1_state="missing"; [ -n "${EXTERNAL_API_CRON_TOKEN:-}" ] && _cron_v1_state="set"
log "Frontend credit crons: CRON_ENABLED=${CRON_ENABLED:-true} CRON_TIMEZONE=${CRON_TIMEZONE:-'(system)'} FRONTEND_BASE_URL=${_cron_base} /api/cron(${_cron_secret_state}) /api/v1/cron(${_cron_v1_state}) daily=00:00"
unset _cron_base _cron_secret_state _cron_v1_state
log "Starting uvicorn: host=$HOST port=$PORT workers=1 app=app.main:app"
exec python -m uvicorn app.main:app --host "$HOST" --port "$PORT" --workers 1