144 lines
5.2 KiB
Bash
Executable File
144 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Sync this repo to the talkingbooklet server and reload PM2.
|
|
# Existing .env files on the server are kept. A chat-engine token is
|
|
# created once if the API does not already have one.
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
|
KEY="${DEPLOY_KEY:-$HOME/Documents/Keys/VirtualEngage.pem}"
|
|
HOST="${DEPLOY_HOST:-ubuntu@15.207.15.52}"
|
|
DEST="${DEPLOY_PATH:-/var/www/talkingbooklet}"
|
|
SITE="${DEPLOY_SITE:-https://talkingbooklet.virtualengage.in}"
|
|
|
|
if [[ ! -f "$KEY" ]]; then
|
|
echo "SSH key not found: $KEY" >&2
|
|
exit 1
|
|
fi
|
|
|
|
rsync -rlz --delete --omit-dir-times \
|
|
--no-perms --no-owner --no-group \
|
|
-e "ssh -i ${KEY} -o StrictHostKeyChecking=accept-new" \
|
|
--exclude node_modules \
|
|
--exclude venv \
|
|
--exclude .env \
|
|
--exclude frontend/dist \
|
|
--exclude .git \
|
|
--exclude .DS_Store \
|
|
--exclude __pycache__ \
|
|
--exclude .pytest_cache \
|
|
--exclude '*.pem' \
|
|
"${ROOT}/" "${HOST}:${DEST}/"
|
|
|
|
ENV_KEYS="$(mktemp)"
|
|
python3 - "$ROOT" <<'PY' > "$ENV_KEYS"
|
|
import pathlib, sys
|
|
root = pathlib.Path(sys.argv[1])
|
|
wanted = [
|
|
"BEDROCK_MODEL_CHEAP", "BEDROCK_MODEL_COUNT", "BEDROCK_MODEL_EMBED", "EMBED_DIMENSIONS",
|
|
"OPENSEARCH_INDEX_ALIAS", "OPENSEARCH_INDEX_VERSION", "INGEST_VERSION",
|
|
"MODEL_FULL_CONTEXT", "MODEL_HYBRID", "MODEL_SUMMARIZE_HISTORY", "MODEL_JUDGE",
|
|
"AUTO_FULL_CONTEXT_MAX_TOKENS", "AUTO_PREMIUM_PLANS",
|
|
"AGENT_MAX_ITERATIONS", "AGENT_MAX_TOOL_CALLS", "AGENT_TURN_TIMEOUT_MS",
|
|
"MAX_ANSWER_TOKENS_VOICE", "MAX_ANSWER_TOKENS_CHAT",
|
|
"CACHE_TTL", "CACHE_KEEPALIVE", "CACHE_KEEPALIVE_MAX", "CACHE_MIN_TOKENS",
|
|
"PERSONA", "HISTORY_VERBATIM_TURNS", "HISTORY_TOKEN_BUDGET",
|
|
"TOOL_RESULT_MAX_CHARS", "CHAPTER_RETURN_TOKEN_CAP", "RERANK_MODEL", "PRICE_TABLE_JSON",
|
|
]
|
|
found = {}
|
|
for name in ("ingestion/.env", "chat-engine/.env"):
|
|
path = root / name
|
|
if not path.exists():
|
|
continue
|
|
for line in path.read_text().splitlines():
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
continue
|
|
key, value = line.split("=", 1)
|
|
if key in wanted and value != "":
|
|
found[key] = value
|
|
sys.stdout.write("".join(f"{key}={value}\n" for key, value in found.items()))
|
|
PY
|
|
ssh -i "$KEY" -o StrictHostKeyChecking=accept-new "$HOST" "python3 ${DEST}/deploy/merge_env.py ${DEST}/chat-engine/.env" < "$ENV_KEYS"
|
|
ssh -i "$KEY" -o StrictHostKeyChecking=accept-new "$HOST" "python3 ${DEST}/deploy/merge_env.py ${DEST}/ingestion/.env" < "$ENV_KEYS"
|
|
rm -f "$ENV_KEYS"
|
|
|
|
ssh -i "$KEY" -o StrictHostKeyChecking=accept-new "$HOST" \
|
|
"DEST=$(printf '%q' "$DEST") SITE=$(printf '%q' "$SITE") bash -s" <<'REMOTE'
|
|
set -euo pipefail
|
|
cd "$DEST"
|
|
|
|
npm install
|
|
(cd backend && npm install)
|
|
(cd frontend && npm install && npm run build)
|
|
./ai_agent/venv/bin/pip install -r ai_agent/requirements.txt
|
|
|
|
python3 - <<'PY'
|
|
import os, pathlib, re, secrets
|
|
root = pathlib.Path(os.environ["DEST"])
|
|
backend = (root / "backend" / ".env").read_text()
|
|
match = re.search(r"^CHAT_ENGINE_TOKEN=(.*)$", backend, re.M)
|
|
token = match.group(1).strip() if match and match.group(1).strip() else secrets.token_hex(32)
|
|
|
|
def upsert(text, key, value):
|
|
line = f"{key}={value}"
|
|
pattern = re.compile("^" + re.escape(key) + "=.*$", re.M)
|
|
if pattern.search(text):
|
|
return pattern.sub(line, text, count=1)
|
|
return text.rstrip() + "\n" + line + "\n"
|
|
|
|
site = os.environ["SITE"]
|
|
backend = upsert(backend, "CHAT_ENGINE_URL", "http://127.0.0.1:3001")
|
|
backend = upsert(backend, "CHAT_ENGINE_TOKEN", token)
|
|
backend = upsert(backend, "FRONTEND_ORIGIN", site)
|
|
backend = upsert(backend, "HOST", "127.0.0.1")
|
|
(root / "backend" / ".env").write_text(backend)
|
|
|
|
engine_path = root / "chat-engine" / ".env"
|
|
engine = engine_path.read_text() if engine_path.exists() else ""
|
|
engine = upsert(engine, "CHAT_ENGINE_HOST", "127.0.0.1")
|
|
engine = upsert(engine, "CHAT_ENGINE_PORT", "3001")
|
|
engine = upsert(engine, "CHAT_ENGINE_TOKEN", token)
|
|
engine_path.write_text(engine)
|
|
|
|
agent_path = root / "ai_agent" / ".env"
|
|
agent = agent_path.read_text() if agent_path.exists() else ""
|
|
agent = upsert(agent, "CHAT_ENGINE_URL", "http://127.0.0.1:3001")
|
|
agent = upsert(agent, "CHAT_ENGINE_TOKEN", token)
|
|
agent_path.write_text(agent)
|
|
print("env linked")
|
|
PY
|
|
|
|
sudo python3 - <<'PY'
|
|
from pathlib import Path
|
|
path = Path("/etc/nginx/sites-enabled/virtualpr")
|
|
text = path.read_text()
|
|
needle = "proxy_pass http://127.0.0.1:3000;"
|
|
extra = """proxy_pass http://127.0.0.1:3000;
|
|
proxy_http_version 1.1;
|
|
proxy_buffering off;
|
|
proxy_cache off;
|
|
proxy_read_timeout 300s;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;"""
|
|
idx = text.find(needle)
|
|
nearby = text[idx:idx + 400] if idx >= 0 else ""
|
|
if idx >= 0 and "proxy_buffering off" not in nearby:
|
|
path.write_text(text.replace(needle, extra, 1))
|
|
print("nginx updated")
|
|
else:
|
|
print("nginx already streams /api")
|
|
PY
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
|
|
pm2 startOrReload "$DEST/ecosystem.config.cjs" --only talkingbooklet-engine
|
|
pm2 startOrReload "$DEST/ecosystem.config.cjs" --only talkingbooklet-api
|
|
pm2 startOrReload "$DEST/ecosystem.config.cjs" --only talkingbooklet-agent
|
|
pm2 save
|
|
|
|
sleep 2
|
|
curl -fsS http://127.0.0.1:3001/health
|
|
echo
|
|
curl -fsS http://127.0.0.1:3000/
|
|
echo
|
|
REMOTE
|