GeminiBot commited on
Commit
50bb115
·
1 Parent(s): d819405

Add retry logic for 418 errors and fix undefined document in eval

Browse files
Files changed (1) hide show
  1. src/duckai.ts +72 -50
src/duckai.ts CHANGED
@@ -150,10 +150,16 @@ export class DuckAI {
150
  return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
151
  };
152
 
153
- mockWindow.top.__DDG_BE_VERSION__ = 1;
154
- mockWindow.top.__DDG_FE_CHAT_HASH__ = 1;
155
 
156
- const result = await mockWindow.eval(jsScript) as any;
 
 
 
 
 
 
157
 
158
  if (!result || !result.client_hashes) {
159
  throw new Error("Invalid Challenge Response");
@@ -186,7 +192,7 @@ export class DuckAI {
186
  return { status: "unknown" };
187
  }
188
 
189
- async chat(request: any): Promise<string> {
190
  const ua = new UserAgent({ deviceCategory: 'desktop' }).toString();
191
  const headers: any = {
192
  "User-Agent": ua,
@@ -194,53 +200,69 @@ export class DuckAI {
194
  "x-vqd-accept": "1"
195
  };
196
 
197
- console.log("[DuckAI] Fetching status...");
198
- const statusRes = await fetch("https://duckduckgo.com/duckchat/v1/status?q=1", { headers });
199
- console.log(`[DuckAI] Status response: ${statusRes.status}`);
200
-
201
- const hashHeader = statusRes.headers.get("x-vqd-hash-1");
202
- console.log(`[DuckAI] x-vqd-hash-1: ${hashHeader ? "FOUND" : "MISSING"}`);
203
-
204
- if (!hashHeader) throw new Error("Missing x-vqd-hash-1 - DuckDuckGo might be blocking this IP or Challenge failed.");
205
-
206
- console.log("[DuckAI] Solving challenge...");
207
- const solvedVqd = await this.solveChallenge(hashHeader, ua);
208
- console.log("[DuckAI] Challenge solved (or fallback used).");
209
-
210
- const response = await fetch("https://duckduckgo.com/duckchat/v1/chat", {
211
- method: "POST",
212
- headers: { ...headers, "x-vqd-hash-1": solvedVqd, "Content-Type": "application/json" },
213
- body: JSON.stringify(request)
214
- });
215
-
216
- console.log(`[DuckAI] Chat response status: ${response.status}`);
217
-
218
- if (!response.ok) {
219
- const errorText = await response.text();
220
- console.log(`[DuckAI] Error body: ${errorText}`);
221
- throw new Error(`DuckDuckGo API Error (${response.status}): ${errorText.substring(0, 100)}`);
222
- }
223
 
224
- const text = await response.text();
225
-
226
- let llmResponse = "";
227
- const lines = text.split("\n");
228
- for (const line of lines) {
229
- if (line.startsWith("data: ")) {
230
- try {
231
- const chunk = line.slice(6);
232
- if (chunk === "[DONE]") break;
233
- const json = JSON.parse(chunk);
234
- if (json.message) llmResponse += json.message;
235
- } catch (e) {}
236
- }
237
- }
238
-
239
- if (!llmResponse) {
240
- console.log("[DuckAI] Warning: Empty LLM response extracted.");
241
- throw new Error("Empty response from DuckDuckGo");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  }
243
-
244
- return llmResponse.trim();
245
  }
246
  }
 
150
  return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
151
  };
152
 
153
+ // Ensure document is globally available for eval
154
+ (mockWindow as any).document = mockWindow.document;
155
 
156
+ const result = await mockWindow.eval(`
157
+ (function() {
158
+ const window = this;
159
+ const document = this.document;
160
+ ${jsScript}
161
+ }).call(window)
162
+ `) as any;
163
 
164
  if (!result || !result.client_hashes) {
165
  throw new Error("Invalid Challenge Response");
 
192
  return { status: "unknown" };
193
  }
194
 
195
+ async chat(request: any, retries = 1): Promise<string> {
196
  const ua = new UserAgent({ deviceCategory: 'desktop' }).toString();
197
  const headers: any = {
198
  "User-Agent": ua,
 
200
  "x-vqd-accept": "1"
201
  };
202
 
203
+ try {
204
+ console.log("[DuckAI] Fetching status...");
205
+ const statusRes = await fetch("https://duckduckgo.com/duckchat/v1/status?q=1", { headers });
206
+ console.log(`[DuckAI] Status response: ${statusRes.status}`);
207
+
208
+ const hashHeader = statusRes.headers.get("x-vqd-hash-1");
209
+ console.log(`[DuckAI] x-vqd-hash-1: ${hashHeader ? "FOUND" : "MISSING"}`);
210
+
211
+ if (!hashHeader) throw new Error("Missing x-vqd-hash-1 - DuckDuckGo might be blocking this IP or Challenge failed.");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
+ console.log("[DuckAI] Solving challenge...");
214
+ const solvedVqd = await this.solveChallenge(hashHeader, ua);
215
+ console.log("[DuckAI] Challenge solved (or fallback used).");
216
+
217
+ const response = await fetch("https://duckduckgo.com/duckchat/v1/chat", {
218
+ method: "POST",
219
+ headers: { ...headers, "x-vqd-hash-1": solvedVqd, "Content-Type": "application/json" },
220
+ body: JSON.stringify(request)
221
+ });
222
+
223
+ console.log(`[DuckAI] Chat response status: ${response.status}`);
224
+
225
+ if (!response.ok) {
226
+ const errorText = await response.text();
227
+
228
+ // Если ошибка 418 (Challenge Failed) и есть попытки - пробуем снова
229
+ if (response.status === 418 && retries > 0) {
230
+ console.log(`[DuckAI] Got 418 Error. Retrying... (${retries} attempts left)`);
231
+ return this.chat(request, retries - 1);
232
+ }
233
+
234
+ console.log(`[DuckAI] Error body: ${errorText}`);
235
+ throw new Error(`DuckDuckGo API Error (${response.status}): ${errorText.substring(0, 100)}`);
236
+ }
237
+
238
+ const text = await response.text();
239
+
240
+ let llmResponse = "";
241
+ const lines = text.split("\n");
242
+ for (const line of lines) {
243
+ if (line.startsWith("data: ")) {
244
+ try {
245
+ const chunk = line.slice(6);
246
+ if (chunk === "[DONE]") break;
247
+ const json = JSON.parse(chunk);
248
+ if (json.message) llmResponse += json.message;
249
+ } catch (e) {}
250
+ }
251
+ }
252
+
253
+ if (!llmResponse) {
254
+ console.log("[DuckAI] Warning: Empty LLM response extracted.");
255
+ throw new Error("Empty response from DuckDuckGo");
256
+ }
257
+
258
+ return llmResponse.trim();
259
+ } catch (error: any) {
260
+ // Если была ошибка сети или другая, и есть попытки - тоже ретраим
261
+ if (retries > 0) {
262
+ console.log(`[DuckAI] Error: ${error.message}. Retrying... (${retries} attempts left)`);
263
+ return this.chat(request, retries - 1);
264
+ }
265
+ throw error;
266
  }
 
 
267
  }
268
  }