1
0

fix GPT-4 model, structural change of access_tokens.json, add har file tutorial to readme

This commit is contained in:
root 2023-08-04 09:44:47 +08:00
parent 0431ff8703
commit ce3c265994
12 changed files with 63 additions and 75 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ freechatgpt
chatgpttoapi chatgpttoapi
tools/authenticator/.proxies.txt.swp tools/authenticator/.proxies.txt.swp
.env .env
*.har

View File

@ -11,7 +11,7 @@ Create a fake API using ChatGPT's website
### Authentication ### 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 `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. 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) ### API Authentication (Optional)
Custom API keys for this fake API, just like OpenAI api 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 - `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_HOST` - Set to 127.0.0.1 by default
- `SERVER_PORT` - Set to 8080 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 - `ENABLE_HISTORY` - Set to true by default
### Files (Optional) ### 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_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 ## Admin API docs

View File

@ -24,7 +24,7 @@ email:password
すべての認証されたアクセストークンは `access_tokens.json` に保存されます すべての認証されたアクセストークンは `access_tokens.json` に保存されます
アクセストークンは 14 日後に自動更新されます アクセストークンは 7 日後に自動更新されます
注意!認証にはブロックされていない ip を使用してください。可能であれば、まず `https://chat.openai.com/` にログインして ip の可用性を確認してください。 注意!認証にはブロックされていない ip を使用してください。可能であれば、まず `https://chat.openai.com/` にログインして ip の可用性を確認してください。

View File

@ -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账号邮箱和密码的文件 `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是否可用 注意! 请使用未封锁的ip登录账号请先打开浏览器登录`https://chat.openai.com/`以检查ip是否可用
### GPT-4 设置(可选)
如果配置PLUS账户并使用GPT-4模型则需要HAR文件`chat.openai.com.har`以完成captcha验证
1. 使用基于chromium的浏览器ChromeEdge或Safari浏览器 登录`https://chat.openai.com/`然后打开浏览器开发者工具F12并切换到网络标签页。
2. 新建聊天并选择GPT-4模型随意问一个问题点击网络标签页下的导出HAR按钮导出文件`chat.openai.com.har`
### API 密钥(可选) ### API 密钥(可选)
如OpenAI的官方API一样可给模拟的API添加API密钥认证 如OpenAI的官方API一样可给模拟的API添加API密钥认证
@ -50,6 +58,7 @@ go build
- `SERVER_HOST` - 默认127.0.0.1 - `SERVER_HOST` - 默认127.0.0.1
- `SERVER_PORT` - 默认8080 - `SERVER_PORT` - 默认8080
- `ENABLE_HISTORY` - 默认true允许网页端历史记录 - `ENABLE_HISTORY` - 默认true允许网页端历史记录
### 可选文件配置 ### 可选文件配置
- `proxies.txt` - 存放代理地址的文件 - `proxies.txt` - 存放代理地址的文件
@ -58,9 +67,9 @@ go build
socks5://127.0.0.1:9999 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"}...]
``` ```
## 用户管理文档 ## 用户管理文档

15
auth.go
View File

