sanbo
commited on
Commit
·
d1d4670
1
Parent(s):
eb6a925
update sth at 2025-10-10 00:55:40
Browse files
main.go
CHANGED
|
@@ -3,10 +3,13 @@ package main
|
|
| 3 |
import (
|
| 4 |
"bufio"
|
| 5 |
"bytes"
|
|
|
|
| 6 |
"crypto/sha256"
|
|
|
|
| 7 |
"encoding/json"
|
| 8 |
"fmt"
|
| 9 |
"io"
|
|
|
|
| 10 |
"log"
|
| 11 |
"net/http"
|
| 12 |
"net/url"
|
|
@@ -15,6 +18,8 @@ import (
|
|
| 15 |
"strings"
|
| 16 |
"sync"
|
| 17 |
"time"
|
|
|
|
|
|
|
| 18 |
)
|
| 19 |
|
| 20 |
// 配置变量(从环境变量读取)
|
|
@@ -60,14 +65,14 @@ var (
|
|
| 60 |
|
| 61 |
// 思考内容处理策略
|
| 62 |
const (
|
| 63 |
-
THINK_TAGS_MODE = "
|
| 64 |
)
|
| 65 |
|
| 66 |
// 系统配置常量
|
| 67 |
const (
|
| 68 |
-
MAX_LIVE_REQUESTS =
|
| 69 |
-
AUTH_TOKEN_TIMEOUT =
|
| 70 |
-
UPSTREAM_TIMEOUT =
|
| 71 |
TOKEN_DISPLAY_LENGTH = 10 // token显示时的截取长度
|
| 72 |
NANOSECONDS_TO_SECONDS = 1000000000 // 纳秒转秒的倍数
|
| 73 |
)
|
|
@@ -106,7 +111,7 @@ func initConfig() {
|
|
| 106 |
DEBUG_MODE = getEnv("DEBUG_MODE", "true") == "true"
|
| 107 |
DEFAULT_STREAM = getEnv("DEFAULT_STREAM", "true") == "true"
|
| 108 |
DASHBOARD_ENABLED = getEnv("DASHBOARD_ENABLED", "true") == "true"
|
| 109 |
-
ENABLE_THINKING = getEnv("ENABLE_THINKING", "
|
| 110 |
}
|
| 111 |
|
| 112 |
// 记录请求统计信息
|
|
@@ -381,6 +386,14 @@ func getUpstreamModelID(modelName string) string {
|
|
| 381 |
switch modelName {
|
| 382 |
case "GLM-4.6":
|
| 383 |
return "GLM-4-6-API-V1" // 使用官方API的真实模型名称
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 384 |
default:
|
| 385 |
debugLog("未知模型名称: %s,使用GLM-4.6作为默认", modelName)
|
| 386 |
return "GLM-4-6-API-V1" // 默认使用GLM-4.6
|
|
@@ -389,39 +402,50 @@ func getUpstreamModelID(modelName string) string {
|
|
| 389 |
|
| 390 |
// 获取匿名token(每次对话使用不同token,避免共享记忆)
|
| 391 |
func getAnonymousToken() (string, error) {
|
|
|
|
|
|
|
|
|
|
| 392 |
client := &http.Client{Timeout: AUTH_TOKEN_TIMEOUT * time.Second}
|
| 393 |
-
req, err := http.NewRequest("GET",
|
| 394 |
if err != nil {
|
|
|
|
| 395 |
return "", err
|
| 396 |
}
|
| 397 |
-
|
| 398 |
-
req.Header.Set("User-Agent", BROWSER_UA)
|
| 399 |
req.Header.Set("Accept", "*/*")
|
| 400 |
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
| 401 |
-
req.Header.Set("
|
| 402 |
-
req.Header.Set("sec-ch-ua", SEC_CH_UA)
|
| 403 |
-
req.Header.Set("sec-ch-ua-mobile", SEC_CH_UA_MOB)
|
| 404 |
-
req.Header.Set("sec-ch-ua-platform", SEC_CH_UA_PLAT)
|
| 405 |
-
req.Header.Set("Origin", ORIGIN_BASE)
|
| 406 |
req.Header.Set("Referer", ORIGIN_BASE+"/")
|
| 407 |
|
| 408 |
resp, err := client.Do(req)
|
| 409 |
if err != nil {
|
|
|
|
| 410 |
return "", err
|
| 411 |
}
|
| 412 |
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
| 413 |
if resp.StatusCode != http.StatusOK {
|
| 414 |
-
|
|
|
|
| 415 |
}
|
|
|
|
| 416 |
var body struct {
|
| 417 |
Token string `json:"token"`
|
| 418 |
}
|
| 419 |
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
|
|
|
|
|
|
| 420 |
return "", err
|
| 421 |
}
|
|
|
|
| 422 |
if body.Token == "" {
|
|
|
|
| 423 |
return "", fmt.Errorf("anon token empty")
|
| 424 |
}
|
|
|
|
|
|
|
| 425 |
return body.Token, nil
|
| 426 |
}
|
| 427 |
|
|
@@ -1484,21 +1508,16 @@ func handleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
|
| 1484 |
chatID := fmt.Sprintf("%d-%d", time.Now().UnixNano(), time.Now().Unix())
|
| 1485 |
msgID := fmt.Sprintf("%d", time.Now().UnixNano())
|
| 1486 |
|
| 1487 |
-
//
|
| 1488 |
-
enableThinking :=
|
| 1489 |
-
|
| 1490 |
-
enableThinking = *req.EnableThinking
|
| 1491 |
-
debugLog("使用请求参数中的思考功能设置: %v", enableThinking)
|
| 1492 |
-
} else {
|
| 1493 |
-
debugLog("使用环境变量中的思考功能设置: %v", enableThinking)
|
| 1494 |
-
}
|
| 1495 |
|
| 1496 |
// 构造上游请求
|
| 1497 |
upstreamReq := UpstreamRequest{
|
| 1498 |
Stream: true, // 总是使用流式从上游获取
|
| 1499 |
ChatID: chatID,
|
| 1500 |
ID: msgID,
|
| 1501 |
-
Model: getUpstreamModelID(
|
| 1502 |
Messages: req.Messages,
|
| 1503 |
Params: map[string]interface{}{},
|
| 1504 |
Features: map[string]interface{}{
|
|
@@ -1513,7 +1532,7 @@ func handleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
|
| 1513 |
ID string `json:"id"`
|
| 1514 |
Name string `json:"name"`
|
| 1515 |
OwnedBy string `json:"owned_by"`
|
| 1516 |
-
}{ID: getUpstreamModelID(
|
| 1517 |
ToolServers: []string{},
|
| 1518 |
Variables: map[string]string{
|
| 1519 |
"{{USER_NAME}}": "User",
|
|
@@ -1553,6 +1572,73 @@ func handleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
|
| 1553 |
}
|
| 1554 |
}
|
| 1555 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1556 |
func callUpstreamWithHeaders(upstreamReq UpstreamRequest, refererChatID string, authToken string) (*http.Response, error) {
|
| 1557 |
reqBody, err := json.Marshal(upstreamReq)
|
| 1558 |
if err != nil {
|
|
@@ -1562,36 +1648,37 @@ func callUpstreamWithHeaders(upstreamReq UpstreamRequest, refererChatID string,
|
|
| 1562 |
|
| 1563 |
// 构建带URL参数的完整URL
|
| 1564 |
baseURL := UPSTREAM_URL
|
| 1565 |
-
|
| 1566 |
-
|
| 1567 |
-
// 生成UUID
|
| 1568 |
-
requestID :=
|
| 1569 |
-
|
| 1570 |
-
|
| 1571 |
-
|
| 1572 |
-
|
| 1573 |
-
|
| 1574 |
-
|
| 1575 |
-
|
| 1576 |
-
|
| 1577 |
-
|
| 1578 |
-
|
| 1579 |
-
|
| 1580 |
-
|
| 1581 |
-
|
| 1582 |
-
|
| 1583 |
-
|
| 1584 |
-
|
| 1585 |
-
|
| 1586 |
-
|
| 1587 |
-
|
| 1588 |
-
|
| 1589 |
-
|
| 1590 |
-
|
| 1591 |
-
|
| 1592 |
-
|
| 1593 |
-
|
| 1594 |
-
|
|
|
|
| 1595 |
|
| 1596 |
debugLog("调用上游API: %s", fullURL)
|
| 1597 |
debugLog("上游请求体: %s", string(reqBody))
|
|
@@ -1602,31 +1689,16 @@ func callUpstreamWithHeaders(upstreamReq UpstreamRequest, refererChatID string,
|
|
| 1602 |
return nil, err
|
| 1603 |
}
|
| 1604 |
|
| 1605 |
-
//
|
| 1606 |
-
hash := sha256.Sum256(reqBody)
|
| 1607 |
-
signature := fmt.Sprintf("%x", hash)
|
| 1608 |
-
|
| 1609 |
-
debugLog("生成签名: %s (基于请求体SHA256)", signature)
|
| 1610 |
-
|
| 1611 |
req.Header.Set("Content-Type", "application/json")
|
| 1612 |
-
req.Header.Set("Accept", "
|
| 1613 |
-
req.Header.Set("Accept-Language", "zh-CN")
|
| 1614 |
req.Header.Set("User-Agent", BROWSER_UA)
|
|
|
|
| 1615 |
req.Header.Set("Authorization", "Bearer "+authToken)
|
| 1616 |
-
req.Header.Set("sec-ch-ua", SEC_CH_UA)
|
| 1617 |
-
req.Header.Set("sec-ch-ua-mobile", SEC_CH_UA_MOB)
|
| 1618 |
-
req.Header.Set("sec-ch-ua-platform", SEC_CH_UA_PLAT)
|
| 1619 |
-
req.Header.Set("X-FE-Version", X_FE_VERSION)
|
| 1620 |
req.Header.Set("X-Signature", signature)
|
|
|
|
| 1621 |
req.Header.Set("Origin", ORIGIN_BASE)
|
| 1622 |
req.Header.Set("Referer", ORIGIN_BASE+"/c/"+refererChatID)
|
| 1623 |
-
req.Header.Set("Connection", "keep-alive")
|
| 1624 |
-
req.Header.Set("Sec-Fetch-Dest", "empty")
|
| 1625 |
-
req.Header.Set("Sec-Fetch-Mode", "cors")
|
| 1626 |
-
req.Header.Set("Sec-Fetch-Site", "same-origin")
|
| 1627 |
-
|
| 1628 |
-
// 添加Cookie
|
| 1629 |
-
req.Header.Set("Cookie", fmt.Sprintf("token=%s", authToken))
|
| 1630 |
|
| 1631 |
client := &http.Client{Timeout: UPSTREAM_TIMEOUT * time.Second}
|
| 1632 |
resp, err := client.Do(req)
|
|
|
|
| 3 |
import (
|
| 4 |
"bufio"
|
| 5 |
"bytes"
|
| 6 |
+
"crypto/hmac"
|
| 7 |
"crypto/sha256"
|
| 8 |
+
"encoding/base64"
|
| 9 |
"encoding/json"
|
| 10 |
"fmt"
|
| 11 |
"io"
|
| 12 |
+
"io/ioutil"
|
| 13 |
"log"
|
| 14 |
"net/http"
|
| 15 |
"net/url"
|
|
|
|
| 18 |
"strings"
|
| 19 |
"sync"
|
| 20 |
"time"
|
| 21 |
+
|
| 22 |
+
"github.com/google/uuid"
|
| 23 |
)
|
| 24 |
|
| 25 |
// 配置变量(从环境变量读取)
|
|
|
|
| 65 |
|
| 66 |
// 思考内容处理策略
|
| 67 |
const (
|
| 68 |
+
THINK_TAGS_MODE = "strip" // strip: 去除<details>标签;think: 转为<think>标签;raw: 保留原样
|
| 69 |
)
|
| 70 |
|
| 71 |
// 系统配置常量
|
| 72 |
const (
|
| 73 |
+
MAX_LIVE_REQUESTS = 100 // 最多保留的实时请求记录数
|
| 74 |
+
AUTH_TOKEN_TIMEOUT = 10 // 获取匿名token的超时时间(秒)
|
| 75 |
+
UPSTREAM_TIMEOUT = 60 // 上游API调用超时时间(秒)
|
| 76 |
TOKEN_DISPLAY_LENGTH = 10 // token显示时的截取长度
|
| 77 |
NANOSECONDS_TO_SECONDS = 1000000000 // 纳秒转秒的倍数
|
| 78 |
)
|
|
|
|
| 111 |
DEBUG_MODE = getEnv("DEBUG_MODE", "true") == "true"
|
| 112 |
DEFAULT_STREAM = getEnv("DEFAULT_STREAM", "true") == "true"
|
| 113 |
DASHBOARD_ENABLED = getEnv("DASHBOARD_ENABLED", "true") == "true"
|
| 114 |
+
ENABLE_THINKING = getEnv("ENABLE_THINKING", "true") == "true"
|
| 115 |
}
|
| 116 |
|
| 117 |
// 记录请求统计信息
|
|
|
|
| 386 |
switch modelName {
|
| 387 |
case "GLM-4.6":
|
| 388 |
return "GLM-4-6-API-V1" // 使用官方API的真实模型名称
|
| 389 |
+
case "GLM-4.5":
|
| 390 |
+
return "0727-360B-API"
|
| 391 |
+
case "GLM-4.5-Thinking":
|
| 392 |
+
return "0727-360B-API"
|
| 393 |
+
case "GLM-4.5-Search":
|
| 394 |
+
return "0727-360B-API"
|
| 395 |
+
case "GLM-4.6-Thinking":
|
| 396 |
+
return "GLM-4-6-API-V1"
|
| 397 |
default:
|
| 398 |
debugLog("未知模型名称: %s,使用GLM-4.6作为默认", modelName)
|
| 399 |
return "GLM-4-6-API-V1" // 默认使用GLM-4.6
|
|
|
|
| 402 |
|
| 403 |
// 获取匿名token(每次对话使用不同token,避免共享记忆)
|
| 404 |
func getAnonymousToken() (string, error) {
|
| 405 |
+
tokenURL := ORIGIN_BASE + "/api/v1/auths/"
|
| 406 |
+
debugLog("获取匿名token: %s", tokenURL)
|
| 407 |
+
|
| 408 |
client := &http.Client{Timeout: AUTH_TOKEN_TIMEOUT * time.Second}
|
| 409 |
+
req, err := http.NewRequest("GET", tokenURL, nil)
|
| 410 |
if err != nil {
|
| 411 |
+
debugLog("创建获取匿名token请求失败: %v", err)
|
| 412 |
return "", err
|
| 413 |
}
|
| 414 |
+
|
|
|
|
| 415 |
req.Header.Set("Accept", "*/*")
|
| 416 |
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
| 417 |
+
req.Header.Set("User-Agent", BROWSER_UA)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 418 |
req.Header.Set("Referer", ORIGIN_BASE+"/")
|
| 419 |
|
| 420 |
resp, err := client.Do(req)
|
| 421 |
if err != nil {
|
| 422 |
+
debugLog("获取匿名token请求失败: %v", err)
|
| 423 |
return "", err
|
| 424 |
}
|
| 425 |
defer resp.Body.Close()
|
| 426 |
+
|
| 427 |
+
debugLog("获取匿名token响应状态: %d", resp.StatusCode)
|
| 428 |
+
|
| 429 |
if resp.StatusCode != http.StatusOK {
|
| 430 |
+
debugLog("获取匿名token失败: 状态码 %d", resp.StatusCode)
|
| 431 |
+
return "", fmt.Errorf("获取匿名token失败: 状态码 %d", resp.StatusCode)
|
| 432 |
}
|
| 433 |
+
|
| 434 |
var body struct {
|
| 435 |
Token string `json:"token"`
|
| 436 |
}
|
| 437 |
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
| 438 |
+
bodyContent, _ := ioutil.ReadAll(resp.Body)
|
| 439 |
+
debugLog("解析匿名token响应失败: %v, 响应内容: %s", err, string(bodyContent))
|
| 440 |
return "", err
|
| 441 |
}
|
| 442 |
+
|
| 443 |
if body.Token == "" {
|
| 444 |
+
debugLog("匿名token为空")
|
| 445 |
return "", fmt.Errorf("anon token empty")
|
| 446 |
}
|
| 447 |
+
|
| 448 |
+
debugLog("成功获取匿名token")
|
| 449 |
return body.Token, nil
|
| 450 |
}
|
| 451 |
|
|
|
|
| 1508 |
chatID := fmt.Sprintf("%d-%d", time.Now().UnixNano(), time.Now().Unix())
|
| 1509 |
msgID := fmt.Sprintf("%d", time.Now().UnixNano())
|
| 1510 |
|
| 1511 |
+
// 决定是否启用思考功能:根据模型名称判断
|
| 1512 |
+
enableThinking := strings.Contains(strings.ToLower(req.Model), "thinking")
|
| 1513 |
+
debugLog("根据模型名称启用思考功能: %v (模型: %s)", enableThinking, req.Model)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1514 |
|
| 1515 |
// 构造上游请求
|
| 1516 |
upstreamReq := UpstreamRequest{
|
| 1517 |
Stream: true, // 总是使用流式从上游获取
|
| 1518 |
ChatID: chatID,
|
| 1519 |
ID: msgID,
|
| 1520 |
+
Model: getUpstreamModelID(req.Model), // 使用用户请求中的模型名称
|
| 1521 |
Messages: req.Messages,
|
| 1522 |
Params: map[string]interface{}{},
|
| 1523 |
Features: map[string]interface{}{
|
|
|
|
| 1532 |
ID string `json:"id"`
|
| 1533 |
Name string `json:"name"`
|
| 1534 |
OwnedBy string `json:"owned_by"`
|
| 1535 |
+
}{ID: getUpstreamModelID(req.Model), Name: req.Model, OwnedBy: "openai"},
|
| 1536 |
ToolServers: []string{},
|
| 1537 |
Variables: map[string]string{
|
| 1538 |
"{{USER_NAME}}": "User",
|
|
|
|
| 1572 |
}
|
| 1573 |
}
|
| 1574 |
|
| 1575 |
+
// 从JWT token中提取user_id
|
| 1576 |
+
func extractUserIDFromToken(token string) string {
|
| 1577 |
+
parts := strings.Split(token, ".")
|
| 1578 |
+
if len(parts) < 2 {
|
| 1579 |
+
return "guest"
|
| 1580 |
+
}
|
| 1581 |
+
|
| 1582 |
+
// Base64解码payload部分
|
| 1583 |
+
payloadRaw := parts[1]
|
| 1584 |
+
// 添加缺失的padding
|
| 1585 |
+
padding := "="
|
| 1586 |
+
numPadding := (-len(payloadRaw)) % 4
|
| 1587 |
+
if numPadding > 0 {
|
| 1588 |
+
padding = strings.Repeat("=", numPadding)
|
| 1589 |
+
}
|
| 1590 |
+
|
| 1591 |
+
payloadBytes, err := base64.RawURLEncoding.DecodeString(payloadRaw + padding)
|
| 1592 |
+
if err != nil {
|
| 1593 |
+
debugLog("JWT payload解码失败: %v", err)
|
| 1594 |
+
return "guest"
|
| 1595 |
+
}
|
| 1596 |
+
|
| 1597 |
+
// 解析JSON payload
|
| 1598 |
+
var payload map[string]interface{}
|
| 1599 |
+
err = json.Unmarshal(payloadBytes, &payload)
|
| 1600 |
+
if err != nil {
|
| 1601 |
+
debugLog("JWT payload解析失败: %v", err)
|
| 1602 |
+
return "guest"
|
| 1603 |
+
}
|
| 1604 |
+
|
| 1605 |
+
// 尝试多个可能的user_id字段
|
| 1606 |
+
userIDKeys := []string{"id", "user_id", "uid", "sub"}
|
| 1607 |
+
for _, key := range userIDKeys {
|
| 1608 |
+
if val, exists := payload[key]; exists && val != nil {
|
| 1609 |
+
// 将值转换为字符串
|
| 1610 |
+
return fmt.Sprintf("%v", val)
|
| 1611 |
+
}
|
| 1612 |
+
}
|
| 1613 |
+
|
| 1614 |
+
return "guest"
|
| 1615 |
+
}
|
| 1616 |
+
|
| 1617 |
+
// 生成双层HMAC-SHA256签名
|
| 1618 |
+
func generateSignature(messageText string, requestID string, timestampMs int64, userID string) string {
|
| 1619 |
+
signingSecret := "junjie" // Z.AI的默认签名密钥
|
| 1620 |
+
|
| 1621 |
+
// 计算时间窗口索引(5分钟窗口)
|
| 1622 |
+
windowIndex := timestampMs / (5 * 60 * 1000)
|
| 1623 |
+
|
| 1624 |
+
// Layer1: 派生密钥
|
| 1625 |
+
rootKey := []byte(signingSecret)
|
| 1626 |
+
h := hmac.New(sha256.New, rootKey)
|
| 1627 |
+
h.Write([]byte(fmt.Sprintf("%d", windowIndex)))
|
| 1628 |
+
derivedHex := fmt.Sprintf("%x", h.Sum(nil))
|
| 1629 |
+
|
| 1630 |
+
// Layer2: 生成签名
|
| 1631 |
+
canonicalString := fmt.Sprintf(
|
| 1632 |
+
"requestId,%s,timestamp,%d,user_id,%s|%s|%d",
|
| 1633 |
+
requestID, timestampMs, userID, messageText, timestampMs,
|
| 1634 |
+
)
|
| 1635 |
+
h2 := hmac.New(sha256.New, []byte(derivedHex))
|
| 1636 |
+
h2.Write([]byte(canonicalString))
|
| 1637 |
+
signature := fmt.Sprintf("%x", h2.Sum(nil))
|
| 1638 |
+
|
| 1639 |
+
return signature
|
| 1640 |
+
}
|
| 1641 |
+
|
| 1642 |
func callUpstreamWithHeaders(upstreamReq UpstreamRequest, refererChatID string, authToken string) (*http.Response, error) {
|
| 1643 |
reqBody, err := json.Marshal(upstreamReq)
|
| 1644 |
if err != nil {
|
|
|
|
| 1648 |
|
| 1649 |
// 构建带URL参数的完整URL
|
| 1650 |
baseURL := UPSTREAM_URL
|
| 1651 |
+
timestampMs := time.Now().UnixMilli()
|
| 1652 |
+
|
| 1653 |
+
// 生成UUID
|
| 1654 |
+
requestID := uuid.New().String()
|
| 1655 |
+
userID := extractUserIDFromToken(authToken)
|
| 1656 |
+
|
| 1657 |
+
// 提取最后一条用户消息用于签名
|
| 1658 |
+
lastUserMessage := ""
|
| 1659 |
+
if len(upstreamReq.Messages) > 0 {
|
| 1660 |
+
for i := len(upstreamReq.Messages) - 1; i >= 0; i-- {
|
| 1661 |
+
if upstreamReq.Messages[i].Role == "user" {
|
| 1662 |
+
lastUserMessage = upstreamReq.Messages[i].Content
|
| 1663 |
+
break
|
| 1664 |
+
}
|
| 1665 |
+
}
|
| 1666 |
+
}
|
| 1667 |
+
|
| 1668 |
+
// 生成签名
|
| 1669 |
+
signature := generateSignature(lastUserMessage, requestID, timestampMs, userID)
|
| 1670 |
+
|
| 1671 |
+
// 构建URL参数
|
| 1672 |
+
queryParams := url.Values{}
|
| 1673 |
+
queryParams.Set("timestamp", fmt.Sprintf("%d", timestampMs))
|
| 1674 |
+
queryParams.Set("requestId", requestID)
|
| 1675 |
+
queryParams.Set("user_id", userID)
|
| 1676 |
+
queryParams.Set("token", authToken)
|
| 1677 |
+
queryParams.Set("current_url", ORIGIN_BASE+"/c/"+refererChatID)
|
| 1678 |
+
queryParams.Set("pathname", fmt.Sprintf("/c/%s", refererChatID))
|
| 1679 |
+
queryParams.Set("signature_timestamp", fmt.Sprintf("%d", timestampMs))
|
| 1680 |
+
|
| 1681 |
+
fullURL := fmt.Sprintf("%s?%s", baseURL, queryParams.Encode())
|
| 1682 |
|
| 1683 |
debugLog("调用上游API: %s", fullURL)
|
| 1684 |
debugLog("上游请求体: %s", string(reqBody))
|
|
|
|
| 1689 |
return nil, err
|
| 1690 |
}
|
| 1691 |
|
| 1692 |
+
// 设置请求头
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1693 |
req.Header.Set("Content-Type", "application/json")
|
| 1694 |
+
req.Header.Set("Accept", "application/json, text/event-stream")
|
|
|
|
| 1695 |
req.Header.Set("User-Agent", BROWSER_UA)
|
| 1696 |
+
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
| 1697 |
req.Header.Set("Authorization", "Bearer "+authToken)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1698 |
req.Header.Set("X-Signature", signature)
|
| 1699 |
+
req.Header.Set("X-FE-Version", "prod-fe-1.0.69")
|
| 1700 |
req.Header.Set("Origin", ORIGIN_BASE)
|
| 1701 |
req.Header.Set("Referer", ORIGIN_BASE+"/c/"+refererChatID)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1702 |
|
| 1703 |
client := &http.Client{Timeout: UPSTREAM_TIMEOUT * time.Second}
|
| 1704 |
resp, err := client.Do(req)
|