Skip to content
This repository has been archived by the owner on Aug 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #92 from xqdoo00o/master
Browse files Browse the repository at this point in the history
Chinese doc, auto renew token, uniform proxy
  • Loading branch information
Antonio Cheong authored Jul 20, 2023
2 parents 59cd92b + 2b22c04 commit 5afd148
Show file tree
Hide file tree
Showing 8 changed files with 540 additions and 323 deletions.
77 changes: 40 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,66 @@ Create a fake API using ChatGPT's website
**API endpoint: http://127.0.0.1:8080/v1/chat/completions.**

[中文文档(Chinese Docs)](README_CN.md)

## Help needed
- Documentation.

[中文文档(Chinese Docs)](https://github.com/xqdoo00o/ChatGPT-to-API/blob/master/README_ZH.md)
## Setup

<details>
<summary>

### Authentication
</summary>

Access token retrieval has been automated:
https://github.com/acheong08/ChatGPT-to-API/tree/master/tools/authenticator

Converting from a newline delimited list of access tokens to `access_tokens.json`
```bash
#!/bin/bash
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

START="["
END="]"
Format:
```
email:password
...
```

TOKENS=""
All authenticated access tokens will store in `access_tokens.json`

while read -r line; do
if [ -z "$TOKENS" ]; then
TOKENS="\"$line\""
else
TOKENS+=",\"$line\""
fi
done < access_tokens.txt
Auto renew access tokens after 14 days

echo "$START$TOKENS$END" > access_tokens.json
```
Caution! please use unblocked ip for authentication, first login to `https://chat.openai.com/` to check ip availability if you can.

### API Authentication (Optional)

</details>
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/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
- `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)
- `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
Expand Down
70 changes: 70 additions & 0 deletions README_ZH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 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`

每14天自动更新Access tokens

注意! 请使用未封锁的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
cd ChatGPT-to-API
go build
./freechatgpt
```

### 环境变量
- `PUID` - Plus账户可在`chat.openai.com`的cookies里找到,用于绕过cf的频率限制
- `SERVER_HOST` - 默认127.0.0.1
- `SERVER_PORT` - 默认8080
- `ENABLE_HISTORY` - 默认true,允许网页端历史记录
### 可选文件配置
- `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
151 changes: 151 additions & 0 deletions auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package main

import (
"bufio"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"time"

"freechatgpt/internal/tokens"

"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() {
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)
}
}
}
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 14 days after last modify token file
toExpire := 1.2096e15 - 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() {
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("Updating access token for " + account.Email)
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 != 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 := authenticator.GetAccessToken()
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 {
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(1.2096e15, updateToken)
}
5 changes: 4 additions & 1 deletion conversion/requests/chatgpt/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ func ConvertAPIRequest(api_request official_types.APIRequest) chatgpt_types.Chat
fmt.Println("Error getting Arkose token: ", err)
}
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 {
chatgpt_request.PluginIDs = api_request.PluginIDs
chatgpt_request.Model = "gpt-4-plugins"
}

for _, api_message := range api_request.Messages {
if api_message.Role == "system" {
api_message.Role = "critic"
Expand Down
Loading

0 comments on commit 5afd148

Please sign in to comment.