getzero11 commited on
Commit
b6ffa6e
·
verified ·
1 Parent(s): 05376c8

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +44 -246
server.js CHANGED
@@ -2,120 +2,27 @@ import express from "express";
2
  import { spawn } from "child_process";
3
  import dotenv from "dotenv";
4
 
5
- console.log('OpenClaw: Starting server...');
6
- console.log('OpenClaw: Node version:', process.version);
7
- console.log('OpenClaw: Current directory:', process.cwd());
8
 
9
  try {
10
  dotenv.config();
11
- console.log('OpenClaw: Environment loaded');
12
  } catch (err) {
13
- console.error('OpenClaw: Failed to load environment:', err.message);
14
  }
15
 
16
  const app = express();
17
  app.use(express.json());
18
 
19
- /* ===============================
20
- 1. BASIC AUTH
21
- ================================ */
22
-
23
- const GATE_KEY = process.env.OPENCLAW_GATE_KEY;
24
-
25
- app.use((req, res, next) => {
26
- if (!GATE_KEY) return next();
27
- if (req.headers["x-openclaw-key"] !== GATE_KEY) {
28
- return res.status(401).json({ error: "Unauthorized" });
29
- }
30
- next();
31
- });
32
-
33
- /* ===============================
34
- 2. RATE LIMITING (IP-based)
35
- ================================ */
36
-
37
- const RATE_LIMIT = 30; // requests
38
- const WINDOW_MS = 60_000;
39
- const ipHits = new Map();
40
-
41
- app.use((req, res, next) => {
42
- const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
43
- const now = Date.now();
44
-
45
- const record = ipHits.get(ip) || { count: 0, ts: now };
46
- if (now - record.ts > WINDOW_MS) {
47
- record.count = 0;
48
- record.ts = now;
49
- }
50
-
51
- record.count++;
52
- ipHits.set(ip, record);
53
-
54
- if (record.count > RATE_LIMIT) {
55
- return res.status(429).json({ error: "Rate limit exceeded" });
56
- }
57
- next();
58
- });
59
-
60
- /* ===============================
61
- 3. LOAD KEY POOLS
62
- ================================ */
63
-
64
- function loadPool(prefix) {
65
- const keys = Object.keys(process.env)
66
- .filter(k => k.startsWith(prefix))
67
- .map(k => process.env[k])
68
- .filter(Boolean);
69
-
70
- console.log(`Loaded ${keys.length} keys for ${prefix}`);
71
- return keys;
72
- }
73
-
74
- const PROVIDERS = {
75
- openai: loadPool("OPENAI_API_KEY_"),
76
- deepseek: loadPool("DEEPSEEK_API_KEY_"),
77
- gemini: loadPool("GEMINI_API_KEY_"),
78
- openrouter: loadPool("OPENROUTER_API_KEY_"),
79
- dashscope: loadPool("DASHSCOPE_API_KEY_")
80
- };
81
-
82
- function randomKey(pool) {
83
- return pool[Math.floor(Math.random() * pool.length)];
84
- }
85
-
86
- /* ===============================
87
- 4. TASK ROUTING
88
- ================================ */
89
-
90
- const TASKS = new Set([
91
- "market_research",
92
- "summarize",
93
- "classify"
94
- ]);
95
-
96
- /* ===============================
97
- 5. RUN AGENT
98
- ================================ */
99
- app.use((req, res, next) => {
100
- if (req.method === "POST" && !req.is("application/json")) {
101
- return res.status(400).json({ error: "JSON body required" });
102
- }
103
- next();
104
- });
105
-
106
  app.get("/", (req, res) => {
107
  res.json({
108
- status: "OpenClaw running on HF Space",
109
- service: "market_research_agent",
110
- endpoints: {
111
- market_research: "POST /api/market-research",
112
- health: "GET /health"
113
- },
114
  timestamp: new Date().toISOString()
115
  });
116
  });
117
 
