aaxaxax's picture
force update files
1de7911
package service
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"zencoder-2api/internal/model"
"zencoder-2api/internal/service/provider"
)
const GrokBaseURL = "https://api.zencoder.ai/xai"
type GrokService struct{}
func NewGrokService() *GrokService {
return &GrokService{}
}
// ChatCompletions 处理/v1/chat/completions请求
func (s *GrokService) ChatCompletions(ctx context.Context, body []byte) (*http.Response, error) {
var req struct {
Model string `json:"model"`
}
if err := json.Unmarshal(body, &req); err != nil {
return nil, fmt.Errorf("invalid request body: %w", err)
}
// 检查模型是否存在于模型字典中
_, exists := model.GetZenModel(req.Model)
if !exists {
DebugLog(ctx, "[Grok] 模型不存在: %s", req.Model)
return nil, ErrNoAvailableAccount
}
DebugLogRequest(ctx, "Grok", "/v1/chat/completions", req.Model)
var lastErr error
for i := 0; i < MaxRetries; i++ {
account, err := GetNextAccountForModel(req.Model)
if err != nil {
DebugLogRequestEnd(ctx, "Grok", false, err)
return nil, err
}
DebugLogAccountSelected(ctx, "Grok", account.ID, account.Email)
resp, err := s.doRequest(ctx, account, req.Model, body)
if err != nil {
MarkAccountError(account)
lastErr = err
DebugLogRetry(ctx, "Grok", i+1, account.ID, err)
continue
}
DebugLogResponseReceived(ctx, "Grok", resp.StatusCode)
DebugLogResponseHeaders(ctx, "Grok", resp.Header)
// 总是输出重要的响应头信息
if resp.Header.Get("Zen-Pricing-Period-Limit") != "" ||
resp.Header.Get("Zen-Pricing-Period-Cost") != "" ||
resp.Header.Get("Zen-Request-Cost") != "" {
log.Printf("[Grok] 积分信息 - 周期限额: %s, 周期消耗: %s, 本次消耗: %s",
resp.Header.Get("Zen-Pricing-Period-Limit"),
resp.Header.Get("Zen-Pricing-Period-Cost"),
resp.Header.Get("Zen-Request-Cost"))
}
if resp.StatusCode >= 400 {
// 读取错误响应内容
errBody, _ := io.ReadAll(resp.Body)
resp.Body.Close()
// 429 错误特殊处理 - 直接返回,不重试
if resp.StatusCode == 429 {
log.Printf("[Grok] 429限流错误,尝试使用代理重试")
// 尝试使用代理池重试
proxyResp, proxyErr := s.retryWithProxy(ctx, account, req.Model, body)
if proxyErr == nil && proxyResp != nil {
// 代理重试成功
return proxyResp, nil
}
log.Printf("[Grok] 代理重试失败: %v", proxyErr)
// 在DEBUG模式下记录详细信息
DebugLogErrorResponse(ctx, "Grok", resp.StatusCode, string(errBody))
// 将账号放入短期冷却(5秒)
MarkAccountRateLimitedShort(account)
// 标记错误并结束请求
DebugLogRequestEnd(ctx, "Grok", false, ErrNoAvailableAccount)
// 返回通用错误
return nil, ErrNoAvailableAccount
}
DebugLogErrorResponse(ctx, "Grok", resp.StatusCode, string(errBody))
// 400和500错误直接返回,不进行账号错误计数
if resp.StatusCode == 400 || resp.StatusCode == 500 {
DebugLogRequestEnd(ctx, "Grok", false, fmt.Errorf("API error: %d", resp.StatusCode))
return nil, fmt.Errorf("API error: %d - %s", resp.StatusCode, string(errBody))
}
MarkAccountError(account)
lastErr = fmt.Errorf("API error: %d", resp.StatusCode)
DebugLogRetry(ctx, "Grok", i+1, account.ID, lastErr)
continue
}
ResetAccountError(account)
zenModel, exists := model.GetZenModel(req.Model)
if !exists {
// 模型不存在,使用默认倍率
UpdateAccountCreditsFromResponse(account, resp, 1.0)
} else {
// 使用统一的积分更新函数,自动处理响应头中的积分信息
UpdateAccountCreditsFromResponse(account, resp, zenModel.Multiplier)
}
DebugLogRequestEnd(ctx, "Grok", true, nil)
return resp, nil
}
DebugLogRequestEnd(ctx, "Grok", false, lastErr)
return nil, fmt.Errorf("all retries failed: %w", lastErr)
}
func (s *GrokService) doRequest(ctx context.Context, account *model.Account, modelID string, body []byte) (*http.Response, error) {
zenModel, exists := model.GetZenModel(modelID)
if !exists {
return nil, ErrNoAvailableAccount
}
httpClient := provider.NewHTTPClient(account.Proxy, 0)
// 处理请求体,Grok Code 模型要求 temperature=0
modifiedBody := body
if strings.Contains(modelID, "grok-code") {
modifiedBody, _ = s.setTemperatureZero(body)
}
reqURL := GrokBaseURL + "/v1/chat/completions"
DebugLogRequestSent(ctx, "Grok", reqURL)
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewReader(modifiedBody))
if err != nil {
return nil, err
}
// 设置Zencoder自定义请求头
SetZencoderHeaders(httpReq, account, zenModel)
// 添加模型配置的额外请求头
if zenModel.Parameters != nil && zenModel.Parameters.ExtraHeaders != nil {
for k, v := range zenModel.Parameters.ExtraHeaders {
httpReq.Header.Set(k, v)
}
}
// 记录请求头用于调试
DebugLogRequestHeaders(ctx, "Grok", httpReq.Header)
return httpClient.Do(httpReq)
}
// setTemperatureZero 设置 temperature=0
func (s *GrokService) setTemperatureZero(body []byte) ([]byte, error) {
var reqMap map[string]interface{}
if err := json.Unmarshal(body, &reqMap); err != nil {
return body, err
}
reqMap["temperature"] = 0
return json.Marshal(reqMap)
}
// ChatCompletionsProxy 代理chat completions请求
func (s *GrokService) ChatCompletionsProxy(ctx context.Context, w http.ResponseWriter, body []byte) error {
resp, err := s.ChatCompletions(ctx, body)
if err != nil {
return err
}
defer resp.Body.Close()
return StreamResponse(w, resp)
}
// retryWithProxy 使用代理池重试Grok请求
func (s *GrokService) retryWithProxy(ctx context.Context, account *model.Account, modelID string, body []byte) (*http.Response, error) {
// 获取模型配置
zenModel, exists := model.GetZenModel(modelID)
if !exists {
return nil, fmt.Errorf("模型配置不存在: %s", modelID)
}
proxyPool := provider.GetProxyPool()
if !proxyPool.HasProxies() {
return nil, fmt.Errorf("没有可用的代理")
}
maxRetries := 3
for i := 0; i < maxRetries; i++ {
// 获取随机代理
proxyURL := proxyPool.GetRandomProxy()
if proxyURL == "" {
continue
}
log.Printf("[Grok] 尝试代理 %s (重试 %d/%d)", proxyURL, i+1, maxRetries)
// 创建使用代理的HTTP客户端
proxyClient, err := provider.NewHTTPClientWithProxy(proxyURL, 0)
if err != nil {
log.Printf("[Grok] 创建代理客户端失败: %v", err)
continue
}
// 处理请求体,Grok Code 模型要求 temperature=0
modifiedBody := body
if strings.Contains(modelID, "grok-code") {
modifiedBody, _ = s.setTemperatureZero(body)
}
// 创建新请求
reqURL := GrokBaseURL + "/v1/chat/completions"
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewReader(modifiedBody))
if err != nil {
log.Printf("[Grok] 创建请求失败: %v", err)
continue
}
// 设置请求头
SetZencoderHeaders(httpReq, account, zenModel)
// 添加模型配置的额外请求头
if zenModel.Parameters != nil && zenModel.Parameters.ExtraHeaders != nil {
for k, v := range zenModel.Parameters.ExtraHeaders {
httpReq.Header.Set(k, v)
}
}
// 执行请求
resp, err := proxyClient.Do(httpReq)
if err != nil {
log.Printf("[Grok] 代理请求失败: %v", err)
continue
}
// 检查响应状态
if resp.StatusCode == 429 {
// 仍然是429,尝试下一个代理
resp.Body.Close()
log.Printf("[Grok] 代理 %s 仍返回429,尝试下一个", proxyURL)
continue
}
if resp.StatusCode >= 400 {
// 其他错误,记录并尝试下一个代理
errBody, _ := io.ReadAll(resp.Body)
resp.Body.Close()
log.Printf("[Grok] 代理 %s 返回错误 %d: %s", proxyURL, resp.StatusCode, string(errBody))
continue
}
// 成功
log.Printf("[Grok] 代理 %s 请求成功", proxyURL)
return resp, nil
}
return nil, fmt.Errorf("所有代理重试均失败")
}