getzero11 commited on
Commit
c4ca79f
·
verified ·
1 Parent(s): af868db

Upload 3 files

Browse files
Files changed (3) hide show
  1. .env.example +17 -0
  2. package.json +6 -2
  3. server.js +203 -191
.env.example ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenClaw Gateway Key
2
+ OPENCLAW_GATE_KEY=openclaw_ZJLv3akrp511lCANb4bcfREvfLsaTf5KGIx4TeheWLQ
3
+
4
+ # DeepSeek API Keys (Primary Provider)
5
+ DEEPSEEK_API_KEY_1=your_deepseek_api_key_here
6
+
7
+ # OpenAI API Keys (Fallback)
8
+ OPENAI_API_KEY_1=your_openai_api_key_here
9
+
10
+ # Gemini API Keys (Fallback)
11
+ GEMINI_API_KEY_1=your_gemini_api_key_here
12
+
13
+ # OpenRouter API Keys (Fallback)
14
+ OPENROUTER_API_KEY_1=your_openrouter_api_key_here
15
+
16
+ # DashScope API Keys (Fallback)
17
+ DASHSCOPE_API_KEY_1=your_dashscope_api_key_here
package.json CHANGED
@@ -3,9 +3,13 @@
3
  "private": true,
4
  "type": "module",
5
  "scripts": {
6
- "start": "node server.js"
 
7
  },
8
  "dependencies": {
9
- "express": "^4.19.2"
 
 
 
10
  }
11
  }
 
3
  "private": true,
4
  "type": "module",
5
  "scripts": {
6
+ "start": "node server.js",
7
+ "dev": "node server.js"
8
  },
9
  "dependencies": {
10
+ "express": "^4.19.2",
11
+ "node-fetch": "^3.3.2",
12
+ "dotenv": "^16.4.5",
13
+ "zod": "^3.23.8"
14
  }
15
  }
server.js CHANGED
@@ -1,210 +1,222 @@
1
  import express from "express";
2
  import { spawn } from "child_process";
3
-
4
- const app = express();
5
- app.use(express.json());
6
-
7
- /* ===============================
8
- 1. BASIC AUTH
9
- ================================ */
10
-
11
- const GATE_KEY = process.env.OPENCLAW_GATE_KEY;
12
-
13
- app.use((req, res, next) => {
14
- if (!GATE_KEY) return next();
15
- if (req.headers["x-openclaw-key"] !== GATE_KEY) {
16
- return res.status(401).json({ error: "Unauthorized" });
17
- }
18
- next();
19
- });
20
-
21
- /* ===============================
22
- 2. RATE LIMITING (IP-based)
23
- ================================ */
24
-
25
- const RATE_LIMIT = 30; // requests
26
- const WINDOW_MS = 60_000;
27
- const ipHits = new Map();
28
-
29
- app.use((req, res, next) => {
30
- const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
31
- const now = Date.now();
32
-
33
- const record = ipHits.get(ip) || { count: 0, ts: now };
34
- if (now - record.ts > WINDOW_MS) {
35
- record.count = 0;
36
- record.ts = now;
37
- }
38
-
39
- record.count++;
40
- ipHits.set(ip, record);
41
-
42
- if (record.count > RATE_LIMIT) {
43
- return res.status(429).json({ error: "Rate limit exceeded" });
44
- }
45
- next();
46
- });
47
-
48
- /* ===============================
49
- 3. LOAD KEY POOLS
50
- ================================ */
51
-
 
 
52
  function loadPool(prefix) {
53
- return Object.keys(process.env)
54
  .filter(k => k.startsWith(prefix))
55
  .map(k => process.env[k])
56
  .filter(Boolean);
 
 
 
57
  }
