khushalcodiste commited on
Commit
0e79077
·
1 Parent(s): 34e1647

feat: added

Browse files
Files changed (2) hide show
  1. README.md +12 -1
  2. server.js +27 -1
README.md CHANGED
@@ -22,13 +22,24 @@ Text-only inference. Returns full response in one JSON body (no streaming).
22
 
23
  **Response:** `{ "response": "..." }`
24
 
 
 
25
  ### `GET /health`
26
- Health check and model load status.
27
 
28
  ## Usage
29
 
30
  ```bash
 
 
 
 
 
 
31
  curl -X POST "http://localhost:7860/prompt" \
32
  -H "Content-Type: application/json" \
 
33
  -d '{"prompt": "What is 2+2?"}'
34
  ```
 
 
 
22
 
23
  **Response:** `{ "response": "..." }`
24
 
25
+ **Auth:** If `API_KEY` env var is set, send it via header `X-API-Key: <key>` or `Authorization: Bearer <key>`. If unset, no auth.
26
+
27
  ### `GET /health`
28
+ Health check and model load status (no auth).
29
 
30
  ## Usage
31
 
32
  ```bash
33
+ # Without API key (when API_KEY is not set)
34
+ curl -X POST "http://localhost:7860/prompt" \
35
+ -H "Content-Type: application/json" \
36
+ -d '{"prompt": "What is 2+2?"}'
37
+
38
+ # With API key
39
  curl -X POST "http://localhost:7860/prompt" \
40
  -H "Content-Type: application/json" \
41
+ -H "X-API-Key: your-secret-key" \
42
  -d '{"prompt": "What is 2+2?"}'
43
  ```
44
+
45
+ Set `API_KEY` in the environment to enable protection (e.g. `API_KEY=your-secret-key node server.js`).
server.js CHANGED
@@ -9,6 +9,7 @@ import crypto from "crypto";
9
  const app = express();
10
  const PORT = 7860;
11
  const MODEL_ID = "huggingworld/Qwen3.5-0.8B-ONNX";
 
12
 
13
  let model = null;
14
  let processor = null;
@@ -87,6 +88,16 @@ const swaggerDoc = {
87
  version: "1.0.0",
88
  description: "Text inference API using Qwen3.5-0.8B ONNX with transformers.js",
89
  },
 
 
 
 
 
 
 
 
 
 
90
  paths: {
91
  "/": {
92
  get: {
@@ -121,13 +132,28 @@ const swaggerDoc = {
121
  responses: {
122
  200: { description: "Inference result" },
123
  400: { description: "Invalid input" },
 
124
  503: { description: "Model not loaded" },
125
  },
 
126
  },
127
  },
128
  },
129
  };
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc));
132
 
133
  app.use((req, res, next) => {
@@ -165,7 +191,7 @@ app.get("/health", (req, res) => {
165
  res.json({ status: "healthy", model_loaded: model !== null });
166
  });
167
 
168
- app.post("/prompt", express.json(), async (req, res) => {
169
  const prompt = req.body.prompt;
170
  const maxTokens = parseInt(req.body.max_tokens) || 256;
171
  log("info", "prompt_request_received", {
 
9
  const app = express();
10
  const PORT = 7860;
11
  const MODEL_ID = "huggingworld/Qwen3.5-0.8B-ONNX";
12
+ const API_KEY = process.env.API_KEY;
13
 
14
  let model = null;
15
  let processor = null;
 
88
  version: "1.0.0",
89
  description: "Text inference API using Qwen3.5-0.8B ONNX with transformers.js",
90
  },
91
+ components: {
92
+ securitySchemes: {
93
+ ApiKeyAuth: {
94
+ type: "apiKey",
95
+ in: "header",
96
+ name: "X-API-Key",
97
+ description: "Set API_KEY env var; send as X-API-Key or Authorization: Bearer <key>",
98
+ },
99
+ },
100
+ },
101
  paths: {
102
  "/": {
103
  get: {
 
132
  responses: {
133
  200: { description: "Inference result" },
134
  400: { description: "Invalid input" },
135
+ 401: { description: "Invalid or missing API key" },
136
  503: { description: "Model not loaded" },
137
  },
138
+ security: [{ ApiKeyAuth: [] }],
139
  },
140
  },
141
  },
142
  };
143
 
144
+ function requireApiKey(req, res, next) {
145
+ if (!API_KEY) return next();
146
+ const bearer = req.headers.authorization?.startsWith("Bearer ")
147
+ ? req.headers.authorization.slice(7)
148
+ : null;
149
+ const key = bearer ?? req.headers["x-api-key"] ?? null;
150
+ if (key !== API_KEY) {
151
+ log("warn", "api_key_rejected", { request_id: req.requestId, path: req.path });
152
+ return res.status(401).json({ detail: "Invalid or missing API key." });
153
+ }
154
+ next();
155
+ }
156
+
157
  app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc));
158
 
159
  app.use((req, res, next) => {
 
191
  res.json({ status: "healthy", model_loaded: model !== null });
192
  });
193
 
194
+ app.post("/prompt", requireApiKey, express.json(), async (req, res) => {
195
  const prompt = req.body.prompt;
196
  const maxTokens = parseInt(req.body.max_tokens) || 256;
197
  log("info", "prompt_request_received", {