#!/usr/bin/env bash set -euo pipefail export PORT="${PORT:-7860}" export API_PORT="${API_PORT:-7860}" export DATABASE_URL="${DATABASE_URL:-postgresql+psycopg://docqa:docqa@127.0.0.1:5432/docqa}" export REDIS_URL="${REDIS_URL:-redis://127.0.0.1:6379/0}" # Force local Ollama mode in Hugging Face Space. export OPENAI_BASE_URL="${OPENAI_BASE_URL:-}" export OPENAI_API_KEY="${OPENAI_API_KEY:-}" export OPENAI_MODEL="${OPENAI_MODEL:-}" export LOCAL_LLM_BASE_URL="${LOCAL_LLM_BASE_URL:-http://127.0.0.1:11434/v1}" export LOCAL_LLM_API_KEY="${LOCAL_LLM_API_KEY:-ollama}" export LOCAL_LLM_MODEL="${LOCAL_LLM_MODEL:-qwen3:0.6b}" export OLLAMA_HOST="${OLLAMA_HOST:-127.0.0.1:11434}" export OLLAMA_MODELS="${OLLAMA_MODELS:-/opt/ollama/models}" export OLLAMA_KEEP_ALIVE="${OLLAMA_KEEP_ALIVE:-5m}" export OLLAMA_NUM_PARALLEL="${OLLAMA_NUM_PARALLEL:-1}" export OPENAI_TIMEOUT_SECONDS="${OPENAI_TIMEOUT_SECONDS:-360}" export LLM_TRACE_ENABLED="${LLM_TRACE_ENABLED:-true}" export LLM_TRACE_MAX_CHARS="${LLM_TRACE_MAX_CHARS:-20000}" export CHUNK_VERIFICATION_TRACE_ENABLED="${CHUNK_VERIFICATION_TRACE_ENABLED:-true}" export CHUNK_VERIFICATION_MAX_WINDOWS="${CHUNK_VERIFICATION_MAX_WINDOWS:-4}" export EMBEDDING_MODEL="${EMBEDDING_MODEL:-infgrad/Jasper-Token-Compression-600M}" export EMBEDDING_DEVICE="${EMBEDDING_DEVICE:-cpu}" export EMBEDDING_BATCH_SIZE="${EMBEDDING_BATCH_SIZE:-2}" export EMBEDDING_TRUST_REMOTE_CODE="${EMBEDDING_TRUST_REMOTE_CODE:-true}" # Avoid duplicate migrations because this script runs alembic explicitly. export RUN_MIGRATIONS_ON_START=false cleanup() { echo "Stopping background services..." jobs -p | xargs -r kill || true } trap cleanup EXIT POSTGRES_VERSION="$(ls /etc/postgresql | sort -V | tail -n 1)" echo "Starting PostgreSQL..." pg_ctlcluster "${POSTGRES_VERSION}" main start || true su postgres -c "psql -tc \"SELECT 1 FROM pg_roles WHERE rolname='docqa'\" | grep -q 1 || psql -c \"CREATE USER docqa WITH PASSWORD 'docqa';\"" su postgres -c "psql -tc \"SELECT 1 FROM pg_database WHERE datname='docqa'\" | grep -q 1 || createdb -O docqa docqa" su postgres -c "psql -c \"ALTER USER postgres WITH PASSWORD 'postgres';\"" su postgres -c "psql -c \"ALTER USER docqa WITH PASSWORD 'docqa';\"" su postgres -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE docqa TO docqa;\"" echo "Starting Redis..." redis-server --daemonize yes --bind 127.0.0.1 --port 6379 --save '' --appendonly no echo "Starting Ollama..." ollama serve > /tmp/ollama.log 2>&1 & OLLAMA_PID=$! echo "Waiting for Ollama API..." for i in $(seq 1 120); do if curl -fsS "http://127.0.0.1:11434/api/tags" >/dev/null 2>&1; then echo "Ollama API is ready." break fi if ! kill -0 "$OLLAMA_PID" >/dev/null 2>&1; then echo "Ollama exited early. Logs:" cat /tmp/ollama.log || true exit 1 fi sleep 1 done if ! curl -fsS "http://127.0.0.1:11434/api/tags" >/dev/null 2>&1; then echo "Ollama did not become ready. Logs:" cat /tmp/ollama.log || true exit 1 fi if ! ollama list | awk 'NR > 1 {print $1}' | grep -Fx "${LOCAL_LLM_MODEL}" >/dev/null 2>&1; then echo "Model ${LOCAL_LLM_MODEL} not found; pulling at runtime..." ollama pull "${LOCAL_LLM_MODEL}" fi echo "Testing Ollama OpenAI-compatible endpoint..." curl -fsS "http://127.0.0.1:11434/v1/chat/completions" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"${LOCAL_LLM_MODEL}\", \"messages\": [{\"role\": \"user\", \"content\": \"Reply exactly: OLLAMA_OK /no_think\"}], \"max_tokens\": 32, \"stream\": false }" >/tmp/ollama-smoke.json || { echo "Ollama smoke test failed." cat /tmp/ollama.log || true cat /tmp/ollama-smoke.json || true exit 1 } tail -n +1 -F /tmp/ollama.log | sed -u 's/^/[ollama] /' & OLLAMA_LOG_TAIL_PID=$! echo "Ollama smoke test passed." echo "Running database migrations..." alembic upgrade head echo "Starting Celery worker..." ./scripts/start-worker.sh & echo "Starting FastAPI..." exec ./scripts/start-api.sh