58
-
59
- const PROVIDERS = {
60
- openai: loadPool("OPENAI_API_KEY_"),
61
- deepseek: loadPool("DEEPSEEK_API_KEY_"),
62
- gemini: loadPool("GEMINI_API_KEY_"),
63
- openrouter: loadPool("OPENROUTER_API_KEY_"),
64
- dashscope: loadPool("DASHSCOPE_API_KEY_")
65
- };
66
-
67
- function randomKey(pool) {
68
- return pool[Math.floor(Math.random() * pool.length)];
69
- }
70
-
71
- /* ===============================
72
- 4. TASK ROUTING
73
- ================================ */
74
-
75
- const TASKS = new Set([
76
- "market_research",
77
- "summarize",
78
- "classify"
79
- ]);
80
-
81
- /* ===============================
82
- 5. RUN AGENT
83
- ================================ */
84
- app.use((req, res, next) => {
85
- if (req.method === "POST" && !req.is("application/json")) {
86
- return res.status(400).json({ error: "JSON body required" });
87
- }
88
- next();
89
- });
90
-
91
- app.get("/", (req, res) => {
92
- res.json({
93
- status: "OpenClaw running",
94
- service: "market_research_agent"
95
- });
96
- });
97
-
98
  app.post("/run", async (req, res) => {
99
- /* console.log("Incoming body:", req.body); */
 
 
 
 
100
 
101
  const { task = "market_research", provider, model, ...payload } = req.body;
102
-
103
- if (!TASKS.has(task)) {
104
- return res.status(400).json({ error: "Unknown task" });
105
- }
106
-
107
- const providersToTry = provider
108
- ? [provider, ...Object.keys(PROVIDERS).filter(p => p !== provider)]
109
- : Object.keys(PROVIDERS);
110
-
111
- let lastError;
112
-
113
- for (const p of providersToTry) {
114
- const pool = PROVIDERS[p];
115
- if (!pool || pool.length === 0) continue;
116
-
117
- for (let i = 0; i < pool.length; i++) {
118
- const apiKey = randomKey(pool);
119
-
120
  const env = {
121
  ...process.env,
122
  OPENCLAW_PROVIDER: p,
123
  OPENCLAW_MODEL: model || "",
124
  OPENCLAW_API_KEY: apiKey,
125
- OPENCLAW_TASK: task
 
126
  };
127
-
128
- try {
129
- const result = await runOpenClaw(env, payload);
130
- return res.json(result);
131
- } catch (err) {
132
- lastError = err;
133
- if (!isRateLimit(err)) break;
134
- }
135
- }
136
- }
137
-
138
  res.status(500).json({
139
  error: "All providers failed",
140
- details: lastError?.message
141
- });
142
- });
143
-
144
- /* ===============================
145
- 6. EXECUTION + JSON PARSE
146
- ================================ */
147
-
148
- function runOpenClaw(env, payload) {
149
- return new Promise((resolve, reject) => {
150
- const proc = spawn(process.execPath, ["src/index.js"], {
151
- cwd: "/app",
152
- env
153
- });
154
-
155
- let stdout = "";
156
- let stderr = "";
157
-
158
- // CRITICAL: handle spawn errors
159
- proc.on("error", err => {
160
- reject(err);
161
- });
162
-
163
- proc.stdout.on("data", data => {
164
- stdout += data.toString();
165
- });
166
-
167
- proc.stderr.on("data", data => {
168
- stderr += data.toString();
169
- });
170
-
171
- proc.on("close", code => {
172
- if (code !== 0) {
173
- return reject(
174
- new Error(stderr || `Agent exited with code ${code}`)
175
- );
176
- }
177
-
178
- try {
179
- const json = JSON.parse(stdout);
180
- resolve(json);
181
- } catch (err) {
182
- reject(new Error("Invalid JSON from OpenClaw agent"));
183
- }
184
- });
185
-
186
- // SEND INPUT TO AGENT
187
- proc.stdin.write(JSON.stringify(payload));
188
- proc.stdin.end();
189
  });
190
- }
191
-
192
-
193
- function isRateLimit(err) {
194
- const msg = err.message?.toLowerCase() || "";
195
- return (
196
- msg.includes("429") ||
197
- msg.includes("rate") ||
198
- msg.includes("quota") ||
199
- msg.includes("limit")
200
- );
201
- }
202
-
203
-
204
- /* ===============================
205
- 7. START
206
- ================================ */
207
-
208
- app.listen(7860, () => {
209
- console.log("🚀 OpenClaw Agent Gateway running");
210
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import express from "express";
2
  import { spawn } from "child_process";
3
+ import dotenv from "dotenv";
4
+ dotenv.config();
5
+
6
+ const app = express();
7
+ app.use(express.json());
8
+
9
+ /* ===============================
10
+ 1. BASIC AUTH
11
+ ================================ */
12
+
13
+ const GATE_KEY = process.env.OPENCLAW_GATE_KEY;
14
+
15
+ app.use((req, res, next) => {
16
+ if (!GATE_KEY) return next();
17
+ if (req.headers["x-openclaw-key"] !== GATE_KEY) {
18
+ return res.status(401).json({ error: "Unauthorized" });
19
+ }
20
+ next();
21
+ });
22
+
23
+ /* ===============================
24
+ 2. RATE LIMITING (IP-based)
25
+ ================================ */
26
+
27
+ const RATE_LIMIT = 30; // requests
28
+ const WINDOW_MS = 60_000;
29
+ const ipHits = new Map();
30
+
31
+ app.use((req, res, next) => {
32
+ const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
33
+ const now = Date.now();
34
+
35
+ const record = ipHits.get(ip) || { count: 0, ts: now };
36
+ if (now - record.ts > WINDOW_MS) {
37
+ record.count = 0;
38
+ record.ts = now;
39
+ }
40
+
41
+ record.count++;
42
+ ipHits.set(ip, record);
43
+
44
+ if (record.count > RATE_LIMIT) {
45
+ return res.status(429).json({ error: "Rate limit exceeded" });
46
+ }
47
+ next();
48
+ });
49
+
50
+ /* ===============================
51
+ 3. LOAD KEY POOLS
52
+ ================================ */
53
+
54
  function loadPool(prefix) {
55
+ const keys = Object.keys(process.env)
56
  .filter(k => k.startsWith(prefix))
57
  .map(k => process.env[k])
58
  .filter(Boolean);
59
+
60
+ console.log(`Loaded ${keys.length} keys for ${prefix}`);
61
+ return keys;
62
  }
63
+
64
+ const PROVIDERS = {
65
+ openai: loadPool("OPENAI_API_KEY_"),
66
+ deepseek: loadPool("DEEPSEEK_API_KEY_"),
67
+ gemini: loadPool("GEMINI_API_KEY_"),
68
+ openrouter: loadPool("OPENROUTER_API_KEY_"),
69
+ dashscope: loadPool("DASHSCOPE_API_KEY_")
70
+ };
71
+
72
+ function randomKey(pool) {
73
+ return pool[Math.floor(Math.random() * pool.length)];
74
+ }
75
+
76
+ /* ===============================
77
+ 4. TASK ROUTING
78
+ ================================ */
79
+
80
+ const TASKS = new Set([
81
+ "market_research",
82
+ "summarize",
83
+ "classify"
84
+ ]);
85
+
86
+ /* ===============================
87
+ 5. RUN AGENT
88
+ ================================ */
89
+ app.use((req, res, next) => {
90
+ if (req.method === "POST" && !req.is("application/json")) {
91
+ return res.status(400).json({ error: "JSON body required" });
92
+ }
93
+ next();
94
+ });
95
+
96
+ app.get("/", (req, res) => {
97
+ res.json({
98
+ status: "OpenClaw running",
99
+ service: "market_research_agent"
100
+ });
101
+ });
102
+
103
  app.post("/run", async (req, res) => {
104
+ console.log('OpenClaw: Received request:', {
105
+ task: req.body.task,
106
+ keyword: req.body.keyword,
107
+ timestamp: new Date().toISOString()
108
+ });
109
 
110
  const { task = "market_research", provider, model, ...payload } = req.body;
111
+
112
+ if (!TASKS.has(task)) {
113
+ return res.status(400).json({ error: "Unknown task" });
114
+ }
115
+
116
+ const providersToTry = provider
117
+ ? [provider, ...Object.keys(PROVIDERS).filter(p => p !== provider)]
118
+ : Object.keys(PROVIDERS);
119
+
120
+ let lastError;
121
+
122
+ for (const p of providersToTry) {
123
+ const pool = PROVIDERS[p];
124
+ if (!pool || pool.length === 0) continue;
125
+
126
+ for (let i = 0; i < pool.length; i++) {
127
+ const apiKey = randomKey(pool);
128
+
129
  const env = {
130
  ...process.env,
131
  OPENCLAW_PROVIDER: p,
132
  OPENCLAW_MODEL: model || "",
133
  OPENCLAW_API_KEY: apiKey,
134
+ OPENCLAW_TASK: task,
135
+ OPENCLAW_TIMEOUT: "180000"
136
  };
137
+
138
+ try {
139
+ const result = await runOpenClaw(env, payload);
140
+ return res.json(result);
141
+ } catch (err) {
142
+ lastError = err;
143
+ if (!isRateLimit(err)) break;
144
+ }
145
+ }
146
+ }
147
+
148
  res.status(500).json({
149
  error: "All providers failed",
150
+ details: lastError?.message,
151
+ keyword: req.body.keyword,
152
+ timestamp: new Date().toISOString()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  });
154
+ });
155
+
156
+ /* ===============================
157
+ 6. EXECUTION + JSON PARSE
158
+ ================================ */
159
+
160
+ function runOpenClaw(env, payload) {
161
+ return new Promise((resolve, reject) => {
162
+ const proc = spawn(process.execPath, ["src/index.js"], {
163
+ cwd: "/app",
164
+ env
165
+ });
166
+
167
+ let stdout = "";
168
+ let stderr = "";
169
+
170
+ // CRITICAL: handle spawn errors
171
+ proc.on("error", err => {
172
+ reject(err);
173
+ });
174
+
175
+ proc.stdout.on("data", data => {
176
+ stdout += data.toString();
177
+ });
178
+
179
+ proc.stderr.on("data", data => {
180
+ stderr += data.toString();
181
+ });
182
+
183
+ proc.on("close", code => {
184
+ if (code !== 0) {
185
+ return reject(
186
+ new Error(stderr || `Agent exited with code ${code}`)
187
+ );
188
+ }
189
+
190
+ try {
191
+ const json = JSON.parse(stdout);
192
+ resolve(json);
193
+ } catch (err) {
194
+ reject(new Error("Invalid JSON from OpenClaw agent"));
195
+ }
196
+ });
197
+
198
+ // SEND INPUT TO AGENT
199
+ proc.stdin.write(JSON.stringify(payload));
200
+ proc.stdin.end();
201
+ });
202
+ }
203
+
204
+
205
+ function isRateLimit(err) {
206
+ const msg = err.message?.toLowerCase() || "";
207
+ return (
208
+ msg.includes("429") ||
209
+ msg.includes("rate") ||
210
+ msg.includes("quota") ||
211
+ msg.includes("limit")
212
+ );
213
+ }
214
+
215
+
216
+ /* ===============================
217
+ 7. START
218
+ ================================ */
219
+
220
+ app.listen(7860, () => {
221
+ console.log("🚀 OpenClaw Agent Gateway running");
222
+ });