dboa9 commited on
Commit
e787148
·
1 Parent(s): 9a86887
Files changed (5) hide show
  1. Dockerfile +21 -5
  2. README.md +13 -2
  3. app.py +66 -22
  4. requirements.txt +2 -1
  5. start.sh +18 -1
Dockerfile CHANGED
@@ -1,8 +1,7 @@
1
  # Moltbot Hybrid Engine - Multi-service Dockerfile
2
- # Runs: FastAPI (port 7860) + Ollama (optional, background)
3
- # Build: 2026-02-08 v6.0
4
  # FIX v6: Dual LLM backend - Ollama (if available) + HF Inference API fallback
5
- # HF Inference API works on Free tier without GPU/Ollama
6
 
7
  FROM python:3.11-slim
8
 
@@ -15,9 +14,22 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
15
  git \
16
  git-lfs \
17
  file \
 
18
  && apt-get clean \
19
  && rm -rf /var/lib/apt/lists/*
20
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  # Install Ollama AS ROOT - pinned version, force amd64
22
  # Using pinned version URL to avoid redirect issues during Docker build
23
  # Mark as OPTIONAL - app works without it via HF Inference API fallback
@@ -52,14 +64,18 @@ RUN pip install --no-cache-dir --upgrade pip
52
  # Copy all files with correct ownership
53
  COPY --chown=user . /app
54
 
 
 
 
 
55
  # Install Python dependencies (includes huggingface_hub for Inference API)
56
  RUN pip install --no-cache-dir -r requirements.txt
57
 
58
  # Make start script executable
59
  RUN chmod +x start.sh
60
 
61
- # Expose HF Spaces port
62
- EXPOSE 7860
63
 
64
  # CMD required (not ENTRYPOINT) for dev mode compatibility
65
  CMD ["./start.sh"]
 
1
  # Moltbot Hybrid Engine - Multi-service Dockerfile
2
+ # Runs: FastAPI (port 7860) + Ollama (optional) + OpenClaw/Clawdbot gateway (port 18789)
3
+ # Build: 2026-02-14 v7.0 — Add Clawdbot (OpenClaw) for autonomous agent in HF Space
4
  # FIX v6: Dual LLM backend - Ollama (if available) + HF Inference API fallback
 
5
 
6
  FROM python:3.11-slim
7
 
 
14
  git \
15
  git-lfs \
16
  file \
17
+ ca-certificates \
18
  && apt-get clean \
19
  && rm -rf /var/lib/apt/lists/*
20
 
21
+ # Install Node.js 22 (required for OpenClaw/Clawdbot)
22
+ RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
23
+ && apt-get install -y nodejs \
24
+ && apt-get clean \
25
+ && rm -rf /var/lib/apt/lists/* \
26
+ && node -v \
27
+ && npm -v
28
+
29
+ # Install OpenClaw (Clawdbot) globally so gateway can run in Space
30
+ RUN npm install -g openclaw@latest \
31
+ && (command -v openclaw || true)
32
+
33
  # Install Ollama AS ROOT - pinned version, force amd64
34
  # Using pinned version URL to avoid redirect issues during Docker build
35
  # Mark as OPTIONAL - app works without it via HF Inference API fallback
 
64
  # Copy all files with correct ownership
65
  COPY --chown=user . /app
66
 
67
+ # OpenClaw/Clawdbot: minimal config so gateway starts without interactive onboarding
68
+ RUN mkdir -p /home/user/.openclaw/workspace
69
+ COPY --chown=user openclaw.json /home/user/.openclaw/openclaw.json
70
+
71
  # Install Python dependencies (includes huggingface_hub for Inference API)
72
  RUN pip install --no-cache-dir -r requirements.txt
73
 
74
  # Make start script executable
75
  RUN chmod +x start.sh
76
 
77
+ # Expose HF Spaces port (7860) and OpenClaw gateway (18789, internal)
78
+ EXPOSE 7860 18789
79
 
80
  # CMD required (not ENTRYPOINT) for dev mode compatibility
81
  CMD ["./start.sh"]
README.md CHANGED
@@ -9,9 +9,9 @@ app_port: 7860
9
  ---
10
 
11
  # Moltbot Hybrid Engine
12
- Safe AI agent for legal document processing - Dual LLM backend + file matching + analysis.
13
 
14
- **Version 6.0.0** - Last updated: 2026-02-08
15
 
16
  ## Required Space Secrets
17
 
@@ -26,3 +26,14 @@ Set these in Space Settings > Repository secrets:
26
 
27
  1. **Ollama** (local in container) - runs qwen2.5:1.5b if binary installs correctly
28
  2. **HF Inference API** (fallback) - uses Qwen/Qwen2.5-7B-Instruct hosted by HuggingFace (requires HF_TOKEN)
 
 
 
 
 
 
 
 
 
 
 
 
9
  ---
10
 
11
  # Moltbot Hybrid Engine
12
+ Safe AI agent for legal document processing - Dual LLM backend + file matching + **Clawdbot (OpenClaw)** in the Space.
13
 
14
+ **Version 7.0.0** - Last updated: 2026-02-14 — Clawdbot installed; gateway runs on port 18789, proxied at `/gateway`
15
 
16
  ## Required Space Secrets
17
 
 
26
 
27
  1. **Ollama** (local in container) - runs qwen2.5:1.5b if binary installs correctly
28
  2. **HF Inference API** (fallback) - uses Qwen/Qwen2.5-7B-Instruct hosted by HuggingFace (requires HF_TOKEN)
29
+
30
+ ## Clawdbot (OpenClaw) in this Space
31
+
32
+ OpenClaw/Clawdbot is **installed and started** in this Space so you can use the autonomous agent with Qwen and Claude.
33
+
34
+ - **Control UI / WebChat:** After the Space is running, open: **`https://<your-space>.hf.space/gateway`**
35
+ - The gateway runs internally on port 18789; the FastAPI app proxies `/gateway` and `/gateway/*` to it so a single Space port (7860) serves both the API and Clawdbot.
36
+ - **To get autonomous behaviour** (Clawdbot working on court bundle changes with Qwen/Claude):
37
+ 1. Open the Control UI at `/gateway` and complete pairing/setup (model, API keys).
38
+ 2. Add a **skill** that triggers your pipeline (e.g. run the web editor flow, call this Engine, run the bundler). Skills live in `~/.openclaw/workspace/skills/`; you can add a custom skill that calls your court bundle project endpoints or scripts.
39
+ 3. Wire that skill to the same Qwen/Claude endpoints the editor uses (this Space’s `/api/generate` and your Claude API).
app.py CHANGED
@@ -1,24 +1,16 @@
1
  """
2
- Moltbot Hybrid Engine - Production v6.0.0
3
- Multi-service: FastAPI endpoints + Dual LLM backend (Ollama + HF Inference API)
4
  Runs on Hugging Face Spaces
5
- Build: 2026-02-08
6
-
7
- LLM Strategy:
8
- 1. Try Ollama (local, if installed and running)
9
- 2. Fallback to HuggingFace Inference API (always available, no GPU needed)
10
 
11
  Endpoints:
12
  GET / - Health check
13
  GET /health - Detailed health status
14
- GET /security - Security posture info
15
- POST /api/generate - LLM text generation (Ollama -> HF Inference API fallback)
16
- POST /api/search - Fuzzy file matching
17
- POST /api/analyze - Report analysis (JSON body)
18
- POST /api/extract_date - Date extraction from filenames
19
- POST /tools/analyze_report - Report analysis via file upload
20
- POST /v1/chat/completions - OpenAI-compatible endpoint (for Cursor IDE)
21
- GET /v1/models - OpenAI-compatible model listing
22
  """
23
  import os
24
  import re
@@ -26,8 +18,8 @@ import json
26
  import subprocess
27
  import logging
28
  from pathlib import Path
29
- from fastapi import FastAPI, HTTPException, Header, UploadFile, File
30
- from fastapi.responses import StreamingResponse
31
  from pydantic import BaseModel
32
  from typing import List, Optional, Dict, Any, Union
33
 
@@ -37,8 +29,8 @@ logger = logging.getLogger("moltbot-engine")
37
  # Initialize App
38
  app = FastAPI(
39
  title="Moltbot Hybrid Engine",
40
- description="AI agent for legal document processing - Dual LLM + file matching + analysis",
41
- version="6.0.0"
42
  )
43
 
44
  # API Key for authentication
@@ -255,8 +247,9 @@ def health_check():
255
  return {
256
  "status": "running",
257
  "service": "Moltbot Hybrid Engine",
258
- "version": "6.0.0",
259
  "ollama": ollama,
 
260
  "hf_inference_api": {
261
  "available": True,
262
  "model": HF_MODEL,
@@ -271,7 +264,7 @@ def detailed_health():
271
  return {
272
  "status": "healthy",
273
  "service": "moltbot-hybrid-engine",
274
- "version": "6.0.0",
275
  "llm_backends": {
276
  "ollama": {
277
  "running": ollama.get("running", False),
@@ -287,7 +280,7 @@ def detailed_health():
287
  },
288
  "endpoints": ["/", "/health", "/api/generate", "/api/search",
289
  "/api/analyze", "/api/extract_date", "/tools/analyze_report",
290
- "/v1/chat/completions", "/v1/models"]
291
  }
292
 
293
  @app.get("/security")
@@ -302,6 +295,57 @@ def security_info():
302
  }
303
 
304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  # Legal document exhibit reference instruction — injected into every generate/chat so edit sources always get it
306
  _prompts_dir = Path(__file__).resolve().parent / "prompts"
307
  _LEGAL_EXHIBIT_PROMPT_PATH = _prompts_dir / "legal_exhibit_instruction.txt"
 
1
  """
2
+ Moltbot Hybrid Engine - Production v7.0.0
3
+ Multi-service: FastAPI + Ollama (optional) + OpenClaw/Clawdbot gateway (proxied at /gateway)
4
  Runs on Hugging Face Spaces
5
+ Build: 2026-02-14 — Clawdbot installed in Space; gateway on 18789, proxied at /gateway
 
 
 
 
6
 
7
  Endpoints:
8
  GET / - Health check
9
  GET /health - Detailed health status
10
+ GET /gateway - OpenClaw/Clawdbot Control UI (reverse proxy to gateway :18789)
11
+ GET /gateway/{path} - OpenClaw proxy (path)
12
+ POST /api/generate - LLM text generation
13
+ ...
 
 
 
 
14
  """
15
  import os
16
  import re
 
18
  import subprocess
19
  import logging
20
  from pathlib import Path
21
+ from fastapi import FastAPI, HTTPException, Header, UploadFile, File, Request
22
+ from fastapi.responses import StreamingResponse, Response
23
  from pydantic import BaseModel
24
  from typing import List, Optional, Dict, Any, Union
25
 
 
29
  # Initialize App
30
  app = FastAPI(
31
  title="Moltbot Hybrid Engine",
32
+ description="AI agent for legal document processing - Dual LLM + file matching + Clawdbot gateway at /gateway",
33
+ version="7.0.0"
34
  )
35
 
36
  # API Key for authentication
 
247
  return {
248
  "status": "running",
249
  "service": "Moltbot Hybrid Engine",
250
+ "version": "7.0.0",
251
  "ollama": ollama,
252
+ "clawdbot": "OpenClaw gateway proxied at /gateway (if running)",
253
  "hf_inference_api": {
254
  "available": True,
255
  "model": HF_MODEL,
 
264
  return {
265
  "status": "healthy",
266
  "service": "moltbot-hybrid-engine",
267
+ "version": "7.0.0",
268
  "llm_backends": {
269
  "ollama": {
270
  "running": ollama.get("running", False),
 
280
  },
281
  "endpoints": ["/", "/health", "/api/generate", "/api/search",
282
  "/api/analyze", "/api/extract_date", "/tools/analyze_report",
283
+ "/v1/chat/completions", "/v1/models", "/gateway (Clawdbot UI)"]
284
  }
285
 
286
  @app.get("/security")
 
295
  }
296
 
297
 
298
+ # OpenClaw/Clawdbot gateway reverse proxy (gateway runs on 18789; Space exposes single port 7860)
299
+ OPENCLAW_GATEWAY_URL = "http://127.0.0.1:18789"
300
+
301
+ @app.api_route("/gateway", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
302
+ @app.api_route("/gateway/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
303
+ async def proxy_openclaw_gateway(request: Request, path: str = ""):
304
+ """Proxy requests to OpenClaw/Clawdbot gateway so Control UI and WebChat are reachable at /gateway."""
305
+ try:
306
+ import httpx
307
+ except ImportError:
308
+ raise HTTPException(status_code=503, detail="httpx not installed; cannot proxy to Clawdbot gateway")
309
+ target_path = request.url.path
310
+ if target_path.startswith("/gateway"):
311
+ target_path = target_path[7:] or "/" # strip /gateway -> / or /foo
312
+ target = f"{OPENCLAW_GATEWAY_URL}{target_path}"
313
+ if request.url.query:
314
+ target += "?" + request.url.query
315
+ headers = {k: v for k, v in request.headers.raw if k.lower() not in (b"host", b"connection")}
316
+ try:
317
+ body = await request.body()
318
+ except Exception:
319
+ body = b""
320
+ async with httpx.AsyncClient(timeout=30.0) as client:
321
+ try:
322
+ r = await client.request(
323
+ request.method,
324
+ target,
325
+ headers=headers,
326
+ content=body,
327
+ )
328
+ except httpx.ConnectError:
329
+ return Response(
330
+ content="Clawdbot gateway not reachable (is it running on 18789?). Start the Space and try again.",
331
+ status_code=503,
332
+ media_type="text/plain",
333
+ )
334
+ except Exception as e:
335
+ logger.warning(f"[GATEWAY PROXY] {e}")
336
+ return Response(content=str(e), status_code=502, media_type="text/plain")
337
+ out_headers = {}
338
+ for k, v in r.headers.items():
339
+ if k.lower() not in ("transfer-encoding", "connection"):
340
+ out_headers[k] = v
341
+ return Response(
342
+ content=r.content,
343
+ status_code=r.status_code,
344
+ headers=out_headers,
345
+ media_type=r.headers.get("content-type", "application/octet-stream"),
346
+ )
347
+
348
+
349
  # Legal document exhibit reference instruction — injected into every generate/chat so edit sources always get it
350
  _prompts_dir = Path(__file__).resolve().parent / "prompts"
351
  _LEGAL_EXHIBIT_PROMPT_PATH = _prompts_dir / "legal_exhibit_instruction.txt"
requirements.txt CHANGED
@@ -4,4 +4,5 @@ uvicorn>=0.24.0
4
  pydantic>=2.0.0
5
  python-multipart>=0.0.6
6
  huggingface_hub>=0.20.0
7
- requests>=2.31.0
 
 
4
  pydantic>=2.0.0
5
  python-multipart>=0.0.6
6
  huggingface_hub>=0.20.0
7
+ requests>=2.31.0
8
+ httpx>=0.25.0
start.sh CHANGED
@@ -79,8 +79,25 @@ echo " 💡 HF Inference API fallback is always available"
79
  echo " (Uses Qwen/Qwen2.5-7B-Instruct hosted by HuggingFace)"
80
  echo ""
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  # 4. Start FastAPI (foreground - keeps container alive)
83
- echo "[4/4] Starting FastAPI on port 7860..."
84
  echo "============================================================"
85
  echo ""
86
  python -m uvicorn app:app --host 0.0.0.0 --port 7860
 
79
  echo " (Uses Qwen/Qwen2.5-7B-Instruct hosted by HuggingFace)"
80
  echo ""
81
 
82
+ # 3b. Start OpenClaw/Clawdbot gateway in background (port 18789) if available
83
+ echo "[3b/5] Starting OpenClaw (Clawdbot) gateway..."
84
+ if command -v openclaw &> /dev/null; then
85
+ export OPENCLAW_HOME="${HOME:-/home/user}/.openclaw"
86
+ if [ -d "$OPENCLAW_HOME" ] || [ -f "$OPENCLAW_HOME/openclaw.json" ]; then
87
+ nohup openclaw gateway --port 18789 > /tmp/openclaw-gateway.log 2>&1 &
88
+ OPENCLAW_PID=$!
89
+ echo " ✅ Clawdbot gateway started (PID $OPENCLAW_PID, port 18789)"
90
+ echo " → Control UI / WebChat available via this Space at /gateway (see app)"
91
+ else
92
+ echo " ⚠️ OpenClaw config not found at $OPENCLAW_HOME — skip gateway"
93
+ fi
94
+ else
95
+ echo " ⚠️ openclaw binary not found — skip Clawdbot gateway"
96
+ fi
97
+ echo ""
98
+
99
  # 4. Start FastAPI (foreground - keeps container alive)
100
+ echo "[4/5] Starting FastAPI on port 7860..."
101
  echo "============================================================"
102
  echo ""
103
  python -m uvicorn app:app --host 0.0.0.0 --port 7860