Download entrypoint.sh from Nerdur/Cowagent: direct link, hf CLI and curl.
- Browser
- Download file 5.84 kB
-
https://huggingface.co/spaces/Nerdur/Cowagent/resolve/main/entrypoint.sh
- Command line
-
hf download hf://spaces/Nerdur/Cowagent/entrypoint.sh
-
curl -L -o entrypoint.sh https://huggingface.co/spaces/Nerdur/Cowagent/resolve/main/entrypoint.sh
5.84 kB
| # ββ CowAgent entrypoint for Hugging Face Spaces βββββββββββββββββββββββββββββββ | |
| # Reads env vars (set as Secrets in HF Space settings) and writes config.json, | |
| # then launches the app on port 7860 (required by HF Spaces). | |
| set -e | |
| cd /app | |
| WORKSPACE="${AGENT_WORKSPACE:-/data/cow}" | |
| CONFIG_PATH="${WORKSPACE}/config.json" | |
| mkdir -p "${WORKSPACE}" | |
| # ββ Build config.json from environment variables ββββββββββββββββββββββββββββββ | |
| python3 - <<PYEOF | |
| import json, os | |
| workspace = os.environ.get("AGENT_WORKSPACE", "/data/cow") | |
| cfg_path = os.path.join(workspace, "config.json") | |
| # Load existing config so user tweaks survive restarts | |
| if os.path.exists(cfg_path): | |
| with open(cfg_path) as f: | |
| cfg = json.load(f) | |
| else: | |
| cfg = {} | |
| def env(key, default=""): | |
| return os.environ.get(key, default) | |
| # ββ Model / API keys ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| cfg.setdefault("model", env("MODEL", "gpt-4o-mini")) | |
| if env("OPEN_AI_API_KEY"): | |
| cfg["open_ai_api_key"] = env("OPEN_AI_API_KEY") | |
| cfg["open_ai_api_base"] = env("OPEN_AI_API_BASE", "https://api.openai.com/v1") | |
| if env("CLAUDE_API_KEY"): | |
| cfg["claude_api_key"] = env("CLAUDE_API_KEY") | |
| cfg["claude_api_base"] = env("CLAUDE_API_BASE", "https://api.anthropic.com/v1") | |
| if env("DEEPSEEK_API_KEY"): | |
| cfg["deepseek_api_key"] = env("DEEPSEEK_API_KEY") | |
| cfg["deepseek_api_base"] = env("DEEPSEEK_API_BASE", "https://api.deepseek.com/v1") | |
| if env("GEMINI_API_KEY"): | |
| cfg["gemini_api_key"] = env("GEMINI_API_KEY") | |
| cfg["gemini_api_base"] = env("GEMINI_API_BASE", "https://generativelanguage.googleapis.com") | |
| if env("QWEN_API_KEY"): | |
| cfg["dashscope_api_key"] = env("QWEN_API_KEY") | |
| if env("ZHIPU_API_KEY"): | |
| cfg["zhipu_ai_api_key"] = env("ZHIPU_API_KEY") | |
| if env("LINKAI_API_KEY"): | |
| cfg["use_linkai"] = True | |
| cfg["linkai_api_key"] = env("LINKAI_API_KEY") | |
| cfg["linkai_app_code"] = env("LINKAI_APP_CODE", "") | |
| # ββ Web console settings ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # HF Spaces requires port 7860; "0.0.0.0" makes it reachable externally | |
| cfg["channel_type"] = "web" | |
| cfg["web_host"] = "0.0.0.0" | |
| cfg["web_port"] = 7860 | |
| cfg["web_console"] = True | |
| if env("WEB_PASSWORD"): | |
| cfg["web_password"] = env("WEB_PASSWORD") | |
| # ββ Agent settings ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| cfg["agent"] = env("AGENT_ENABLED", "true").lower() not in ("false", "0", "no") | |
| cfg["agent_workspace"] = workspace | |
| cfg["agent_max_steps"] = int(env("AGENT_MAX_STEPS", "20")) | |
| cfg.setdefault("knowledge", True) | |
| cfg.setdefault("self_evolution_enabled", False) # off by default in cloud env | |
| cfg.setdefault("cow_lang", env("COW_LANG", "auto")) | |
| with open(cfg_path, "w") as f: | |
| json.dump(cfg, f, indent=2, ensure_ascii=False) | |
| print(f"[entrypoint] Config written to {cfg_path}") | |
| print(f"[entrypoint] Model: {cfg.get('model')}") | |
| print(f"[entrypoint] Web console: http://0.0.0.0:{cfg['web_port']}") | |
| PYEOF | |
| # ββ Symlink config to app root (CowAgent looks here) βββββββββββββββββββββββββ | |
| ln -sf "${CONFIG_PATH}" /app/config.json | |
| # ββ Apply mobile responsiveness CSS patch (idempotent) ββββββββββββββββββββββββ | |
| CHAT_HTML="/app/channel/web/chat.html" | |
| WEB_CHANNEL_PY="/app/channel/web/web_channel.py" | |
| MOBILE_CSS_LINK='<link rel="stylesheet" href="assets/css/mobile-fix.css">' | |
| if [ -f "${CHAT_HTML}" ]; then | |
| cp -f /app/mobile-fix.css /app/channel/web/static/css/mobile-fix.css | |
| if ! grep -q "mobile-fix.css" "${CHAT_HTML}"; then | |
| # Insert the stylesheet link right before </head>, after console.css | |
| # so our !important rules load last and win on cascade order too. | |
| sed -i "s|</head>| ${MOBILE_CSS_LINK}\n</head>|" "${CHAT_HTML}" | |
| echo "[entrypoint] Mobile CSS patch link injected into chat.html" | |
| else | |
| echo "[entrypoint] Mobile CSS patch link already present, file refreshed" | |
| fi | |
| else | |
| echo "[entrypoint] WARNING: ${CHAT_HTML} not found, mobile CSS patch skipped" | |
| fi | |
| # Make sure mobile-fix.css also gets the same cache-busting query param as | |
| # console.css/console.js, so browsers never serve a stale cached copy after | |
| # we update the file on a redeploy. | |
| if [ -f "${WEB_CHANNEL_PY}" ] && ! grep -q "mobile-fix.css'," "${WEB_CHANNEL_PY}"; then | |
| python3 - <<'PYEOF' | |
| path = "/app/channel/web/web_channel.py" | |
| with open(path, "r", encoding="utf-8") as f: | |
| content = f.read() | |
| marker = "html = html.replace('assets/css/console.css', f'assets/css/console.css?v={cache_bust}')" | |
| addition = "\n html = html.replace('assets/css/mobile-fix.css', f'assets/css/mobile-fix.css?v={cache_bust}')" | |
| if marker in content and "mobile-fix.css', f'assets/css/mobile-fix.css" not in content: | |
| content = content.replace(marker, marker + addition, 1) | |
| with open(path, "w", encoding="utf-8") as f: | |
| f.write(content) | |
| print("[entrypoint] Cache-busting patch applied to web_channel.py") | |
| else: | |
| print("[entrypoint] Cache-busting patch not applicable or already present") | |
| PYEOF | |
| fi | |
| # ββ Start CowAgent ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| echo "[entrypoint] Starting CowAgent..." | |
| exec python3 /app/app.py | |