From 20190b233ac16d4ee949a4f02b83f017cc3d3b7b Mon Sep 17 00:00:00 2001 From: David xu Date: Thu, 18 May 2023 11:42:54 +0800 Subject: [PATCH 01/12] auto generate access tokens --- README.md | 60 ++++++++---------- auth.go | 117 ++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 + handlers.go | 13 +++- internal/chatgpt/request.go | 43 +------------ internal/tokens/tokens.go | 22 +++++-- main.go | 70 +++++++++++++++------ 8 files changed, 225 insertions(+), 103 deletions(-) create mode 100644 auth.go diff --git a/README.md b/README.md index 8f4765d..bcfef1d 100644 --- a/README.md +++ b/README.md @@ -3,60 +3,48 @@ Create a fake API using ChatGPT's website **API endpoint: http://127.0.0.1:8080/v1/chat/completions.** -## Help needed -- Documentation. - ## Setup - -
- ### Authentication - -Access token retrieval has been automated: -https://github.com/acheong08/ChatGPT-to-API/tree/master/tools/authenticator +Access token retrieval has been automated by [OpenAIAuth](https://github.com/acheong08/OpenAIAuth/) with account email & password. -Converting from a newline delimited list of access tokens to `access_tokens.json` -```bash -#!/bin/bash +`accounts.txt` - A list of accounts separated by new line -START="[" -END="]" - -TOKENS="" - -while read -r line; do - if [ -z "$TOKENS" ]; then - TOKENS="\"$line\"" - else - TOKENS+=",\"$line\"" - fi -done < access_tokens.txt - -echo "$START$TOKENS$END" > access_tokens.json +Format: +``` +email:password +... ``` -
+All authenticated access tokens will store in `access_tokens.json` + +Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. ## Getting set up - -`git clone https://github.com/acheong08/ChatGPT-to-API` -`cd ChatGPT-to-API` -`go build` -`./freechatgpt` +``` +git clone https://github.com/xqdoo00o/ChatGPT-to-API +cd ChatGPT-to-API +go build +./freechatgpt +``` ### Environment variables - `PUID` - A cookie found on chat.openai.com for Plus users. This gets around Cloudflare rate limits - - `http_proxy` - SOCKS5 or HTTP proxy. `socks5://HOST:PORT` - `SERVER_HOST` - Set to 127.0.0.1 by default - `SERVER_PORT` - Set to 8080 by default ### Files (Optional) - - `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)) - - `proxies.txt` - A list of proxies separated by new line (Format: `USERNAME:PASSWORD:HOST:PORT`) - + - `proxies.txt` - A list of proxies separated by new line + ``` + http://127.0.0.1:8888 + ... + ``` + - `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"...] + ``` ## Admin API docs https://github.com/acheong08/ChatGPT-to-API/blob/master/docs/admin.md diff --git a/auth.go b/auth.go new file mode 100644 index 0000000..76a6d79 --- /dev/null +++ b/auth.go @@ -0,0 +1,117 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "strings" + "time" + + "freechatgpt/internal/tokens" + "github.com/acheong08/OpenAIAuth/auth" +) + +type Account struct { + Email string `json:"username"` + Password string `json:"password"` +} + +// Read accounts.txt and create a list of accounts +func readAccounts() []Account { + accounts := []Account{} + // Read accounts.txt and create a list of accounts + if _, err := os.Stat("accounts.txt"); err == nil { + // Each line is a proxy, put in proxies array + file, _ := os.Open("accounts.txt") + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + // Split by : + line := strings.Split(scanner.Text(), ":") + // Create an account + account := Account{ + Email: line[0], + Password: line[1], + } + // Append to accounts + accounts = append(accounts, account) + } + } + return accounts +} + +func updateToken() { + accounts := readAccounts() + token_list := []string{} + // Loop through each account + for _, account := range accounts { + if os.Getenv("CF_PROXY") != "" { + // exec warp-cli disconnect and connect + exec.Command("warp-cli", "disconnect").Run() + exec.Command("warp-cli", "connect").Run() + time.Sleep(5 * time.Second) + } + println(account.Email) + println(account.Password) + var proxy_url string + if len(proxies) == 0 { + proxy_url = "" + } else { + proxy_url = proxies[0] + // Push used proxy to the back of the list + proxies = append(proxies[1:], proxies[0]) + } + authenticator := auth.NewAuthenticator(account.Email, account.Password, proxy_url) + err := authenticator.Begin() + if err.Error != nil { + // println("Error: " + err.Details) + println("Location: " + err.Location) + println("Status code: " + fmt.Sprint(err.StatusCode)) + println("Details: " + err.Details) + println("Embedded error: " + err.Error.Error()) + return + } + access_token, err := authenticator.GetAccessToken() + if err.Error != nil { + // println("Error: " + err.Details) + println("Location: " + err.Location) + println("Status code: " + fmt.Sprint(err.StatusCode)) + println("Embedded error: " + err.Error.Error()) + return + } + token_list = append(token_list, access_token) + // Write authenticated account to authenticated_accounts.txt + f, go_err := os.OpenFile("authenticated_accounts.txt", os.O_APPEND|os.O_WRONLY, 0600) + if go_err != nil { + continue + } + defer f.Close() + if _, go_err = f.WriteString(account.Email + ":" + account.Password + "\n"); go_err != nil { + continue + } + // Remove accounts.txt + os.Remove("accounts.txt") + // Create accounts.txt + f, go_err = os.Create("accounts.txt") + if go_err != nil { + continue + } + defer f.Close() + // Remove account from accounts + accounts = accounts[1:] + // Write unauthenticated accounts to accounts.txt + for _, acc := range accounts { + // Check if account is authenticated + if acc.Email == account.Email { + continue + } + if _, go_err = f.WriteString(acc.Email + ":" + acc.Password + "\n"); go_err != nil { + continue + } + } + } + // Append access token to access_tokens.json + ACCESS_TOKENS = tokens.NewAccessToken(token_list, true) + time.AfterFunc(2.16e15, updateToken) +} diff --git a/go.mod b/go.mod index 9d347f3..a0a4abf 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( ) require ( + github.com/acheong08/OpenAIAuth v0.0.0-20230429120645-cf04cc5986cc // indirect github.com/andybalholm/brotli v1.0.4 // indirect github.com/bogdanfinn/utls v1.5.15 // indirect github.com/bytedance/sonic v1.8.0 // indirect diff --git a/go.sum b/go.sum index 0e140a7..4b99d97 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/acheong08/OpenAIAuth v0.0.0-20230429120645-cf04cc5986cc h1:WpbCaZsudUpNTRkuwrpap+X0d76qydqNYg1s0OqtcnI= +github.com/acheong08/OpenAIAuth v0.0.0-20230429120645-cf04cc5986cc/go.mod h1:QAJ15BSNp3HNgPWPn2CK1zsZnCeBR60v2u798OTBif8= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/bogdanfinn/fhttp v0.5.19 h1:/FKuFAtSw3+iZyNkaWXRDSVqMmOvThDjXanlG6/DXos= diff --git a/handlers.go b/handlers.go index 5eb146c..1e66358 100644 --- a/handlers.go +++ b/handlers.go @@ -39,7 +39,7 @@ func tokensHandler(c *gin.Context) { c.String(400, "tokens not provided") return } - ACCESS_TOKENS = tokens.NewAccessToken(request_tokens) + ACCESS_TOKENS = tokens.NewAccessToken(request_tokens, true) c.String(200, "tokens updated") } func optionsHandler(c *gin.Context) { @@ -75,8 +75,15 @@ func nightmare(c *gin.Context) { // println("customAccessToken set:" + customAccessToken) // } // } - - response, err := chatgpt.SendRequest(translated_request, token) + var proxy_url string + if len(proxies) == 0 { + proxy_url = "" + } else { + proxy_url = proxies[0] + // Push used proxy to the back of the list + proxies = append(proxies[1:], proxies[0]) + } + response, err := chatgpt.SendRequest(translated_request, token, 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 cbeb074..c09c976 100644 --- a/internal/chatgpt/request.go +++ b/internal/chatgpt/request.go @@ -1,12 +1,9 @@ package chatgpt import ( - "bufio" "bytes" "encoding/json" - "math/rand" "os" - "strings" typings "freechatgpt/internal/typings" @@ -14,8 +11,6 @@ import ( tls_client "github.com/bogdanfinn/tls-client" ) -var proxies []string - var ( jar = tls_client.NewCookieJar() options = []tls_client.HttpClientOption{ @@ -27,44 +22,12 @@ var ( tls_client.WithInsecureSkipVerify(), } client, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) - http_proxy = os.Getenv("http_proxy") API_REVERSE_PROXY = os.Getenv("API_REVERSE_PROXY") ) -func init() { - // Check for proxies.txt - if _, err := os.Stat("proxies.txt"); err == nil { - // Each line is a proxy, put in proxies array - file, _ := os.Open("proxies.txt") - defer file.Close() - scanner := bufio.NewScanner(file) - for scanner.Scan() { - // Split line by : - proxy := scanner.Text() - proxy_parts := strings.Split(proxy, ":") - if len(proxy_parts) == 2 { - proxy = "socks5://" + proxy - } else if len(proxy_parts) == 4 { - proxy = "socks5://" + proxy_parts[2] + ":" + proxy_parts[3] + "@" + proxy_parts[0] + ":" + proxy_parts[1] - } else { - continue - } - proxies = append(proxies, proxy) - } - } -} - -func random_int(min int, max int) int { - return min + rand.Intn(max-min) -} - -func SendRequest(message typings.ChatGPTRequest, access_token string) (*http.Response, error) { - if http_proxy != "" && len(proxies) == 0 { - client.SetProxy(http_proxy) - } - // Take random proxy from proxies.txt - if len(proxies) > 0 { - client.SetProxy(proxies[random_int(0, len(proxies))]) +func SendRequest(message typings.ChatGPTRequest, access_token string, proxy string) (*http.Response, error) { + if proxy != "" { + client.SetProxy(proxy) } apiUrl := "https://chat.openai.com/backend-api/conversation" diff --git a/internal/tokens/tokens.go b/internal/tokens/tokens.go index d118d26..48ca0a3 100644 --- a/internal/tokens/tokens.go +++ b/internal/tokens/tokens.go @@ -11,7 +11,7 @@ type AccessToken struct { lock sync.Mutex } -func NewAccessToken(tokens []string) AccessToken { +func NewAccessToken(tokens []string, save bool) AccessToken { // Save the tokens to a file if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { // Create the file @@ -21,19 +21,29 @@ func NewAccessToken(tokens []string) AccessToken { } defer file.Close() } + if save { + saved := Save(tokens) + if saved == false { + return AccessToken{} + } + } + return AccessToken{ + tokens: tokens, + } +} + +func Save(tokens []string) bool { file, err := os.OpenFile("access_tokens.json", os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { - return AccessToken{} + return false } defer file.Close() encoder := json.NewEncoder(file) err = encoder.Encode(tokens) if err != nil { - return AccessToken{} - } - return AccessToken{ - tokens: tokens, + return false } + return true } func (a *AccessToken) GetToken() string { diff --git a/main.go b/main.go index e9b2f40..3bc3dc0 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,12 @@ package main import ( + "bufio" "encoding/json" "freechatgpt/internal/tokens" "os" "strings" + "time" "github.com/fvbock/endless" "github.com/gin-gonic/gin" @@ -13,6 +15,28 @@ import ( var HOST string var PORT string var ACCESS_TOKENS tokens.AccessToken +var proxies []string + +func checkProxy() { + // Check for proxies.txt + proxies = []string{} + if _, err := os.Stat("proxies.txt"); err == nil { + // Each line is a proxy, put in proxies array + file, _ := os.Open("proxies.txt") + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + // Split line by : + proxy := scanner.Text() + proxy_parts := strings.Split(proxy, ":") + if len(proxy_parts) > 0 { + proxies = append(proxies, proxy) + } else { + continue + } + } + } +} func init() { HOST = os.Getenv("SERVER_HOST") @@ -23,33 +47,43 @@ func init() { if PORT == "" { PORT = "8080" } - accessToken := os.Getenv("ACCESS_TOKENS") - if accessToken != "" { - accessTokens := strings.Split(accessToken, ",") - ACCESS_TOKENS = tokens.NewAccessToken(accessTokens) - } + checkProxy() // Check if access_tokens.json exists - if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { + if stat, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { // Create the file file, err := os.Create("access_tokens.json") if err != nil { panic(err) } defer file.Close() + updateToken() } else { - // Load the tokens - file, err := os.Open("access_tokens.json") - if err != nil { - panic(err) + nowTime := time.Now() + usedTime := nowTime.Sub(stat.ModTime()) + // update access token 25 days after last modify token file + toExpire := 2.16e15 - usedTime + if toExpire > 0 { + file, err := os.Open("access_tokens.json") + if err != nil { + panic(err) + } + defer file.Close() + decoder := json.NewDecoder(file) + var token_list []string + err = decoder.Decode(&token_list) + if err != nil { + updateToken() + return + } + if len(token_list) == 0 { + updateToken() + } else { + ACCESS_TOKENS = tokens.NewAccessToken(token_list, false) + time.AfterFunc(toExpire, updateToken) + } + } else { + updateToken() } - defer file.Close() - decoder := json.NewDecoder(file) - var token_list []string - err = decoder.Decode(&token_list) - if err != nil { - return - } - ACCESS_TOKENS = tokens.NewAccessToken(token_list) } } From 5afc25d596b3b2a7b759afc1d479bfa75aa204bb Mon Sep 17 00:00:00 2001 From: root Date: Thu, 18 May 2023 23:20:24 +0800 Subject: [PATCH 02/12] update renew interval --- auth.go | 2 +- main.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/auth.go b/auth.go index 76a6d79..ef1d098 100644 --- a/auth.go +++ b/auth.go @@ -113,5 +113,5 @@ func updateToken() { } // Append access token to access_tokens.json ACCESS_TOKENS = tokens.NewAccessToken(token_list, true) - time.AfterFunc(2.16e15, updateToken) + time.AfterFunc(1.728e15, updateToken) } diff --git a/main.go b/main.go index 3bc3dc0..b9a4faf 100644 --- a/main.go +++ b/main.go @@ -60,8 +60,8 @@ func init() { } else { nowTime := time.Now() usedTime := nowTime.Sub(stat.ModTime()) - // update access token 25 days after last modify token file - toExpire := 2.16e15 - usedTime + // update access token 20 days after last modify token file + toExpire := 1.728e15 - usedTime if toExpire > 0 { file, err := os.Open("access_tokens.json") if err != nil { From 011a8d0feac7cb6ef990e2190246df4e8ade55dc Mon Sep 17 00:00:00 2001 From: David xu Date: Fri, 19 May 2023 15:47:02 +0800 Subject: [PATCH 03/12] complete readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bcfef1d..ea66437 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ email:password ``` All authenticated access tokens will store in `access_tokens.json` +Auto renew access tokens after 20 days Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. From b264b048fe55a0e9b11873b625ed0e75fe50d141 Mon Sep 17 00:00:00 2001 From: David xu Date: Fri, 19 May 2023 15:58:05 +0800 Subject: [PATCH 04/12] complete readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ea66437..8c308a1 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ email:password ``` All authenticated access tokens will store in `access_tokens.json` + Auto renew access tokens after 20 days Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. From dadb8949c391ac1b0a94cf7683fecbf90fa280e8 Mon Sep 17 00:00:00 2001 From: David xu Date: Mon, 22 May 2023 14:34:44 +0800 Subject: [PATCH 05/12] complete readme --- README.md | 4 ++-- README_ZH.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 README_ZH.md diff --git a/README.md b/README.md index 8c308a1..98ac427 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # ChatGPT-to-API -Create a fake API using ChatGPT's website +Create a fake API using ChatGPT's website [中文说明](https://github.com/xqdoo00o/ChatGPT-to-API/blob/master/README_ZH.md) **API endpoint: http://127.0.0.1:8080/v1/chat/completions.** ## Setup ### Authentication - + Access token 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 diff --git a/README_ZH.md b/README_ZH.md new file mode 100644 index 0000000..e805058 --- /dev/null +++ b/README_ZH.md @@ -0,0 +1,56 @@ +# ChatGPT-to-API +从ChatGPT网站模拟使用API + +**模拟API地址: http://127.0.0.1:8080/v1/chat/completions.** + +## 使用 + +### 设置 + +配置账户邮箱和密码,自动生成和更新Access tokens(使用[OpenAIAuth](https://github.com/acheong08/OpenAIAuth/)) + +`accounts.txt` - 存放OpenAI账号邮箱和密码的文件 + +格式: +``` +邮箱:密码 +邮箱:密码 +... +``` + +所有登录后的Access tokens会存放在`access_tokens.json` + +每20天自动更新Access tokens + +注意! 请使用未封锁的ip登录账号,请先打开浏览器登录`https://chat.openai.com/`以检查ip是否可用 + +## 开始 +``` +git clone https://github.com/xqdoo00o/ChatGPT-to-API +cd ChatGPT-to-API +go build +./freechatgpt +``` + +### 环境变量 + - `PUID` - Plus账户可在`chat.openai.com`的cookies里找到,用于绕过cf的频率限制 + - `SERVER_HOST` - 默认127.0.0.1 + - `SERVER_PORT` - 默认8080 +### 可选文件配置 + - `proxies.txt` - 存放代理地址的文件 + + ``` + http://127.0.0.1:8888 + 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_token1", "access_token2"...] + ``` + +## 用户管理文档 +https://github.com/acheong08/ChatGPT-to-API/blob/master/docs/admin.md + +## API使用说明 +https://platform.openai.com/docs/api-reference/chat From c4e4679ccb5799e4fa82a6a80b997d117227534d Mon Sep 17 00:00:00 2001 From: root Date: Tue, 23 May 2023 15:15:58 +0800 Subject: [PATCH 06/12] friendly print for update token --- auth.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth.go b/auth.go index ef1d098..db61177 100644 --- a/auth.go +++ b/auth.go @@ -52,8 +52,7 @@ func updateToken() { exec.Command("warp-cli", "connect").Run() time.Sleep(5 * time.Second) } - println(account.Email) - println(account.Password) + println("Updating access token for " + account.Email) var proxy_url string if len(proxies) == 0 { proxy_url = "" @@ -81,6 +80,7 @@ func updateToken() { return } token_list = append(token_list, access_token) + println("Success!") // Write authenticated account to authenticated_accounts.txt f, go_err := os.OpenFile("authenticated_accounts.txt", os.O_APPEND|os.O_WRONLY, 0600) if go_err != nil { From adb26f3829eb3149a3c26587e540b1d905744341 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 27 May 2023 15:27:40 +0800 Subject: [PATCH 07/12] fix proxies --- go.mod | 7 ++++--- go.sum | 19 ++++++++++--------- main.go | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 7162359..4ef8292 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module freechatgpt go 1.20 require ( + github.com/acheong08/OpenAIAuth v0.0.0-20230527070416-f4984abea338 github.com/acheong08/endless v0.0.0-20230522010333-1359fd84c836 github.com/bogdanfinn/fhttp v0.5.22 github.com/bogdanfinn/tls-client v1.3.12 @@ -11,10 +12,9 @@ require ( ) require ( - github.com/acheong08/OpenAIAuth v0.0.0-20230429120645-cf04cc5986cc // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/bogdanfinn/utls v1.5.16 // indirect - github.com/bytedance/sonic v1.8.9 // indirect + github.com/bytedance/sonic v1.9.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -29,7 +29,8 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect diff --git a/go.sum b/go.sum index 77ef3ce..524c46e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/acheong08/OpenAIAuth v0.0.0-20230429120645-cf04cc5986cc h1:WpbCaZsudUpNTRkuwrpap+X0d76qydqNYg1s0OqtcnI= -github.com/acheong08/OpenAIAuth v0.0.0-20230429120645-cf04cc5986cc/go.mod h1:QAJ15BSNp3HNgPWPn2CK1zsZnCeBR60v2u798OTBif8= +github.com/acheong08/OpenAIAuth v0.0.0-20230527070416-f4984abea338 h1:Mv4YyBEPlxJki5zMoZjtu7fWu/Q5O2b6e2rnE2yQ0aE= +github.com/acheong08/OpenAIAuth v0.0.0-20230527070416-f4984abea338/go.mod h1:ES3Dh9hnbR2mDPlNTagj5e3b4nXECd4tbAjVgxggXEE= github.com/acheong08/endless v0.0.0-20230522010333-1359fd84c836 h1:1qPj/+BrLWPt+V0/DpWrysvZKj8VRjQ+VNcePUpL6Y8= github.com/acheong08/endless v0.0.0-20230522010333-1359fd84c836/go.mod h1:0yO7neMeJLvKk/B/fq5votDY8rByrOPDubpvU+6saKo= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= @@ -11,10 +11,8 @@ github.com/bogdanfinn/tls-client v1.3.12/go.mod h1:Q46nwIm0wPCweDM3XZcupxEIsTOWo github.com/bogdanfinn/utls v1.5.16 h1:NhhWkegEcYETBMj9nvgO4lwvc6NcLH+znrXzO3gnw4M= github.com/bogdanfinn/utls v1.5.16/go.mod h1:mHeRCi69cUiEyVBkKONB1cAbLjRcZnlJbGzttmiuK4o= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q= -github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/bytedance/sonic v1.8.9 h1:mXB6OoHaI9OrWugkvNxWiuHTy5RCrVfxg2Nn40sf0oc= -github.com/bytedance/sonic v1.8.9/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.9.0 h1:iwLYBds8bYtzwOX7kmdYwtS+aY2GgekVoIs2/IxR0tM= +github.com/bytedance/sonic v1.9.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= @@ -58,8 +56,10 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= -github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -70,8 +70,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc= github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= diff --git a/main.go b/main.go index bb33c7e..b33ed1a 100644 --- a/main.go +++ b/main.go @@ -29,7 +29,7 @@ func checkProxy() { // Split line by : proxy := scanner.Text() proxy_parts := strings.Split(proxy, ":") - if len(proxy_parts) > 0 { + if len(proxy_parts) > 1 { proxies = append(proxies, proxy) } else { continue From 1d6d7a3ce32c52e3cb27e0ec062d1297ef8ffd69 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 27 May 2023 15:44:23 +0800 Subject: [PATCH 08/12] complete readme --- README.md | 13 +++++++++++++ README_ZH.md | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/README.md b/README.md index 98ac427..7fb3704 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,19 @@ Auto renew access tokens after 20 days Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. +### API Authentication (Optional) + +Custom API keys for this fake API, just like OpenAI api + +`api_keys.txt` - A list of API keys separated by new line + +Format: +``` +sk-123456 +88888888 +... +``` + ## Getting set up ``` git clone https://github.com/xqdoo00o/ChatGPT-to-API diff --git a/README_ZH.md b/README_ZH.md index e805058..1999463 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -24,6 +24,19 @@ 注意! 请使用未封锁的ip登录账号,请先打开浏览器登录`https://chat.openai.com/`以检查ip是否可用 +### API 密钥(可选) + +如OpenAI的官方API一样,可给模拟的API添加API密钥认证 + +`api_keys.txt` - 存放API密钥的文件 + +格式: +``` +sk-123456 +88888888 +... +``` + ## 开始 ``` git clone https://github.com/xqdoo00o/ChatGPT-to-API From 0301b7d6071fdd92296d781efd3126804d504e08 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 14 Jun 2023 11:06:16 +0800 Subject: [PATCH 09/12] auth code --- auth.go | 57 ++++++++++++++---- go.mod | 24 ++++---- go.sum | 50 ++++++++-------- internal/tokens/tokens.go | 120 +++++++++++++++++++------------------- main.go | 40 +------------ 5 files changed, 144 insertions(+), 147 deletions(-) diff --git a/auth.go b/auth.go index 7a3d493..e312b1c 100644 --- a/auth.go +++ b/auth.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "encoding/json" "fmt" "os" "os/exec" @@ -13,14 +14,16 @@ import ( "github.com/acheong08/OpenAIAuth/auth" ) +var accounts []Account + type Account struct { Email string `json:"username"` Password string `json:"password"` } // Read accounts.txt and create a list of accounts -func readAccounts() []Account { - accounts := []Account{} +func readAccounts() { + accounts = []Account{} // Read accounts.txt and create a list of accounts if _, err := os.Stat("accounts.txt"); err == nil { // Each line is a proxy, put in proxies array @@ -39,11 +42,48 @@ func readAccounts() []Account { accounts = append(accounts, account) } } - return accounts +} +func scheduleToken() { + // Check if access_tokens.json exists + if stat, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { + // Create the file + file, err := os.Create("access_tokens.json") + if err != nil { + panic(err) + } + defer file.Close() + updateToken() + } else { + nowTime := time.Now() + usedTime := nowTime.Sub(stat.ModTime()) + // update access token 20 days after last modify token file + toExpire := 1.728e15 - usedTime + if toExpire > 0 { + file, err := os.Open("access_tokens.json") + if err != nil { + panic(err) + } + defer file.Close() + decoder := json.NewDecoder(file) + var token_list []string + err = decoder.Decode(&token_list) + if err != nil { + updateToken() + return + } + if len(token_list) == 0 { + updateToken() + } else { + ACCESS_TOKENS = tokens.NewAccessToken(token_list, false) + time.AfterFunc(toExpire, updateToken) + } + } else { + updateToken() + } + } } func updateToken() { - accounts := readAccounts() token_list := []string{} // Loop through each account for _, account := range accounts { @@ -64,7 +104,7 @@ func updateToken() { } authenticator := auth.NewAuthenticator(account.Email, account.Password, proxy_url) err := authenticator.Begin() - if err.Error != nil { + if err != nil { // println("Error: " + err.Details) println("Location: " + err.Location) println("Status code: " + fmt.Sprint(err.StatusCode)) @@ -73,13 +113,6 @@ func updateToken() { return } access_token := authenticator.GetAccessToken() - if err.Error != nil { - // println("Error: " + err.Details) - println("Location: " + err.Location) - println("Status code: " + fmt.Sprint(err.StatusCode)) - println("Embedded error: " + err.Error.Error()) - return - } token_list = append(token_list, access_token) println("Success!") // Write authenticated account to authenticated_accounts.txt diff --git a/go.mod b/go.mod index 76ff858..4a86a65 100644 --- a/go.mod +++ b/go.mod @@ -3,28 +3,28 @@ module freechatgpt go 1.20 require ( - github.com/acheong08/OpenAIAuth v0.0.0-20230530050836-f2a06cd52911 + github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057 github.com/acheong08/endless v0.0.0-20230529075213-74050cf641c8 - github.com/bogdanfinn/fhttp v0.5.22 - github.com/bogdanfinn/tls-client v1.3.12 - github.com/gin-gonic/gin v1.9.0 + github.com/bogdanfinn/fhttp v0.5.23 + github.com/bogdanfinn/tls-client v1.4.0 + github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 ) require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/bogdanfinn/utls v1.5.16 // indirect - github.com/bytedance/sonic v1.9.0 // indirect + github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.14.1 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.5 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -35,10 +35,10 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.9.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/crypto v0.10.0 // indirect + golang.org/x/net v0.11.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 6516dde..375826e 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,18 @@ -github.com/acheong08/OpenAIAuth v0.0.0-20230530050836-f2a06cd52911 h1:KNdCGjt2DkrFn4RNS6Uh41rHwyD6dUhYxYuhVFxsZkc= -github.com/acheong08/OpenAIAuth v0.0.0-20230530050836-f2a06cd52911/go.mod h1:ES3Dh9hnbR2mDPlNTagj5e3b4nXECd4tbAjVgxggXEE= +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/endless v0.0.0-20230529075213-74050cf641c8 h1:mHtMoGlGNUfMRjsWcb5Kvd1mJfJG8Gr1TtIghE8iiN8= github.com/acheong08/endless v0.0.0-20230529075213-74050cf641c8/go.mod h1:0yO7neMeJLvKk/B/fq5votDY8rByrOPDubpvU+6saKo= 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.22 h1:U1jhZRtuaOanWWcm1WdMFnwMvSxUQgvO6berqAVTc5o= -github.com/bogdanfinn/fhttp v0.5.22/go.mod h1:brqi5woc5eSCVHdKYBV8aZLbO7HGqpwyDLeXW+fT18I= -github.com/bogdanfinn/tls-client v1.3.12 h1:jpNj7owMY/oULUQyAhAv6tRFkliFGLyr8Qx1ZZY/gp8= -github.com/bogdanfinn/tls-client v1.3.12/go.mod h1:Q46nwIm0wPCweDM3XZcupxEIsTOWo3HVYSSsDj02/Qo= +github.com/bogdanfinn/fhttp v0.5.23 h1:4Xb5OjYArB8GpnUw4A4r5jmt8UW0/Cvey3R9nS2dC9U= +github.com/bogdanfinn/fhttp v0.5.23/go.mod h1:brqi5woc5eSCVHdKYBV8aZLbO7HGqpwyDLeXW+fT18I= +github.com/bogdanfinn/tls-client v1.4.0 h1:ptZmkvVyRTjMFPc3Kevholf+ioePkCM5oj3qkOmOuoM= +github.com/bogdanfinn/tls-client v1.4.0/go.mod h1:lgtqsHjoJYQMPz6H08bc8t30bmUaYnVjwtfVEzMGJDs= github.com/bogdanfinn/utls v1.5.16 h1:NhhWkegEcYETBMj9nvgO4lwvc6NcLH+znrXzO3gnw4M= github.com/bogdanfinn/utls v1.5.16/go.mod h1:mHeRCi69cUiEyVBkKONB1cAbLjRcZnlJbGzttmiuK4o= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.0 h1:iwLYBds8bYtzwOX7kmdYwtS+aY2GgekVoIs2/IxR0tM= -github.com/bytedance/sonic v1.9.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= @@ -23,15 +23,15 @@ github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= -github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= +github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -42,11 +42,11 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= +github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= @@ -82,16 +82,16 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= diff --git a/internal/tokens/tokens.go b/internal/tokens/tokens.go index 48ca0a3..50d6530 100644 --- a/internal/tokens/tokens.go +++ b/internal/tokens/tokens.go @@ -1,60 +1,60 @@ -package tokens - -import ( - "encoding/json" - "os" - "sync" -) - -type AccessToken struct { - tokens []string - lock sync.Mutex -} - -func NewAccessToken(tokens []string, save bool) AccessToken { - // Save the tokens to a file - if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { - // Create the file - file, err := os.Create("access_tokens.json") - if err != nil { - return AccessToken{} - } - defer file.Close() - } - if save { - saved := Save(tokens) - if saved == false { - return AccessToken{} - } - } - return AccessToken{ - tokens: tokens, - } -} - -func Save(tokens []string) bool { - file, err := os.OpenFile("access_tokens.json", os.O_WRONLY|os.O_TRUNC, 0644) - if err != nil { - return false - } - defer file.Close() - encoder := json.NewEncoder(file) - err = encoder.Encode(tokens) - if err != nil { - return false - } - return true -} - -func (a *AccessToken) GetToken() string { - a.lock.Lock() - defer a.lock.Unlock() - - if len(a.tokens) == 0 { - return "" - } - - token := a.tokens[0] - a.tokens = append(a.tokens[1:], token) - return token -} +package tokens + +import ( + "encoding/json" + "os" + "sync" +) + +type AccessToken struct { + tokens []string + lock sync.Mutex +} + +func NewAccessToken(tokens []string, save bool) AccessToken { + // Save the tokens to a file + if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { + // Create the file + file, err := os.Create("access_tokens.json") + if err != nil { + return AccessToken{} + } + defer file.Close() + } + if save { + saved := Save(tokens) + if saved == false { + return AccessToken{} + } + } + return AccessToken{ + tokens: tokens, + } +} + +func Save(tokens []string) bool { + file, err := os.OpenFile("access_tokens.json", os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return false + } + defer file.Close() + encoder := json.NewEncoder(file) + err = encoder.Encode(tokens) + if err != nil { + return false + } + return true +} + +func (a *AccessToken) GetToken() string { + a.lock.Lock() + defer a.lock.Unlock() + + if len(a.tokens) == 0 { + return "" + } + + token := a.tokens[0] + a.tokens = append(a.tokens[1:], token) + return token +} diff --git a/main.go b/main.go index 69a29b1..a7b33fb 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,6 @@ package main import ( "bufio" - "encoding/json" "freechatgpt/internal/tokens" "log" "os" @@ -76,43 +75,8 @@ func init() { PORT = "8080" } checkProxy() - // Check if access_tokens.json exists - if stat, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { - // Create the file - file, err := os.Create("access_tokens.json") - if err != nil { - panic(err) - } - defer file.Close() - updateToken() - } else { - nowTime := time.Now() - usedTime := nowTime.Sub(stat.ModTime()) - // update access token 20 days after last modify token file - toExpire := 1.728e15 - usedTime - if toExpire > 0 { - file, err := os.Open("access_tokens.json") - if err != nil { - panic(err) - } - defer file.Close() - decoder := json.NewDecoder(file) - var token_list []string - err = decoder.Decode(&token_list) - if err != nil { - updateToken() - return - } - if len(token_list) == 0 { - updateToken() - } else { - ACCESS_TOKENS = tokens.NewAccessToken(token_list, false) - time.AfterFunc(toExpire, updateToken) - } - } else { - updateToken() - } - } + readAccounts() + scheduleToken() } func main() { router := gin.Default() From dee1ff15a42095395e0be2d207bf406917fe17b3 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 14 Jun 2023 11:20:48 +0800 Subject: [PATCH 10/12] fix gpt-4 --- conversion/requests/chatgpt/convert.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/conversion/requests/chatgpt/convert.go b/conversion/requests/chatgpt/convert.go index 00178ea..a2bab58 100644 --- a/conversion/requests/chatgpt/convert.go +++ b/conversion/requests/chatgpt/convert.go @@ -3,12 +3,16 @@ package chatgpt import ( chatgpt_types "freechatgpt/typings/chatgpt" official_types "freechatgpt/typings/official" + "strings" ) func ConvertAPIRequest(api_request official_types.APIRequest) chatgpt_types.ChatGPTRequest { chatgpt_request := chatgpt_types.NewChatGPTRequest() - if api_request.Model == "gpt-4" || api_request.Model == "gpt-4-browsing" || api_request.Model == "gpt-4-plugins" || api_request.Model == "gpt-4-mobile" || api_request.Model == "gpt-4-code-interpreter" { - chatgpt_request.Model = api_request.Model + if strings.HasPrefix(api_request.Model, "gpt-4") { + chatgpt_request.Model = "gpt-4" + if api_request.Model == "gpt-4-browsing" || api_request.Model == "gpt-4-plugins" || api_request.Model == "gpt-4-mobile" || api_request.Model == "gpt-4-code-interpreter" { + chatgpt_request.Model = api_request.Model + } } for _, api_message := range api_request.Messages { From baf8da9268c6f0160e24759172b3569ecc4a118b Mon Sep 17 00:00:00 2001 From: root Date: Mon, 17 Jul 2023 10:57:17 +0800 Subject: [PATCH 11/12] shorten cycle --- auth.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/auth.go b/auth.go index e312b1c..b07969d 100644 --- a/auth.go +++ b/auth.go @@ -56,8 +56,8 @@ func scheduleToken() { } else { nowTime := time.Now() usedTime := nowTime.Sub(stat.ModTime()) - // update access token 20 days after last modify token file - toExpire := 1.728e15 - usedTime + // update access token 14 days after last modify token file + toExpire := 1.2096e15 - usedTime if toExpire > 0 { file, err := os.Open("access_tokens.json") if err != nil { @@ -147,5 +147,5 @@ func updateToken() { } // Append access token to access_tokens.json ACCESS_TOKENS = tokens.NewAccessToken(token_list, true) - time.AfterFunc(1.728e15, updateToken) + time.AfterFunc(1.2096e15, updateToken) } From 2b22c0427d6c02977833a265a32701ee020a947f Mon Sep 17 00:00:00 2001 From: root Date: Thu, 20 Jul 2023 11:14:47 +0800 Subject: [PATCH 12/12] update renew schedule --- README.md | 6 ++++-- README_ZH.md | 2 +- conversion/requests/chatgpt/convert.go | 7 ++++--- main.go | 9 ++++++++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 30ae569..56dc3ce 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # ChatGPT-to-API -Create a fake API using ChatGPT's website [中文说明](https://github.com/xqdoo00o/ChatGPT-to-API/blob/master/README_ZH.md) +Create a fake API using ChatGPT's website > ## IMPORTANT > You will not get free support for this repository. This was made for my own personal use and documentation will continue to be limited as I don't really need documentation. You will find more detailed documentation in the Chinese docs by a contributor. **API endpoint: http://127.0.0.1:8080/v1/chat/completions.** +[中文文档(Chinese Docs)](https://github.com/xqdoo00o/ChatGPT-to-API/blob/master/README_ZH.md) ## Setup ### Authentication @@ -22,7 +23,7 @@ email:password All authenticated access tokens will store in `access_tokens.json` -Auto renew access tokens after 20 days +Auto renew access tokens after 14 days Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can. @@ -52,6 +53,7 @@ go build - `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) - `proxies.txt` - A list of proxies separated by new line diff --git a/README_ZH.md b/README_ZH.md index 328b2c0..f0eb6d6 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -20,7 +20,7 @@ 所有登录后的Access tokens会存放在`access_tokens.json` -每20天自动更新Access tokens +每14天自动更新Access tokens 注意! 请使用未封锁的ip登录账号,请先打开浏览器登录`https://chat.openai.com/`以检查ip是否可用 diff --git a/conversion/requests/chatgpt/convert.go b/conversion/requests/chatgpt/convert.go index 7ece96d..8bb97ac 100644 --- a/conversion/requests/chatgpt/convert.go +++ b/conversion/requests/chatgpt/convert.go @@ -21,9 +21,10 @@ func ConvertAPIRequest(api_request official_types.APIRequest) chatgpt_types.Chat } else { fmt.Println("Error getting Arkose token: ", err) } - chatgpt_request.Model = "gpt-4" - if api_request.Model == "gpt-4-browsing" || api_request.Model == "gpt-4-mobile" || api_request.Model == "gpt-4-code-interpreter" { - chatgpt_request.Model = api_request.Model + chatgpt_request.Model = api_request.Model + // Cover some models like gpt-4-32k + if len(api_request.Model) >= 7 && api_request.Model[6] >= 48 && api_request.Model[6] <= 57 { + chatgpt_request.Model = "gpt-4" } } if api_request.PluginIDs != nil { diff --git a/main.go b/main.go index 0cd3940..1007e54 100644 --- a/main.go +++ b/main.go @@ -20,7 +20,7 @@ var ACCESS_TOKENS tokens.AccessToken var proxies []string func checkProxy() { - // Check for proxies.txt + // first check for proxies.txt proxies = []string{} if _, err := os.Stat("proxies.txt"); err == nil { // Each line is a proxy, put in proxies array @@ -38,6 +38,13 @@ func checkProxy() { } } } + // if no proxies, then check env http_proxy + if len(proxies) == 0 { + proxy := os.Getenv("http_proxy") + if proxy != "" { + proxies = append(proxies, proxy) + } + } } func init() {