From ce3c2659946e246c1e86f3e8f2aeb75633740ccf Mon Sep 17 00:00:00 2001 From: root Date: Fri, 4 Aug 2023 09:44:47 +0800 Subject: [PATCH] fix GPT-4 model, structural change of access_tokens.json, add har file tutorial to readme --- .gitignore | 3 ++- README.md | 17 ++++++++++++----- README_JA.md | 2 +- README_ZH.md | 19 ++++++++++++++----- auth.go | 15 ++++++++------- conversion/requests/chatgpt/convert.go | 4 ++-- go.mod | 2 +- go.sum | 14 ++------------ handlers.go | 10 +++++----- internal/chatgpt/request.go | 6 +++--- internal/tokens/tokens.go | 20 ++++++++++++-------- main.go | 26 +------------------------- 12 files changed, 63 insertions(+), 75 deletions(-) diff --git a/.gitignore b/.gitignore index c7720d7..bb23c3c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ access_tokens.json freechatgpt chatgpttoapi tools/authenticator/.proxies.txt.swp -.env \ No newline at end of file +.env +*.har \ No newline at end of file diff --git a/README.md b/README.md index b3231dc..1157d9f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Create a fake API using ChatGPT's website ### Authentication -Access token retrieval has been automated by [OpenAIAuth](https://github.com/acheong08/OpenAIAuth/) with account email & password. +Access token and PUID(only for PLUS account) retrieval has been automated by [OpenAIAuth](https://github.com/acheong08/OpenAIAuth/) with account email & password. `accounts.txt` - A list of accounts separated by new line @@ -21,12 +21,20 @@ email:password ... ``` -All authenticated access tokens will store in `access_tokens.json` +All authenticated access tokens and PUID will store in `access_tokens.json` -Auto renew access tokens after 14 days +Auto renew access tokens and PUID after 7 days Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. +### GPT-4 Model (Optional) + +If you configured a PLUS account and use the GPT-4 model, a HAR file (`chat.openai.com.har`) is required to complete CAPTCHA verification + +1. Use a chromium-based browser (Chrome, Edge) or Safari to login to `https://chat.openai.com/`, then open the browser developer tools (F12), and switch to the Network tab. + +2. Create a new chat and select the GPT-4 model, ask a question at will, click the Export HAR button under the Network tab, export the file `chat.openai.com.har` + ### API Authentication (Optional) Custom API keys for this fake API, just like OpenAI api @@ -52,7 +60,6 @@ go build - `PUID` - A cookie found on chat.openai.com for Plus users. This gets around Cloudflare rate limits - `SERVER_HOST` - Set to 127.0.0.1 by default - `SERVER_PORT` - Set to 8080 by default - - `OPENAI_EMAIL` and `OPENAI_PASSWORD` - It will automatically refresh your PUID if set (requires Plus account) - `ENABLE_HISTORY` - Set to true by default ### Files (Optional) @@ -64,7 +71,7 @@ go build ``` - `access_tokens.json` - A JSON array of access tokens for cycling (Alternatively, send a PATCH request to the [correct endpoint](https://github.com/acheong08/ChatGPT-to-API/blob/master/docs/admin.md)) ``` - ["access_token1", "access_token2"...] + [{token:"access_token1", puid:"puid1"}, {token:"access_token2", puid:"puid2"}...] ``` ## Admin API docs diff --git a/README_JA.md b/README_JA.md index c5bc3b2..7579731 100644 --- a/README_JA.md +++ b/README_JA.md @@ -24,7 +24,7 @@ email:password すべての認証されたアクセストークンは `access_tokens.json` に保存されます -アクセストークンは 14 日後に自動更新されます +アクセストークンは 7 日後に自動更新されます 注意!認証にはブロックされていない ip を使用してください。可能であれば、まず `https://chat.openai.com/` にログインして ip の可用性を確認してください。 diff --git a/README_ZH.md b/README_ZH.md index 4b7e97e..ae932b5 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -7,7 +7,7 @@ ### 设置 -配置账户邮箱和密码,自动生成和更新Access tokens(使用[OpenAIAuth](https://github.com/acheong08/OpenAIAuth/)) +配置账户邮箱和密码,自动生成和更新Access tokens 和 PUID(仅PLUS账户)(使用[OpenAIAuth](https://github.com/acheong08/OpenAIAuth/)) `accounts.txt` - 存放OpenAI账号邮箱和密码的文件 @@ -18,12 +18,20 @@ ... ``` -所有登录后的Access tokens会存放在`access_tokens.json` +所有登录后的Access tokens和PUID会存放在`access_tokens.json` -每14天自动更新Access tokens +每7天自动更新Access tokens和PUID 注意! 请使用未封锁的ip登录账号,请先打开浏览器登录`https://chat.openai.com/`以检查ip是否可用 +### GPT-4 设置(可选) + +如果配置PLUS账户并使用GPT-4模型,则需要HAR文件(`chat.openai.com.har`)以完成captcha验证 + +1. 使用基于chromium的浏览器(Chrome,Edge)或Safari浏览器 登录`https://chat.openai.com/`,然后打开浏览器开发者工具(F12),并切换到网络标签页。 + +2. 新建聊天并选择GPT-4模型,随意问一个问题,点击网络标签页下的导出HAR按钮,导出文件`chat.openai.com.har` + ### API 密钥(可选) 如OpenAI的官方API一样,可给模拟的API添加API密钥认证 @@ -50,6 +58,7 @@ go build - `SERVER_HOST` - 默认127.0.0.1 - `SERVER_PORT` - 默认8080 - `ENABLE_HISTORY` - 默认true,允许网页端历史记录 + ### 可选文件配置 - `proxies.txt` - 存放代理地址的文件 @@ -58,9 +67,9 @@ go build socks5://127.0.0.1:9999 ... ``` - - `access_tokens.json` - 一个存放Access tokens JSON数组的文件 (可使用 PATCH请求更新Access tokens [correct endpoint](https://github.com/acheong08/ChatGPT-to-API/blob/master/docs/admin.md)) + - `access_tokens.json` - 一个存放Access tokens 和PUID JSON数组的文件 (可使用 PATCH请求更新Access tokens [correct endpoint](https://github.com/acheong08/ChatGPT-to-API/blob/master/docs/admin.md)) ``` - ["access_token1", "access_token2"...] + [{token:"access_token1", puid:"puid1"}, {token:"access_token2", puid:"puid2"}...] ``` ## 用户管理文档 diff --git a/auth.go b/auth.go index b07969d..537aa45 100644 --- a/auth.go +++ b/auth.go @@ -43,7 +43,7 @@ func readAccounts() { } } } -func scheduleToken() { +func scheduleTokenPUID() { // Check if access_tokens.json exists if stat, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { // Create the file @@ -56,8 +56,8 @@ func scheduleToken() { } else { nowTime := time.Now() usedTime := nowTime.Sub(stat.ModTime()) - // update access token 14 days after last modify token file - toExpire := 1.2096e15 - usedTime + // update access token 7 days after last modify token file + toExpire := 6.048e14 - usedTime if toExpire > 0 { file, err := os.Open("access_tokens.json") if err != nil { @@ -65,7 +65,7 @@ func scheduleToken() { } defer file.Close() decoder := json.NewDecoder(file) - var token_list []string + var token_list []tokens.Secret err = decoder.Decode(&token_list) if err != nil { updateToken() @@ -84,7 +84,7 @@ func scheduleToken() { } func updateToken() { - token_list := []string{} + token_list := []tokens.Secret{} // Loop through each account for _, account := range accounts { if os.Getenv("CF_PROXY") != "" { @@ -113,7 +113,8 @@ func updateToken() { return } access_token := authenticator.GetAccessToken() - token_list = append(token_list, access_token) + puid, _ := authenticator.GetPUID() + token_list = append(token_list, tokens.Secret{access_token, puid}) println("Success!") // Write authenticated account to authenticated_accounts.txt f, go_err := os.OpenFile("authenticated_accounts.txt", os.O_APPEND|os.O_WRONLY, 0600) @@ -147,5 +148,5 @@ func updateToken() { } // Append access token to access_tokens.json ACCESS_TOKENS = tokens.NewAccessToken(token_list, true) - time.AfterFunc(1.2096e15, updateToken) + time.AfterFunc(6.048e14, updateToken) } diff --git a/conversion/requests/chatgpt/convert.go b/conversion/requests/chatgpt/convert.go index 8bb97ac..e32bb11 100644 --- a/conversion/requests/chatgpt/convert.go +++ b/conversion/requests/chatgpt/convert.go @@ -9,13 +9,13 @@ import ( arkose "github.com/acheong08/funcaptcha" ) -func ConvertAPIRequest(api_request official_types.APIRequest) chatgpt_types.ChatGPTRequest { +func ConvertAPIRequest(api_request official_types.APIRequest, puid string, proxy string) chatgpt_types.ChatGPTRequest { chatgpt_request := chatgpt_types.NewChatGPTRequest() if strings.HasPrefix(api_request.Model, "gpt-3.5") { chatgpt_request.Model = "text-davinci-002-render-sha" } if strings.HasPrefix(api_request.Model, "gpt-4") { - token, _, err := arkose.GetOpenAIToken() + token, _, err := arkose.GetOpenAIToken(puid, proxy) if err == nil { chatgpt_request.ArkoseToken = token } else { diff --git a/go.mod b/go.mod index 491996e..c85dc23 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/acheong08/OpenAIAuth v0.0.0-20230719092354-c8cd4e19491b github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd - github.com/acheong08/funcaptcha v1.2.2-0.20230702093045-02d1fbf1b0e8 + github.com/acheong08/funcaptcha v1.9.3-0.20230803133445-f4d081d60ac7 github.com/bogdanfinn/fhttp v0.5.23 github.com/bogdanfinn/tls-client v1.4.0 github.com/gin-gonic/gin v1.9.1 diff --git a/go.sum b/go.sum index 08158c8..1c88319 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,9 @@ -github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057 h1:AmqKpClFTUHREYekSfSy3Yn7MR/oc6WTfKtEyzB/J7o= -github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057/go.mod h1:ES3Dh9hnbR2mDPlNTagj5e3b4nXECd4tbAjVgxggXEE= -github.com/acheong08/OpenAIAuth v0.0.0-20230716134840-dbf5ba4f9507 h1:1kZEmE1DeQEeIMHhQUqn+NqOdApF9BIv835ox09E2k8= -github.com/acheong08/OpenAIAuth v0.0.0-20230716134840-dbf5ba4f9507/go.mod h1:bkiXtklBFVpWHyWTys6Zhqb521i/gtT8cIUKWVx2m/M= github.com/acheong08/OpenAIAuth v0.0.0-20230719092354-c8cd4e19491b h1:Jg+UV8bO5dXaisG/loeYFewewqmUJjjHGSxB9XZVqoc= github.com/acheong08/OpenAIAuth v0.0.0-20230719092354-c8cd4e19491b/go.mod h1:bkiXtklBFVpWHyWTys6Zhqb521i/gtT8cIUKWVx2m/M= github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd h1:oIpfrRhD7Jus41dotbK+SQjWSFRnf1cLZUYCZpF/o/4= github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd/go.mod h1:0yO7neMeJLvKk/B/fq5votDY8rByrOPDubpvU+6saKo= -github.com/acheong08/funcaptcha v0.2.1-0.20230628085018-57a8c9b81bc8 h1:COt2vPM8gz+PiUjeWH1enYPfMM3FiM/HFELqU6nO2PQ= -github.com/acheong08/funcaptcha v0.2.1-0.20230628085018-57a8c9b81bc8/go.mod h1:VupbjtVAODvgyAB3Zo86fOA53G+UAmaV/Rk9jUCGuTU= -github.com/acheong08/funcaptcha v0.2.1-0.20230628154248-28b05efd8e52 h1:cZ9RUUz+A5HUXQjIf9KJzF+K90EEcVdSJyWJc8S7qds= -github.com/acheong08/funcaptcha v0.2.1-0.20230628154248-28b05efd8e52/go.mod h1:VupbjtVAODvgyAB3Zo86fOA53G+UAmaV/Rk9jUCGuTU= -github.com/acheong08/funcaptcha v0.2.1-0.20230629044031-084e7dfaffef h1:B5fq4j+Qiu/6vay/70BG9mBuBgF28CnA4MTx1+J2V+o= -github.com/acheong08/funcaptcha v0.2.1-0.20230629044031-084e7dfaffef/go.mod h1:VupbjtVAODvgyAB3Zo86fOA53G+UAmaV/Rk9jUCGuTU= -github.com/acheong08/funcaptcha v1.2.2-0.20230702093045-02d1fbf1b0e8 h1:6VDA9GYZeDBc5xB6mmG9M/U2scvKCxd8izGxk6qHWmY= -github.com/acheong08/funcaptcha v1.2.2-0.20230702093045-02d1fbf1b0e8/go.mod h1:azmXv2Mfbw5eBOnMw5e1yTMNVyku17klWhGtkHwm7PY= +github.com/acheong08/funcaptcha v1.9.3-0.20230803133445-f4d081d60ac7 h1:lnvGKeyLfHKZOeYhUFRZE/GJjCAV1k3jW50e1UsZcVk= +github.com/acheong08/funcaptcha v1.9.3-0.20230803133445-f4d081d60ac7/go.mod h1:azmXv2Mfbw5eBOnMw5e1yTMNVyku17klWhGtkHwm7PY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/bogdanfinn/fhttp v0.5.23 h1:4Xb5OjYArB8GpnUw4A4r5jmt8UW0/Cvey3R9nS2dC9U= diff --git a/handlers.go b/handlers.go index c9cd553..94b0a64 100644 --- a/handlers.go +++ b/handlers.go @@ -70,7 +70,7 @@ func puidHandler(c *gin.Context) { func tokensHandler(c *gin.Context) { // Get the request_tokens from the request (json) and update the request_tokens - var request_tokens []string + var request_tokens []tokens.Secret err := c.BindJSON(&request_tokens) if err != nil { c.String(400, "tokens not provided") @@ -102,7 +102,7 @@ func nightmare(c *gin.Context) { } authHeader := c.GetHeader("Authorization") - token := ACCESS_TOKENS.GetToken() + token, puid := ACCESS_TOKENS.GetSecret() if authHeader != "" { customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1) // Check if customAccessToken starts with sk- @@ -120,9 +120,9 @@ func nightmare(c *gin.Context) { } // Convert the chat request to a ChatGPT request - translated_request := chatgpt_request_converter.ConvertAPIRequest(original_request) + translated_request := chatgpt_request_converter.ConvertAPIRequest(original_request, puid, proxy_url) - response, err := chatgpt.POSTconversation(translated_request, token, proxy_url) + response, err := chatgpt.POSTconversation(translated_request, token, puid, proxy_url) if err != nil { c.JSON(500, gin.H{ "error": "error sending request", @@ -147,7 +147,7 @@ func nightmare(c *gin.Context) { translated_request.Action = "continue" translated_request.ConversationID = continue_info.ConversationID translated_request.ParentMessageID = continue_info.ParentID - response, err = chatgpt.POSTconversation(translated_request, token, proxy_url) + response, err = chatgpt.POSTconversation(translated_request, token, puid, proxy_url) if err != nil { c.JSON(500, gin.H{ "error": "error sending request", diff --git a/internal/chatgpt/request.go b/internal/chatgpt/request.go index a096f9e..8f58b8a 100644 --- a/internal/chatgpt/request.go +++ b/internal/chatgpt/request.go @@ -40,7 +40,7 @@ func init() { arkose.SetTLSClient(&client) } -func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, proxy string) (*http.Response, error) { +func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, puid string, proxy string) (*http.Response, error) { if proxy != "" { client.SetProxy(proxy) } @@ -61,8 +61,8 @@ func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, return &http.Response{}, err } // Clear cookies - if os.Getenv("PUID") != "" { - request.Header.Set("Cookie", "_puid="+os.Getenv("PUID")+";") + if puid != "" { + request.Header.Set("Cookie", "_puid="+puid+";") } request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36") diff --git a/internal/tokens/tokens.go b/internal/tokens/tokens.go index 50d6530..f8423c7 100644 --- a/internal/tokens/tokens.go +++ b/internal/tokens/tokens.go @@ -6,12 +6,16 @@ import ( "sync" ) +type Secret struct { + Token string `json:"token"` + PUID string `json:"puid"` +} type AccessToken struct { - tokens []string + tokens []Secret lock sync.Mutex } -func NewAccessToken(tokens []string, save bool) AccessToken { +func NewAccessToken(tokens []Secret, save bool) AccessToken { // Save the tokens to a file if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { // Create the file @@ -32,7 +36,7 @@ func NewAccessToken(tokens []string, save bool) AccessToken { } } -func Save(tokens []string) bool { +func Save(tokens []Secret) bool { file, err := os.OpenFile("access_tokens.json", os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { return false @@ -46,15 +50,15 @@ func Save(tokens []string) bool { return true } -func (a *AccessToken) GetToken() string { +func (a *AccessToken) GetSecret() (string, string) { a.lock.Lock() defer a.lock.Unlock() if len(a.tokens) == 0 { - return "" + return "", "" } - token := a.tokens[0] - a.tokens = append(a.tokens[1:], token) - return token + secret := a.tokens[0] + a.tokens = append(a.tokens[1:], secret) + return secret.Token, secret.PUID } diff --git a/main.go b/main.go index 1007e54..26cedbc 100644 --- a/main.go +++ b/main.go @@ -3,12 +3,9 @@ package main import ( "bufio" "freechatgpt/internal/tokens" - "log" "os" "strings" - "time" - "github.com/acheong08/OpenAIAuth/auth" "github.com/acheong08/endless" "github.com/gin-gonic/gin" "github.com/joho/godotenv" @@ -49,27 +46,6 @@ func checkProxy() { func init() { _ = godotenv.Load(".env") - go func() { - for { - if os.Getenv("OPENAI_EMAIL") == "" || os.Getenv("OPENAI_PASSWORD") == "" { - time.Sleep(24 * time.Hour * 7) - continue - } - authenticator := auth.NewAuthenticator(os.Getenv("OPENAI_EMAIL"), os.Getenv("OPENAI_PASSWORD"), os.Getenv("http_proxy")) - err := authenticator.Begin() - if err != nil { - log.Println(err) - break - } - puid, err := authenticator.GetPUID() - if err != nil { - break - } - os.Setenv("PUID", puid) - println(puid) - time.Sleep(24 * time.Hour * 7) - } - }() HOST = os.Getenv("SERVER_HOST") PORT = os.Getenv("SERVER_PORT") @@ -84,7 +60,7 @@ func init() { } checkProxy() readAccounts() - scheduleToken() + scheduleTokenPUID() } func main() { router := gin.Default()