118
- // Simple health check endpoint
119
  app.get("/health", (req, res) => {
120
  res.json({
121
  status: "healthy",
@@ -124,62 +31,9 @@ app.get("/health", (req, res) => {
124
  });
125
  });
126
 
127
- app.post("/run", async (req, res) => {
128
- console.log('OpenClaw: Received request:', {
129
- task: req.body.task,
130
- keyword: req.body.keyword,
131
- timestamp: new Date().toISOString()
132
- });
133
-
134
- const { task = "market_research", provider, model, ...payload } = req.body;
135
-
136
- if (!TASKS.has(task)) {
137
- return res.status(400).json({ error: "Unknown task" });
138
- }
139
-
140
- const providersToTry = provider
141
- ? [provider, ...Object.keys(PROVIDERS).filter(p => p !== provider)]
142
- : Object.keys(PROVIDERS);
143
-
144
- let lastError;
145
-
146
- for (const p of providersToTry) {
147
- const pool = PROVIDERS[p];
148
- if (!pool || pool.length === 0) continue;
149
-
150
- for (let i = 0; i < pool.length; i++) {
151
- const apiKey = randomKey(pool);
152
-
153
- const env = {
154
- ...process.env,
155
- OPENCLAW_PROVIDER: p,
156
- OPENCLAW_MODEL: model || "",
157
- OPENCLAW_API_KEY: apiKey,
158
- OPENCLAW_TASK: task,
159
- OPENCLAW_TIMEOUT: "180000"
160
- };
161
-
162
- try {
163
- const result = await runOpenClaw(env, payload);
164
- return res.json(result);
165
- } catch (err) {
166
- lastError = err;
167
- if (!isRateLimit(err)) break;
168
- }
169
- }
170
- }
171
-
172
- res.status(500).json({
173
- error: "All providers failed",
174
- details: lastError?.message,
175
- keyword: req.body.keyword,
176
- timestamp: new Date().toISOString()
177
- });
178
- });
179
-
180
- // Add specific market research endpoint for n8n compatibility
181
  app.post("/api/market-research", async (req, res) => {
182
- console.log('OpenClaw: Market research request:', {
183
  keyword: req.body.keyword,
184
  timestamp: new Date().toISOString()
185
  });
@@ -190,81 +44,49 @@ app.post("/api/market-research", async (req, res) => {
190
  return res.status(400).json({ error: "keyword is required" });
191
  }
192
 
193
- // Use API key from request or fallback to environment
194
- let providersToTry;
195
- let apiKeys = {};
196
-
197
- if (api_key) {
198
- // Use API key from n8n request
199
- console.log('OpenClaw: Using API key from request');
200
- apiKeys[provider] = [api_key];
201
- providersToTry = [provider];
202
- } else {
203
- // Fallback to environment variables (for local testing)
204
- console.log('OpenClaw: Using API keys from environment');
205
- providersToTry = Object.keys(PROVIDERS);
206
- apiKeys = PROVIDERS;
207
  }
208
 
209
- let lastError;
210
-
211
- for (const p of providersToTry) {
212
- const pool = apiKeys[p];
213
- if (!pool || pool.length === 0) {
214
- console.log(`OpenClaw: No API keys for provider ${p}`);
215
- continue;
216
- }
217
-
218
- for (let i = 0; i < pool.length; i++) {
219
- const apiKey = pool[i];
220
-
221
- const env = {
222
- ...process.env,
223
- OPENCLAW_PROVIDER: p,
224
- OPENCLAW_API_KEY: apiKey,
225
- OPENCLAW_TASK: "market_research",
226
- OPENCLAW_TIMEOUT: "180000"
227
- };
228
-
229
- try {
230
- console.log(`OpenClaw: Trying provider ${p} with key ${apiKey.substring(0, 10)}...`);
231
- const result = await runOpenClaw(env, { keyword });
232
- console.log('OpenClaw: Success with provider', p);
233
- return res.json(result);
234
- } catch (err) {
235
- lastError = err;
236
- console.error('OpenClaw: Provider failed:', p, err.message);
237
- if (!isRateLimit(err)) break;
238
- }
239
- }
240
  }
241
-
242
- res.status(500).json({
243
- error: "All providers failed",
244
- details: lastError?.message || "No API keys configured",
245
- keyword: keyword,
246
- timestamp: new Date().toISOString()
247
- });
248
  });
249
 
250
- /* ===============================
251
- 6. EXECUTION + JSON PARSE
252
- ================================ */
253
-
254
  function runOpenClaw(env, payload) {
255
  return new Promise((resolve, reject) => {
256
- // For HF Space, use current directory instead of /app
257
  const proc = spawn(process.execPath, ["src/index.js"], {
258
- cwd: process.cwd(), // Use current working directory
259
  env
260
  });
261
 
262
  let stdout = "";
263
  let stderr = "";
264
 
265
- // CRITICAL: handle spawn errors
266
  proc.on("error", err => {
267
- console.error('OpenClaw: Spawn error:', err);
268
  reject(err);
269
  });
270
 
@@ -278,50 +100,26 @@ function runOpenClaw(env, payload) {
278
 
279
  proc.on("close", code => {
280
  if (code !== 0) {
281
- console.error('OpenClaw: Agent exited with code:', code);
282
- console.error('OpenClaw: stderr:', stderr);
283
- return reject(
284
- new Error(stderr || `Agent exited with code ${code}`)
285
- );
286
  }
287
 
288
  try {
289
- console.log('OpenClaw: Agent response length:', stdout.length);
290
  const json = JSON.parse(stdout);
291
- console.log('OpenClaw: JSON parsed successfully');
292
  resolve(json);
293
  } catch (err) {
294
- console.error('OpenClaw: JSON parse error:', err.message);
295
- console.error('OpenClaw: Raw stdout (first 500 chars):', stdout.substring(0, 500));
296
- reject(new Error("Invalid JSON from OpenClaw agent: " + err.message));
297
  }
298
  });
299
 
300
- // SEND INPUT TO AGENT
301
  proc.stdin.write(JSON.stringify(payload));
302
  proc.stdin.end();
303
  });
304
  }
305
 
306
-
307
- function isRateLimit(err) {
308
- const msg = err.message?.toLowerCase() || "";
309
- return (
310
- msg.includes("429") ||
311
- msg.includes("rate") ||
312
- msg.includes("quota") ||
313
- msg.includes("limit")
314
- );
315
- }
316
-
317
-
318
- /* ===============================
319
- 7. START (HF Space compatible)
320
- =============================== */
321
-
322
- const PORT = process.env.PORT || 7860; // HF Space uses 7860
323
  app.listen(PORT, "0.0.0.0", () => {
324
- console.log(`🚀 OpenClaw Agent Gateway running on port ${PORT}`);
325
- console.log(`📡 Endpoint: /api/market-research`);
326
- console.log(`🔑 API keys from: ${Object.keys(PROVIDERS).filter(p => PROVIDERS[p].length > 0).join(', ') || 'requests only'}`);
327
- });
 
2
  import { spawn } from "child_process";
3
  import dotenv from "dotenv";
4
 
5
+ console.log('OpenClaw HF Space: Starting server...');
 
 
6
 
7
  try {
8
  dotenv.config();
9
+ console.log('Environment loaded');
10
  } catch (err) {
11
+ console.error('Failed to load environment:', err.message);
12
  }
13
 
14
  const app = express();
15
  app.use(express.json());
16
 
17
+ // Simple health check
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  app.get("/", (req, res) => {
19
  res.json({
20
+ status: "OpenClaw HF Space Running",
21
+ endpoint: "POST /api/market-research",
 
 
 
 
22
  timestamp: new Date().toISOString()
23
  });
24
  });
25
 
 
26
  app.get("/health", (req, res) => {
27
  res.json({
28
  status: "healthy",
 
31
  });
32
  });
33
 
34
+ // Market research endpoint
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  app.post("/api/market-research", async (req, res) => {
36
+ console.log('Market research request:', {
37
  keyword: req.body.keyword,
38
  timestamp: new Date().toISOString()
39
  });
 
44
  return res.status(400).json({ error: "keyword is required" });
45
  }
46
 
47
+ if (!api_key) {
48
+ return res.status(400).json({
49
+ error: "API key required",
50
+ message: "Send api_key in request body from n8n credentials"
51
+ });
 
 
 
 
 
 
 
 
 
52
  }
53
 
54
+ const env = {
55
+ ...process.env,
56
+ OPENCLAW_PROVIDER: provider,
57
+ OPENCLAW_API_KEY: api_key,
58
+ OPENCLAW_TASK: "market_research",
59
+ OPENCLAW_TIMEOUT: "180000"
60
+ };
61
+
62
+ try {
63
+ console.log(`Calling OpenClaw agent with provider: ${provider}`);
64
+ const result = await runOpenClaw(env, { keyword });
65
+ console.log('OpenClaw agent succeeded');
66
+ return res.json(result);
67
+ } catch (err) {
68
+ console.error('OpenClaw agent failed:', err.message);
69
+ return res.status(500).json({
70
+ error: "OpenClaw agent failed",
71
+ details: err.message,
72
+ keyword: keyword,
73
+ timestamp: new Date().toISOString()
74
+ });
 
 
 
 
 
 
 
 
 
 
75
  }
 
 
 
 
 
 
 
76
  });
77
 
 
 
 
 
78
  function runOpenClaw(env, payload) {
79
  return new Promise((resolve, reject) => {
 
80
  const proc = spawn(process.execPath, ["src/index.js"], {
81
+ cwd: process.cwd(),
82
  env
83
  });
84
 
85
  let stdout = "";
86
  let stderr = "";
87
 
 
88
  proc.on("error", err => {
89
+ console.error('Spawn error:', err);
90
  reject(err);
91
  });
92
 
 
100
 
101
  proc.on("close", code => {
102
  if (code !== 0) {
103
+ console.error('Agent exited with code:', code, 'stderr:', stderr);
104
+ return reject(new Error(`Agent failed: ${stderr || code}`));
 
 
 
105
  }
106
 
107
  try {
 
108
  const json = JSON.parse(stdout);
 
109
  resolve(json);
110
  } catch (err) {
111
+ console.error('JSON parse error:', err.message);
112
+ console.error('Raw output (first 500 chars):', stdout.substring(0, 500));
113
+ reject(new Error("Invalid JSON from agent"));
114
  }
115
  });
116
 
 
117
  proc.stdin.write(JSON.stringify(payload));
118
  proc.stdin.end();
119
  });
120
  }
121
 
122
+ const PORT = process.env.PORT || 7860;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  app.listen(PORT, "0.0.0.0", () => {
124
+ console.log(`🚀 Server running on port ${PORT}`);
125
+ });