Update start-hf.sh
Browse files- start-hf.sh +13 -43
start-hf.sh
CHANGED
|
@@ -1,32 +1,35 @@
|
|
| 1 |
#!/usr/bin/env bash
|
| 2 |
set -euo pipefail
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
OPENAI_API_KEY="${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
|
| 7 |
-
:-${key:-}}"
|
| 8 |
SPACE_PASSWORD="${PASSWORD:-${password:-}}"
|
| 9 |
PORT="${PORT:-7860}"
|
| 10 |
-
|
| 11 |
if [ -z "${OPENAI_API_KEY}" ]; then
|
| 12 |
echo "OPENAI_API_KEY is required"
|
| 13 |
exit 1
|
| 14 |
fi
|
| 15 |
-
|
| 16 |
export OPENAI_API_KEY
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
PERSIST_ROOT="${DEER_FLOW_HOME:-/data/deer-flow}"
|
| 19 |
if ! mkdir -p "${PERSIST_ROOT}" 2>/dev/null; then
|
| 20 |
PERSIST_ROOT="/app/backend/.deer-flow"
|
| 21 |
mkdir -p "${PERSIST_ROOT}"
|
| 22 |
fi
|
| 23 |
-
|
| 24 |
export DEER_FLOW_HOME="${PERSIST_ROOT}"
|
| 25 |
export DEER_FLOW_EXTENSIONS_CONFIG_PATH="${DEER_FLOW_EXTENSIONS_CONFIG_PATH:-${DEER_FLOW_HOME}/extensions_config.json}"
|
| 26 |
export LANGGRAPH_CHECKPOINT_SQLITE_PATH="${LANGGRAPH_CHECKPOINT_SQLITE_PATH:-${DEER_FLOW_HOME}/checkpoints.sqlite}"
|
| 27 |
export DEER_FLOW_MEMORY_PATH="${DEER_FLOW_MEMORY_PATH:-${DEER_FLOW_HOME}/memory.json}"
|
| 28 |
export DEER_FLOW_SKILLS_PATH="${DEER_FLOW_SKILLS_PATH:-${DEER_FLOW_HOME}/skills}"
|
| 29 |
-
|
| 30 |
mkdir -p /app/logs "${DEER_FLOW_HOME}"
|
| 31 |
if [ ! -f "${DEER_FLOW_EXTENSIONS_CONFIG_PATH}" ]; then
|
| 32 |
cp /app/extensions_config.example.json "${DEER_FLOW_EXTENSIONS_CONFIG_PATH}"
|
|
@@ -34,24 +37,19 @@ fi
|
|
| 34 |
if [ ! -d "${DEER_FLOW_SKILLS_PATH}" ]; then
|
| 35 |
cp -R /app/skills "${DEER_FLOW_SKILLS_PATH}"
|
| 36 |
fi
|
| 37 |
-
|
| 38 |
# Resolve env placeholders in extensions config and disable invalid MCP servers.
|
| 39 |
python3 - "${DEER_FLOW_EXTENSIONS_CONFIG_PATH}" <<'PY'
|
| 40 |
import json
|
| 41 |
import os
|
| 42 |
import sys
|
| 43 |
from pathlib import Path
|
| 44 |
-
|
| 45 |
config_path = Path(sys.argv[1])
|
| 46 |
if not config_path.exists():
|
| 47 |
raise SystemExit(0)
|
| 48 |
-
|
| 49 |
try:
|
| 50 |
config = json.loads(config_path.read_text(encoding="utf-8"))
|
| 51 |
except Exception:
|
| 52 |
raise SystemExit(0)
|
| 53 |
-
|
| 54 |
-
|
| 55 |
def sanitize(node, missing_vars):
|
| 56 |
if isinstance(node, str) and node.startswith("$"):
|
| 57 |
env_name = node[1:]
|
|
@@ -65,8 +63,6 @@ def sanitize(node, missing_vars):
|
|
| 65 |
if isinstance(node, list):
|
| 66 |
return [sanitize(value, missing_vars) for value in node]
|
| 67 |
return node
|
| 68 |
-
|
| 69 |
-
|
| 70 |
mcp_servers = config.get("mcpServers")
|
| 71 |
if isinstance(mcp_servers, dict):
|
| 72 |
for name, server_config in list(mcp_servers.items()):
|
|
@@ -80,17 +76,13 @@ if isinstance(mcp_servers, dict):
|
|
| 80 |
f"Disabled MCP server '{name}' due to missing env vars: {', '.join(sorted(missing))}"
|
| 81 |
)
|
| 82 |
mcp_servers[name] = sanitized_server
|
| 83 |
-
|
| 84 |
for key, value in list(config.items()):
|
| 85 |
if key == "mcpServers":
|
| 86 |
continue
|
| 87 |
config[key] = sanitize(value, set())
|
| 88 |
-
|
| 89 |
config_path.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8")
|
| 90 |
PY
|
| 91 |
-
|
| 92 |
touch /app/.env /app/backend/.env /app/frontend/.env
|
| 93 |
-
|
| 94 |
if [ -n "${SPACE_PASSWORD}" ]; then
|
| 95 |
password_hash="$(openssl passwd -apr1 "${SPACE_PASSWORD}")"
|
| 96 |
printf "admin:%s\n" "${password_hash}" >/tmp/.htpasswd
|
|
@@ -101,7 +93,6 @@ EOF
|
|
| 101 |
else
|
| 102 |
: >/tmp/nginx.auth.conf
|
| 103 |
fi
|
| 104 |
-
|
| 105 |
cat >/app/config.yaml <<EOF
|
| 106 |
models:
|
| 107 |
- name: default
|
|
@@ -113,77 +104,59 @@ models:
|
|
| 113 |
max_tokens: 4096
|
| 114 |
temperature: 0.7
|
| 115 |
supports_vision: true
|
| 116 |
-
|
| 117 |
tool_groups:
|
| 118 |
- name: web
|
| 119 |
- name: file:read
|
| 120 |
- name: file:write
|
| 121 |
- name: bash
|
| 122 |
-
|
| 123 |
tools:
|
| 124 |
- name: web_search
|
| 125 |
group: web
|
| 126 |
use: src.community.tavily.tools:web_search_tool
|
| 127 |
max_results: 5
|
| 128 |
-
|
| 129 |
- name: web_fetch
|
| 130 |
group: web
|
| 131 |
use: src.community.jina_ai.tools:web_fetch_tool
|
| 132 |
timeout: 10
|
| 133 |
-
|
| 134 |
- name: image_search
|
| 135 |
group: web
|
| 136 |
use: src.community.image_search.tools:image_search_tool
|
| 137 |
max_results: 5
|
| 138 |
-
|
| 139 |
- name: agent_browser
|
| 140 |
group: web
|
| 141 |
use: src.community.agent_browser.tools:agent_browser_tool
|
| 142 |
-
|
| 143 |
- name: ls
|
| 144 |
group: file:read
|
| 145 |
use: src.sandbox.tools:ls_tool
|
| 146 |
-
|
| 147 |
- name: read_file
|
| 148 |
group: file:read
|
| 149 |
use: src.sandbox.tools:read_file_tool
|
| 150 |
-
|
| 151 |
- name: write_file
|
| 152 |
group: file:write
|
| 153 |
use: src.sandbox.tools:write_file_tool
|
| 154 |
-
|
| 155 |
- name: str_replace
|
| 156 |
group: file:write
|
| 157 |
use: src.sandbox.tools:str_replace_tool
|
| 158 |
-
|
| 159 |
- name: bash
|
| 160 |
group: bash
|
| 161 |
use: src.sandbox.tools:bash_tool
|
| 162 |
-
|
| 163 |
skills:
|
| 164 |
path: ${DEER_FLOW_SKILLS_PATH}
|
| 165 |
container_path: /mnt/skills
|
| 166 |
-
|
| 167 |
memory:
|
| 168 |
enabled: true
|
| 169 |
storage_path: ${DEER_FLOW_MEMORY_PATH}
|
| 170 |
-
|
| 171 |
sandbox:
|
| 172 |
use: src.sandbox.local:LocalSandboxProvider
|
| 173 |
EOF
|
| 174 |
-
|
| 175 |
sed "s/__PORT__/${PORT}/g" /app/hf.nginx.conf >/tmp/nginx.conf
|
| 176 |
-
|
| 177 |
pids=()
|
| 178 |
-
|
| 179 |
cleanup() {
|
| 180 |
for pid in "${pids[@]:-}"; do
|
| 181 |
kill "$pid" 2>/dev/null || true
|
| 182 |
done
|
| 183 |
}
|
| 184 |
-
|
| 185 |
trap cleanup SIGINT SIGTERM
|
| 186 |
-
|
| 187 |
start_service() {
|
| 188 |
local name="$1"
|
| 189 |
local logfile="$2"
|
|
@@ -193,17 +166,14 @@ start_service() {
|
|
| 193 |
) &
|
| 194 |
pids+=("$!")
|
| 195 |
}
|
| 196 |
-
|
| 197 |
start_service "langgraph" "/app/logs/langgraph.log" "cd /app/backend && NO_COLOR=1 DEER_FLOW_CONFIG_PATH=/app/config.yaml /root/.local/bin/uv run langgraph dev --no-browser --allow-blocking --no-reload --host 0.0.0.0 --port 2024"
|
| 198 |
start_service "gateway" "/app/logs/gateway.log" "cd /app/backend && DEER_FLOW_CONFIG_PATH=/app/config.yaml /root/.local/bin/uv run uvicorn src.gateway.app:app --host 0.0.0.0 --port 8001"
|
| 199 |
start_service "frontend" "/app/logs/frontend.log" "cd /app/frontend && SKIP_ENV_VALIDATION=1 pnpm exec next start -H 0.0.0.0 -p 3000"
|
| 200 |
start_service "nginx" "/app/logs/nginx.log" "cd /app && nginx -g 'daemon off;' -c /tmp/nginx.conf"
|
| 201 |
-
|
| 202 |
set +e
|
| 203 |
wait -n "${pids[@]}"
|
| 204 |
status=$?
|
| 205 |
set -e
|
| 206 |
-
|
| 207 |
cleanup
|
| 208 |
wait || true
|
| 209 |
-
exit "$status"
|
|
|
|
| 1 |
#!/usr/bin/env bash
|
| 2 |
set -euo pipefail
|
| 3 |
+
OPENAI_BASE_URL="${OPENAI_BASE_URL:-${url:-https://api.openai.com/v1}}"
|
| 4 |
+
OPENAI_MODEL="${OPENAI_MODEL:-${model:-gpt-5.1}}"
|
| 5 |
+
OPENAI_API_KEY="${OPENAI_API_KEY:-${key:-}}"
|
|
|
|
|
|
|
| 6 |
SPACE_PASSWORD="${PASSWORD:-${password:-}}"
|
| 7 |
PORT="${PORT:-7860}"
|
|
|
|
| 8 |
if [ -z "${OPENAI_API_KEY}" ]; then
|
| 9 |
echo "OPENAI_API_KEY is required"
|
| 10 |
exit 1
|
| 11 |
fi
|
|
|
|
| 12 |
export OPENAI_API_KEY
|
| 13 |
|
| 14 |
+
# === DEBUG ===
|
| 15 |
+
echo "=== DEBUG: OPENAI_BASE_URL=${OPENAI_BASE_URL}"
|
| 16 |
+
echo "=== DEBUG: OPENAI_MODEL=${OPENAI_MODEL}"
|
| 17 |
+
echo "=== DEBUG: API_KEY_PREFIX=${OPENAI_API_KEY:0:8}..."
|
| 18 |
+
curl -s -o /dev/null -w "=== DEBUG: API reachable HTTP status: %{http_code}\n" \
|
| 19 |
+
"${OPENAI_BASE_URL}/models" \
|
| 20 |
+
-H "Authorization: Bearer ${OPENAI_API_KEY}" || echo "=== DEBUG: curl FAILED entirely"
|
| 21 |
+
# === END DEBUG ===
|
| 22 |
+
|
| 23 |
PERSIST_ROOT="${DEER_FLOW_HOME:-/data/deer-flow}"
|
| 24 |
if ! mkdir -p "${PERSIST_ROOT}" 2>/dev/null; then
|
| 25 |
PERSIST_ROOT="/app/backend/.deer-flow"
|
| 26 |
mkdir -p "${PERSIST_ROOT}"
|
| 27 |
fi
|
|
|
|
| 28 |
export DEER_FLOW_HOME="${PERSIST_ROOT}"
|
| 29 |
export DEER_FLOW_EXTENSIONS_CONFIG_PATH="${DEER_FLOW_EXTENSIONS_CONFIG_PATH:-${DEER_FLOW_HOME}/extensions_config.json}"
|
| 30 |
export LANGGRAPH_CHECKPOINT_SQLITE_PATH="${LANGGRAPH_CHECKPOINT_SQLITE_PATH:-${DEER_FLOW_HOME}/checkpoints.sqlite}"
|
| 31 |
export DEER_FLOW_MEMORY_PATH="${DEER_FLOW_MEMORY_PATH:-${DEER_FLOW_HOME}/memory.json}"
|
| 32 |
export DEER_FLOW_SKILLS_PATH="${DEER_FLOW_SKILLS_PATH:-${DEER_FLOW_HOME}/skills}"
|
|
|
|
| 33 |
mkdir -p /app/logs "${DEER_FLOW_HOME}"
|
| 34 |
if [ ! -f "${DEER_FLOW_EXTENSIONS_CONFIG_PATH}" ]; then
|
| 35 |
cp /app/extensions_config.example.json "${DEER_FLOW_EXTENSIONS_CONFIG_PATH}"
|
|
|
|
| 37 |
if [ ! -d "${DEER_FLOW_SKILLS_PATH}" ]; then
|
| 38 |
cp -R /app/skills "${DEER_FLOW_SKILLS_PATH}"
|
| 39 |
fi
|
|
|
|
| 40 |
# Resolve env placeholders in extensions config and disable invalid MCP servers.
|
| 41 |
python3 - "${DEER_FLOW_EXTENSIONS_CONFIG_PATH}" <<'PY'
|
| 42 |
import json
|
| 43 |
import os
|
| 44 |
import sys
|
| 45 |
from pathlib import Path
|
|
|
|
| 46 |
config_path = Path(sys.argv[1])
|
| 47 |
if not config_path.exists():
|
| 48 |
raise SystemExit(0)
|
|
|
|
| 49 |
try:
|
| 50 |
config = json.loads(config_path.read_text(encoding="utf-8"))
|
| 51 |
except Exception:
|
| 52 |
raise SystemExit(0)
|
|
|
|
|
|
|
| 53 |
def sanitize(node, missing_vars):
|
| 54 |
if isinstance(node, str) and node.startswith("$"):
|
| 55 |
env_name = node[1:]
|
|
|
|
| 63 |
if isinstance(node, list):
|
| 64 |
return [sanitize(value, missing_vars) for value in node]
|
| 65 |
return node
|
|
|
|
|
|
|
| 66 |
mcp_servers = config.get("mcpServers")
|
| 67 |
if isinstance(mcp_servers, dict):
|
| 68 |
for name, server_config in list(mcp_servers.items()):
|
|
|
|
| 76 |
f"Disabled MCP server '{name}' due to missing env vars: {', '.join(sorted(missing))}"
|
| 77 |
)
|
| 78 |
mcp_servers[name] = sanitized_server
|
|
|
|
| 79 |
for key, value in list(config.items()):
|
| 80 |
if key == "mcpServers":
|
| 81 |
continue
|
| 82 |
config[key] = sanitize(value, set())
|
|
|
|
| 83 |
config_path.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8")
|
| 84 |
PY
|
|
|
|
| 85 |
touch /app/.env /app/backend/.env /app/frontend/.env
|
|
|
|
| 86 |
if [ -n "${SPACE_PASSWORD}" ]; then
|
| 87 |
password_hash="$(openssl passwd -apr1 "${SPACE_PASSWORD}")"
|
| 88 |
printf "admin:%s\n" "${password_hash}" >/tmp/.htpasswd
|
|
|
|
| 93 |
else
|
| 94 |
: >/tmp/nginx.auth.conf
|
| 95 |
fi
|
|
|
|
| 96 |
cat >/app/config.yaml <<EOF
|
| 97 |
models:
|
| 98 |
- name: default
|
|
|
|
| 104 |
max_tokens: 4096
|
| 105 |
temperature: 0.7
|
| 106 |
supports_vision: true
|
|
|
|
| 107 |
tool_groups:
|
| 108 |
- name: web
|
| 109 |
- name: file:read
|
| 110 |
- name: file:write
|
| 111 |
- name: bash
|
|
|
|
| 112 |
tools:
|
| 113 |
- name: web_search
|
| 114 |
group: web
|
| 115 |
use: src.community.tavily.tools:web_search_tool
|
| 116 |
max_results: 5
|
|
|
|
| 117 |
- name: web_fetch
|
| 118 |
group: web
|
| 119 |
use: src.community.jina_ai.tools:web_fetch_tool
|
| 120 |
timeout: 10
|
|
|
|
| 121 |
- name: image_search
|
| 122 |
group: web
|
| 123 |
use: src.community.image_search.tools:image_search_tool
|
| 124 |
max_results: 5
|
|
|
|
| 125 |
- name: agent_browser
|
| 126 |
group: web
|
| 127 |
use: src.community.agent_browser.tools:agent_browser_tool
|
|
|
|
| 128 |
- name: ls
|
| 129 |
group: file:read
|
| 130 |
use: src.sandbox.tools:ls_tool
|
|
|
|
| 131 |
- name: read_file
|
| 132 |
group: file:read
|
| 133 |
use: src.sandbox.tools:read_file_tool
|
|
|
|
| 134 |
- name: write_file
|
| 135 |
group: file:write
|
| 136 |
use: src.sandbox.tools:write_file_tool
|
|
|
|
| 137 |
- name: str_replace
|
| 138 |
group: file:write
|
| 139 |
use: src.sandbox.tools:str_replace_tool
|
|
|
|
| 140 |
- name: bash
|
| 141 |
group: bash
|
| 142 |
use: src.sandbox.tools:bash_tool
|
|
|
|
| 143 |
skills:
|
| 144 |
path: ${DEER_FLOW_SKILLS_PATH}
|
| 145 |
container_path: /mnt/skills
|
|
|
|
| 146 |
memory:
|
| 147 |
enabled: true
|
| 148 |
storage_path: ${DEER_FLOW_MEMORY_PATH}
|
|
|
|
| 149 |
sandbox:
|
| 150 |
use: src.sandbox.local:LocalSandboxProvider
|
| 151 |
EOF
|
|
|
|
| 152 |
sed "s/__PORT__/${PORT}/g" /app/hf.nginx.conf >/tmp/nginx.conf
|
|
|
|
| 153 |
pids=()
|
|
|
|
| 154 |
cleanup() {
|
| 155 |
for pid in "${pids[@]:-}"; do
|
| 156 |
kill "$pid" 2>/dev/null || true
|
| 157 |
done
|
| 158 |
}
|
|
|
|
| 159 |
trap cleanup SIGINT SIGTERM
|
|
|
|
| 160 |
start_service() {
|
| 161 |
local name="$1"
|
| 162 |
local logfile="$2"
|
|
|
|
| 166 |
) &
|
| 167 |
pids+=("$!")
|
| 168 |
}
|
|
|
|
| 169 |
start_service "langgraph" "/app/logs/langgraph.log" "cd /app/backend && NO_COLOR=1 DEER_FLOW_CONFIG_PATH=/app/config.yaml /root/.local/bin/uv run langgraph dev --no-browser --allow-blocking --no-reload --host 0.0.0.0 --port 2024"
|
| 170 |
start_service "gateway" "/app/logs/gateway.log" "cd /app/backend && DEER_FLOW_CONFIG_PATH=/app/config.yaml /root/.local/bin/uv run uvicorn src.gateway.app:app --host 0.0.0.0 --port 8001"
|
| 171 |
start_service "frontend" "/app/logs/frontend.log" "cd /app/frontend && SKIP_ENV_VALIDATION=1 pnpm exec next start -H 0.0.0.0 -p 3000"
|
| 172 |
start_service "nginx" "/app/logs/nginx.log" "cd /app && nginx -g 'daemon off;' -c /tmp/nginx.conf"
|
|
|
|
| 173 |
set +e
|
| 174 |
wait -n "${pids[@]}"
|
| 175 |
status=$?
|
| 176 |
set -e
|
|
|
|
| 177 |
cleanup
|
| 178 |
wait || true
|
| 179 |
+
exit "$status"
|