diff --git a/FreeChat/FreeChat.go b/FreeChat/FreeChat.go index 67cb37b..527ee6d 100644 --- a/FreeChat/FreeChat.go +++ b/FreeChat/FreeChat.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "free-gpt3.5-2api/AccAuthPool" ProofWork2 "free-gpt3.5-2api/ProofWork" "free-gpt3.5-2api/ProxyPool" "free-gpt3.5-2api/RequestClient" @@ -27,16 +28,9 @@ var ( // NewFreeAuthType 定义一个枚举类型 type NewFreeAuthType int -const ( - NewFreeAuthNormal NewFreeAuthType = 0 //正常获取 - NewFreeAuthRefresh NewFreeAuthType = 1 // 刷新获取 -) - type FreeChat struct { RequestClient RequestClient.RequestClient Proxy *ProxyPool.Proxy - MaxUseCount int - ExpiresAt int64 FreeAuth *freeAuth AccAuth string ChatUrl string @@ -64,20 +58,17 @@ type turnstile struct { } // NewFreeChat 创建 FreeChat 实例 0 无论网络是否被标记限制都获取 1 在网络未标记时才能获取 -func NewFreeChat(newType NewFreeAuthType, maxUseCount int, expiresAt int64, accAuth string) *FreeChat { +func NewFreeChat(accAuth string) *FreeChat { // 创建 FreeChat 实例 freeChat := &FreeChat{ - MaxUseCount: maxUseCount, - ExpiresAt: expiresAt, - FreeAuth: &freeAuth{}, - Ua: RequestClient.Ua, + FreeAuth: &freeAuth{}, + Ua: RequestClient.GetUa(), + ChatUrl: FreeAuthChatUrl, } // ChatUrl if strings.HasPrefix(accAuth, "Bearer eyJhbGciOiJSUzI1NiI") { freeChat.ChatUrl = AccAuthChatUrl freeChat.AccAuth = accAuth - } else { - freeChat.ChatUrl = FreeAuthChatUrl } // 获取请求客户端 err := freeChat.newRequestClient() @@ -86,7 +77,7 @@ func NewFreeChat(newType NewFreeAuthType, maxUseCount int, expiresAt int64, accA return nil } // 获取并设置代理 - err = freeChat.getProxy(newType) + err = freeChat.getProxy() if err != nil { logger.Logger.Debug(err.Error()) return nil @@ -100,7 +91,7 @@ func NewFreeChat(newType NewFreeAuthType, maxUseCount int, expiresAt int64, accA } } // 获取 FreeAuth - err = freeChat.newFreeAuth(newType) + err = freeChat.newFreeAuth() if err != nil { logger.Logger.Debug(err.Error()) return nil @@ -108,6 +99,31 @@ func NewFreeChat(newType NewFreeAuthType, maxUseCount int, expiresAt int64, accA return freeChat } +func GetFreeChat(accAuth string, retry int) *FreeChat { + // 判断是否为指定账号 + if strings.HasPrefix(accAuth, "Bearer eyJhbGciOiJSUzI1NiI") { + freeChat := NewFreeChat(accAuth) + if freeChat == nil && retry > 0 { + return GetFreeChat(accAuth, retry-1) + } + return freeChat + } + // 判断是否使用 AccAuthPool + if strings.HasPrefix(accAuth, "Bearer "+AccAuthPool.AccAuthAuthorizationPre) && !AccAuthPool.GetAccAuthPoolInstance().IsEmpty() { + accA := AccAuthPool.GetAccAuthPoolInstance().GetAccAuth() + freeChat := NewFreeChat(accA) + if freeChat == nil && retry > 0 { + return GetFreeChat(accAuth, retry-1) + } + return freeChat + } + // 返回免登 FreeChat 实例 + freeChat := NewFreeChat("") + if freeChat == nil && retry > 0 { + return GetFreeChat(accAuth, retry-1) + } + return freeChat +} func (FG *FreeChat) NewRequest(method, url string, body io.Reader) (*fhttp.Request, error) { request, err := RequestClient.NewRequest(method, url, body) if err != nil { @@ -146,16 +162,11 @@ func (FG *FreeChat) newRequestClient() error { return nil } -func (FG *FreeChat) getProxy(newFreeAuthType NewFreeAuthType) error { +func (FG *FreeChat) getProxy() error { // 获取代理池 ProxyPoolInstance := ProxyPool.GetProxyPoolInstance() // 获取代理 FG.Proxy = ProxyPoolInstance.GetProxy() - // 判断代理是否可用 - if FG.Proxy.CanUseAt > common.GetTimestampSecond(0) && newFreeAuthType == NewFreeAuthRefresh { - errStr := fmt.Sprint(FG.Proxy.Link, ": Proxy restricted, Reuse at ", FG.Proxy.CanUseAt) - return fmt.Errorf(errStr) - } // 补全cookies FG.Cookies = append(FG.Cookies, FG.Proxy.Cookies...) // 设置代理 @@ -205,7 +216,7 @@ func (FG *FreeChat) getCookies() error { return nil } -func (FG *FreeChat) newFreeAuth(newFreeAuthType NewFreeAuthType) error { +func (FG *FreeChat) newFreeAuth() error { // 生成新的设备 ID if FG.FreeAuth.OaiDeviceId == "" { FG.FreeAuth.OaiDeviceId = uuid.New().String() @@ -227,15 +238,7 @@ func (FG *FreeChat) newFreeAuth(newFreeAuthType NewFreeAuthType) error { } if response.StatusCode != 200 { logger.Logger.Debug(fmt.Sprint("newFreeAuth: StatusCode: ", response.StatusCode)) - if (response.StatusCode == 429 || response.StatusCode == 403) && newFreeAuthType == NewFreeAuthRefresh { - FG.Proxy.CanUseAt = common.GetTimestampSecond(300) - logger.Logger.Debug(fmt.Sprint("newFreeAuth: Proxy(", FG.Proxy.Link, ")restricted, Reuse at ", FG.Proxy.CanUseAt)) - } return fmt.Errorf("StatusCode: %d", response.StatusCode) - } else if newFreeAuthType == 0 { - // 成功后更新代理的可用时间 - FG.Proxy.CanUseAt = common.GetTimestampSecond(0) - logger.Logger.Debug(fmt.Sprint("newFreeAuth: Proxy(", FG.Proxy.Link, ")Reuse at ", FG.Proxy.CanUseAt)) } defer func(Body io.ReadCloser) { _ = Body.Close() @@ -262,9 +265,3 @@ func (FG *FreeChat) newFreeAuth(newFreeAuthType NewFreeAuthType) error { } return nil } - -// SubFreeChatMaxUseCount 减少 FreeChat 实例的最大使用次数 -func (FG *FreeChat) SubFreeChatMaxUseCount() *FreeChat { - FG.MaxUseCount-- - return FG -} diff --git a/FreeChatPool/FreeChatPool.go b/FreeChatPool/FreeChatPool.go deleted file mode 100644 index 2615ffb..0000000 --- a/FreeChatPool/FreeChatPool.go +++ /dev/null @@ -1,146 +0,0 @@ -package FreeChatPool - -import ( - "fmt" - "free-gpt3.5-2api/AccAuthPool" - "free-gpt3.5-2api/FreeChat" - "free-gpt3.5-2api/common" - "free-gpt3.5-2api/config" - "free-gpt3.5-2api/queue" - "github.com/aurorax-neo/go-logger" - "strings" - "sync" - "time" -) - -var ( - instance *FreeChatPool - once sync.Once -) - -type FreeChatPool struct { - queue *queue.Queue - capacity int // 队列容量 -} - -func newFreeChatPool(capacity int) *FreeChatPool { - return &FreeChatPool{ - queue: queue.New(), - capacity: capacity, - } -} - -func GetFreeChatPoolInstance() *FreeChatPool { - once.Do(func() { - logger.Logger.Info(fmt.Sprint("Init FreeChatPool...")) - // 初始化 FreeChatPool - instance = newFreeChatPool(config.PoolMaxCount) - // 定时刷新 FreeChatPool - instance.refreshFreeChatPool(time.Millisecond * 128) - // - logger.Logger.Info(fmt.Sprint("Init FreeChatPool Success", ", PoolMaxCount: ", config.PoolMaxCount, ", AuthExpirationDate: ", config.AuthED)) - }) - return instance -} - -func (G *FreeChatPool) refreshFreeChatPool(sleep time.Duration) { - // 检测 FreeChatPool 是否已满 - common.AsyncLoopTask(sleep, func() { - // 判断 FreeChatPool 是否已满 - if G.IsFull() { - return - } - // 获取新 FreeChat 实例 - freeChat := FreeChat.NewFreeChat(FreeChat.NewFreeAuthRefresh, 1, common.GetTimestampSecond(config.AuthED), "") - // 判断 FreeChat 实例是否有效 - if G.isLiveFreeChat(freeChat) { - // 入队新 FreeChat 实例 - G.AddFreeChat(freeChat) - } - }) - // 检测并移除无效 FreeChat 实例 - common.AsyncLoopTask(sleep, func() { - // 遍历队列中的所有元素 - G.queue.Traverse(func(n *queue.Node) { - // 判断是否为无效 FreeChat 实例 - if !G.isLiveFreeChat(n.Value.(*FreeChat.FreeChat)) { - // 移除无效 FreeChat 实例 - G.queue.Remove(n) - } - }) - }) -} - -func (G *FreeChatPool) isLiveFreeChat(freeChat *FreeChat.FreeChat) bool { - //判断是否为空 - if freeChat == nil || - freeChat.MaxUseCount <= 0 || //无可用次数 - freeChat.ExpiresAt <= common.GetTimestampSecond(0) { - return false - } - return true -} - -func (G *FreeChatPool) GetFreeChat(accAuth string, retry int) *FreeChat.FreeChat { - // 判断是否为指定账号 - if strings.HasPrefix(accAuth, "Bearer eyJhbGciOiJSUzI1NiI") { - freeChat := FreeChat.NewFreeChat(FreeChat.NewFreeAuthNormal, 1, common.GetTimestampSecond(config.AuthED), accAuth) - if freeChat == nil && retry > 0 { - return G.GetFreeChat(accAuth, retry-1) - } - return freeChat - } - // 判断是否使用 AccAuthPool - if strings.HasPrefix(accAuth, "Bearer "+AccAuthPool.AccAuthAuthorizationPre) && !AccAuthPool.GetAccAuthPoolInstance().IsEmpty() { - accA := AccAuthPool.GetAccAuthPoolInstance().GetAccAuth() - freeChat := FreeChat.NewFreeChat(FreeChat.NewFreeAuthNormal, 1, common.GetTimestampSecond(config.AuthED), accA) - if freeChat == nil && retry > 0 { - return G.GetFreeChat(accAuth, retry-1) - } - return freeChat - } - // 获取 FreeChat 实例 - n := G.queue.Peek() - if n != nil { - freeChat := n.Value.(*FreeChat.FreeChat) - // 判断 FreeChat 实例是否有效 - if G.isLiveFreeChat(freeChat) { - // 减少 FreeChat 实例可用次数 - freeChat.SubFreeChatMaxUseCount() - // 判断 FreeChat 实例是否有效 无效则移除 - if !G.isLiveFreeChat(freeChat) { - G.queue.Dequeue() - } - return freeChat - } else if retry > 0 { - time.Sleep(time.Millisecond * 128) - return G.GetFreeChat(accAuth, retry-1) - } - } - // 缓存内无可用 FreeChat 实例,返回新 FreeChat 实例 - return FreeChat.NewFreeChat(FreeChat.NewFreeAuthNormal, 1, common.GetTimestampSecond(config.AuthED), "") -} - -// GetSize 获取队列当前元素个数 -func (G *FreeChatPool) GetSize() int { - return G.queue.Len() -} - -// GetCapacity 获取队列容量 -func (G *FreeChatPool) GetCapacity() int { - return G.capacity -} - -// IsFull 检查队列是否已满 -func (G *FreeChatPool) IsFull() bool { - return G.queue.Len() == G.capacity -} - -// AddFreeChat 入队 -func (G *FreeChatPool) AddFreeChat(v *FreeChat.FreeChat) bool { - if G.IsFull() || v == nil { - return false - } - G.queue.Enqueue(v) - return true -} diff --git a/ProxyPool/ProxyPool.go b/ProxyPool/ProxyPool.go index 5ac4548..c63f07b 100644 --- a/ProxyPool/ProxyPool.go +++ b/ProxyPool/ProxyPool.go @@ -8,7 +8,6 @@ import ( fhttp "github.com/bogdanfinn/fhttp" "net/url" "sync" - "time" ) var ( @@ -22,36 +21,27 @@ type ProxyPool struct { } type Proxy struct { - Link *url.URL - CanUseAt int64 - Cookies []*fhttp.Cookie + Link *url.URL + Cookies []*fhttp.Cookie } func GetProxyPoolInstance() *ProxyPool { Once.Do(func() { - logger.Logger.Info(fmt.Sprint("Init ProxyPool...")) + logger.Logger.Debug(fmt.Sprint("Init ProxyPool...")) // 初始化 ProxyPool Instance = NewProxyPool(nil) // 遍历配置文件中的代理 添加到代理池 for _, px := range config.Proxy { - proxy := NewProxy(px, common.GetTimestampSecond(0)) - _ = proxy.getCookies() + proxy := NewProxy(px) Instance.AddProxy(proxy) } - //定时刷新代理cookies - common.AsyncLoopTask(1*time.Minute, func() { - for _, proxy := range Instance.Proxies { - _ = proxy.getCookies() - } - }) - logger.Logger.Info(fmt.Sprint("Init ProxyPool Success")) + logger.Logger.Debug(fmt.Sprint("Init ProxyPool Success")) }) return Instance } func NewProxyPool(proxies []*Proxy) *ProxyPool { - proxy := NewProxy("", common.GetTimestampSecond(0)) - _ = proxy.getCookies() + proxy := NewProxy("") return &ProxyPool{ Proxies: append([]*Proxy{proxy}, proxies...), Index: 0, @@ -72,13 +62,8 @@ func (PP *ProxyPool) AddProxy(proxy *Proxy) { PP.Proxies = append(PP.Proxies, proxy) } -func NewProxy(link string, cannotUseTime int64) *Proxy { +func NewProxy(link string) *Proxy { return &Proxy{ - Link: common.ParseUrl(link), - CanUseAt: cannotUseTime, + Link: common.ParseUrl(link), } } - -func (P *Proxy) getCookies() error { - return nil -} diff --git a/README.md b/README.md index c6b3855..0595957 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,6 @@ ACCESS_TOKENS= # 账号token池(eyJhbGci****,eyJhbGci****) PROXY= # http://127.0.0.1:7890,http://127.0.0.1:7890 已支持多个代理(英文 "," 分隔) AUTHORIZATIONS= # abc,bac (英文 "," 分隔) BASE_URL= # 默认:https://chat.openai.com -POOL_MAX_COUNT=64 # max number of connections to keep in the pool 默认:64 -AUTH_ED=600 # expiration time for the authorization in seconds 默认:600 ``` ###### 也可使用与程序同目录下 `.env` 文件配置上述字段 @@ -61,22 +59,7 @@ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtow ## 四、接口 -#### 1./v1/tokens - -``` -curl --location --request GET 'http://127.0.0.1:9846/v1/tokens' \ ---header 'Authorization: Bearer abc' -``` - -返回示例说明:`count`为授权池中可用授权数,如果`count` 为 `0`请检查`ip`是否支持 `openai` - -``` -{ - "count": 0 -} -``` - -#### 2./v1/accTokens +#### 1./v1/accTokens ``` curl --location --request GET 'http://127.0.0.1:9846/v1/accTokens' \ @@ -92,7 +75,7 @@ curl --location --request GET 'http://127.0.0.1:9846/v1/accTokens' \ } ``` -#### 3./v1/chat/completions +#### 2./v1/chat/completions ###### 支持返回stream和json @@ -127,5 +110,3 @@ curl --location --request POST 'http://127.0.0.1:9846/v1/chat/completions' \ - https://github.com/aurora-develop/aurora - https://github.com/xqdoo00o/ChatGPT-to-API - - diff --git a/RequestClient/ClientProfileTool.go b/RequestClient/ClientProfileTool.go index 06b1df0..f571ac7 100644 --- a/RequestClient/ClientProfileTool.go +++ b/RequestClient/ClientProfileTool.go @@ -1,18 +1,17 @@ package RequestClient import ( + "free-gpt3.5-2api/constant" browser "github.com/EDDYCJY/fake-useragent" "github.com/bogdanfinn/tls-client/profiles" "math/rand" "time" ) -const maxForceLogin = 5 - var ( - ClientProfile = randomClientProfile() - Ua = browser.Random() - MaxForceLogin = maxForceLogin + clientProfile = randomClientProfile() + ua = browser.Random() + maxForceLogin = constant.ReTry ) func randomClientProfile() profiles.ClientProfile { @@ -31,15 +30,18 @@ func randomClientProfile() profiles.ClientProfile { } func SubMaxForceLogin() { - MaxForceLogin-- + maxForceLogin-- + if maxForceLogin < 0 { + clientProfile = randomClientProfile() + ua = browser.Random() + maxForceLogin = constant.ReTry + } } func GetClientProfile() profiles.ClientProfile { - if MaxForceLogin > 0 { - return ClientProfile - } - ClientProfile = randomClientProfile() - Ua = browser.Random() - MaxForceLogin = maxForceLogin - return ClientProfile + return clientProfile +} + +func GetUa() string { + return ua } diff --git a/config/config.go b/config/config.go index 3eba9f3..222ba6a 100644 --- a/config/config.go +++ b/config/config.go @@ -74,7 +74,7 @@ func init() { // AUTH_ED authED := os.Getenv("AUTH_ED") if authED == "" { - AuthED = 600 + AuthED = 60 } else { AuthED, err = strconv.Atoi(authED) if err != nil { diff --git a/constant/constant.go b/constant/constant.go index 913c564..c6b199f 100644 --- a/constant/constant.go +++ b/constant/constant.go @@ -2,4 +2,6 @@ package constant var () -const () +const ( + ReTry = 5 +) diff --git a/env.template b/env.template index 44eaccf..0954b65 100644 --- a/env.template +++ b/env.template @@ -3,6 +3,3 @@ BIND=127.0.0.1 # PORT=8080 PROXY= AUTHORIZATIONS= -POOL_MAX_COUNT=5 # max number of connections to keep in the pool -AUTH_ED=180 # expiration time for the authorization in seconds -AUTH_USE_COUNT=5 # number of times an authorization can be used \ No newline at end of file diff --git a/main.go b/main.go index baf7a60..452517a 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "free-gpt3.5-2api/FreeChatPool" "free-gpt3.5-2api/ProxyPool" "free-gpt3.5-2api/config" "free-gpt3.5-2api/router" @@ -12,7 +11,6 @@ import ( func Init() { ProxyPool.GetProxyPoolInstance() - FreeChatPool.GetFreeChatPoolInstance() } func main() { diff --git a/queue/queue.go b/queue/queue.go deleted file mode 100644 index 3278488..0000000 --- a/queue/queue.go +++ /dev/null @@ -1,106 +0,0 @@ -package queue - -type ( - Queue struct { - start, end *Node - length int - } - Node struct { - Value interface{} - next *Node - } -) - -// New 新建一个队列 -func New() *Queue { - return &Queue{nil, nil, 0} -} - -// Dequeue 出队 -func (Q *Queue) Dequeue() *Node { - if Q.length == 0 { - return nil - } - n := Q.start - if Q.length == 1 { - Q.start = nil - Q.end = nil - } else { - Q.start = Q.start.next - } - Q.length-- - return n -} - -// Enqueue 入队 -func (Q *Queue) Enqueue(value interface{}) { - n := &Node{value, nil} - if Q.length == 0 { - Q.start = n - Q.end = n - } else { - Q.end.next = n - Q.end = n - } - Q.length++ -} - -// Len 获取队列长度 -func (Q *Queue) Len() int { - return Q.length -} - -// Peek 返回队列的第一个元素 -func (Q *Queue) Peek() *Node { - if Q.length == 0 { - return nil - } - return Q.start -} - -// Remove 移除指定节点 -func (Q *Queue) Remove(n *Node) { - if Q.length == 0 || n == nil { - return - } - - // 如果移除的是队列的第一个元素 - if n == Q.start { - Q.start = Q.start.next - if Q.start == nil { - // 如果移除后队列为空,则end也应该设置为nil - Q.end = nil - } - Q.length-- - return - } - - // 找到n的前一个节点 - prevNode := Q.start - for prevNode != nil && prevNode.next != n { - prevNode = prevNode.next - } - - if prevNode == nil { - // 没有找到n的前一个节点(n不在队列中) - return - } - - // 移除节点n - prevNode.next = n.next - // 如果移除的是最后一个元素,更新end指针 - if n.next == nil { - Q.end = prevNode - } - Q.length-- -} - -// Traverse 遍历队列 -func (Q *Queue) Traverse(cb func(n *Node)) { - if Q.length == 0 { - return - } - for n := Q.start; n != nil; n = n.next { - cb(n) - } -} diff --git a/router/router.go b/router/router.go index 46b9dc1..3ddef6a 100644 --- a/router/router.go +++ b/router/router.go @@ -15,7 +15,6 @@ func SetRouter(router *gin.Engine) { v1Router.Use(V1Request) v1Router.Use(V1Response) v1Router.Use(V1Auth) - v1Router.GET("/tokens", v1.Tokens) v1Router.GET("/accTokens", v1.AccTokens) v1Router.OPTIONS("/chat/completions", nil) v1Router.POST("/chat/completions", v1Chat.Completions) diff --git a/service/v1/tokens.go b/service/v1/tokens.go deleted file mode 100644 index f8caeb8..0000000 --- a/service/v1/tokens.go +++ /dev/null @@ -1,20 +0,0 @@ -package v1 - -import ( - "fmt" - "free-gpt3.5-2api/FreeChatPool" - "github.com/aurorax-neo/go-logger" - "github.com/gin-gonic/gin" -) - -type TokensResp struct { - Count int `json:"count"` -} - -func Tokens(c *gin.Context) { - resp := &TokensResp{ - Count: FreeChatPool.GetFreeChatPoolInstance().GetSize(), - } - logger.Logger.Info(fmt.Sprint("FreeChatPool Tokens: ", resp.Count)) - c.JSON(200, resp) -} diff --git a/service/v1Chat/completions.go b/service/v1Chat/completions.go index bb9ef8c..2c809d4 100644 --- a/service/v1Chat/completions.go +++ b/service/v1Chat/completions.go @@ -10,7 +10,7 @@ import ( "fmt" "free-gpt3.5-2api/AccAuthPool" "free-gpt3.5-2api/FreeChat" - "free-gpt3.5-2api/FreeChatPool" + "free-gpt3.5-2api/constant" "free-gpt3.5-2api/typings" "github.com/gorilla/websocket" "net/url" @@ -55,7 +55,7 @@ func Completions(c *gin.Context) { } authToken := c.Request.Header.Get("Authorization") - freeChat := FreeChatPool.GetFreeChatPoolInstance().GetFreeChat(authToken, 3) + freeChat := FreeChat.GetFreeChat(authToken, constant.ReTry) if freeChat == nil { errStr := "please restart the program、change the IP address、use a proxy to try again." logger.Logger.Error(errStr)