@ -43,7 +43,7 @@ func readAccounts() {
} }
} }
} }
func scheduleToken() { func scheduleTokenPUID() {
// Check if access_tokens.json exists // Check if access_tokens.json exists
if stat, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { if stat, err := os.Stat("access_tokens.json"); os.IsNotExist(err) {
// Create the file // Create the file
@ -56,8 +56,8 @@ func scheduleToken() {
} else { } else {
nowTime := time.Now() nowTime := time.Now()
usedTime := nowTime.Sub(stat.ModTime()) usedTime := nowTime.Sub(stat.ModTime())
// update access token 14 days after last modify token file // update access token 7 days after last modify token file
toExpire := 1.2096e15 - usedTime toExpire := 6.048e14 - usedTime
if toExpire > 0 { if toExpire > 0 {
file, err := os.Open("access_tokens.json") file, err := os.Open("access_tokens.json")
if err != nil { if err != nil {
@ -65,7 +65,7 @@ func scheduleToken() {
} }
defer file.Close() defer file.Close()
decoder := json.NewDecoder(file) decoder := json.NewDecoder(file)
var token_list []string var token_list []tokens.Secret
err = decoder.Decode(&token_list) err = decoder.Decode(&token_list)
if err != nil { if err != nil {
updateToken() updateToken()
@ -84,7 +84,7 @@ func scheduleToken() {
} }
func updateToken() { func updateToken() {
token_list := []string{} token_list := []tokens.Secret{}
// Loop through each account // Loop through each account
for _, account := range accounts { for _, account := range accounts {
if os.Getenv("CF_PROXY") != "" { if os.Getenv("CF_PROXY") != "" {
@ -113,7 +113,8 @@ func updateToken() {
return return
} }
access_token := authenticator.GetAccessToken() 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!") println("Success!")
// Write authenticated account to authenticated_accounts.txt // Write authenticated account to authenticated_accounts.txt
f, go_err := os.OpenFile("authenticated_accounts.txt", os.O_APPEND|os.O_WRONLY, 0600) 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 // Append access token to access_tokens.json
ACCESS_TOKENS = tokens.NewAccessToken(token_list, true) ACCESS_TOKENS = tokens.NewAccessToken(token_list, true)
time.AfterFunc(1.2096e15, updateToken) time.AfterFunc(6.048e14, updateToken)
} }

View File

@ -9,13 +9,13 @@ import (
arkose "github.com/acheong08/funcaptcha" 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() chatgpt_request := chatgpt_types.NewChatGPTRequest()
if strings.HasPrefix(api_request.Model, "gpt-3.5") { if strings.HasPrefix(api_request.Model, "gpt-3.5") {
chatgpt_request.Model = "text-davinci-002-render-sha" chatgpt_request.Model = "text-davinci-002-render-sha"
} }
if strings.HasPrefix(api_request.Model, "gpt-4") { if strings.HasPrefix(api_request.Model, "gpt-4") {
token, _, err := arkose.GetOpenAIToken() token, _, err := arkose.GetOpenAIToken(puid, proxy)
if err == nil { if err == nil {
chatgpt_request.ArkoseToken = token chatgpt_request.ArkoseToken = token
} else { } else {

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.20
require ( require (
github.com/acheong08/OpenAIAuth v0.0.0-20230719092354-c8cd4e19491b github.com/acheong08/OpenAIAuth v0.0.0-20230719092354-c8cd4e19491b
github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd 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/fhttp v0.5.23
github.com/bogdanfinn/tls-client v1.4.0 github.com/bogdanfinn/tls-client v1.4.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1

14
go.sum
View File

@ -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 h1:Jg+UV8bO5dXaisG/loeYFewewqmUJjjHGSxB9XZVqoc=
github.com/acheong08/OpenAIAuth v0.0.0-20230719092354-c8cd4e19491b/go.mod h1:bkiXtklBFVpWHyWTys6Zhqb521i/gtT8cIUKWVx2m/M= 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 h1:oIpfrRhD7Jus41dotbK+SQjWSFRnf1cLZUYCZpF/o/4=
github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd/go.mod h1:0yO7neMeJLvKk/B/fq5votDY8rByrOPDubpvU+6saKo= 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 v1.9.3-0.20230803133445-f4d081d60ac7 h1:lnvGKeyLfHKZOeYhUFRZE/GJjCAV1k3jW50e1UsZcVk=
github.com/acheong08/funcaptcha v0.2.1-0.20230628085018-57a8c9b81bc8/go.mod h1:VupbjtVAODvgyAB3Zo86fOA53G+UAmaV/Rk9jUCGuTU= github.com/acheong08/funcaptcha v1.9.3-0.20230803133445-f4d081d60ac7/go.mod h1:azmXv2Mfbw5eBOnMw5e1yTMNVyku17klWhGtkHwm7PY=
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/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/bogdanfinn/fhttp v0.5.23 h1:4Xb5OjYArB8GpnUw4A4r5jmt8UW0/Cvey3R9nS2dC9U= github.com/bogdanfinn/fhttp v0.5.23 h1:4Xb5OjYArB8GpnUw4A4r5jmt8UW0/Cvey3R9nS2dC9U=

View File

@ -70,7 +70,7 @@ func puidHandler(c *gin.Context) {
func tokensHandler(c *gin.Context) { func tokensHandler(c *gin.Context) {
// Get the request_tokens from the request (json) and update the request_tokens // 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) err := c.BindJSON(&request_tokens)
if err != nil { if err != nil {
c.String(400, "tokens not provided") c.String(400, "tokens not provided")
@ -102,7 +102,7 @@ func nightmare(c *gin.Context) {
} }
authHeader := c.GetHeader("Authorization") authHeader := c.GetHeader("Authorization")
token := ACCESS_TOKENS.GetToken() token, puid := ACCESS_TOKENS.GetSecret()
if authHeader != "" { if authHeader != "" {
customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1) customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1)
// Check if customAccessToken starts with sk- // Check if customAccessToken starts with sk-
@ -120,9 +120,9 @@ func nightmare(c *gin.Context) {
} }
// Convert the chat request to a ChatGPT request // 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 { if err != nil {
c.JSON(500, gin.H{ c.JSON(500, gin.H{
"error": "error sending request", "error": "error sending request",
@ -147,7 +147,7 @@ func nightmare(c *gin.Context) {
translated_request.Action = "continue" translated_request.Action = "continue"
translated_request.ConversationID = continue_info.ConversationID translated_request.ConversationID = continue_info.ConversationID
translated_request.ParentMessageID = continue_info.ParentID 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 { if err != nil {
c.JSON(500, gin.H{ c.JSON(500, gin.H{
"error": "error sending request", "error": "error sending request",

View File

@ -40,7 +40,7 @@ func init() {
arkose.SetTLSClient(&client) 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 != "" { if proxy != "" {
client.SetProxy(proxy) client.SetProxy(proxy)
} }
@ -61,8 +61,8 @@ func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string,
return &http.Response{}, err return &http.Response{}, err
} }
// Clear cookies // Clear cookies
if os.Getenv("PUID") != "" { if puid != "" {
request.Header.Set("Cookie", "_puid="+os.Getenv("PUID")+";") request.Header.Set("Cookie", "_puid="+puid+";")
} }
request.Header.Set("Content-Type", "application/json") 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") 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")

View File

@ -6,12 +6,16 @@ import (
"sync" "sync"
) )
type Secret struct {
Token string `json:"token"`
PUID string `json:"puid"`
}
type AccessToken struct { type AccessToken struct {
tokens []string tokens []Secret
lock sync.Mutex lock sync.Mutex
} }
func NewAccessToken(tokens []string, save bool) AccessToken { func NewAccessToken(tokens []Secret, save bool) AccessToken {
// Save the tokens to a file // Save the tokens to a file
if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) {
// Create the file // 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) file, err := os.OpenFile("access_tokens.json", os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil { if err != nil {
return false return false
@ -46,15 +50,15 @@ func Save(tokens []string) bool {
return true return true
} }
func (a *AccessToken) GetToken() string { func (a *AccessToken) GetSecret() (string, string) {
a.lock.Lock() a.lock.Lock()
defer a.lock.Unlock() defer a.lock.Unlock()
if len(a.tokens) == 0 { if len(a.tokens) == 0 {
return "" return "", ""
} }
token := a.tokens[0] secret := a.tokens[0]
a.tokens = append(a.tokens[1:], token) a.tokens = append(a.tokens[1:], secret)
return token return secret.Token, secret.PUID
} }

26
main.go
View File

@ -3,12 +3,9 @@ package main
import ( import (
"bufio" "bufio"
"freechatgpt/internal/tokens" "freechatgpt/internal/tokens"
"log"
"os" "os"
"strings" "strings"
"time"
"github.com/acheong08/OpenAIAuth/auth"
"github.com/acheong08/endless" "github.com/acheong08/endless"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/joho/godotenv" "github.com/joho/godotenv"
@ -49,27 +46,6 @@ func checkProxy() {
func init() { func init() {
_ = godotenv.Load(".env") _ = 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") HOST = os.Getenv("SERVER_HOST")
PORT = os.Getenv("SERVER_PORT") PORT = os.Getenv("SERVER_PORT")
@ -84,7 +60,7 @@ func init() {
} }
checkProxy() checkProxy()
readAccounts() readAccounts()
scheduleToken() scheduleTokenPUID()
} }
func main() { func main() {
router := gin.Default() router := gin.Default()