Repository: mufeng510/Free-ChatGPT-API
Branch: master
Commit: 5b800446a605
Files: 13
Total size: 10.2 MB
Directory structure:
gitextract_hr91y0mv/
├── .gitignore
├── LICENSE
├── Readme.md
└── demo/
├── linux_arm64/
│ ├── PandoraNext
│ └── scripts/
│ ├── add_auto_run_job.sh
│ ├── delete_auto_run_job.sh
│ └── update_pool_token.sh
├── python/
│ ├── add_auto_run_job.bat
│ ├── run_job.bat
│ └── update_pool_token.py
└── win/
└── scripts/
├── add_auto_run_job.bat
├── run_job.bat
└── update_pool_token.ps1
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
**/credentials.txt
**/pool_token.txt
**/tokens.json
**/config.json
**/license.jwt
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 沐风
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Readme.md
================================================
# 基于pandora的ChatGPT API
## 说明
感谢[pandora](https://github.com/pandora-next)项目,这一次真正实现了ChatGPT自由。本项目主要实现了根据账号密码自动获取accessToken并更新至pool-token。初始脚本来源于旧的pandora,该库被删除,无法添加链接,这个脚本是我进行修改过后的,使用更方便。本人也是小白一枚,欢迎大家一起补充完善。
建了一个Q群:698974728,有问题可以在这里说
2023/12/11 重写了脚本,不再需要Python环境
**如果对您有帮助,请给一个免费的star,谢谢!**
## 写在前面
我们的目标是获得一个 `ChatGPT API Key`,通常是在使用`ChatGPT`的衍生项目时使用,比如[ChatGPT-Next-Web](https://github.com/Yidadaa/ChatGPT-Next-Web)、[gpt_academic](https://github.com/binary-husky/gpt_academic)等。这些项目需要我们提供一个 `API Key` 及其对应的 `APIUrl`。
通过使用本项目的脚本,我们将获得一个 `pk-xxxxxxx` 格式的`api key`。`APIUrl`则为你部署的`PandoraNext`地址
### 大致流程
准备账号密码 => 获取 `Access Token` => 获取 `Share Token` => 获取 `Pool Token`
**`Pool Token` 就是我们最后需要的 `api key`。**
### 简单说明
`Access Token`是 OpenAI 官方的用户鉴权信息,相当于用户的唯一标识了,直接使用`Access Token`和使用官方key一样会扣额度,`Access Token`有效期是14天,所以我们至少要14天运行一次脚本。
`Share Token` 和 `Pool Token` 均是由 pandora 作者提供的服务,与官方无关。`Share Token`可以实现多人共享一个账号,可以进行会话隔离,不会扣除额度,实现了ChatGPT自由。但是`Share Token`依旧存在 `1` 个会话的限制,所以作者提供了 `Pool Token`,使用由最多 `100` 个`Share Token`组合的 `Pool Token` 时会自动轮转,实现了多人同时会话。
更多信息可以查看[pandora文档](https://fakeopen.org/PandoraNext/)
### 文件说明
`demo`目录下存放了各环境的示例,本项目是通过`scripts`下的文件实现功能的。
- `run_job.bat` windows执行脚本的批处理脚本
- `add_auto_run_job.bat` 添加定时任务的批处理脚本
- `update_pool_token.*` 实现功能的脚本。
- `credentials.txt` 存储账号、密码
- `pool_token.txt` 存储 `Pool Token`
## 使用方法
## 部署PandoraNext
首先你需要参考[PandoraNext文档](https://fakeopen.org/PandoraNext/)进行部署,本项目的脚本无需与PandoraNext在同一位置。如果你怕出问题,就按照demo一样,将本项目的`scripts`文件夹放在`PandoraNext`目录下。
**部署PandoraNext时,你至少应配置`config.json`中的 `bind`,`license_id`、`proxy_api_prefix`**
```
示例
{
"bind": "0.0.0.0:8181",
"license_id": "xxxxxxxxxxx",
"proxy_api_prefix": "qqrr123123",
}
```
我们在使用 `api key` 时需要将反代url设置为`http(s)://<bind>/<proxy_api_prefix>`
如: `http://127.0.0.1:8181/qqrr123123`
### 自动更新pool token脚本
1. 下载[scripts](https://github.com/mufeng510/Free-ChatGPT-API/tree/master/demo/)到你本地
2. 打开`update_pool_token`文件,修改`$api_url`为`http(s)://<bind>/<proxy_api_prefix>`。
3. 新建`credentials.txt`并设置内容为账号密码,一行一个,账号密码用逗号分隔
```
xxx@outlook.com,xxxxxx
xxx@outlook.com,xxxxxx
```
4. 新建`pool_token.txt`并设置内容为你的pool tohen (可选,没有会自动生成)
```
pk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
pool tohen设置一次后就不会再变了,以后添加修改账号密码只需要执行一次脚本就行了。
5. windows执行`run_job.bat` 即可,linux 执行`bash update_pool_token.sh`,
如果缺少权限先执行
win: `Set-ExecutionPolicy RemoteSigned`
linux: `chmod +x update_pool_token.sh`。
pool tohen最后会保存到`pool_token.txt`。
<details> <summary>python额外要做的(在上述步骤之前)</summary>
1. 安装python环境
方法一:下载[python](https://www.python.org/downloads/)安装并设置环境变量。
方法二:使用`miniconda`。
- 在终端中执行:
```
# 使用scoop安装miniconda3 (没有scoop请手动安装miniconda)
scoop install miniconda3
# 创建pandora专用的环境
conda create -n pool python=3.10
conda init bash
conda activate pool
```
- 打开`run_job.bat`,在`python update_pool_token.py`之前添加`call conda activate pool`

2. 安装依赖
```
pip install pandora-chatgpt
```
</details>
## 在其他项目中使用 pool token
### [ChatGPT-Next-Web](https://github.com/Yidadaa/ChatGPT-Next-Web)
```
OPENAI_API_KEY: 'pk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
BASE_URL: 'http(s)://<bind>/<proxy_api_prefix>'
```
### [gpt_academic](https://github.com/binary-husky/gpt_academic)
```
API_KEY: 'pk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
CUSTOM_API_KEY_PATTERN : 'pk-[a-zA-Z0-9-]+$$'
API_URL_REDIRECT : '{"https://api.openai.com/v1/chat/completions": "http(s)://<bind>/<proxy_api_prefix>/v1/chat/completions"}'
```
## 定时执行
**windows:**
运行`add_auto_run_job.bat`,默认每周二执行,想修改可以发给GPT说明你的需求进行改,添加好后可以运行一次试试有没有问题。

**linux:**
执行`bash add_auto_run_job.sh`,每隔7天执行一次,需要删除可执行 `bash delete_auto_run_job.sh`。可在 `crontab -e` 查看
### 共享站
PandoraNext提供了一个功能等同[chat-shared3.zhile.io](https://chat-shared3.zhile.io/)的共享站,如果你需要保存`access_token`以供共享站使用,需要做以下修改
1. 将本项目脚本放置`PandoraNext`的子目录下,如本项目demo一样
2. 打开`update_pool_token`文件,取消 `Run` 方法中的 `Save-Tokens` 的注释
3. 运行脚本
================================================
FILE: demo/linux_arm64/PandoraNext
================================================
[File too large to display: 10.2 MB]
================================================
FILE: demo/linux_arm64/scripts/add_auto_run_job.sh
================================================
#!/bin/bash
# 获取脚本所在的目录
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# 检查是否已经存在定时任务
croncmd="$script_dir/update_pool_token.sh"
cronjob="0 0 */7 * * $croncmd"
# 检查是否已经存在定时任务
if ! crontab -l | grep -q "$croncmd"; then
# 如果不存在,则添加定时任务
(crontab -l ; echo "$cronjob") | crontab -
echo "定时任务已添加"
else
echo "定时任务已存在"
fi
================================================
FILE: demo/linux_arm64/scripts/delete_auto_run_job.sh
================================================
#!/bin/bash
# 获取脚本所在的目录
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# 要删除的定时任务命令
croncmd="$script_dir/update_pool_token.sh"
# 从cron中删除指定的定时任务
if crontab -l | grep -q "$croncmd"; then
crontab -l | grep -v "$croncmd" | crontab -
echo "定时任务已删除"
else
echo "定时任务不存在"
fi
================================================
FILE: demo/linux_arm64/scripts/update_pool_token.sh
================================================
#!/bin/bash
api_url="http://127.0.0.1:8181/qqrr123123"
unique_name=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 10)
expires_in=0
current_dir=$(dirname "$(readlink -f "\$0")")
credentials_file="$current_dir/credentials.txt"
pool_token_file="$current_dir/pool_token.txt"
tokens_file="$current_dir/../tokens.json"
read_credentials() {
credentials=()
while IFS=, read -r username password || [[ -n $username ]]; do
credentials+=("$username" "$password")
done < "$credentials_file"
}
get_access_token() {
local payload="username=$username&password=$password"
local resp=$(curl -s -X POST -d "$payload" "$api_url/api/auth/login")
if [[ $resp == *"access_token"* ]]; then
access_token=$(echo "$resp" | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
echo "$access_token"
else
err_str=$(echo "$resp" | tr -d '\n\r' | sed 's/^[ \t]*//;s/[ \t]*$//')
echo "Login failed: $username, $err_str"
fi
}
get_share_token() {
local data="unique_name=$unique_name&access_token=$access_token&expires_in=$expires_in"
local resp=$(curl -s -X POST -d "$data" "$api_url/api/token/register")
if [[ $resp == *"token_key"* ]]; then
share_token=$(echo "$resp" | grep -o '"token_key":"[^"]*' | cut -d'"' -f4)
echo "$share_token"
else
err_str=$(echo "$resp" | tr -d '\n\r' | sed 's/^[ \t]*//;s/[ \t]*$//')
echo "share token failed: $err_str"
fi
}
read_pool_token() {
if [[ -f $pool_token_file ]]; then
pool_token=$(<"$pool_token_file")
if [[ $pool_token =~ pk-[0-9a-zA-Z_\-]{43} ]]; then
echo "已存在: pool token: $pool_token"
else
echo "pool token: 格式不正确,将重新生成"
pool_token=""
fi
else
pool_token=""
fi
}
update_pool_token() {
local filtered_tokens=()
for token in "${share_token_keys[@]}"; do
if [[ $token =~ fk-[0-9a-zA-Z_\-]{43} ]]; then
filtered_tokens+=("$token")
fi
done
if [[ ${#filtered_tokens[@]} -eq 0 ]]; then
echo "无可用账号,请检查后重试"
return
fi
local data="share_tokens=$(printf "%s\n" "${filtered_tokens[@]}")&pool_token=$pool_token"
local resp=$(curl -s -X POST -d "$data" "$api_url/api/pool/update")
if [[ $resp == *"pool_token"* ]]; then
count=$(echo "$resp" | grep -o '"count":[0-9]*' | cut -d':' -f2)
new_pool_token=$(echo "$resp" | grep -o '"pool_token":"[^"]*' | cut -d'"' -f4)
echo "pool token 更新结果: count: $count pool_token: $new_pool_token"
echo "$new_pool_token" > "$pool_token_file"
else
echo "pool token 更新失败"
fi
}
save_tokens() {
local access_token_keys=("$@")
tokens_data="{"
for ((i=0; i<${#access_token_keys[@]}; i++)); do
tokens_data+="\"user-$(($i+1))\": {\"token\": \"${access_token_keys[$i]}\", \"shared\": true, \"show_user_info\": false}"
if [[ $i -lt $((${#access_token_keys[@]}-1)) ]]; then
tokens_data+=", "
fi
done
tokens_data+="}"
echo "$tokens_data" > "$tokens_file"
}
generate_random_string() {
cat /dev/urandom | tr -dc 'a-zA-Z' | fold -w "\$1" | head -n 1
}
run() {
read_credentials
declare -a access_token_keys
declare -a share_token_keys
local count=0
for ((i=0; i<${#credentials[@]}; i+=2)); do
username=${credentials[$i]}
password=${credentials[$i+1]}
sleep_seconds=1
echo "开始休眠 $sleep_seconds 秒..."
sleep $sleep_seconds
echo "休眠结束,继续执行后续代码."
echo "Login begin: $username, $((i/2+1))/$((${#credentials[@]}/2))"
access_token=$(get_access_token "$username" "$password")
if [[ -n $access_token && $access_token != *failed* ]]; then
echo "Login success."
access_token_keys+=("$access_token")
share_token=$(get_share_token "$access_token")
echo "$share_token"
if [[ -n $share_token && $share_token != *failed* ]]; then
share_token_keys+=("$share_token")
else
echo "Share token retrieval failed."
fi
else
echo "Login failed or access token retrieval failed."
fi
done
read_pool_token
update_pool_token
# save_tokens "${access_token_keys[@]}"
}
run
================================================
FILE: demo/python/add_auto_run_job.bat
================================================
@echo off
chcp 65001 > nul
REM 获取当前目录的绝对路径
for %%I in ("%~dp0.") do set "currentDir=%%~fI"
set "username=%USERNAME%"
set "password="
set /p password=请输入windows登录密码(如果不需要静默执行或无密码直接按回车):
if not "%password%"=="" (
schtasks /create /tn "auto-update-pool-token" /tr "%currentDir%\run_job.bat" /sc weekly /d TUE /ru %username% /rp %password%
) else (
schtasks /create /tn "auto-update-pool-token" /tr "%currentDir%\run_job.bat" /sc weekly /d TUE
)
pause
================================================
FILE: demo/python/run_job.bat
================================================
chcp 65001
@echo off
cd %~dp0
echo ------正在执行中,请等待------
@REM call conda activate pool
python update_pool_token.py
echo ------执行完成------
pause
exit
================================================
FILE: demo/python/update_pool_token.py
================================================
# -*- coding: utf-8 -*-
import requests
import random
import string
import time
import re
import json
from os import path
def run():
api_url = "http://127.0.0.1:8181/qqrr123123";
unique_name = generate_random_string(10)
expires_in = 0
current_dir = path.dirname(path.abspath(__file__))
credentials_file = path.join(current_dir, 'credentials.txt')
pool_token_file = path.join(current_dir, 'pool_token.txt')
tokens_file = path.join(current_dir, '../tokens.json')
credentials = read_credentials(credentials_file)
count = 0
access_token_keys = []
share_token_keys = []
for index, credential in enumerate(credentials):
# 接口有限流。
sleep_seconds = 15
print(f"开始休眠 {sleep_seconds} 秒...")
time.sleep(sleep_seconds)
print("休眠结束,继续执行后续代码。")
username, password = credential[0].strip(), credential[1].strip()
print('Login begin: {}, {}'.format(username, f"{index+1}/{len(credentials)}"))
access_token = get_access_token(api_url, username, password)
if access_token:
access_token_keys.append(access_token)
share_token = get_share_token(api_url, unique_name, access_token, expires_in)
if share_token:
share_token_keys.append(share_token)
pool_token = read_pool_token(pool_token_file)
update_pool_token(api_url, share_token_keys, pool_token, pool_token_file)
# save_tokens(tokens_file, access_token_keys)
def read_credentials(credentials_file):
with open(credentials_file, 'r', encoding='utf-8') as f:
credentials = [line.strip().split(',', 1) for line in f if ',' in line]
return credentials
def get_access_token(api_url, username, password):
payload = {'username': username, 'password': password}
resp = requests.post(api_url + '/api/auth/login', data=payload)
if resp.status_code == 200:
print('Login success: {}'.format(username))
return resp.json().get('access_token')
else:
err_str = resp.text.replace('\n', '').replace('\r', '').strip()
print('Login failed: {}, {}'.format(username, err_str))
return None
def get_share_token(api_url, unique_name, access_token, expires_in):
data = {'unique_name': unique_name, 'access_token': access_token, 'expires_in': expires_in}
resp = requests.post(api_url + '/api/token/register', data=data)
if resp.status_code == 200:
share_token = resp.json().get('token_key')
print('share token: {}'.format(share_token))
return share_token
else:
err_str = resp.text.replace('\n', '').replace('\r', '').strip()
print('share token failed: {}'.format(err_str))
return None
def read_pool_token(pool_token_file):
# 如果已有pool token则更新, 没有则生成。
if path.exists(pool_token_file):
with open(pool_token_file, 'r', encoding='utf-8') as f:
pool_token = f.read().strip()
if(re.compile(r'pk-[0-9a-zA-Z_\-]{43}').match(pool_token)):
print('已存在: pool token: {}'.format(pool_token))
return pool_token
else:
print('pool token: 格式不正确,将重新生成')
return ""
else:
return ""
def update_pool_token(api_url, share_token_keys, pool_token, pool_token_file):
filtered_tokens = [token for token in share_token_keys if re.match(r'fk-[0-9a-zA-Z_\-]{43}', token)]
if not filtered_tokens:
print('无可用账号,请检查后重试')
return
data = {'share_tokens': '\n'.join(filtered_tokens), 'pool_token': pool_token}
resp = requests.post(api_url + '/api/pool/update', data=data)
if resp.status_code == 200:
result = resp.json()
print('pool token 更新结果: count:{} pool_token:{}'.format(result['count'], result['pool_token']))
with open(pool_token_file, 'w', encoding='utf-8') as f:
f.write(result['pool_token'])
else:
print('pool token 更新失败')
def save_tokens(tokens_file, access_token_keys):
tokens_data = {f"user-{i+1}": {"token": token, "shared": True, "show_user_info": False} for i, token in enumerate(access_token_keys)}
with open(tokens_file, 'w', encoding='utf-8') as f:
json.dump(tokens_data, f, indent=2)
def generate_random_string(length):
letters = string.ascii_letters
return ''.join(random.choice(letters) for _ in range(length))
if __name__ == '__main__':
run()
================================================
FILE: demo/win/scripts/add_auto_run_job.bat
================================================
@echo off
chcp 65001 > nul
REM 获取当前目录的绝对路径
for %%I in ("%~dp0.") do set "currentDir=%%~fI"
set "username=%USERNAME%"
set "password="
set /p password=请输入windows登录密码(如果不需要静默执行或无密码直接按回车):
if not "%password%"=="" (
schtasks /create /tn "auto-update-pool-token" /tr "%currentDir%\run_job.bat" /sc weekly /d TUE /ru %username% /rp %password%
) else (
schtasks /create /tn "auto-update-pool-token" /tr "%currentDir%\run_job.bat" /sc weekly /d TUE
)
pause
================================================
FILE: demo/win/scripts/run_job.bat
================================================
chcp 65001
@echo off
cd %~dp0
echo ------正在执行中,请等待------
echo %~dp0
powershell %~dp0\update_pool_token.ps1
echo ------执行完成------
pause
exit
================================================
FILE: demo/win/scripts/update_pool_token.ps1
================================================
$api_url = "http://127.0.0.1:8181/xxxxxxxxx"
$unique_name = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 10 | % {[char]$_})
$expires_in = 0
$current_dir = Split-Path -Path $MyInvocation.MyCommand.Path
$credentials_file = Join-Path -Path $current_dir -ChildPath 'credentials.txt'
$pool_token_file = Join-Path -Path $current_dir -ChildPath 'pool_token.txt'
$tokens_file = Join-Path -Path $current_dir -ChildPath '../tokens.json'
function Run {
$currentDateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "-----------------------$currentDateTime-----------------------"
$credentials = Read-Credentials -FilePath $credentials_file
$access_token_keys = @()
$share_token_keys = @()
$count = 0
foreach ($credential in $credentials) {
# Interface rate limited.
$sleep_seconds = 5
Start-Sleep -Seconds $sleep_seconds
$username = $credential[0].Trim()
$password = $credential[1].Trim()
Write-Host "Login begin: $username, $($count+1)/$($credentials.Count)"
$access_token = Get-AccessToken -ApiUrl $api_url -Username $username -Password $password
if ($access_token) {
$access_token_keys += $access_token
$share_token = Get-ShareToken -ApiUrl $api_url -UniqueName $unique_name -AccessToken $access_token -ExpiresIn $expires_in
if ($share_token) {
$share_token_keys += $share_token
}
}
}
$pool_token = Read-PoolToken -PoolTokenFile $pool_token_file
Update-PoolToken -ApiUrl $api_url -ShareTokenKeys $share_token_keys -PoolToken $pool_token -PoolTokenFile $pool_token_file
# Save-Tokens -TokensFile $tokens_file -AccessTokenKeys $access_token_keys
}
function Read-Credentials {
param (
[string]$FilePath
)
$credentials = Get-Content -Path $FilePath | Where-Object {$_ -match ','} | ForEach-Object {$_ -split ','}
$credentialPairs = @()
for ($i = 0; $i -lt $credentials.Length; $i += 2) {
$credentialPairs += ,@($credentials[$i], $credentials[$i + 1])
}
return ,$credentialPairs
}
function Get-AccessToken {
param (
[string]$ApiUrl,
[string]$Username,
[string]$Password
)
$payload = @{
username = $Username
password = $Password
}
try {
$resp = Invoke-RestMethod -Uri ($ApiUrl + '/api/auth/login') -Method Post -Body $payload
if ($resp.access_token) {
Write-Host "Login success"
return $resp.access_token
}
}
catch {
Write-Host "Login failed:" $_.Exception.Message.ToString().Replace("`n", "").Replace("`r", "").Trim()
return $null
}
}
function Get-ShareToken {
param (
[string]$ApiUrl,
[string]$UniqueName,
[string]$AccessToken,
[int]$ExpiresIn
)
$data = @{
unique_name = $UniqueName
access_token = $AccessToken
expires_in = $ExpiresIn
}
try {
$resp = Invoke-RestMethod -Uri ($ApiUrl + '/api/token/register') -Method Post -Body $data
if ($resp.token_key) {
$share_token = $resp.token_key
Write-Host "share token: $share_token"
return $share_token
}
}
catch {
$err_str = $_.Exception.Message.ToString().ToString().Replace("`n", "").Replace("`r", "").Trim()
Write-Host "share token failed: $err_str"
return $null
}
}
function Read-PoolToken {
param (
[string]$PoolTokenFile
)
if (Test-Path $PoolTokenFile) {
$pool_token = Get-Content -Path $PoolTokenFile
if ($pool_token -match 'pk-[0-9a-zA-Z_\-]{43}') {
Write-Host "Already exists: pool token: $pool_token"
return $pool_token
} else {
return ""
}
}else {
return ""
}
}
function Update-PoolToken {
param (
[string]$ApiUrl,
[string[]]$ShareTokenKeys,
[string]$PoolToken,
[string]$PoolTokenFile
)
$filtered_tokens = $ShareTokenKeys -match 'fk-[0-9a-zA-Z_\-]{43}'
if (-not $filtered_tokens) {
Write-Host "No available accounts, please check and try again"
return
}
$data = @{
share_tokens = $filtered_tokens -join "`n"
pool_token = $PoolToken
}
try {
$resp = Invoke-RestMethod -Uri ($ApiUrl + '/api/pool/update') -Method Post -Body $data
if ($resp.pool_token) {
$result = $resp | ConvertTo-Json
Write-Host "$result"
Write-Host "pool token update result: count:$($result.count) pool_token:$($result.pool_token)"
Set-Content -Path $PoolTokenFile -Value $result.pool_token
}
}
catch {
$err_str = $_.Exception.Message.ToString().ToString().Replace("`n", "").Replace("`r", "").Trim()
Write-Host "pool token update failed: $err_str"
}
}
function Save-Tokens {
param (
[string]$TokensFile,
[string[]]$AccessTokenKeys
)
$tokens_data = @{}
for ($i=0; $i -lt $AccessTokenKeys.Count; $i++) {
$tokens_data["user-$($i+1)"] = @{
token = $AccessTokenKeys[$i]
shared = $true
show_user_info = $false
}
}
$tokens_data | ConvertTo-Json | Set-Content -Path $TokensFile
}
Run
gitextract_hr91y0mv/
├── .gitignore
├── LICENSE
├── Readme.md
└── demo/
├── linux_arm64/
│ ├── PandoraNext
│ └── scripts/
│ ├── add_auto_run_job.sh
│ ├── delete_auto_run_job.sh
│ └── update_pool_token.sh
├── python/
│ ├── add_auto_run_job.bat
│ ├── run_job.bat
│ └── update_pool_token.py
└── win/
└── scripts/
├── add_auto_run_job.bat
├── run_job.bat
└── update_pool_token.ps1
SYMBOL INDEX (8 symbols across 1 files) FILE: demo/python/update_pool_token.py function run (line 13) | def run(): function read_credentials (line 49) | def read_credentials(credentials_file): function get_access_token (line 54) | def get_access_token(api_url, username, password): function get_share_token (line 65) | def get_share_token(api_url, unique_name, access_token, expires_in): function read_pool_token (line 77) | def read_pool_token(pool_token_file): function update_pool_token (line 91) | def update_pool_token(api_url, share_token_keys, pool_token, pool_token_... function save_tokens (line 107) | def save_tokens(tokens_file, access_token_keys): function generate_random_string (line 112) | def generate_random_string(length):
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (29K chars).
[
{
"path": ".gitignore",
"chars": 3160,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": "LICENSE",
"chars": 1059,
"preview": "MIT License\n\nCopyright (c) 2023 沐风\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this"
},
{
"path": "Readme.md",
"chars": 4012,
"preview": "# 基于pandora的ChatGPT API\n\n## 说明\n\n感谢[pandora](https://github.com/pandora-next)项目,这一次真正实现了ChatGPT自由。本项目主要实现了根据账号密码自动获取acces"
},
{
"path": "demo/linux_arm64/scripts/add_auto_run_job.sh",
"chars": 342,
"preview": "#!/bin/bash\n\n# 获取脚本所在的目录\nscript_dir=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\n# 检查是否已经存在定时任务\ncroncmd=\"$script"
},
{
"path": "demo/linux_arm64/scripts/delete_auto_run_job.sh",
"chars": 294,
"preview": "#!/bin/bash\n\n# 获取脚本所在的目录\nscript_dir=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\n# 要删除的定时任务命令\ncroncmd=\"$script_d"
},
{
"path": "demo/linux_arm64/scripts/update_pool_token.sh",
"chars": 4320,
"preview": "#!/bin/bash\n\napi_url=\"http://127.0.0.1:8181/qqrr123123\"\nunique_name=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 10)"
},
{
"path": "demo/python/add_auto_run_job.bat",
"chars": 461,
"preview": "@echo off\nchcp 65001 > nul\n\nREM 获取当前目录的绝对路径\nfor %%I in (\"%~dp0.\") do set \"currentDir=%%~fI\"\n\nset \"username=%USERNAME%\"\ns"
},
{
"path": "demo/python/run_job.bat",
"chars": 148,
"preview": "chcp 65001\n@echo off\ncd %~dp0\necho ------正在执行中,请等待------\n@REM call conda activate pool\npython update_pool_token.py\necho "
},
{
"path": "demo/python/update_pool_token.py",
"chars": 4382,
"preview": "# -*- coding: utf-8 -*-\n\n\nimport requests\nimport random\nimport string\nimport time\nimport re\nimport json\nfrom os import p"
},
{
"path": "demo/win/scripts/add_auto_run_job.bat",
"chars": 461,
"preview": "@echo off\nchcp 65001 > nul\n\nREM 获取当前目录的绝对路径\nfor %%I in (\"%~dp0.\") do set \"currentDir=%%~fI\"\n\nset \"username=%USERNAME%\"\ns"
},
{
"path": "demo/win/scripts/run_job.bat",
"chars": 140,
"preview": "chcp 65001\n@echo off\ncd %~dp0\necho ------正在执行中,请等待------\necho %~dp0\npowershell %~dp0\\update_pool_token.ps1\necho ------执行"
},
{
"path": "demo/win/scripts/update_pool_token.ps1",
"chars": 5349,
"preview": "$api_url = \"http://127.0.0.1:8181/xxxxxxxxx\"\n\n$unique_name = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count "
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the mufeng510/Free-ChatGPT-API GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (10.2 MB), approximately 7.6k tokens, and a symbol index with 8 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.