File size: 3,714 Bytes
bc0be9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { generateVqdHash } from "./vm.ts";
import { userAgent } from "./utils.ts";
import { CONFIG, getHash, setHash } from "./utils.ts";
import { ChatMessage } from "./types.ts";
import { errorResponse } from "./response.ts";

export class DDGService {
  private hash: string | null = null;

  async getVqdHash(): Promise<string | Response> {
    // 优先使用环境变量中的hash
    const envHash = getHash();
    if (envHash) {
      return envHash;
    }

    try {
      const response = await fetch(CONFIG.DDG_STATUS_URL, {
        method: "GET",
        headers: {
          "User-Agent": userAgent,
          "x-vqd-accept": "1",
        },
      });

      if (!response.ok) {
        return errorResponse(`hash初始化请求失败: ${response.status}`, 502);
      }

      const hash = response.headers.get("x-vqd-hash-1");

      if (!hash) {
        return errorResponse(`未找到hash头部,状态码: ${response.status}`, 502);
      }

      let decryptedHash: string;
      try {
        decryptedHash = generateVqdHash(hash);
      } catch (decryptError) {
        return errorResponse(`hash解密失败: ${decryptError.message}`, 502);
      }

      if (!decryptedHash || decryptedHash.trim() === "") {
        return errorResponse(`hash解密结果为空`, 502);
      }
      setHash(decryptedHash);
      return decryptedHash;
    } catch (error) {
      return errorResponse(`获取hash失败: ${error.message}`, 502);
    }
  }

  // 内部发送消息方法,返回具体的错误信息
  private async sendMessage(
    model: string,
    messages: ChatMessage[]
  ): Promise<{
    success: boolean;
    response?: Response;
    error?: string;
    status?: number;
  }> {
    const hash = await this.getVqdHash();
    if (hash instanceof Response) {
      return { success: false, error: "获取hash失败", status: hash.status };
    }

    const payload = {
      model,
      messages,
      canUseTools: false,
      canUseApproxLocation: false,
    };

    try {
      const response = await fetch(CONFIG.DDG_CHAT_URL, {
        method: "POST",
        headers: {
          "User-Agent": userAgent,
          "x-vqd-hash-1": hash,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        const errorText = await response.text();
        return {
          success: false,
          error: `上游错误: ${response.status} - ${errorText}`,
          status: response.status,
        };
      }

      return { success: true, response };
    } catch (error) {
      return {
        success: false,
        error: `请求失败: ${error.message}`,
        status: 502,
      };
    }
  }

  // 带重试机制的发送消息方法 - 只对418错误重试
  async sendMessageWithRetry(
    model: string,
    messages: ChatMessage[],
    maxRetries = 1
  ): Promise<Response> {
    let lastResult: {
      success: boolean;
      response?: Response;
      error?: string;
      status?: number;
    } | null = null;

    for (let attempt = 0; attempt <= maxRetries; attempt++) {
      if (attempt > 0) {
        setHash(""); // 重置hash,强制重新获取
      }

      const result = await this.sendMessage(model, messages);

      if (result.success && result.response) {
        return result.response;
      }

      lastResult = result;

      // 只有418错误才重试
      if (result.status === 418 || 429) {
        continue;
      } else {
        // 其他错误直接返回,不重试
        break;
      }
    }

    // 返回最后一次的错误
    return errorResponse(
      lastResult?.error || "发送消息失败",
      lastResult?.status || 502
    );
  }
}