GeminiBot commited on
Commit
783fb1f
·
1 Parent(s): a521d64

Update diagnostic logs and stabilize fetch

Browse files
Files changed (1) hide show
  1. src/duckai.ts +50 -35
src/duckai.ts CHANGED
@@ -1,51 +1,66 @@
1
- import { gotScraping } from 'got-scraping';
2
  import { JSDOM } from "jsdom";
3
  import { createHash } from "node:crypto";
 
4
 
5
  export class DuckAI {
6
  private async solveChallenge(vqdHash: string, ua: string): Promise<string> {
7
- const jsScript = Buffer.from(vqdHash, 'base64').toString('utf-8');
8
- const dom = new JSDOM(`<!DOCTYPE html><html><body></body></html>`, { runScripts: 'dangerously' });
9
- dom.window.top.__DDG_BE_VERSION__ = 1;
10
- dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
11
-
12
- const result = await dom.window.eval(jsScript) as any;
13
- result.client_hashes[0] = ua;
14
- result.client_hashes = result.client_hashes.map((t: string) => {
15
- const hash = createHash('sha256');
16
- hash.update(t);
17
- return hash.digest('base64');
18
- });
19
- return btoa(JSON.stringify(result));
 
 
 
 
20
  }
21
 
22
  async chat(request: any): Promise<string> {
 
 
 
 
 
 
 
 
 
 
23
  try {
24
- // gotScraping автоматически подберет идеальные заголовки и TLS отпечаток
25
- // под каждый запрос, имитируя случайный современный браузер.
26
-
27
- // 1. Получаем токен
28
- const statusRes = await gotScraping.get("https://duckduckgo.com/duckchat/v1/status?q=1", {
29
- headers: { "x-vqd-accept": "1" }
30
- });
31
 
32
- const ua = statusRes.request.options.headers['user-agent'] as string;
33
- const hashHeader = statusRes.headers["x-vqd-hash-1"] as string;
34
-
35
  const solvedVqd = await this.solveChallenge(hashHeader, ua);
36
 
37
  // 2. Делаем запрос в чат
38
- const chatRes = await gotScraping.post("https://duckduckgo.com/duckchat/v1/chat", {
 
39
  headers: {
 
40
  "x-vqd-hash-1": solvedVqd,
41
- "content-type": "application/json",
42
- "accept": "text/event-stream"
43
  },
44
- json: request,
45
- retry: { limit: 2 } // Авто-повтор при сбоях
46
  });
47
 
48
- const text = chatRes.body;
 
 
 
 
 
49
  let llmResponse = "";
50
  const lines = text.split("\n");
51
  for (const line of lines) {
@@ -56,11 +71,11 @@ export class DuckAI {
56
  } catch (e) {}
57
  }
58
  }
59
- return llmResponse.trim() || "⚠️ Пустой ответ от ИИ.";
60
 
61
- } catch (error) {
62
- console.error("Scraping Error:", error);
63
- return "⚠️ Ошибка маскировки. Попробуйте еще раз.";
64
  }
65
  }
66
- }
 
 
1
  import { JSDOM } from "jsdom";
2
  import { createHash } from "node:crypto";
3
+ import UserAgent from "user-agents";
4
 
5
  export class DuckAI {
6
  private async solveChallenge(vqdHash: string, ua: string): Promise<string> {
7
+ try {
8
+ const jsScript = Buffer.from(vqdHash, 'base64').toString('utf-8');
9
+ const dom = new JSDOM(`<!DOCTYPE html><html><body></body></html>`, { runScripts: 'dangerously' });
10
+ dom.window.top.__DDG_BE_VERSION__ = 1;
11
+ dom.window.top.__DDG_FE_CHAT_HASH__ = 1;
12
+
13
+ const result = await dom.window.eval(jsScript) as any;
14
+ result.client_hashes[0] = ua;
15
+ result.client_hashes = result.client_hashes.map((t: string) => {
16
+ const hash = createHash('sha256');
17
+ hash.update(t);
18
+ return hash.digest('base64');
19
+ });
20
+ return btoa(JSON.stringify(result));
21
+ } catch (e: any) {
22
+ throw new Error("Challenge Solver Error: " + e.message);
23
+ }
24
  }
25
 
26
  async chat(request: any): Promise<string> {
27
+ const ua = new UserAgent({ deviceCategory: 'desktop' }).toString();
28
+ const headers: any = {
29
+ "User-Agent": ua,
30
+ "Accept": "text/event-stream",
31
+ "Accept-Language": "en-US,en;q=0.9",
32
+ "Referer": "https://duckduckgo.com/",
33
+ "Origin": "https://duckduckgo.com",
34
+ "x-vqd-accept": "1"
35
+ };
36
+
37
  try {
38
+ // 1. Получаем статус
39
+ const statusRes = await fetch("https://duckduckgo.com/duckchat/v1/status?q=1", { headers });
40
+ if (!statusRes.ok) throw new Error(`DDG Status Fail: ${statusRes.status}`);
41
+
42
+ const hashHeader = statusRes.headers.get("x-vqd-hash-1");
43
+ if (!hashHeader) throw new Error("Missing x-vqd-hash-1 header");
 
44
 
 
 
 
45
  const solvedVqd = await this.solveChallenge(hashHeader, ua);
46
 
47
  // 2. Делаем запрос в чат
48
+ const chatRes = await fetch("https://duckduckgo.com/duckchat/v1/chat", {
49
+ method: "POST",
50
  headers: {
51
+ ...headers,
52
  "x-vqd-hash-1": solvedVqd,
53
+ "Content-Type": "application/json"
 
54
  },
55
+ body: JSON.stringify(request)
 
56
  });
57
 
58
+ if (!chatRes.ok) {
59
+ const errText = await chatRes.text();
60
+ throw new Error(`DDG Chat Fail: ${chatRes.status} - ${errText.substring(0, 100)}`);
61
+ }
62
+
63
+ const text = await chatRes.text();
64
  let llmResponse = "";
65
  const lines = text.split("\n");
66
  for (const line of lines) {
 
71
  } catch (e) {}
72
  }
73
  }
74
+ return llmResponse.trim() || "⚠️ Пустой ответ от DDG.";
75
 
76
+ } catch (error: any) {
77
+ console.error("Scraping Detail:", error.message);
78
+ return `⚠️ Ошибка бэкенда: ${error.message}`;
79
  }
80
  }
81
+ }