├── Quick-Translator.py ├── API ├── pandora │ ├── src │ │ └── pandora │ │ │ ├── py.typed │ │ │ ├── bots │ │ │ └── __init__.py │ │ │ ├── exts │ │ │ ├── __init__.py │ │ │ ├── config.py │ │ │ ├── sentry.py │ │ │ ├── hooks.py │ │ │ └── token.py │ │ │ ├── openai │ │ │ ├── __init__.py │ │ │ ├── token.py │ │ │ └── utils.py │ │ │ ├── turbo │ │ │ ├── __init__.py │ │ │ └── base.py │ │ │ ├── migrations │ │ │ ├── __init__.py │ │ │ ├── database.py │ │ │ ├── migrate.py │ │ │ ├── scripts │ │ │ │ └── 20230308_01_7ctOr.sql │ │ │ └── models.py │ │ │ ├── __init__.py │ │ │ ├── __main__.py │ │ │ ├── flask │ │ │ └── static │ │ │ │ ├── _next │ │ │ │ └── static │ │ │ │ │ ├── olf4sv64FWIcQ_zCGl90t │ │ │ │ │ ├── _ssgManifest.js │ │ │ │ │ └── _buildManifest.js │ │ │ │ │ └── chunks │ │ │ │ │ ├── pages │ │ │ │ │ └── _error-786d27d84962122a.js │ │ │ │ │ ├── 68a27ff6-1185184b61bc22d0.js │ │ │ │ │ ├── bd26816a-981e1ddc27b37cc6.js │ │ │ │ │ ├── 949.1a6eb804b5e91f61.js │ │ │ │ │ ├── 554.9b8bfd0762461d74.js │ │ │ │ │ └── webpack-c9a868e8e0796ec6.js │ │ │ │ ├── favicon-16x16.png │ │ │ │ ├── favicon-32x32.png │ │ │ │ ├── apple-touch-icon.png │ │ │ │ ├── fonts │ │ │ │ ├── Sohne-Buch.otf │ │ │ │ ├── KaTeX_Main-Bold.woff │ │ │ │ ├── Sohne-Halbfett.otf │ │ │ │ ├── SohneMono-Buch.otf │ │ │ │ ├── KaTeX_Main-Italic.woff │ │ │ │ ├── KaTeX_Math-Italic.woff │ │ │ │ ├── Signifier-Regular.otf │ │ │ │ ├── SohneMono-Halbfett.otf │ │ │ │ ├── KaTeX_Fraktur-Bold.woff │ │ │ │ ├── KaTeX_Main-Regular.woff │ │ │ │ ├── KaTeX_SansSerif-Bold.woff │ │ │ │ ├── KaTeX_Script-Regular.woff │ │ │ │ ├── KaTeX_Size1-Regular.woff │ │ │ │ ├── KaTeX_Size2-Regular.woff │ │ │ │ ├── KaTeX_Size3-Regular.woff │ │ │ │ ├── KaTeX_Size4-Regular.woff │ │ │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ │ │ ├── KaTeX_Fraktur-Regular.woff │ │ │ │ ├── KaTeX_Main-BoldItalic.woff │ │ │ │ ├── KaTeX_Math-BoldItalic.woff │ │ │ │ ├── KaTeX_SansSerif-Italic.woff │ │ │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ │ │ ├── KaTeX_SansSerif-Regular.woff │ │ │ │ └── KaTeX_Typewriter-Regular.woff │ │ │ │ └── images │ │ │ │ └── 2022 │ │ │ │ └── 11 │ │ │ │ └── ChatGPT.jpg │ │ │ └── cloud_launcher.py │ ├── requirements_api.txt │ ├── doc │ │ ├── images │ │ │ ├── s01.png │ │ │ ├── s02.png │ │ │ ├── s03.png │ │ │ ├── s04.png │ │ │ ├── s05.png │ │ │ ├── s06.png │ │ │ ├── t0.png │ │ │ ├── t1.png │ │ │ ├── t2.png │ │ │ ├── t3.png │ │ │ ├── t4.png │ │ │ ├── t7.png │ │ │ ├── s11.jpeg │ │ │ ├── s12.jpeg │ │ │ └── t1.1.png │ │ ├── HTTP-API.md │ │ ├── wiki_en.md │ │ └── wiki.md │ ├── .dockerignore │ ├── MANIFEST.in │ ├── Dockerfile │ ├── requirements.txt │ ├── docker-compose.yml │ ├── bin │ │ └── startup.sh │ ├── .gitignore │ ├── setup.py │ └── README.md ├── go-chatgpt-api │ ├── .gitignore │ ├── .env.example │ ├── compose.yaml │ ├── Dockerfile │ ├── middleware │ │ ├── cors.go │ │ └── check_header.go │ ├── util │ │ └── logger │ │ │ └── logger.go │ ├── LICENSE │ ├── api │ │ ├── chatgpt │ │ │ ├── constant.go │ │ │ ├── typings.go │ │ │ ├── health_check.go │ │ │ └── access_token.go │ │ ├── platform │ │ │ ├── constant.go │ │ │ ├── typings.go │ │ │ ├── access_token.go │ │ │ └── api.go │ │ └── common.go │ ├── go.mod │ └── main.go ├── ChatGPT-to-API │ ├── .gitignore │ ├── internal │ │ ├── typings │ │ │ ├── api.go │ │ │ └── responses │ │ │ │ └── typings.go │ │ ├── chatgpt │ │ │ ├── convert.go │ │ │ ├── typings.go │ │ │ └── request.go │ │ └── tokens │ │ │ └── tokens.go │ ├── tools │ │ ├── authenticator │ │ │ ├── README.md │ │ │ ├── go.mod │ │ │ ├── remove_duplicates.py │ │ │ ├── go.sum │ │ │ └── main.go │ │ ├── plugin_check │ │ │ └── check_access.go │ │ └── proxy_check │ │ │ └── proxy_check.go │ ├── docs │ │ ├── TOKEN_CN.md │ │ ├── admin.md │ │ ├── Docker_CN.md │ │ └── GUIDE_CN.md │ ├── docker-compose.yml │ ├── Dockerfile │ ├── middleware.go │ ├── README_CN.md │ ├── go.mod │ ├── README.md │ ├── main.go │ └── handlers.go ├── talkx2api │ ├── talkx2api.js │ └── talkx2api.py ├── cerebras2api │ └── cerebras2api.py └── snova2api │ ├── snova-api.js │ └── snova2api.js ├── README.md ├── GPT-Config.example.ini ├── QT_MD.py ├── chat2api-docker-host.yaml ├── chat2api-docker-warp.yaml ├── chat2api-docker-warp-host.yaml ├── .gitignore └── Quick-ASK.py /Quick-Translator.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/bots/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/exts/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/openai/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/turbo/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAI-Quick-DEV 2 | 面向OpenAI开发的代码库,目标是构建一些轻松快速上手的小程序来使用OpenAI/ChatGPT的服务 3 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .env 3 | go-chatgpt-api 4 | undetected_chromedriver 5 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __version__ = '1.1.9' 4 | -------------------------------------------------------------------------------- /API/pandora/requirements_api.txt: -------------------------------------------------------------------------------- 1 | pandora-tiktoken~=0.3.1 2 | sqlalchemy~=2.0.7 3 | yoyo-migrations~=8.2.0 -------------------------------------------------------------------------------- /API/pandora/doc/images/s01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s01.png -------------------------------------------------------------------------------- /API/pandora/doc/images/s02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s02.png -------------------------------------------------------------------------------- /API/pandora/doc/images/s03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s03.png -------------------------------------------------------------------------------- /API/pandora/doc/images/s04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s04.png -------------------------------------------------------------------------------- /API/pandora/doc/images/s05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s05.png -------------------------------------------------------------------------------- /API/pandora/doc/images/s06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s06.png -------------------------------------------------------------------------------- /API/pandora/doc/images/t0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/t0.png -------------------------------------------------------------------------------- /API/pandora/doc/images/t1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/t1.png -------------------------------------------------------------------------------- /API/pandora/doc/images/t2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/t2.png -------------------------------------------------------------------------------- /API/pandora/doc/images/t3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/t3.png -------------------------------------------------------------------------------- /API/pandora/doc/images/t4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/t4.png -------------------------------------------------------------------------------- /API/pandora/doc/images/t7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/t7.png -------------------------------------------------------------------------------- /API/pandora/doc/images/s11.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s11.jpeg -------------------------------------------------------------------------------- /API/pandora/doc/images/s12.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/s12.jpeg -------------------------------------------------------------------------------- /API/pandora/doc/images/t1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/doc/images/t1.1.png -------------------------------------------------------------------------------- /API/pandora/.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | .git/ 4 | .idea/ 5 | .run/ 6 | .github/ 7 | 8 | venv/ 9 | build/ 10 | dist/ 11 | *.egg-info/ 12 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/.env.example: -------------------------------------------------------------------------------- 1 | # API server port 2 | GO_CHATGPT_API_PORT=8080 3 | # Network proxy server address 4 | GO_CHATGPT_API_PROXY=socks5://ip:port 5 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/__main__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from pandora import launcher 4 | 5 | if __name__ == '__main__': 6 | launcher.run() 7 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/olf4sv64FWIcQ_zCGl90t/_ssgManifest.js: -------------------------------------------------------------------------------- 1 | self.__SSG_MANIFEST=new Set,self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB(); -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/favicon-16x16.png -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/favicon-32x32.png -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/apple-touch-icon.png -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/Sohne-Buch.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/Sohne-Buch.otf -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/Sohne-Halbfett.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/Sohne-Halbfett.otf -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/SohneMono-Buch.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/SohneMono-Buch.otf -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/Signifier-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/Signifier-Regular.otf -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/SohneMono-Halbfett.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/SohneMono-Halbfett.otf -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueSkyXN/OpenAI-Quick-DEV/HEAD/API/pandora/src/pandora/flask/static/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /API/pandora/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt 2 | include requirements_api.txt 3 | include src/pandora/py.typed 4 | recursive-include src/pandora/flask * 5 | recursive-include src/pandora/migrations/scripts * 6 | -------------------------------------------------------------------------------- /API/pandora/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | MAINTAINER "Neo Peng " 4 | 5 | VOLUME /data 6 | 7 | WORKDIR /opt/app 8 | 9 | ADD . . 10 | 11 | RUN pip --no-cache-dir install --upgrade pip && pip --no-cache-dir install .[api,cloud] 12 | 13 | ENTRYPOINT ["bin/startup.sh"] 14 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/.gitignore: -------------------------------------------------------------------------------- 1 | tools/authenticator/100-ACCOUNTS_COMPILED.txt 2 | tools/authenticator/accounts.txt 3 | tools/authenticator/proxies.txt 4 | tools/authenticator/authenticated_accounts.txt 5 | tools/authenticator/access_tokens.txt 6 | *.txt 7 | access_tokens.json 8 | freechatgpt 9 | chatgpttoapi 10 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | go-chatgpt-api: 3 | build: . 4 | container_name: go-chatgpt-api 5 | image: linweiyuan/go-chatgpt-api 6 | ports: 7 | - 8080:8080 8 | environment: 9 | - TZ=Asia/Shanghai 10 | - GO_CHATGPT_API_PROXY= 11 | restart: unless-stopped 12 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/chunks/pages/_error-786d27d84962122a.js: -------------------------------------------------------------------------------- 1 | (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[820],{17917:function(n,_,u){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_error",function(){return u(14902)}])}},function(n){n.O(0,[774,888,179],function(){return n(n.s=17917)}),_N_E=n.O()}]); -------------------------------------------------------------------------------- /API/ChatGPT-to-API/internal/typings/api.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type APIRequest struct { 4 | Messages []api_message `json:"messages"` 5 | Stream bool `json:"stream"` 6 | Model string `json:"model"` 7 | } 8 | 9 | type api_message struct { 10 | Role string `json:"role"` 11 | Content string `json:"content"` 12 | } 13 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS builder 2 | WORKDIR /app 3 | COPY . . 4 | RUN go build -ldflags="-w -s" -o go-chatgpt-api main.go 5 | 6 | FROM alpine 7 | WORKDIR /app 8 | COPY --from=builder /app/go-chatgpt-api . 9 | RUN apk add --no-cache tzdata 10 | ENV TZ=Asia/Shanghai 11 | EXPOSE 8080 12 | CMD ["/app/go-chatgpt-api"] 13 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/migrations/database.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from sqlalchemy import create_engine 4 | from sqlalchemy.orm import sessionmaker 5 | 6 | from ..exts.config import DATABASE_URI 7 | 8 | engine = create_engine(DATABASE_URI, echo=False) 9 | 10 | Session = sessionmaker(bind=engine) 11 | 12 | session = Session() 13 | -------------------------------------------------------------------------------- /API/pandora/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi 2 | pyreadline3 ~= 3.4.0; platform_system == 'Windows' 3 | httpx[socks]~=0.23.3 4 | requests[socks]~=2.28.2 5 | rich~=13.3.2 6 | appdirs~=1.4.4 7 | werkzeug~=2.2.3 8 | flask~=2.2.3 9 | flask-cors~=3.0.10 10 | waitress~=2.1.2 11 | loguru~=0.6.0 12 | sentry-sdk~=1.17.0 13 | pyjwt[crypto]~=2.6.0 14 | pyperclip~=1.8.2 15 | -------------------------------------------------------------------------------- /API/pandora/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | pandora: 4 | image: pengzhile/pandora:latest 5 | platform: linux/amd64 6 | ports: 7 | - 18848:8848 8 | environment: 9 | - PANDORA_SERVER=0.0.0.0:8848 10 | - PANDORA_ACCESS_TOKEN=eyJhGUiOnsiZW1 11 | ##- PANDORA_API=sk 12 | ##- PANDORA_VERBOSE=False 13 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/exts/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from os import getenv 4 | from os.path import join 5 | 6 | from appdirs import user_config_dir 7 | 8 | USER_CONFIG_DIR = getenv('USER_CONFIG_DIR', user_config_dir('Pandora-ChatGPT')) 9 | DATABASE_URI = getenv('DATABASE_URI', 10 | 'sqlite:///{}?check_same_thread=False'.format(join(USER_CONFIG_DIR, 'pandora-chatgpt.db'))) 11 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/tools/authenticator/README.md: -------------------------------------------------------------------------------- 1 | # Automated authentication for ChatGPT 2 | Fetches access tokens from a large number of accounts 3 | 4 | ## Setup 5 | ### `proxies.txt` 6 | Format: 7 | ``` 8 | IP:HOST:User:Password 9 | ... 10 | ``` 11 | 12 | ### `accounts.txt` 13 | Format: 14 | ``` 15 | email:password 16 | ... 17 | ``` 18 | 19 | Remember to: 20 | `touch access_tokens.txt authenticated_accounts.txt` 21 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/chunks/68a27ff6-1185184b61bc22d0.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[798],{13002:function(t,n,r){r.d(n,{oT$:function(){return o}});var e=r(50913);function o(t){return(0,e.w_)({tag:"svg",attr:{fill:"none",viewBox:"0 0 24 24",stroke:"currentColor"},child:[{tag:"path",attr:{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"2",d:"M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"}}]})(t)}}}]); -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/chunks/bd26816a-981e1ddc27b37cc6.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[786],{54655:function(t,n,e){e.d(n,{Ny3:function(){return o}});var r=e(50913);function o(t){return(0,r.w_)({tag:"svg",attr:{viewBox:"0 0 24 24",strokeWidth:"2",stroke:"currentColor",fill:"none",strokeLinecap:"round",strokeLinejoin:"round"},child:[{tag:"desc",attr:{},child:[]},{tag:"path",attr:{stroke:"none",d:"M0 0h24v24H0z",fill:"none"}},{tag:"path",attr:{d:"M5 9h14m-14 6h14"}}]})(t)}}}]); -------------------------------------------------------------------------------- /API/pandora/src/pandora/openai/token.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import tiktoken 4 | 5 | 6 | def gpt_num_tokens(messages, model='gpt-3.5-turbo'): 7 | encoding = tiktoken.encoding_for_model(model) 8 | 9 | num_tokens = 0 10 | for message in messages: 11 | num_tokens += 4 12 | for key, value in message.items(): 13 | num_tokens += len(encoding.encode(value)) 14 | if 'name' == key: 15 | num_tokens -= 1 16 | num_tokens += 2 17 | 18 | return num_tokens 19 | -------------------------------------------------------------------------------- /GPT-Config.example.ini: -------------------------------------------------------------------------------- 1 | ; GPT-Config.ini 配置文件 2 | ; 本配置文件用于设置GPT应用程序的相关参数。 3 | ; 请在明确了解相关配置项含义和作用的情况下修改本文件。 4 | 5 | [Settings] 6 | ; 以下是API端点的URL。 7 | ; 除非有特定的需要,否则请勿修改此设置。 8 | ; 默认值: http://127.0.0.1:31480/v1/chat/completions 9 | url = http://127.0.0.1:31480/v1/chat/completions 10 | 11 | ; 以下是API的认证令牌。 12 | ; 你应该将此项修改为你自己的独特且安全的令牌。 13 | ; 默认值: TotallySecurePassword 14 | auth = TotallySecurePassword 15 | 16 | ; 以下是API使用的模型。 17 | ; 如果你需要,可以将此项更改为任何其他兼容的模型。 18 | ; 默认值: gpt-3.5 19 | ; 可选值: gpt-3.5, gpt-3.5-mobile, gpt-4-mobile, gpt-4, gpt-4-browsing, gpt-4-plugins 20 | model = gpt-3.5 21 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/middleware/cors.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | 6 | http "github.com/bogdanfinn/fhttp" 7 | ) 8 | 9 | func CORSMiddleware() gin.HandlerFunc { 10 | return func(c *gin.Context) { 11 | c.Writer.Header().Set("Access-Control-Allow-Origin", "*") 12 | c.Writer.Header().Set("Access-Control-Allow-Headers", "*") 13 | c.Writer.Header().Set("Access-Control-Allow-Methods", "*") 14 | 15 | if c.Request.Method == http.MethodOptions { 16 | c.AbortWithStatus(http.StatusNoContent) 17 | return 18 | } 19 | 20 | c.Next() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/exts/sentry.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sentry_sdk 4 | from sentry_sdk import capture_exception 5 | 6 | from .. import __version__ 7 | 8 | 9 | def init(proxy): 10 | sentry_sdk.init( 11 | dsn="https://8f3144c644b5410d825c644aa0040c71@o4504791776755712.ingest.sentry.io/4504791778394112", 12 | http_proxy=proxy, 13 | https_proxy=proxy, 14 | traces_sample_rate=0, 15 | environment='production', 16 | release='pandora@{}'.format(__version__), 17 | ) 18 | 19 | 20 | def capture(e): 21 | capture_exception(e) 22 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/middleware/check_header.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/linweiyuan/go-chatgpt-api/api" 8 | ) 9 | 10 | func CheckHeaderMiddleware() gin.HandlerFunc { 11 | return func(c *gin.Context) { 12 | if c.GetHeader(api.AuthorizationHeader) == "" && 13 | c.Request.URL.Path != "/chatgpt/login" && 14 | c.Request.URL.Path != "/platform/login" { 15 | c.AbortWithStatusJSON(http.StatusUnauthorized, api.ReturnMessage("Missing accessToken.")) 16 | return 17 | } 18 | 19 | c.Header("Content-Type", "application/json") 20 | c.Next() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /QT_MD.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PyQt6.QtWidgets import QApplication, QTextBrowser 3 | import markdown 4 | 5 | class MainWindow(QTextBrowser): 6 | def __init__(self): 7 | super().__init__() 8 | 9 | # Markdown text 10 | md_text = """ 11 | # Hello 12 | 13 | This is some **Markdown** text. 14 | - First item 15 | - Second item 16 | """ 17 | 18 | # Convert Markdown to HTML 19 | html = markdown.markdown(md_text) 20 | 21 | # Display HTML in QTextBrowser 22 | self.setHtml(html) 23 | 24 | app = QApplication(sys.argv) 25 | window = MainWindow() 26 | window.show() 27 | sys.exit(app.exec()) 28 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/docs/TOKEN_CN.md: -------------------------------------------------------------------------------- 1 | # 获取Token 2 | --- 3 | # 参考Pandora项目的作者指导 4 | 5 | https://github.com/pengzhile/pandora 6 | 7 | 获取Token的技术原理 https://zhile.io/2023/05/19/how-to-get-chatgpt-access-token-via-pkce.html 8 | 9 | ## 第三方接口获取Token 10 | http://ai.fakeopen.com/auth 11 | 12 | 你需要在这个新的网站的指导下安装浏览器插件,官方说明的有效期是14天。支持谷歌微软等第三方登录。(我谷歌注册的OpenAI就可以用这个) 13 | 14 | ## 官网获取 Token 15 | https://chat.openai.com/api/auth/session 16 | 17 | 打开后是个JSON,你需要先登录官方的ChatGPT网页版。里面有一个参数就是AccessToken。 18 | 19 | # 参考go-chatgpt-api项目的作者指导 20 | https://github.com/linweiyuan/go-chatgpt-api 21 | 22 | ChatGPT 登录(返回 accessToken)(目前仅支持 ChatGPT 账号,谷歌或微软账号没有测试) 23 | 24 | ```POST /chatgpt/login``` -------------------------------------------------------------------------------- /API/ChatGPT-to-API/tools/authenticator/go.mod: -------------------------------------------------------------------------------- 1 | module authenticator 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/bogdanfinn/fhttp v0.5.22 7 | github.com/bogdanfinn/tls-client v1.3.12 8 | github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c 9 | ) 10 | 11 | require ( 12 | github.com/andybalholm/brotli v1.0.5 // indirect 13 | github.com/bogdanfinn/utls v1.5.16 // indirect 14 | github.com/klauspost/compress v1.16.5 // indirect 15 | github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect 16 | golang.org/x/crypto v0.9.0 // indirect 17 | golang.org/x/net v0.10.0 // indirect 18 | golang.org/x/sys v0.8.0 // indirect 19 | golang.org/x/text v0.9.0 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/migrations/migrate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from os import makedirs, path 4 | from os.path import abspath, join, dirname 5 | 6 | from yoyo import get_backend 7 | from yoyo import read_migrations 8 | 9 | from ..exts.config import DATABASE_URI, USER_CONFIG_DIR 10 | 11 | 12 | def do_migrate(): 13 | if not path.exists(USER_CONFIG_DIR): 14 | makedirs(USER_CONFIG_DIR) 15 | 16 | url = 'mysql:{}'.format(DATABASE_URI[14:]) if 'mysql+pymysql:' == DATABASE_URI[0:14] else DATABASE_URI 17 | backend = get_backend(url) 18 | migrations = read_migrations(abspath(join(dirname(__file__), 'scripts'))) 19 | 20 | with backend.lock(): 21 | backend.apply_migrations(backend.to_apply(migrations)) 22 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/util/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | func init() { 10 | logrus.SetFormatter(&logrus.TextFormatter{ 11 | ForceColors: true, 12 | }) 13 | } 14 | 15 | func Ansi(colorString string) func(...interface{}) string { 16 | return func(args ...interface{}) string { 17 | return fmt.Sprintf(colorString, fmt.Sprint(args...)) 18 | } 19 | } 20 | 21 | var ( 22 | Green = Ansi("\033[1;32m%s\033[0m") 23 | Yellow = Ansi("\033[1;33m%s\033[0m") 24 | Red = Ansi("\033[1;31m%s\033[0m") 25 | ) 26 | 27 | func Info(msg string) { 28 | logrus.Info(Green(msg)) 29 | } 30 | 31 | func Warn(msg string) { 32 | logrus.Warn(Yellow(msg)) 33 | } 34 | 35 | func Error(msg string) { 36 | logrus.Error(Red(msg)) 37 | } 38 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | app: 5 | image: acheong08/chatgpt-to-api # 总是使用latest,更新时重新pull该tag镜像即可 6 | container_name: chatgpttoapi 7 | restart: unless-stopped 8 | ports: 9 | - '8080:8080' 10 | environment: 11 | SERVER_HOST: 0.0.0.0 12 | SERVER_PORT: 8080 13 | ADMIN_PASSWORD: TotallySecurePassword 14 | # Reverse Proxy - Available on accessToken 15 | API_REVERSE_PROXY: https://bypass.churchless.tech/api/conversation 16 | # If the parameter API_REVERSE_PROXY is empty, the default request URL is https://chat.openai.com/backend-api/conversation, and the PUID is required. 17 | # You can get your PUID for Plus account from the following link: https://chat.openai.com/api/auth/session. 18 | PUID: xxx 19 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/internal/chatgpt/convert.go: -------------------------------------------------------------------------------- 1 | package chatgpt 2 | 3 | import ( 4 | typings "freechatgpt/internal/typings" 5 | "strings" 6 | ) 7 | 8 | func ConvertAPIRequest(api_request typings.APIRequest) ChatGPTRequest { 9 | chatgpt_request := NewChatGPTRequest() 10 | if strings.HasPrefix(api_request.Model, "gpt-4") { 11 | chatgpt_request.Model = "gpt-4" 12 | 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" { 13 | chatgpt_request.Model = api_request.Model 14 | } 15 | } 16 | for _, api_message := range api_request.Messages { 17 | if api_message.Role == "system" { 18 | api_message.Role = "critic" 19 | } 20 | chatgpt_request.AddMessage(api_message.Role, api_message.Content) 21 | } 22 | return chatgpt_request 23 | } 24 | -------------------------------------------------------------------------------- /chat2api-docker-host.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | chat2api: 5 | image: lanqian528/chat2api:latest 6 | container_name: chat2api 7 | restart: unless-stopped 8 | network_mode: host # 使用 host 网络模式 9 | volumes: 10 | - ./data:/app/data # 挂载一些需要保存的数据 11 | environment: 12 | - TZ=Asia/Shanghai # 设置时区 13 | - ARKOSE_TOKEN_URL=http://127.0.0.1:5006/token # 使用 host 模式后,直接使用 localhost 访问 arkose 服务 14 | - USER_AGENTS=["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/121.2.3.4"] 15 | 16 | arkose: 17 | image: lanqian528/funcaptcha_solver:latest 18 | container_name: funcaptcha_solver 19 | restart: unless-stopped 20 | network_mode: host # 使用 host 网络模式 21 | environment: 22 | - TZ=Asia/Shanghai # 设置时区 23 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/tools/authenticator/remove_duplicates.py: -------------------------------------------------------------------------------- 1 | # Removes duplicate lines from a file 2 | # Usage: python remove_duplicates.py 3 | 4 | import sys 5 | import json 6 | 7 | 8 | def remove_duplicates(file_lines): 9 | """ 10 | Removes duplicate lines from a file 11 | """ 12 | lines_set = set() 13 | for lin in file_lines: 14 | #if json.loads(lin)["output"] == "": 15 | # continue 16 | lines_set.add(lin) 17 | return lines_set 18 | 19 | 20 | if __name__ == "__main__": 21 | if len(sys.argv) != 2: 22 | print("Usage: python remove_duplicates.py ") 23 | sys.exit(1) 24 | orig_file = open(sys.argv[1], "r", encoding="utf-8").readlines() 25 | lines = remove_duplicates(orig_file) 26 | file = open("clean_" + sys.argv[1], "w", encoding="utf-8") 27 | for line in lines: 28 | file.write(line) 29 | file.close() 30 | # Print difference 31 | print(len(orig_file) - len(lines)) 32 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Golang image as the builder 2 | FROM golang:1.20.3-alpine as builder 3 | 4 | # Enable CGO to use C libraries (set to 0 to disable it) 5 | # We set it to 0 to build a fully static binary for our final image 6 | ENV CGO_ENABLED=0 7 | 8 | # Set the working directory 9 | WORKDIR /app 10 | 11 | # Copy the Go Modules manifests (go.mod and go.sum files) 12 | COPY go.mod go.sum ./ 13 | 14 | # Download the dependencies 15 | RUN go mod download 16 | 17 | # Copy the source code 18 | COPY . . 19 | 20 | # Build the Go application and output the binary to /app/ChatGPT-Proxy-V4 21 | RUN go build -o /app/ChatGPT-To-API . 22 | 23 | # Use a scratch image as the final distroless image 24 | FROM scratch 25 | 26 | # Set the working directory 27 | WORKDIR /app 28 | 29 | # Copy the built Go binary from the builder stage 30 | COPY --from=builder /app/ChatGPT-To-API /app/ChatGPT-To-API 31 | 32 | # Expose the port where the application is running 33 | EXPOSE 8080 34 | 35 | # Start the application 36 | CMD [ "./ChatGPT-To-API" ] 37 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/migrations/scripts/20230308_01_7ctOr.sql: -------------------------------------------------------------------------------- 1 | -- Init database 2 | -- depends: 3 | 4 | drop table if exists conversation_official; 5 | create table conversation_official 6 | ( 7 | conversation_id char(36) 8 | primary key, 9 | title text not null, 10 | create_time integer not null 11 | ); 12 | 13 | drop table if exists conversation_info; 14 | create table conversation_info 15 | ( 16 | conversation_id char(36) 17 | primary key, 18 | title varchar(200) not null, 19 | create_time integer not null, 20 | current_node char(36) 21 | ); 22 | 23 | drop table if exists prompt_info; 24 | create table prompt_info 25 | ( 26 | prompt_id char(36) not null, 27 | conversation_id char(36) not null, 28 | model varchar(64), 29 | parent_id char(36), 30 | role varchar(20), 31 | content longtext, 32 | create_time integer not null, 33 | constraint prompt_info_pk 34 | primary key (conversation_id, prompt_id) 35 | ); 36 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/exts/hooks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | import sys 5 | 6 | from loguru import logger 7 | 8 | 9 | def __exception_handle(e_type, e_value, e_traceback): 10 | if issubclass(e_type, KeyboardInterrupt): 11 | print('\nBye...') 12 | sys.exit(0) 13 | 14 | sys.__excepthook__(e_type, e_value, e_traceback) 15 | 16 | 17 | class __InterceptHandler(logging.Handler): 18 | def emit(self, record): 19 | try: 20 | level = logger.level(record.levelname).name 21 | except ValueError: 22 | level = record.levelno 23 | 24 | frame, depth = logging.currentframe(), 2 25 | while frame.f_code.co_filename == logging.__file__: 26 | frame = frame.f_back 27 | depth += 1 28 | 29 | logger.opt(depth=depth, exception=record.exc_info).log( 30 | level, record.getMessage() 31 | ) 32 | 33 | 34 | def hook_except_handle(): 35 | sys.excepthook = __exception_handle 36 | 37 | 38 | def hook_logging(**kwargs): 39 | logging.basicConfig(handlers=[__InterceptHandler()], **kwargs) 40 | -------------------------------------------------------------------------------- /API/pandora/bin/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PANDORA_ARGS="" 4 | PANDORA_COMMAND="pandora" 5 | USER_CONFIG_DIR="/data" 6 | 7 | if [ -n "${PANDORA_PROXY}" ]; then 8 | PANDORA_ARGS="${PANDORA_ARGS} -p ${PANDORA_PROXY}" 9 | fi 10 | 11 | if [ -n "${PANDORA_ACCESS_TOKEN}" ]; then 12 | mkdir -p "${USER_CONFIG_DIR}" 13 | 14 | echo "${PANDORA_ACCESS_TOKEN}" >"${USER_CONFIG_DIR}/access_token.dat" 15 | fi 16 | 17 | if [ -n "${PANDORA_TOKENS_FILE}" ]; then 18 | PANDORA_ARGS="${PANDORA_ARGS} --tokens_file ${PANDORA_TOKENS_FILE}" 19 | fi 20 | 21 | if [ -n "${PANDORA_SERVER}" ]; then 22 | PANDORA_ARGS="${PANDORA_ARGS} -s ${PANDORA_SERVER}" 23 | fi 24 | 25 | if [ -n "${PANDORA_API}" ]; then 26 | PANDORA_ARGS="${PANDORA_ARGS} -a" 27 | fi 28 | 29 | if [ -n "${PANDORA_SENTRY}" ]; then 30 | PANDORA_ARGS="${PANDORA_ARGS} --sentry" 31 | fi 32 | 33 | if [ -n "${PANDORA_VERBOSE}" ]; then 34 | PANDORA_ARGS="${PANDORA_ARGS} -v" 35 | fi 36 | 37 | if [ -n "${PANDORA_CLOUD}" ]; then 38 | PANDORA_COMMAND="pandora-cloud" 39 | fi 40 | 41 | export USER_CONFIG_DIR 42 | 43 | # shellcheck disable=SC2086 44 | $(command -v ${PANDORA_COMMAND}) ${PANDORA_ARGS} 45 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/internal/tokens/tokens.go: -------------------------------------------------------------------------------- 1 | package tokens 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "sync" 7 | ) 8 | 9 | type AccessToken struct { 10 | tokens []string 11 | lock sync.Mutex 12 | } 13 | 14 | func NewAccessToken(tokens []string) AccessToken { 15 | // Save the tokens to a file 16 | if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { 17 | // Create the file 18 | file, err := os.Create("access_tokens.json") 19 | if err != nil { 20 | return AccessToken{} 21 | } 22 | defer file.Close() 23 | } 24 | file, err := os.OpenFile("access_tokens.json", os.O_WRONLY|os.O_TRUNC, 0644) 25 | if err != nil { 26 | return AccessToken{} 27 | } 28 | defer file.Close() 29 | encoder := json.NewEncoder(file) 30 | err = encoder.Encode(tokens) 31 | if err != nil { 32 | return AccessToken{} 33 | } 34 | return AccessToken{ 35 | tokens: tokens, 36 | } 37 | } 38 | 39 | func (a *AccessToken) GetToken() string { 40 | a.lock.Lock() 41 | defer a.lock.Unlock() 42 | 43 | if len(a.tokens) == 0 { 44 | return "" 45 | } 46 | 47 | token := a.tokens[0] 48 | a.tokens = append(a.tokens[1:], token) 49 | return token 50 | } 51 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 linweiyuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/docs/admin.md: -------------------------------------------------------------------------------- 1 | # API Documentation: 2 | 3 | ## passwordHandler: 4 | 5 | This API endpoint receives a POST request with a JSON body that contains a "password" field. The API updates the value of the ADMIN_PASSWORD variable with the value provided in the request body. 6 | 7 | HTTP method: PATCH 8 | 9 | Endpoint: /password 10 | 11 | Request body: 12 | 13 | ```json 14 | { 15 | "password": string 16 | } 17 | ``` 18 | 19 | Response status codes: 20 | - 200 OK: The ADMIN_PASSWORD variable was successfully updated. 21 | - 400 Bad Request: The "password" field is missing or not provided in the request body. 22 | 23 | ## tokensHandler: 24 | 25 | This API endpoint receives a POST request with a JSON body that contains an array of request tokens. The API updates the value of the ACCESS_TOKENS variable with a new access token generated from the request tokens provided in the request body. 26 | 27 | HTTP method: PATCH 28 | 29 | Endpoint: /tokens 30 | 31 | Request body: 32 | 33 | ```json 34 | [ 35 | "string", "..." 36 | ] 37 | ``` 38 | 39 | Response status codes: 40 | - 200 OK: The ACCESS_TOKENS variable was successfully updated. 41 | - 400 Bad Request: The request tokens are missing or not provided in the request body. 42 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/chatgpt/constant.go: -------------------------------------------------------------------------------- 1 | package chatgpt 2 | 3 | const ( 4 | apiPrefix = "https://chat.openai.com/backend-api" 5 | defaultRole = "user" 6 | getConversationsErrorMessage = "Failed to get conversations." 7 | generateTitleErrorMessage = "Failed to generate title." 8 | getContentErrorMessage = "Failed to get content." 9 | updateConversationErrorMessage = "Failed to update conversation." 10 | clearConversationsErrorMessage = "Failed to clear conversations." 11 | feedbackMessageErrorMessage = "Failed to add feedback." 12 | getModelsErrorMessage = "Failed to get models." 13 | getAccountCheckErrorMessage = "Check failed." // Placeholder. Never encountered. 14 | parseJsonErrorMessage = "Failed to parse json request body." 15 | fallbackErrorMessage = "Fallback failed." 16 | fallbackMethodNotAllowedMessage = "Fallback method not allowed." 17 | 18 | csrfUrl = "https://chat.openai.com/api/auth/csrf" 19 | promptLoginUrl = "https://chat.openai.com/api/auth/signin/auth0?prompt=login" 20 | getCsrfTokenErrorMessage = "Failed to get CSRF token." 21 | authSessionUrl = "https://chat.openai.com/api/auth/session" 22 | ) 23 | -------------------------------------------------------------------------------- /chat2api-docker-warp.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | arkose: 5 | image: lanqian528/funcaptcha_solver:latest 6 | container_name: funcaptcha-solver 7 | restart: unless-stopped 8 | environment: 9 | - TZ=Asia/Shanghai 10 | ports: 11 | - "5006:5006" 12 | networks: 13 | - chat2api-network 14 | 15 | chat2api: 16 | image: lanqian528/chat2api:latest 17 | container_name: chat2api 18 | restart: unless-stopped 19 | environment: 20 | - ARKOSE_TOKEN_URL=http://arkose:5006/token 21 | - PROXY_URL=socks5://openai:chatgpt@warp:1080 22 | - TZ=Asia/Shanghai 23 | - ENABLE_GATEWAY=false 24 | ports: 25 | - "5005:5005" 26 | volumes: 27 | - /DATA/AppData/Chat2API/app/data:/app/data 28 | networks: 29 | - chat2api-network 30 | 31 | warp: 32 | image: caomingjun/warp:latest 33 | container_name: warp 34 | restart: always 35 | environment: 36 | - WARP_SLEEP=2 37 | - GOST_ARGS=-L openai:chatgpt@:1080 38 | ports: 39 | - "1080:1080" 40 | sysctls: 41 | net.ipv4.conf.all.src_valid_mark: "1" 42 | net.ipv6.conf.all.disable_ipv6: "0" 43 | networks: 44 | - chat2api-network 45 | 46 | networks: 47 | chat2api-network: 48 | name: my_chat2api_network 49 | -------------------------------------------------------------------------------- /chat2api-docker-warp-host.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | chat2api: 5 | image: lanqian528/chat2api:latest 6 | container_name: chat2api 7 | restart: unless-stopped 8 | network_mode: host # 使用 host 网络模式 9 | volumes: 10 | - ./data:/app/data # 挂载一些需要保存的数据 11 | environment: 12 | - TZ=Asia/Shanghai # 设置时区 13 | - ARKOSE_TOKEN_URL=http://127.0.0.1:5006/token # 使用 host 模式后,直接使用 localhost 访问 arkose 服务 14 | - USER_AGENTS=["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.2.3.4 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/121.2.3.4"] 15 | - PROXY_URL=socks5://openai:chatgpt@127.0.0.1:1080 16 | - ENABLE_GATEWAY=true 17 | - HISTORY_DISABLED=false 18 | - SCHEDULED_REFRESH=true 19 | 20 | arkose: 21 | image: lanqian528/funcaptcha_solver:latest 22 | container_name: funcaptcha_solver 23 | restart: unless-stopped 24 | network_mode: host # 使用 host 网络模式 25 | environment: 26 | - TZ=Asia/Shanghai # 设置时区 27 | 28 | warp: 29 | image: caomingjun/warp:latest 30 | container_name: warp 31 | restart: always 32 | network_mode: host # 使用 host 网络模式 33 | environment: 34 | - WARP_SLEEP=2 35 | - GOST_ARGS=-L 0.0.0.0:1080 # 监听所有 IP 地址的 1080 端口 36 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/middleware.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "os" 6 | 7 | gin "github.com/gin-gonic/gin" 8 | ) 9 | 10 | var ADMIN_PASSWORD string 11 | var API_KEYS map[string]bool 12 | 13 | func init() { 14 | ADMIN_PASSWORD = os.Getenv("ADMIN_PASSWORD") 15 | if ADMIN_PASSWORD == "" { 16 | ADMIN_PASSWORD = "TotallySecurePassword" 17 | } 18 | } 19 | 20 | func adminCheck(c *gin.Context) { 21 | password := c.Request.Header.Get("Authorization") 22 | if password != ADMIN_PASSWORD { 23 | c.String(401, "Unauthorized") 24 | c.Abort() 25 | return 26 | } 27 | c.Next() 28 | } 29 | 30 | func cors(c *gin.Context) { 31 | c.Header("Access-Control-Allow-Origin", "*") 32 | c.Header("Access-Control-Allow-Methods", "*") 33 | c.Header("Access-Control-Allow-Headers", "*") 34 | c.Next() 35 | } 36 | 37 | func Authorization(c *gin.Context) { 38 | if API_KEYS == nil { 39 | API_KEYS = make(map[string]bool) 40 | if _, err := os.Stat("api_keys.txt"); err == nil { 41 | file, _ := os.Open("api_keys.txt") 42 | defer file.Close() 43 | scanner := bufio.NewScanner(file) 44 | for scanner.Scan() { 45 | key := scanner.Text() 46 | if key != "" { 47 | API_KEYS["Bearer "+key] = true 48 | } 49 | } 50 | } 51 | } 52 | if len(API_KEYS) != 0 && !API_KEYS[c.Request.Header.Get("Authorization")] { 53 | c.String(401, "Unauthorized") 54 | c.Abort() 55 | return 56 | } 57 | c.Next() 58 | } 59 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/internal/chatgpt/typings.go: -------------------------------------------------------------------------------- 1 | package chatgpt 2 | 3 | import "github.com/google/uuid" 4 | 5 | type chatgpt_message struct { 6 | ID uuid.UUID `json:"id"` 7 | Author chatgpt_author `json:"author"` 8 | Content chatgpt_content `json:"content"` 9 | } 10 | 11 | type chatgpt_content struct { 12 | ContentType string `json:"content_type"` 13 | Parts []string `json:"parts"` 14 | } 15 | 16 | type chatgpt_author struct { 17 | Role string `json:"role"` 18 | } 19 | 20 | type ChatGPTRequest struct { 21 | Action string `json:"action"` 22 | Messages []chatgpt_message `json:"messages"` 23 | ParentMessageID string `json:"parent_message_id,omitempty"` 24 | Model string `json:"model"` 25 | HistoryAndTrainingDisabled bool `json:"history_and_training_disabled"` 26 | } 27 | 28 | func NewChatGPTRequest() ChatGPTRequest { 29 | return ChatGPTRequest{ 30 | Action: "next", 31 | ParentMessageID: uuid.NewString(), 32 | Model: "text-davinci-002-render-sha", 33 | HistoryAndTrainingDisabled: true, 34 | } 35 | } 36 | 37 | func (c *ChatGPTRequest) AddMessage(role string, content string) { 38 | c.Messages = append(c.Messages, chatgpt_message{ 39 | ID: uuid.New(), 40 | Author: chatgpt_author{Role: role}, 41 | Content: chatgpt_content{ContentType: "text", Parts: []string{content}}, 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/chatgpt/typings.go: -------------------------------------------------------------------------------- 1 | package chatgpt 2 | 3 | //goland:noinspection GoSnakeCaseUsage 4 | import tls_client "github.com/bogdanfinn/tls-client" 5 | 6 | type UserLogin struct { 7 | client tls_client.HttpClient 8 | } 9 | 10 | type CreateConversationRequest struct { 11 | Action string `json:"action"` 12 | Messages []Message `json:"messages"` 13 | Model string `json:"model"` 14 | ParentMessageID string `json:"parent_message_id"` 15 | ConversationID *string `json:"conversation_id"` 16 | TimezoneOffsetMin int `json:"timezone_offset_min"` 17 | VariantPurpose string `json:"variant_purpose"` 18 | ContinueText string `json:"continue_text"` 19 | } 20 | 21 | type Message struct { 22 | Author Author `json:"author"` 23 | Content Content `json:"content"` 24 | ID string `json:"id"` 25 | } 26 | 27 | type Author struct { 28 | Role string `json:"role"` 29 | } 30 | 31 | type Content struct { 32 | ContentType string `json:"content_type"` 33 | Parts []string `json:"parts"` 34 | } 35 | 36 | type FeedbackMessageRequest struct { 37 | MessageID string `json:"message_id"` 38 | ConversationID string `json:"conversation_id"` 39 | Rating string `json:"rating"` 40 | } 41 | 42 | type GenerateTitleRequest struct { 43 | MessageID string `json:"message_id"` 44 | } 45 | 46 | type PatchConversationRequest struct { 47 | Title *string `json:"title"` 48 | IsVisible bool `json:"is_visible"` 49 | } 50 | 51 | type Cookie struct { 52 | Name string `json:"name"` 53 | Value string `json:"value"` 54 | Expiry int64 `json:"expiry"` 55 | } 56 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/README_CN.md: -------------------------------------------------------------------------------- 1 | # ChatGPT-to-API 2 | 创建一个模拟API(通过ChatGPT网页版) 3 | 4 | 本中文手册由 [@BlueSkyXN](https://github.com/BlueSkyXN) 编写 5 | 6 | [英文文档(English Docs)](README.md) 7 | 8 | ## 认证和各项准备工作 9 | 10 | 在使用之前,你需要完成一系列准备工作 11 | 12 | 1. 准备ChatGPT账号,最好的PLUS订阅的,有没有开API不重要 13 | 2. 完善的运行环境和网络环境(否则你总是要寻找方法绕过) 14 | 3. Access Token和PUID,下面会教你怎么获取 15 | 4. 选择一个代理后端或者自行搭建 16 | 5. 你可以在 https://github.com/BlueSkyXN/OpenAI-Quick-DEV 项目找到一些常用组件以及一些快速运行的教程或程序。 17 | 18 | ### 获取PUID 19 | 20 | PUID,就是Personal User ID。这是这个项目中一个特色,其他项目没遇到需要这个的,不过还是弄一下吧。(可能直接访问官网才要,使用或搭建的绕过WAF的代理不需要,目前第三方代理源已经可以自带绕过WAF) 21 | 22 | 获取链接是 https://chat.openai.com/api/auth/session 打开这个URL会得到一个JSON,最前面的 ```{"user":{"id":"user-XXXX","name":"XXXX","email":"XXX",``` 这里面的 user.id 就是我要的PUID(至少我的实践是这个,我并没有找到作者具体的说明)(有可能需要PLUS用户权限,作者的说明是用于绕过CloudFlare的速率限制) 23 | 24 | ### 获取Access Token 25 | 目前有多种方法和原理,这部分内容可以参考 [TOKEN中文手册](docs\TOKEN_CN.md) 26 | 27 | ## 安装和运行 28 | 29 | 作者在[英文版介绍](README.md) 通过GO编译来构建二进制程序,但是我猜测这可能需要一个GO编译环境。所以我建议基于作者的Compose配置文件来Docker运行。 30 | 31 | 有关docker的指导请阅读 [DOCKER中文手册](docs\Docker_CN.md) 32 | 33 | 安装好Docker和Docker-Compase后,通过Compase来启动 34 | 35 | ```docker-compose up -d``` 36 | 37 | 注意,启动之前你需要配置 yml 配置文件,主要是端口和环境变量,各项参数、用法请参考 [中文指导手册](docs\GUIDE_CN.md) 38 | 39 | 最后的API端点(Endpoint)是 40 | 41 | ```http://127.0.0.1:8080/v1/chat/completions``` 42 | 43 | 注意域名/IP和端口要改成你自己的 44 | 45 | ### 环境变量 46 | - `PUID` - 用户ID 47 | - `http_proxy` - SOCKS5 或 HTTP 代理 `socks5://HOST:PORT` 48 | - `SERVER_HOST` - (default)比如 127.0.0.1 49 | - `SERVER_PORT` - (default)比如 8080 by 50 | 51 | ### 文件选项 52 | - `access_tokens.json` - 附带AccessToken的Json文件 53 | - `proxies.txt` - 代理表 (格式: `USERNAME:PASSWORD:HOST:PORT`) 54 | 55 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/images/2022/11/ChatGPT.jpg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/tools/plugin_check/check_access.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | var access_tokens []string 12 | // Read access_tokens.txt and split by new line 13 | file, err := os.Open("access_tokens.txt") 14 | if err != nil { 15 | panic(err) 16 | } 17 | defer file.Close() 18 | scanner := bufio.NewScanner(file) 19 | for scanner.Scan() { 20 | access_tokens = append(access_tokens, scanner.Text()) 21 | } 22 | if err := scanner.Err(); err != nil { 23 | panic(err) 24 | } 25 | // Go routine to check access for each token (limit to 20 simultaneous) 26 | sem := make(chan bool, 20) 27 | for _, token := range access_tokens { 28 | sem <- true 29 | go func(token string) { 30 | defer func() { <-sem }() 31 | if check_access(token) { 32 | println(token) 33 | } 34 | }(token) 35 | } 36 | for i := 0; i < cap(sem); i++ { 37 | sem <- true 38 | } 39 | } 40 | 41 | func check_access(token string) bool { 42 | print(".") 43 | req, _ := http.NewRequest("GET", "https://ai.fakeopen.com/api/accounts/check", nil) 44 | req.Header.Set("Authorization", "Bearer "+token) 45 | client := &http.Client{} 46 | resp, err := client.Do(req) 47 | if err != nil { 48 | panic(err) 49 | } 50 | defer resp.Body.Close() 51 | if resp.StatusCode == 200 { 52 | // Parse response body as JSON 53 | var result map[string]interface{} 54 | json.NewDecoder(resp.Body).Decode(&result) 55 | // Check if "tool1", "tool2", or "tool3" is in the features array 56 | for _, feature := range result["features"].([]interface{}) { 57 | if feature == "tools1" || feature == "tools2" || feature == "tools3" { 58 | return true 59 | } 60 | } 61 | return false 62 | } 63 | println(resp.StatusCode) 64 | return false 65 | } 66 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/platform/constant.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import "github.com/linweiyuan/go-chatgpt-api/api" 4 | 5 | //goland:noinspection SpellCheckingInspection 6 | const ( 7 | apiUrl = "https://api.openai.com" 8 | 9 | apiListModels = apiUrl + "/v1/models" 10 | apiRetrieveModel = apiUrl + "/v1/models/%s" 11 | apiCreateCompletions = apiUrl + "/v1/completions" 12 | apiCreataeChatCompletions = apiUrl + "/v1/chat/completions" 13 | apiCreateEdit = apiUrl + "/v1/edits" 14 | apiCreateImage = apiUrl + "/v1/images/generations" 15 | apiCreateEmbeddings = apiUrl + "/v1/embeddings" 16 | apiListFiles = apiUrl + "/v1/files" 17 | 18 | apiGetCreditGrants = apiUrl + "/dashboard/billing/credit_grants" 19 | apiGetSubscription = apiUrl + "/dashboard/billing/subscription" 20 | apiGetApiKeys = apiUrl + "/dashboard/user/api_keys" 21 | 22 | platformAuthClientID = "DRivsnm2Mu42T3KOpqdtwB3NYviHYzwD" 23 | platformAuthAudience = "https://api.openai.com/v1" 24 | platformAuthRedirectURL = "https://platform.openai.com/auth/callback" 25 | platformAuthScope = "openid profile email offline_access" 26 | platformAuthResponseType = "code" 27 | platformAuthGrantType = "authorization_code" 28 | platformAuth0Url = api.Auth0Url + "/authorize?" 29 | getTokenUrl = api.Auth0Url + "/oauth/token" 30 | auth0Client = "eyJuYW1lIjoiYXV0aDAtc3BhLWpzIiwidmVyc2lvbiI6IjEuMjEuMCJ9" // '{"name":"auth0-spa-js","version":"1.21.0"}' 31 | auth0LogoutUrl = api.Auth0Url + "/v2/logout?returnTo=https%3A%2F%2Fplatform.openai.com%2Floggedout&client_id=" + platformAuthClientID + "&auth0Client=" + auth0Client 32 | dashboardLoginUrl = "https://api.openai.com/dashboard/onboarding/login" 33 | getSessionKeyErrorMessage = "Failed to get session key." 34 | ) 35 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/go.mod: -------------------------------------------------------------------------------- 1 | module freechatgpt 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/acheong08/endless v0.0.0-20230522010333-1359fd84c836 7 | github.com/bogdanfinn/fhttp v0.5.22 8 | github.com/bogdanfinn/tls-client v1.3.12 9 | github.com/gin-gonic/gin v1.9.0 10 | github.com/google/uuid v1.3.0 11 | ) 12 | 13 | require ( 14 | github.com/andybalholm/brotli v1.0.5 // indirect 15 | github.com/bogdanfinn/utls v1.5.16 // indirect 16 | github.com/bytedance/sonic v1.8.9 // indirect 17 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 18 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 19 | github.com/gin-contrib/sse v0.1.0 // indirect 20 | github.com/go-playground/locales v0.14.1 // indirect 21 | github.com/go-playground/universal-translator v0.18.1 // indirect 22 | github.com/go-playground/validator/v10 v10.14.0 // indirect 23 | github.com/goccy/go-json v0.10.2 // indirect 24 | github.com/json-iterator/go v1.1.12 // indirect 25 | github.com/klauspost/compress v1.16.5 // indirect 26 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 27 | github.com/leodido/go-urn v1.2.4 // indirect 28 | github.com/mattn/go-isatty v0.0.19 // indirect 29 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 30 | github.com/modern-go/reflect2 v1.0.2 // indirect 31 | github.com/pelletier/go-toml/v2 v2.0.7 // indirect 32 | github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect 33 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 34 | github.com/ugorji/go/codec v1.2.11 // indirect 35 | golang.org/x/arch v0.3.0 // indirect 36 | golang.org/x/crypto v0.9.0 // indirect 37 | golang.org/x/net v0.10.0 // indirect 38 | golang.org/x/sys v0.8.0 // indirect 39 | golang.org/x/text v0.9.0 // indirect 40 | google.golang.org/protobuf v1.30.0 // indirect 41 | gopkg.in/yaml.v3 v3.0.1 // indirect 42 | ) 43 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/exts/token.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from jwt import decode 4 | 5 | from ..openai.utils import Console 6 | 7 | __public_key = b'-----BEGIN PUBLIC KEY-----\n' \ 8 | b'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA27rOErDOPvPc3mOADYtQ\n' \ 9 | b'BeenQm5NS5VHVaoO/Zmgsf1M0Wa/2WgLm9jX65Ru/K8Az2f4MOdpBxxLL686ZS+K\n' \ 10 | b'7eJC/oOnrxCRzFYBqQbYo+JMeqNkrCn34yed4XkX4ttoHi7MwCEpVfb05Qf/ZAmN\n' \ 11 | b'I1XjecFYTyZQFrd9LjkX6lr05zY6aM/+MCBNeBWp35pLLKhiq9AieB1wbDPcGnqx\n' \ 12 | b'lXuU/bLgIyqUltqLkr9JHsf/2T4VrXXNyNeQyBq5wjYlRkpBQDDDNOcdGpx1buRr\n' \ 13 | b'Z2hFyYuXDRrMcR6BQGC0ur9hI5obRYlchDFhlb0ElsJ2bshDDGRk5k3doHqbhj2I\n' \ 14 | b'gQIDAQAB\n' \ 15 | b'-----END PUBLIC KEY-----' 16 | 17 | 18 | def check_access_token(access_token, api=False): 19 | if api and access_token.startswith('sk-'): 20 | return True 21 | 22 | payload = (decode(access_token, key=__public_key, algorithms='RS256', audience=[ 23 | "https://api.openai.com/v1", 24 | "https://openai.openai.auth0app.com/userinfo" 25 | ], issuer='https://auth0.openai.com/')) 26 | 27 | if 'scope' not in payload: 28 | raise Exception('miss scope') 29 | 30 | scope = payload['scope'] 31 | if 'model.read' not in scope or 'model.request' not in scope: 32 | raise Exception('invalid scope') 33 | 34 | if 'https://api.openai.com/auth' not in payload or 'https://api.openai.com/profile' not in payload: 35 | raise Exception('belonging to an unregistered user.') 36 | 37 | return payload 38 | 39 | 40 | def check_access_token_out(access_token, api=False): 41 | try: 42 | return check_access_token(access_token, api) 43 | except Exception as e: 44 | Console.error('### Invalid access token: {}'.format(str(e))) 45 | return False 46 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT-to-API 2 | Create a fake API using ChatGPT's website 3 | 4 | **API endpoint: http://127.0.0.1:8080/v1/chat/completions.** 5 | 6 | [中文文档(Chinese Docs)](README_CN.md) 7 | 8 | ## Help needed 9 | - Documentation. 10 | 11 | ## Setup 12 | 13 |
14 | 15 | 16 | ### Authentication 17 | 18 | 19 | Access token retrieval has been automated: 20 | https://github.com/acheong08/ChatGPT-to-API/tree/master/tools/authenticator 21 | 22 | Converting from a newline delimited list of access tokens to `access_tokens.json` 23 | ```bash 24 | #!/bin/bash 25 | 26 | START="[" 27 | END="]" 28 | 29 | TOKENS="" 30 | 31 | while read -r line; do 32 | if [ -z "$TOKENS" ]; then 33 | TOKENS="\"$line\"" 34 | else 35 | TOKENS+=",\"$line\"" 36 | fi 37 | done < access_tokens.txt 38 | 39 | echo "$START$TOKENS$END" > access_tokens.json 40 | ``` 41 | 42 |
43 | 44 | ## Getting set up 45 | 46 | `git clone https://github.com/acheong08/ChatGPT-to-API` 47 | `cd ChatGPT-to-API` 48 | `go build` 49 | `./freechatgpt` 50 | 51 | ### Environment variables 52 | - `PUID` - A cookie found on chat.openai.com for Plus users. This gets around Cloudflare rate limits 53 | - `http_proxy` - SOCKS5 or HTTP proxy. `socks5://HOST:PORT` 54 | - `SERVER_HOST` - Set to 127.0.0.1 by default 55 | - `SERVER_PORT` - Set to 8080 by default 56 | 57 | ### Files (Optional) 58 | - `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)) 59 | - `proxies.txt` - A list of proxies separated by new line (Format: `USERNAME:PASSWORD:HOST:PORT`) 60 | 61 | 62 | 63 | ## Admin API docs 64 | https://github.com/acheong08/ChatGPT-to-API/blob/master/docs/admin.md 65 | 66 | ## API usage docs 67 | https://platform.openai.com/docs/api-reference/chat 68 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/linweiyuan/go-chatgpt-api 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/PuerkitoBio/goquery v1.8.1 7 | github.com/bogdanfinn/fhttp v0.5.22 8 | github.com/bogdanfinn/tls-client v1.3.11 9 | github.com/gin-gonic/gin v1.9.0 10 | github.com/joho/godotenv v1.5.1 11 | github.com/sirupsen/logrus v1.9.0 12 | ) 13 | 14 | require ( 15 | github.com/andybalholm/brotli v1.0.4 // indirect 16 | github.com/andybalholm/cascadia v1.3.1 // indirect 17 | github.com/bogdanfinn/utls v1.5.16 // indirect 18 | github.com/bytedance/sonic v1.8.0 // indirect 19 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 20 | github.com/gin-contrib/sse v0.1.0 // indirect 21 | github.com/go-playground/locales v0.14.1 // indirect 22 | github.com/go-playground/universal-translator v0.18.1 // indirect 23 | github.com/go-playground/validator/v10 v10.11.2 // indirect 24 | github.com/goccy/go-json v0.10.0 // indirect 25 | github.com/json-iterator/go v1.1.12 // indirect 26 | github.com/klauspost/compress v1.15.12 // indirect 27 | github.com/klauspost/cpuid/v2 v2.0.9 // indirect 28 | github.com/leodido/go-urn v1.2.1 // indirect 29 | github.com/mattn/go-isatty v0.0.17 // indirect 30 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect 31 | github.com/modern-go/reflect2 v1.0.2 // indirect 32 | github.com/pelletier/go-toml/v2 v2.0.6 // indirect 33 | github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect 34 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 35 | github.com/ugorji/go/codec v1.2.9 // indirect 36 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect 37 | golang.org/x/crypto v0.5.0 // indirect 38 | golang.org/x/net v0.7.0 // indirect 39 | golang.org/x/sys v0.5.0 // indirect 40 | golang.org/x/text v0.7.0 // indirect 41 | google.golang.org/protobuf v1.28.1 // indirect 42 | gopkg.in/yaml.v3 v3.0.1 // indirect 43 | ) 44 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/docs/Docker_CN.md: -------------------------------------------------------------------------------- 1 | # 使用阿里源实现Docker安装 2 | 3 | 移除旧的 4 | 5 | ```yum remove -y docker docker-common docker-selinux docker-engine``` 6 | 7 | 安装依赖 8 | 9 | ```yum install -y yum-utils device-mapper-persistent-data lvm2``` 10 | 11 | 配置Docker安装源(阿里) 12 | 13 | ```yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo``` 14 | 15 | 检查可用的Docker-CE版本 16 | 17 | ```yum list docker-ce --showduplicates | sort -r``` 18 | 19 | 安装Docker-CE 20 | 21 | ```yum -y install docker-ce``` 22 | 23 | 运行Docker(默认不运行) 24 | 25 | ```systemctl start docker``` 26 | 27 | 配置开机启动Docker 28 | 29 | ```systemctl enable docker``` 30 | 31 | # 使用官方二进制包安装Docker-Compase 32 | 33 | 下载 Docker-Compose 的二进制文件 34 | ```sudo curl -L "https://github.com/docker/compose/releases/download/v2.18.1/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose``` 35 | 36 | 添加可执行权限 37 | 38 | ```sudo chmod +x /usr/local/bin/docker-compose``` 39 | 40 | 验证 Docker-Compose 是否安装成功 41 | 42 | ```docker-compose --version``` 43 | 44 | 启动容器 45 | 46 | ```docker-compose up -d``` 47 | 48 | 关闭容器 49 | 50 | ```docker-compose down``` 51 | 52 | 查看容器(如果启动了这里没有说明启动失败) 53 | 54 | ```docker ps``` 55 | 56 | # ChatGPT-TO-API的Docker-Compase文件 57 | 58 | ``` 59 | ports: 60 | - '31480:31480' 61 | environment: 62 | SERVER_HOST: 0.0.0.0 63 | SERVER_PORT: 31480 64 | ADMIN_PASSWORD: TotallySecurePassword 65 | # Reverse Proxy - Available on accessToken 66 | #API_REVERSE_PROXY: https://bypass.churchless.tech/api/conversation 67 | #API_REVERSE_PROXY: https://ai.fakeopen.com/api/conversation 68 | PUID: user-7J4tdvHySlcilVgjFIrAtK1k 69 | 70 | ``` 71 | 72 | - 这里的ports,左边是外部端口,用于外部访问。右边的Docker端口,需要匹配下面程序设置的监听Port。 73 | - 如果参数`API_REVERSE_PROXY`为空,则默认的请求URL为`https://chat.openai.com/backend-api/conversation`,并且需要提供PUID。PUID的获取参考 [README_CN.md](README_CN.md) 74 | - 这个密码需要自定义,我们构建请求的时候需要它来鉴权。默认是```TotallySecurePassword``` 75 | 76 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "freechatgpt/internal/tokens" 6 | "os" 7 | "strings" 8 | 9 | "github.com/acheong08/endless" 10 | "github.com/gin-gonic/gin" 11 | ) 12 | 13 | var HOST string 14 | var PORT string 15 | var ACCESS_TOKENS tokens.AccessToken 16 | 17 | func init() { 18 | HOST = os.Getenv("SERVER_HOST") 19 | PORT = os.Getenv("SERVER_PORT") 20 | if HOST == "" { 21 | HOST = "127.0.0.1" 22 | } 23 | if PORT == "" { 24 | PORT = "8080" 25 | } 26 | accessToken := os.Getenv("ACCESS_TOKENS") 27 | if accessToken != "" { 28 | accessTokens := strings.Split(accessToken, ",") 29 | ACCESS_TOKENS = tokens.NewAccessToken(accessTokens) 30 | } 31 | // Check if access_tokens.json exists 32 | if _, err := os.Stat("access_tokens.json"); os.IsNotExist(err) { 33 | // Create the file 34 | file, err := os.Create("access_tokens.json") 35 | if err != nil { 36 | panic(err) 37 | } 38 | defer file.Close() 39 | } else { 40 | // Load the tokens 41 | file, err := os.Open("access_tokens.json") 42 | if err != nil { 43 | panic(err) 44 | } 45 | defer file.Close() 46 | decoder := json.NewDecoder(file) 47 | var token_list []string 48 | err = decoder.Decode(&token_list) 49 | if err != nil { 50 | return 51 | } 52 | ACCESS_TOKENS = tokens.NewAccessToken(token_list) 53 | } 54 | } 55 | 56 | func main() { 57 | router := gin.Default() 58 | 59 | router.Use(cors) 60 | 61 | router.GET("/ping", func(c *gin.Context) { 62 | c.JSON(200, gin.H{ 63 | "message": "pong", 64 | }) 65 | }) 66 | 67 | admin_routes := router.Group("/admin") 68 | admin_routes.Use(adminCheck) 69 | 70 | /// Admin routes 71 | admin_routes.PATCH("/password", passwordHandler) 72 | admin_routes.PATCH("/tokens", tokensHandler) 73 | admin_routes.PATCH("/puid", puidHandler) 74 | /// Public routes 75 | router.OPTIONS("/v1/chat/completions", optionsHandler) 76 | router.POST("/v1/chat/completions", Authorization, nightmare) 77 | endless.ListenAndServe(HOST+":"+PORT, router) 78 | } 79 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/tools/authenticator/go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= 2 | github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 3 | github.com/bogdanfinn/fhttp v0.5.22 h1:U1jhZRtuaOanWWcm1WdMFnwMvSxUQgvO6berqAVTc5o= 4 | github.com/bogdanfinn/fhttp v0.5.22/go.mod h1:brqi5woc5eSCVHdKYBV8aZLbO7HGqpwyDLeXW+fT18I= 5 | github.com/bogdanfinn/tls-client v1.3.12 h1:jpNj7owMY/oULUQyAhAv6tRFkliFGLyr8Qx1ZZY/gp8= 6 | github.com/bogdanfinn/tls-client v1.3.12/go.mod h1:Q46nwIm0wPCweDM3XZcupxEIsTOWo3HVYSSsDj02/Qo= 7 | github.com/bogdanfinn/utls v1.5.16 h1:NhhWkegEcYETBMj9nvgO4lwvc6NcLH+znrXzO3gnw4M= 8 | github.com/bogdanfinn/utls v1.5.16/go.mod h1:mHeRCi69cUiEyVBkKONB1cAbLjRcZnlJbGzttmiuK4o= 9 | github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= 10 | github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 11 | github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= 12 | github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= 13 | github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc= 14 | github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng= 15 | golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= 16 | golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= 17 | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= 18 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 19 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= 20 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 21 | golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= 22 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 23 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/tools/proxy_check/proxy_check.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strings" 8 | "sync" 9 | 10 | tls_client "github.com/bogdanfinn/tls-client" 11 | ) 12 | 13 | var proxies []string 14 | 15 | // Read proxies.txt and check if they work 16 | func init() { 17 | // Check for proxies.txt 18 | if _, err := os.Stat("proxies.txt"); err == nil { 19 | // Each line is a proxy, put in proxies array 20 | file, _ := os.Open("proxies.txt") 21 | defer file.Close() 22 | scanner := bufio.NewScanner(file) 23 | for scanner.Scan() { 24 | // Split line by : 25 | proxy := scanner.Text() 26 | proxy_parts := strings.Split(proxy, ":") 27 | if len(proxy_parts) == 2 { 28 | proxy = "socks5://" + proxy 29 | } else if len(proxy_parts) == 4 { 30 | proxy = "socks5://" + proxy_parts[2] + ":" + proxy_parts[3] + "@" + proxy_parts[0] + ":" + proxy_parts[1] 31 | } else { 32 | continue 33 | } 34 | proxies = append(proxies, proxy) 35 | } 36 | } 37 | 38 | } 39 | 40 | func main() { 41 | wg := sync.WaitGroup{} 42 | for _, proxy := range proxies { 43 | wg.Add(1) 44 | go func(proxy string) { 45 | defer wg.Done() 46 | jar := tls_client.NewCookieJar() 47 | options := []tls_client.HttpClientOption{ 48 | tls_client.WithTimeoutSeconds(360), 49 | tls_client.WithClientProfile(tls_client.Chrome_110), 50 | tls_client.WithNotFollowRedirects(), 51 | tls_client.WithCookieJar(jar), // create cookieJar instance and pass it as argument 52 | // Disable SSL verification 53 | tls_client.WithInsecureSkipVerify(), 54 | } 55 | client, _ := tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) 56 | 57 | client.SetProxy(proxy) 58 | resp, err := client.Get("https://example.com") 59 | if err != nil { 60 | fmt.Println("Error: ", err) 61 | fmt.Println("Proxy: ", proxy) 62 | return 63 | } 64 | if resp.StatusCode != 200 { 65 | fmt.Println("Error: ", resp.StatusCode) 66 | fmt.Println("Proxy: ", proxy) 67 | return 68 | } else { 69 | fmt.Println(".") 70 | } 71 | }(proxy) 72 | } 73 | wg.Wait() 74 | } 75 | -------------------------------------------------------------------------------- /API/pandora/doc/HTTP-API.md: -------------------------------------------------------------------------------- 1 | # Pandora HTTP API 2 | 3 | ### 特殊说明:如果有多个`Access Token`,可以使用`X-Use-Token: token_name` 头指定使用哪个。 4 | 5 | ### `/api/models` 6 | 7 | * **HTTP方法:** `GET` 8 | * **URL参数:** `无` 9 | * **接口描述:** 列出账号可用的模型。 10 | 11 | ### `/api/conversations` 12 | 13 | * **HTTP方法:** `GET` 14 | * **URL参数:** 15 | * `offset` 数字类型,默认为:`1`。 16 | * `limit` 数字类型,默认为:`20`。 17 | * **接口描述:** 以分页方式列出会话列表。 18 | 19 | ### `/api/conversations` 20 | 21 | * **HTTP方法:** `DELETE` 22 | * **URL参数:** `无` 23 | * **接口描述:** 删除所有会话。 24 | 25 | ### `/api/conversation/` 26 | 27 | * **HTTP方法:** `GET` 28 | * **URL参数:** `无` 29 | * **接口描述:** 通过会话ID获取指定会话详情。 30 | 31 | ### `/api/conversation/` 32 | 33 | * **HTTP方法:** `DELETE` 34 | * **URL参数:** `无` 35 | * **接口描述:** 通过会话ID删除指定会话。 36 | 37 | ### `/api/conversation/` 38 | 39 | * **HTTP方法:** `PATCH` 40 | * **JSON字段:** 41 | * `title` 新标题。 42 | * **接口描述:** 通过会话ID设置指定的会话标题。 43 | 44 | ### `/api/conversation/gen_title/` 45 | 46 | * **HTTP方法:** `POST` 47 | * **JSON字段:** 48 | * `model` 对话所使用的模型。 49 | * `message_id` `ChatGPT`回复的那条消息的ID。 50 | * **接口描述:** 自动生成指定新会话的标题,通常首次问答后调用。 51 | 52 | ### `/api/conversation/talk` 53 | 54 | * **HTTP方法:** `POST` 55 | * **JSON字段:** 56 | * `prompt` 提问的内容。 57 | * `model` 对话使用的模型,通常整个会话中保持不变。 58 | * `message_id` 消息ID,通常使用`str(uuid.uuid4())`来生成一个。 59 | * `parent_message_id` 父消息ID,首次同样需要生成。之后获取上一条回复的消息ID即可。 60 | * `conversation_id` 首次对话可不传。`ChatGPT`回复时可获取。 61 | * `stream` 是否使用流的方式输出内容,默认为:`True` 62 | * **接口描述:** 向`ChatGPT`提问,等待其回复。 63 | 64 | ### `/api/conversation/regenerate` 65 | 66 | * **HTTP方法:** `POST` 67 | * **JSON字段:** 68 | * `prompt` 提问的内容。 69 | * `model` 对话使用的模型,通常整个会话中保持不变。 70 | * `message_id` 上一条用户发送消息的ID。 71 | * `parent_message_id` 上一条用户发送消息的父消息ID。 72 | * `conversation_id` 会话ID,在这个接口不可不传。 73 | * `stream` 是否使用流的方式输出内容,默认为:`True` 74 | * **接口描述:** 让`ChatGPT`重新生成回复。 75 | 76 | ### `/api/conversation/goon` 77 | 78 | * **HTTP方法:** `POST` 79 | * **JSON字段:** 80 | * `model` 对话使用的模型,通常整个会话中保持不变。 81 | * `parent_message_id` 父消息ID,上一次`ChatGPT`应答的消息ID。 82 | * `conversation_id` 会话ID。 83 | * `stream` 是否使用流的方式输出内容,默认为:`True` 84 | * **接口描述:** 让`ChatGPT`讲之前的恢复继续下去。 85 | 86 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/olf4sv64FWIcQ_zCGl90t/_buildManifest.js: -------------------------------------------------------------------------------- 1 | self.__BUILD_MANIFEST=function(a,c,s,t,e,u,n,h){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[t,a,e,"static/chunks/pages/index-f5560462cc9a5a86.js"],"/_error":["static/chunks/pages/_error-786d27d84962122a.js"],"/account/cancel":["static/chunks/pages/account/cancel-1c0d62f7e98cea5a.js"],"/account/manage":["static/chunks/pages/account/manage-515510f9fdcd7b92.js"],"/account/upgrade":[a,c,u,s,n,"static/chunks/pages/account/upgrade-0c6c79f25e11ac2f.js"],"/aip/[pluginId]/oauth/callback":[a,c,s,"static/chunks/pages/aip/[pluginId]/oauth/callback-8bae9003d60a57e1.js"],"/auth/error":["static/chunks/pages/auth/error-31ef8e5e6df49f9f.js"],"/auth/ext_callback":["static/chunks/pages/auth/ext_callback-8a3dba350878939d.js"],"/auth/ext_callback_refresh":["static/chunks/pages/auth/ext_callback_refresh-4cd753ececf58a64.js"],"/auth/login":[c,s,h,"static/chunks/pages/auth/login-7495d2c866b44897.js"],"/auth/logout":[a,"static/chunks/pages/auth/logout-0abf409a2bbf22c9.js"],"/auth/mocked_login":[a,"static/chunks/pages/auth/mocked_login-28119a8b1a5c2bce.js"],"/bypass":["static/chunks/pages/bypass-df27e0f8a3e360f1.js"],"/chat/[[...chatId]]":[t,"static/chunks/1f110208-44a6f43ddc5e9011.js","static/chunks/bd26816a-981e1ddc27b37cc6.js",a,c,e,u,"static/chunks/113-23682f80a24dd00d.js",s,n,"static/chunks/pages/chat/[[...chatId]]-76751174916fa3f7.js"],"/error":[t,a,e,"static/chunks/pages/error-1e886758cd4aa96f.js"],"/payments/success":[a,c,"static/chunks/882-025bd3b738a692ef.js",s,"static/chunks/pages/payments/success-5424184b119a4b94.js"],"/status":[c,s,h,"static/chunks/pages/status-696d2aa0dcc8e977.js"],sortedPages:["/","/_app","/_error","/account/cancel","/account/manage","/account/upgrade","/aip/[pluginId]/oauth/callback","/auth/error","/auth/ext_callback","/auth/ext_callback_refresh","/auth/login","/auth/logout","/auth/mocked_login","/bypass","/chat/[[...chatId]]","/error","/payments/success","/status"]}}("static/chunks/762-222df1028c0c1555.js","static/chunks/424-d1d3bfe6a3ca6c4a.js","static/chunks/264-13e92c51b0315184.js","static/chunks/68a27ff6-1185184b61bc22d0.js","static/chunks/174-bd28069f281ef76f.js","static/chunks/360-442b869f1ba4bb1b.js","static/chunks/14-0cb0d20affbd720d.js","static/chunks/417-2ccfee5029bb2a8b.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/chunks/949.1a6eb804b5e91f61.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[949],{93949:function(e,n,t){t.r(n),t.d(n,{SANDBOX_LINK_PREFIX:function(){return s},default:function(){return f},handleSandboxLinkClick:function(){return d}});var r=t(61706),a=t(45813),i=t(35250),c=t(70079),l=t(33264);function o(e){var n=e.accept,t=e.children,r=e.onFilePicked,a=(0,c.useRef)(null),l=(0,c.useCallback)(function(){var e;null===(e=a.current)||void 0===e||e.click()},[]),o=(0,c.useCallback)(function(e){var n,t=null===(n=e.target.files)||void 0===n?void 0:n[0];t&&(r(t),e.target.value="")},[r]);return(0,i.jsxs)(i.Fragment,{children:["function"==typeof t?t({onClick:l}):(0,i.jsx)("span",{role:"button",onClick:l,children:t}),(0,i.jsx)("input",{type:"file",accept:n,ref:a,className:"hidden",onChange:o})]})}var u=t(74516),s="sandbox:";function d(e,n,t){var i;return i=(0,r.Z)(function(r){var i,c,o,s,d,f,h,p,b,v;return(0,a.__generator)(this,function(a){switch(a.label){case 0:if(!(e.has("tools2")&&(null==n?void 0:null===(i=n.enabledTools)||void 0===i?void 0:i.includes("tools2"))))return[2];return c=r.substring(8),[4,l.ZP.checkFile(t.current,c)];case 1:if((o=a.sent()).exists)return[3,2];return u.m.warning("File does not exist: ".concat(c)),[3,6];case 2:if(!o.too_large)return[3,3];return s=(o.size/1024/1024).toFixed(0),d="100",u.m.warning("File is larger than download limit: ".concat(s," MB vs ").concat(d," MB")),[3,6];case 3:return[4,l.ZP.fetchFileForDownload(t.current,c)];case 4:return[4,a.sent().blob()];case 5:h=a.sent(),p=window.URL.createObjectURL(h),(b=document.createElement("a")).href=p,v=c.split("/").pop(),b.download=v,b.click(),a.label=6;case 6:return[2]}})}),function(e){return i.apply(this,arguments)}}function f(e){var n,t=e.onFileUpload,s=e.threadId,d=e.currentLeafId,f=e.modelBackend,h=e.disabled,p=e.children,b=(0,c.useState)(!1),v=b[0],k=b[1],g=(0,c.useCallback)((n=(0,r.Z)(function(e){var n,r,i;return(0,a.__generator)(this,function(a){switch(a.label){case 0:k(!0),a.label=1;case 1:if(a.trys.push([1,,3,4]),e.size>104857600)return n=(e.size/1024/1024).toFixed(0),r="100",u.m.warning("File is larger than upload limit: ".concat(n," MB vs ").concat(r," MB"),{hasCloseButton:!0,duration:15}),[2];return[4,l.ZP.upload(d,s,f,e)];case 2:return t(a.sent()),[3,4];case 3:return k(!1),[7];case 4:return[2]}})}),function(e){return n.apply(this,arguments)}),[t,s,d,f]);return h||v?p(v):(0,i.jsx)(o,{onFilePicked:g,children:p(v)})}}}]); -------------------------------------------------------------------------------- /API/pandora/src/pandora/cloud_launcher.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import argparse 4 | 5 | from loguru import logger 6 | 7 | from . import __version__ 8 | from .exts import sentry 9 | from .exts.hooks import hook_except_handle 10 | from .openai.utils import Console 11 | 12 | __show_verbose = False 13 | 14 | 15 | def main(): 16 | global __show_verbose 17 | 18 | Console.debug_b( 19 | ''' 20 | Pandora-Cloud - A web interface to ChatGPT 21 | Github: https://github.com/pengzhile/pandora 22 | Version: {}, Mode: cloud, Engine: free 23 | '''.format(__version__) 24 | ) 25 | 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument( 28 | '-p', 29 | '--proxy', 30 | help='Use a proxy. Format: protocol://user:pass@ip:port', 31 | required=False, 32 | type=str, 33 | default=None, 34 | ) 35 | parser.add_argument( 36 | '-s', 37 | '--server', 38 | help='Specific server bind. Format: ip:port, default: 127.0.0.1:8018', 39 | required=False, 40 | type=str, 41 | default='127.0.0.1:8018', 42 | ) 43 | parser.add_argument( 44 | '--threads', 45 | help='Define the number of server workers, default: 4', 46 | required=False, 47 | type=int, 48 | default=4, 49 | ) 50 | parser.add_argument( 51 | '--sentry', 52 | help='Enable sentry to send error reports when errors occur.', 53 | action='store_true', 54 | ) 55 | parser.add_argument( 56 | '-v', 57 | '--verbose', 58 | help='Show exception traceback.', 59 | action='store_true', 60 | ) 61 | args, _ = parser.parse_known_args() 62 | __show_verbose = args.verbose 63 | 64 | if args.sentry: 65 | sentry.init(args.proxy) 66 | 67 | try: 68 | from pandora_cloud.server import ChatBot as CloudServer 69 | 70 | return CloudServer(args.proxy, args.verbose, args.sentry, True).run(args.server, args.threads) 71 | except (ImportError, ModuleNotFoundError): 72 | Console.error_bh('### You need `pip install Pandora-ChatGPT[cloud]` to support cloud mode.') 73 | 74 | 75 | def run(): 76 | hook_except_handle() 77 | 78 | try: 79 | main() 80 | except Exception as e: 81 | Console.error_bh('### Error occurred: ' + str(e)) 82 | 83 | if __show_verbose: 84 | logger.exception('Exception occurred.') 85 | 86 | sentry.capture(e) 87 | -------------------------------------------------------------------------------- /API/pandora/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | #Usually these files are written by a python script from a template 32 | #before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | # Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # JetBrains IDEs configuration 132 | .idea/ 133 | 134 | # macOS 135 | .DS_Store 136 | -------------------------------------------------------------------------------- /API/pandora/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from setuptools import setup, find_packages 4 | 5 | from src.pandora import __version__ 6 | 7 | with open('README.md', 'r', encoding='utf-8') as f: 8 | long_description = f.read() 9 | 10 | with open('requirements.txt', 'r', encoding='utf-8') as f: 11 | requirements = f.read().split('\n') 12 | 13 | with open('requirements_api.txt', 'r', encoding='utf-8') as f: 14 | requirements_api = f.read().split('\n') 15 | 16 | setup( 17 | name='Pandora-ChatGPT', 18 | version=__version__, 19 | python_requires='>=3.7', 20 | author='Neo Peng', 21 | author_email='pengzhile@gmail.com', 22 | keywords='OpenAI ChatGPT ChatGPT-Plus gpt-3.5-turbo gpt-3.5-turbo-0301', 23 | description='A command-line interface to ChatGPT', 24 | long_description=long_description, 25 | long_description_content_type='text/markdown', 26 | url='https://github.com/pengzhile/pandora', 27 | packages=find_packages('src'), 28 | package_dir={'pandora': 'src/pandora'}, 29 | include_package_data=True, 30 | install_requires=requirements, 31 | extras_require={ 32 | 'api': requirements_api, 33 | 'cloud': ['pandora-cloud~=0.3.2'], 34 | }, 35 | entry_points={ 36 | 'console_scripts': [ 37 | 'pandora = pandora.launcher:run', 38 | 'pandora-cloud = pandora.cloud_launcher:run', 39 | ] 40 | }, 41 | project_urls={ 42 | 'Source': 'https://github.com/pengzhile/pandora', 43 | 'Tracker': 'https://github.com/pengzhile/pandora/issues', 44 | }, 45 | classifiers=[ 46 | 'Development Status :: 5 - Production/Stable', 47 | 48 | 'Environment :: Console', 49 | 'Environment :: Web Environment', 50 | 51 | 'Framework :: Flask', 52 | 53 | 'Intended Audience :: Developers', 54 | 'Intended Audience :: End Users/Desktop', 55 | 56 | 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', 57 | 58 | 'Natural Language :: English', 59 | 'Natural Language :: Chinese (Simplified)', 60 | 61 | 'Operating System :: MacOS', 62 | 'Operating System :: Microsoft :: Windows', 63 | 'Operating System :: POSIX :: Linux', 64 | 65 | 'Programming Language :: SQL', 66 | 'Programming Language :: JavaScript', 67 | 'Programming Language :: Python :: 3.7', 68 | 'Programming Language :: Python :: 3.8', 69 | 'Programming Language :: Python :: 3.9', 70 | 'Programming Language :: Python :: 3.10', 71 | 'Programming Language :: Python :: 3.11', 72 | 73 | 'Topic :: Communications :: Chat', 74 | 'Topic :: Internet :: WWW/HTTP', 75 | ], 76 | ) 77 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/internal/chatgpt/request.go: -------------------------------------------------------------------------------- 1 | package chatgpt 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "encoding/json" 7 | "math/rand" 8 | "os" 9 | "strings" 10 | 11 | http "github.com/bogdanfinn/fhttp" 12 | tls_client "github.com/bogdanfinn/tls-client" 13 | ) 14 | 15 | var proxies []string 16 | 17 | var ( 18 | jar = tls_client.NewCookieJar() 19 | options = []tls_client.HttpClientOption{ 20 | tls_client.WithTimeoutSeconds(360), 21 | tls_client.WithClientProfile(tls_client.Firefox_110), 22 | tls_client.WithNotFollowRedirects(), 23 | tls_client.WithCookieJar(jar), // create cookieJar instance and pass it as argument 24 | // Disable SSL verification 25 | tls_client.WithInsecureSkipVerify(), 26 | } 27 | client, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) 28 | http_proxy = os.Getenv("http_proxy") 29 | API_REVERSE_PROXY = os.Getenv("API_REVERSE_PROXY") 30 | ) 31 | 32 | func init() { 33 | // Check for proxies.txt 34 | if _, err := os.Stat("proxies.txt"); err == nil { 35 | // Each line is a proxy, put in proxies array 36 | file, _ := os.Open("proxies.txt") 37 | defer file.Close() 38 | scanner := bufio.NewScanner(file) 39 | for scanner.Scan() { 40 | // Split line by : 41 | proxy := scanner.Text() 42 | proxy_parts := strings.Split(proxy, ":") 43 | if len(proxy_parts) == 2 { 44 | proxy = "socks5://" + proxy 45 | } else if len(proxy_parts) == 4 { 46 | proxy = "socks5://" + proxy_parts[2] + ":" + proxy_parts[3] + "@" + proxy_parts[0] + ":" + proxy_parts[1] 47 | } else { 48 | continue 49 | } 50 | proxies = append(proxies, proxy) 51 | } 52 | } 53 | } 54 | 55 | func random_int(min int, max int) int { 56 | return min + rand.Intn(max-min) 57 | } 58 | 59 | func SendRequest(message ChatGPTRequest, access_token string) (*http.Response, error) { 60 | if http_proxy != "" && len(proxies) == 0 { 61 | client.SetProxy(http_proxy) 62 | } 63 | // Take random proxy from proxies.txt 64 | if len(proxies) > 0 { 65 | client.SetProxy(proxies[random_int(0, len(proxies))]) 66 | } 67 | 68 | apiUrl := "https://chat.openai.com/backend-api/conversation" 69 | if API_REVERSE_PROXY != "" { 70 | apiUrl = API_REVERSE_PROXY 71 | } 72 | 73 | // JSONify the body and add it to the request 74 | body_json, err := json.Marshal(message) 75 | if err != nil { 76 | return &http.Response{}, err 77 | } 78 | 79 | request, err := http.NewRequest(http.MethodPost, apiUrl, bytes.NewBuffer(body_json)) 80 | if err != nil { 81 | return &http.Response{}, err 82 | } 83 | // Clear cookies 84 | if os.Getenv("PUID") != "" { 85 | request.Header.Set("Cookie", "_puid="+os.Getenv("PUID")+";") 86 | } 87 | request.Header.Set("Content-Type", "application/json") 88 | 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") 89 | request.Header.Set("Accept", "*/*") 90 | if access_token != "" { 91 | request.Header.Set("Authorization", "Bearer "+access_token) 92 | } 93 | if err != nil { 94 | return &http.Response{}, err 95 | } 96 | response, err := client.Do(request) 97 | return response, err 98 | } 99 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/chunks/554.9b8bfd0762461d74.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[554],{76554:function(t,e,n){n.r(e),n.d(e,{getLocalhostPluginHttpApiCallData:function(){return l},makeLocalhostPluginHttpApiCall:function(){return c}});var r=n(61706),a=n(31501),o=n(45813),s=n(8844),i=n(68619);function l(t){var e,n=null===(e=t.metadata)||void 0===e?void 0:e.http_api_call_data;if(void 0!==n){if(t.author.role!==i.uU.Assistant){console.error("Refusing to make localhost plugin HTTP call from non-assistant message",t);return}if("object"!=typeof n||"string"!=typeof n.namespace||0===n.namespace.length||"string"!=typeof n.function_name||0===n.function_name.length||"string"!=typeof n.parent_message_id||0===n.parent_message_id.length||"string"!=typeof n.url||0===n.url.length||"string"!=typeof n.method||!["get","post","put","delete","patch"].includes(n.method)||!Array.isArray(n.qs_params)||n.qs_params.some(function(t){return!Array.isArray(t)||2!==t.length||"string"!=typeof t[0]||"string"!=typeof t[1]})||"object"!=typeof n.headers||Object.keys(n.headers).some(function(t){return"string"!=typeof t})||Object.values(n.headers).some(function(t){return"string"!=typeof t})||!(null===n.body||"object"==typeof n.body&&Object.keys(n.body).every(function(t){return"string"==typeof t}))||"string"!=typeof n.api_function_type||!["kwargs","chat"].includes(n.api_function_type)){console.error("Refusing to make localhost plugin HTTP call with invalid metadata",t);return}if(!/^https?:\/\/localhost:/.test(n.url)){console.error("Refusing to make localhost plugin HTTP call with non-localhost URL",t);return}return n}}function c(t){return u.apply(this,arguments)}function u(){return(u=(0,r.Z)(function(t){var e,n;return(0,o.__generator)(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,function(t){return p.apply(this,arguments)}(t)];case 1:return[2,n.sent()];case 2:return e=n.sent(),console.error("Error making localhost plugin HTTP call",e),[2,[{id:(0,s.Z)(),author:{role:i.uU.System},role:i.uU.Tool,content:{content_type:"text",parts:["Error making localhost plugin HTTP call: ".concat(e)]},metadata:{parent_message_id:t.parent_message_id,is_complete:!0}}]];case 3:return[2]}})})).apply(this,arguments)}function p(){return(p=(0,r.Z)(function(t){var e,n,r,l,c,u;function p(t){return Object.keys(t).map(function(t){return t.toLowerCase()})}return(0,o.__generator)(this,function(o){switch(o.label){case 0:var l,u;if(e={"content-type":"application/json"},u=(l=[p(t.headers),p(e)]).flat(),new Set(u).size!==u.length)throw Error("Refusing to make localhost plugin HTTP call with duplicate header keys");return n=t.url,t.qs_params.length>0&&(n=n+"?"+new URLSearchParams(t.qs_params)),r=void 0,null!==t.body&&(r=JSON.stringify(t.body)),[4,fetch(n,{method:t.method,headers:(0,a.Z)({},e,t.headers),body:r})];case 1:return[4,o.sent().text()];case 2:if(c=o.sent(),"chat"===t.api_function_type)return[2,[JSON.parse(c)]];if("kwargs"===t.api_function_type)return[2,[{id:(0,s.Z)(),author:{role:i.uU.Tool,name:"".concat(t.namespace,".").concat(t.function_name)},role:i.uU.Tool,content:{content_type:"text",parts:[c]},metadata:{parent_message_id:t.parent_message_id,is_complete:!0}}]];throw Error("Not implemented")}})})).apply(this,arguments)}}}]); -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/common.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | //goland:noinspection GoSnakeCaseUsage 4 | import ( 5 | "bufio" 6 | "os" 7 | "strings" 8 | 9 | "github.com/gin-gonic/gin" 10 | _ "github.com/linweiyuan/go-chatgpt-api/env" 11 | 12 | http "github.com/bogdanfinn/fhttp" 13 | tls_client "github.com/bogdanfinn/tls-client" 14 | ) 15 | 16 | const ( 17 | defaultErrorMessageKey = "errorMessage" 18 | AuthorizationHeader = "Authorization" 19 | ContentType = "application/x-www-form-urlencoded" 20 | UserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36" 21 | Auth0Url = "https://auth0.openai.com" 22 | LoginUsernameUrl = Auth0Url + "/u/login/identifier?state=" 23 | LoginPasswordUrl = Auth0Url + "/u/login/password?state=" 24 | ParseUserInfoErrorMessage = "Failed to parse user login info." 25 | GetAuthorizedUrlErrorMessage = "Failed to get authorized url." 26 | GetStateErrorMessage = "Failed to get state." 27 | EmailInvalidErrorMessage = "Email is not valid." 28 | EmailOrPasswordInvalidErrorMessage = "Email or password is not correct." 29 | GetAccessTokenErrorMessage = "Failed to get access token." 30 | defaultTimeoutSeconds = 300 // 5 minutes 31 | ) 32 | 33 | var Client tls_client.HttpClient 34 | 35 | type LoginInfo struct { 36 | Username string `json:"username"` 37 | Password string `json:"password"` 38 | } 39 | 40 | type AuthLogin interface { 41 | GetAuthorizedUrl(csrfToken string) (string, int, error) 42 | GetState(authorizedUrl string) (string, int, error) 43 | CheckUsername(state string, username string) (int, error) 44 | CheckPassword(state string, username string, password string) (string, int, error) 45 | GetAccessToken(code string) (string, int, error) 46 | } 47 | 48 | //goland:noinspection GoUnhandledErrorResult 49 | func init() { 50 | Client, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), []tls_client.HttpClientOption{ 51 | tls_client.WithCookieJar(tls_client.NewCookieJar()), 52 | tls_client.WithTimeoutSeconds(defaultTimeoutSeconds), 53 | }...) 54 | } 55 | 56 | func ReturnMessage(msg string) gin.H { 57 | return gin.H{ 58 | defaultErrorMessageKey: msg, 59 | } 60 | } 61 | 62 | func GetAccessToken(accessToken string) string { 63 | if !strings.HasPrefix(accessToken, "Bearer") { 64 | return "Bearer " + accessToken 65 | } 66 | return accessToken 67 | } 68 | 69 | //goland:noinspection GoUnhandledErrorResult 70 | func HandleConversationResponse(c *gin.Context, resp *http.Response) { 71 | reader := bufio.NewReader(resp.Body) 72 | for { 73 | if c.Request.Context().Err() != nil { 74 | break 75 | } 76 | 77 | line, err := reader.ReadString('\n') 78 | if err != nil { 79 | break 80 | } 81 | 82 | line = strings.TrimSpace(line) 83 | if strings.HasPrefix(line, "event") || 84 | strings.HasPrefix(line, "data: 20") || 85 | line == "" { 86 | continue 87 | } 88 | 89 | c.Writer.Write([]byte(line + "\n\n")) 90 | c.Writer.Flush() 91 | } 92 | } 93 | 94 | //goland:noinspection GoUnhandledErrorResult 95 | func NewHttpClient() tls_client.HttpClient { 96 | client, _ := tls_client.NewHttpClient(tls_client.NewNoopLogger(), []tls_client.HttpClientOption{ 97 | tls_client.WithCookieJar(tls_client.NewCookieJar()), 98 | }...) 99 | 100 | proxyUrl := os.Getenv("GO_CHATGPT_API_PROXY") 101 | if proxyUrl != "" { 102 | client.SetProxy(proxyUrl) 103 | } 104 | 105 | return client 106 | } 107 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | "strings" 8 | 9 | "github.com/gin-gonic/gin" 10 | "github.com/linweiyuan/go-chatgpt-api/api/chatgpt" 11 | "github.com/linweiyuan/go-chatgpt-api/api/platform" 12 | _ "github.com/linweiyuan/go-chatgpt-api/env" 13 | "github.com/linweiyuan/go-chatgpt-api/middleware" 14 | ) 15 | 16 | func init() { 17 | gin.ForceConsoleColor() 18 | gin.SetMode(gin.ReleaseMode) 19 | } 20 | 21 | func main() { 22 | router := gin.Default() 23 | router.Use(middleware.CORSMiddleware()) 24 | router.Use(middleware.CheckHeaderMiddleware()) 25 | 26 | setupChatGPTAPIs(router) 27 | 28 | setupPlatformAPIs(router) 29 | 30 | router.NoRoute(handleFallbackRoute) 31 | 32 | port := os.Getenv("GO_CHATGPT_API_PORT") 33 | if port == "" { 34 | port = "8080" 35 | } 36 | err := router.Run(":" + port) 37 | if err != nil { 38 | log.Fatal("Failed to start server: " + err.Error()) 39 | } 40 | } 41 | 42 | func setupChatGPTAPIs(router *gin.Engine) { 43 | chatgptGroup := router.Group("/chatgpt") 44 | { 45 | chatgptGroup.POST("/login", chatgpt.Login) 46 | 47 | conversationsGroup := chatgptGroup.Group("/conversations") 48 | { 49 | conversationsGroup.GET("", chatgpt.GetConversations) 50 | 51 | // PATCH is official method, POST is added for Java support 52 | conversationsGroup.PATCH("", chatgpt.ClearConversations) 53 | conversationsGroup.POST("", chatgpt.ClearConversations) 54 | } 55 | 56 | conversationGroup := chatgptGroup.Group("/conversation") 57 | { 58 | conversationGroup.POST("", chatgpt.CreateConversation) 59 | conversationGroup.POST("/gen_title/:id", chatgpt.GenerateTitle) 60 | conversationGroup.GET("/:id", chatgpt.GetConversation) 61 | 62 | // rename or delete conversation use a same API with different parameters 63 | conversationGroup.PATCH("/:id", chatgpt.UpdateConversation) 64 | conversationGroup.POST("/:id", chatgpt.UpdateConversation) 65 | 66 | conversationGroup.POST("/message_feedback", chatgpt.FeedbackMessage) 67 | } 68 | 69 | // misc 70 | chatgptGroup.GET("/models", chatgpt.GetModels) 71 | chatgptGroup.GET("/accounts/check", chatgpt.GetAccountCheck) 72 | } 73 | } 74 | 75 | func setupPlatformAPIs(router *gin.Engine) { 76 | platformGroup := router.Group("/platform") 77 | { 78 | platformGroup.POST("/login", platform.Login) 79 | 80 | apiGroup := platformGroup.Group("/v1") 81 | { 82 | apiGroup.GET("/models", platform.ListModels) 83 | apiGroup.GET("/models/:model", platform.RetrieveModel) 84 | apiGroup.POST("/completions", platform.CreateCompletions) 85 | apiGroup.POST("/chat/completions", platform.CreateChatCompletions) 86 | apiGroup.POST("/edits", platform.CreateEdit) 87 | apiGroup.POST("/images/generations", platform.CreateImage) 88 | apiGroup.POST("/embeddings", platform.CreateEmbeddings) 89 | apiGroup.GET("/files", platform.ListFiles) 90 | } 91 | 92 | dashboardGroup := platformGroup.Group("/dashboard") 93 | { 94 | billingGroup := dashboardGroup.Group("/billing") 95 | { 96 | billingGroup.GET("/credit_grants", platform.GetCreditGrants) 97 | billingGroup.GET("/subscription", platform.GetSubscription) 98 | } 99 | 100 | userGroup := dashboardGroup.Group("/user") 101 | { 102 | userGroup.GET("/api_keys", platform.GetApiKeys) 103 | } 104 | } 105 | } 106 | } 107 | 108 | func handleFallbackRoute(c *gin.Context) { 109 | path := c.Request.URL.Path 110 | 111 | if strings.HasPrefix(path, "/chatgpt") { 112 | trimmedPath := strings.TrimPrefix(path, "/chatgpt") 113 | c.Request.URL.Path = trimmedPath 114 | chatgpt.Fallback(c) 115 | } else { 116 | c.JSON(http.StatusNotFound, gin.H{"message": "Route not found"}) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/platform/typings.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | //goland:noinspection GoSnakeCaseUsage 4 | import tls_client "github.com/bogdanfinn/tls-client" 5 | 6 | type UserLogin struct { 7 | client tls_client.HttpClient 8 | } 9 | 10 | type GetAccessTokenRequest struct { 11 | ClientID string `json:"client_id"` 12 | GrantType string `json:"grant_type"` 13 | Code string `json:"code"` 14 | RedirectURI string `json:"redirect_uri"` 15 | } 16 | 17 | type GetAccessTokenResponse struct { 18 | AccessToken string `json:"access_token"` 19 | RefreshToken string `json:"refresh_token"` 20 | IDToken string `json:"id_token"` 21 | Scope string `json:"scope"` 22 | ExpiresIn int `json:"expires_in"` 23 | TokenType string `json:"token_type"` 24 | } 25 | 26 | //goland:noinspection SpellCheckingInspection 27 | type CreateCompletionsRequest struct { 28 | Model string `json:"model"` 29 | Prompt string `json:"prompt,omitempty"` 30 | Suffix string `json:"suffix,omitempty"` 31 | MaxTokens int `json:"max_tokens,omitempty"` 32 | Temperature int `json:"temperature,omitempty"` 33 | TopP int `json:"top_p,omitempty"` 34 | N int `json:"n,omitempty"` 35 | Stream bool `json:"stream,omitempty"` 36 | Logprobs int `json:"logprobs,omitempty"` 37 | Echo bool `json:"echo,omitempty"` 38 | Stop string `json:"stop,omitempty"` 39 | PresencePenalty int `json:"presence_penalty,omitempty"` 40 | FrequencyPenalty int `json:"frequency_penalty,omitempty"` 41 | BestOf int `json:"best_of,omitempty"` 42 | LogitBias map[string]interface{} `json:"logit_bias,omitempty"` 43 | User string `json:"user,omitempty"` 44 | } 45 | 46 | type ChatCompletionsRequest struct { 47 | Model string `json:"model"` 48 | Messages []ChatCompletionsMessage `json:"messages"` 49 | Temperature int `json:"temperature,omitempty"` 50 | TopP int `json:"top_p,omitempty"` 51 | N int `json:"n,omitempty"` 52 | Stream bool `json:"stream,omitempty"` 53 | Stop string `json:"stop,omitempty"` 54 | MaxTokens int `json:"max_tokens,omitempty"` 55 | PresencePenalty int `json:"presence_penalty,omitempty"` 56 | FrequencyPenalty int `json:"frequency_penalty,omitempty"` 57 | LogitBias map[string]interface{} `json:"logit_bias,omitempty"` 58 | User string `json:"user,omitempty"` 59 | } 60 | 61 | type ChatCompletionsMessage struct { 62 | Role string `json:"role"` 63 | Content string `json:"content"` 64 | Name string `json:"name,omitempty"` 65 | } 66 | 67 | type CreateEditRequest struct { 68 | Model string `json:"model"` 69 | Input string `json:"input"` 70 | Instruction string `json:"instruction"` 71 | N int `json:"n,omitempty"` 72 | Temperature int `json:"temperature,omitempty"` 73 | TopP int `json:"top_p,omitempty"` 74 | } 75 | 76 | type CreateImageRequest struct { 77 | Prompt string `json:"prompt"` 78 | N int `json:"n,omitempty"` 79 | Size string `json:"size,omitempty"` 80 | ResponseFormat string `json:"response_format,omitempty"` 81 | User string `json:"user,omitempty"` 82 | } 83 | 84 | type CreateEmbeddingsRequest struct { 85 | Model string `json:"model"` 86 | Input string `json:"input"` 87 | User string `json:"user,omitempty"` 88 | } 89 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/flask/static/_next/static/chunks/webpack-c9a868e8e0796ec6.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var e,t,r,n,o,i,u,c={},a={};function d(e){var t=a[e];if(void 0!==t)return t.exports;var r=a[e]={id:e,loaded:!1,exports:{}},n=!0;try{c[e].call(r.exports,r,r.exports,d),n=!1}finally{n&&delete a[e]}return r.loaded=!0,r.exports}d.m=c,d.amdD=function(){throw Error("define cannot be used indirect")},d.amdO={},e=[],d.O=function(t,r,n,o){if(r){o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[r,n,o];return}for(var u=1/0,i=0;i=o&&Object.keys(d.O).every(function(e){return d.O[e](r[a])})?r.splice(a--,1):(c=!1,o { 2 | event.respondWith(handleRequest(event.request)) 3 | }) 4 | // More: https://www.blueskyxn.com/202408/7089.html 5 | async function handleRequest(request) { 6 | try { 7 | // 解析请求体 8 | const requestData = await request.json() 9 | const messages = requestData.messages || [] 10 | 11 | // 构建要发送到 talkx API 的请求体 12 | const talkxPayload = { 13 | roleType: '0', 14 | productId: 0, 15 | sessionId: generateUUID(), 16 | messages: messages.map(msg => ({ 17 | role: msg.role, 18 | content: msg.content 19 | })) 20 | } 21 | 22 | // 向 talkx API 发送请求 23 | const talkxResponse = await fetch('https://api.talkx.cn/gpt/chat', { 24 | method: 'POST', 25 | headers: { 26 | 'accept': '*/*', 27 | 'accept-language': 'zh-CN,zh;q=0.9', 28 | 'content-type': 'application/json;charset=utf-8', 29 | 'origin': 'https://web.talkx.cn', 30 | 'referer': 'https://web.talkx.cn/', 31 | 'sec-ch-ua': '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"', 32 | 'sec-ch-ua-mobile': '?0', 33 | 'sec-ch-ua-platform': '"Windows"', 34 | 'sec-fetch-dest': 'empty', 35 | 'sec-fetch-mode': 'cors', 36 | 'sec-fetch-site': 'same-site', 37 | 'talkx-token': '', 38 | 'user-agent': generateUserAgent(), 39 | }, 40 | body: JSON.stringify(talkxPayload) 41 | }) 42 | 43 | // 处理 talkx API 的响应 44 | const contentType = talkxResponse.headers.get('Content-Type') || '' 45 | let talkxData 46 | 47 | if (contentType.includes('application/json')) { 48 | talkxData = await talkxResponse.json() 49 | } else { 50 | const textResponse = await talkxResponse.text() 51 | talkxData = { 52 | choices: [ 53 | { 54 | message: { 55 | role: 'assistant', 56 | content: textResponse 57 | } 58 | } 59 | ] 60 | } 61 | } 62 | 63 | // 构建 OpenAI 标准格式的响应 64 | const openaiResponse = { 65 | id: generateUUID(), 66 | object: 'chat.completion', 67 | created: Math.floor(Date.now() / 1000), 68 | model: 'gpt-3.5-turbo', 69 | choices: talkxData.choices || [], 70 | usage: { 71 | prompt_tokens: messages.length, 72 | completion_tokens: talkxData.choices.length, 73 | total_tokens: messages.length + talkxData.choices.length 74 | } 75 | } 76 | 77 | // 返回响应 78 | return new Response(JSON.stringify(openaiResponse), { 79 | headers: { 'Content-Type': 'application/json' } 80 | }) 81 | 82 | } catch (error) { 83 | return new Response(JSON.stringify({ error: 'Internal Server Error' }), { 84 | status: 500, 85 | headers: { 'Content-Type': 'application/json' } 86 | }) 87 | } 88 | } 89 | 90 | // 生成随机 UUID 91 | function generateUUID() { 92 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 93 | const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8) 94 | return v.toString(16) 95 | }) 96 | } 97 | 98 | // 生成随机 User-Agent 99 | function generateUserAgent() { 100 | const osList = [ 101 | 'Windows NT 10.0; Win64; x64', 102 | 'Macintosh; Intel Mac OS X 10_15_7', 103 | 'X11; Linux x86_64' 104 | ] 105 | 106 | const browserList = [ 107 | `Chrome/${getRandomInt(90, 122)}.${getRandomInt(0, 9)}.${getRandomInt(0, 99)}.${getRandomInt(0, 99)}`, 108 | `Firefox/${getRandomInt(90, 122)}.${getRandomInt(0, 9)}.${getRandomInt(0, 99)}`, 109 | `Safari/605.1.15` 110 | ] 111 | 112 | const os = osList[Math.floor(Math.random() * osList.length)] 113 | const browser = browserList[Math.floor(Math.random() * browserList.length)] 114 | 115 | return `Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) ${browser} Safari/537.36` 116 | } 117 | 118 | // 生成随机整数 119 | function getRandomInt(min, max) { 120 | min = Math.ceil(min) 121 | max = Math.floor(max) 122 | return Math.floor(Math.random() * (max - min + 1)) + min 123 | } 124 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/platform/access_token.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "net/url" 9 | "strings" 10 | 11 | "github.com/linweiyuan/go-chatgpt-api/api" 12 | 13 | http "github.com/bogdanfinn/fhttp" 14 | ) 15 | 16 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat,GoUnusedParameter 17 | func (userLogin *UserLogin) GetAuthorizedUrl(csrfToken string) (string, int, error) { 18 | urlParams := url.Values{ 19 | "client_id": {platformAuthClientID}, 20 | "audience": {platformAuthAudience}, 21 | "redirect_uri": {platformAuthRedirectURL}, 22 | "scope": {platformAuthScope}, 23 | "response_type": {platformAuthResponseType}, 24 | } 25 | req, _ := http.NewRequest(http.MethodGet, platformAuth0Url+urlParams.Encode(), nil) 26 | req.Header.Set("Content-Type", api.ContentType) 27 | req.Header.Set("User-Agent", api.UserAgent) 28 | resp, err := userLogin.client.Do(req) 29 | if err != nil { 30 | return "", http.StatusInternalServerError, err 31 | } 32 | 33 | defer resp.Body.Close() 34 | if resp.StatusCode != http.StatusOK { 35 | return "", resp.StatusCode, errors.New(api.GetAuthorizedUrlErrorMessage) 36 | } 37 | 38 | return resp.Request.URL.String(), http.StatusOK, nil 39 | } 40 | 41 | func (userLogin *UserLogin) GetState(authorizedUrl string) (string, int, error) { 42 | split := strings.Split(authorizedUrl, "=") 43 | return split[1], http.StatusOK, nil 44 | } 45 | 46 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat 47 | func (userLogin *UserLogin) CheckUsername(state string, username string) (int, error) { 48 | formParams := fmt.Sprintf( 49 | "state=%s&username=%s&js-available=true&webauthn-available=true&is-brave=false&webauthn-platform-available=false&action=default", 50 | state, 51 | username, 52 | ) 53 | req, err := http.NewRequest(http.MethodPost, api.LoginUsernameUrl+state, strings.NewReader(formParams)) 54 | req.Header.Set("Content-Type", api.ContentType) 55 | req.Header.Set("User-Agent", api.UserAgent) 56 | resp, err := userLogin.client.Do(req) 57 | if err != nil { 58 | return http.StatusInternalServerError, err 59 | } 60 | 61 | defer resp.Body.Close() 62 | if resp.StatusCode != http.StatusOK { 63 | return resp.StatusCode, errors.New(api.EmailInvalidErrorMessage) 64 | } 65 | 66 | return http.StatusOK, nil 67 | } 68 | 69 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat 70 | func (userLogin *UserLogin) CheckPassword(state string, username string, password string) (string, int, error) { 71 | formParams := fmt.Sprintf( 72 | "state=%s&username=%s&password=%s&action=default", 73 | state, 74 | username, 75 | password, 76 | ) 77 | req, err := http.NewRequest(http.MethodPost, api.LoginPasswordUrl+state, strings.NewReader(formParams)) 78 | req.Header.Set("Content-Type", api.ContentType) 79 | req.Header.Set("User-Agent", api.UserAgent) 80 | resp, err := userLogin.client.Do(req) 81 | if err != nil { 82 | return "", http.StatusInternalServerError, err 83 | } 84 | 85 | defer resp.Body.Close() 86 | if resp.StatusCode != http.StatusOK { 87 | return "", resp.StatusCode, errors.New(api.EmailOrPasswordInvalidErrorMessage) 88 | } 89 | 90 | return resp.Request.URL.Query().Get("code"), http.StatusOK, nil 91 | } 92 | 93 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat 94 | func (userLogin *UserLogin) GetAccessToken(code string) (string, int, error) { 95 | jsonBytes, _ := json.Marshal(GetAccessTokenRequest{ 96 | ClientID: platformAuthClientID, 97 | Code: code, 98 | GrantType: platformAuthGrantType, 99 | RedirectURI: platformAuthRedirectURL, 100 | }) 101 | req, err := http.NewRequest(http.MethodPost, getTokenUrl, strings.NewReader(string(jsonBytes))) 102 | req.Header.Set("Content-Type", "application/json") 103 | req.Header.Set("User-Agent", api.UserAgent) 104 | resp, err := userLogin.client.Do(req) 105 | if err != nil { 106 | return "", http.StatusInternalServerError, err 107 | } 108 | 109 | defer resp.Body.Close() 110 | if resp.StatusCode != http.StatusOK { 111 | return "", resp.StatusCode, errors.New(api.GetAccessTokenErrorMessage) 112 | } 113 | 114 | data, _ := io.ReadAll(resp.Body) 115 | return string(data), http.StatusOK, nil 116 | } 117 | -------------------------------------------------------------------------------- /API/cerebras2api/cerebras2api.py: -------------------------------------------------------------------------------- 1 | import random 2 | import json 3 | import aiohttp 4 | import asyncio 5 | from aiohttp import web 6 | from datetime import datetime 7 | 8 | # More: https://www.blueskyxn.com/202408/7089.html 9 | # llama3.1-8b、llama3.1-70b 10 | # 调试信息开关 11 | DEBUG_MODE = False # 设置为 True 可以打印详细的调试信息 12 | 13 | # 定义固定的模型信息 14 | DEFAULT_MODEL = "llama3.1-8b" 15 | ALTERNATE_MODEL = "llama3.1-70b" 16 | FIXED_URL = "https://api.cerebras.ai/v1/chat/completions" 17 | FIXED_TEMPERATURE = 0.2 18 | FIXED_TOP_P = 1 19 | FIXED_MAX_TOKENS = 4096 20 | 21 | # 记录基本信息的日志函数 22 | def log_basic_info(message): 23 | timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 24 | print(f"[{timestamp}] {message}") 25 | 26 | # 异步发送请求并打印调试信息 27 | async def send_request(auth_tokens, data): 28 | try: 29 | headers = { 30 | "accept": "application/json", 31 | "authorization": f"Bearer {auth_tokens[0]}", 32 | "content-type": "application/json" 33 | } 34 | 35 | # 检查传入的数据是否指定了 llama3.1-70b 模型 36 | requested_model = data.get("model", DEFAULT_MODEL) 37 | model_to_use = DEFAULT_MODEL 38 | if requested_model == ALTERNATE_MODEL: 39 | model_to_use = ALTERNATE_MODEL 40 | 41 | # 记录收到的模型请求以及实际使用的模型 42 | log_basic_info(f"Requested model: {requested_model}, Using model: {model_to_use}") 43 | 44 | # 构造请求体 45 | payload = { 46 | "messages": data.get("messages", []), 47 | "model": model_to_use, 48 | "temperature": FIXED_TEMPERATURE, 49 | "top_p": FIXED_TOP_P, 50 | "max_tokens": FIXED_MAX_TOKENS 51 | } 52 | 53 | if DEBUG_MODE: 54 | print("Request Payload:", json.dumps(payload, indent=4)) 55 | print("Request Headers:", headers) 56 | 57 | async with aiohttp.ClientSession() as session: 58 | async with session.post(FIXED_URL, headers=headers, json=payload) as resp: 59 | response_text = await resp.text() 60 | 61 | # 尝试解析响应体 62 | response_json = json.loads(response_text) 63 | 64 | # 提取total_time和total_tokens信息 65 | total_tokens = response_json.get('usage', {}).get('total_tokens', 'N/A') 66 | total_time = response_json.get('time_info', {}).get('total_time', 'N/A') 67 | 68 | # 打印所有关键信息到同一行 69 | log_basic_info(f"Path: {FIXED_URL}, Status Code: {resp.status}, Total Tokens Used: {total_tokens}, Total Time: {total_time:.3f} seconds") 70 | 71 | return response_text 72 | 73 | except Exception as e: 74 | log_basic_info(f"Exception occurred: {str(e)}") 75 | 76 | # 主函数 77 | async def handle_request(request): 78 | try: 79 | # 获取请求数据 80 | request_data = await request.json() 81 | headers = dict(request.headers) 82 | 83 | # 检查并处理 Authorization 头 84 | authorization_header = headers.get('Authorization', '') 85 | auth_tokens = [auth.strip() for auth in authorization_header.replace('Bearer ', '').split(',')] 86 | 87 | if not auth_tokens: 88 | return web.json_response({"error": "Missing Authorization token"}, status=400) 89 | 90 | # 如果有多个 auth token,随机选择一个 91 | auth_token = random.choice(auth_tokens) 92 | headers['Authorization'] = f"Bearer {auth_token}" 93 | 94 | # 打印传入请求的基本信息 95 | log_basic_info(f"Received request for path: {request.path}") 96 | 97 | if DEBUG_MODE: 98 | print("Received Request Data:", json.dumps(request_data, indent=4)) 99 | print("Received Headers:", headers) 100 | 101 | # 发送请求并获取响应 102 | response_text = await send_request(auth_tokens, request_data) 103 | 104 | # 返回最终的响应 105 | return web.json_response(json.loads(response_text)) 106 | 107 | except Exception as e: 108 | log_basic_info(f"Exception occurred in handling request: {str(e)}") 109 | return web.json_response({"error": str(e)}, status=500) 110 | 111 | # 设置路由 112 | app = web.Application() 113 | app.router.add_post('/v1/chat/completions', handle_request) 114 | 115 | # 运行服务器,监听5804端口 116 | if __name__ == '__main__': 117 | web.run_app(app, port=5804) 118 | -------------------------------------------------------------------------------- /API/pandora/README.md: -------------------------------------------------------------------------------- 1 | # Pandora 2 | 3 | 潘多拉 (Pandora),一个让你呼吸顺畅的 ChatGPT。 4 | 5 | 潘多拉实现了网页版 ChatGPT 的主要操作。后端优化,绕过 Cloudflare,速度喜人。 6 | 7 | 8 | 9 | ![Python version](https://img.shields.io/badge/python-%3E%3D3.7-green) 10 | [![Issues](https://img.shields.io/github/issues-raw/pengzhile/pandora)](https://github.com/pengzhile/pandora/issues) 11 | [![Commits](https://img.shields.io/github/last-commit/pengzhile/pandora/master)](https://github.com/pengzhile/pandora/commits/master) 12 | [![PyPi](https://img.shields.io/pypi/v/pandora-chatgpt.svg)](https://pypi.python.org/pypi/pandora-chatgpt) 13 | [![Downloads](https://static.pepy.tech/badge/pandora-chatgpt)](https://pypi.python.org/pypi/pandora-chatgpt) 14 | [![PyPi workflow](https://github.com/pengzhile/pandora/actions/workflows/python-publish.yml/badge.svg)](https://github.com/pengzhile/pandora/actions/workflows/python-publish.yml) 15 | [![Docker workflow](https://github.com/pengzhile/pandora/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/pengzhile/pandora/actions/workflows/docker-publish.yml) 16 | [![Discord](https://img.shields.io/discord/1098772912242163795?label=Discord)](https://discord.gg/QBkd9JAaWa) 17 | 18 | ## 体验地址 19 | * 点击 https://chat.zhile.io 20 | * 最新拿 `Access Token` 的技术原理,我记录在[这里](https://zhile.io/2023/05/19/how-to-get-chatgpt-access-token-via-pkce.html)了。 21 | * 可以访问 [这里](http://ai.fakeopen.com/auth) 拿 `Access Token` 22 | * 也可以官方登录,然后访问 [这里](http://chat.openai.com/api/auth/session) 拿 `Access Token` 23 | * `Access Token` 有效期 `14` 天,期间访问**不需要梯子**。这意味着你在手机上也可随意使用。 24 | * 这个页面上还包含一个共享账号的链接,**没有账号**的可以点进去体验一下。 25 | 26 | ## ChatGPT使用时可能会遇到: 27 | 28 | ### 1. Please stand by, while we are checking your browser... 29 | ###    动不动来一下,有时候还不动或者出人机验证。痛! 30 | ![t0](https://github.com/pengzhile/pandora/raw/master/doc/images/t0.png) 31 | 32 | ### 2. Access denied. Sorry, you have been blocked 33 | ###    经典问题,只能到处找可用VPN,费时费力,更费钱。移动端访问更难。痛! 34 | ![t1.1](https://github.com/pengzhile/pandora/raw/master/doc/images/t1.1.png) 35 | 36 | ### 3. ChatGPT is at capacity right now 37 | ###    系统负载高,白嫖用户不给用。痛! 38 | ![t2](https://github.com/pengzhile/pandora/raw/master/doc/images/t2.png) 39 | 40 | ### 4. This content may violate our content policy. 41 | ###    道德审查,多触发几次可能就封号了。痛!!! 42 | ![t3](https://github.com/pengzhile/pandora/raw/master/doc/images/t3.png) 43 | 44 | ### 5. Something went wrong. 45 | ###    吃着火锅唱着歌,突然就出故障了。痛! 46 | ![t4](https://github.com/pengzhile/pandora/raw/master/doc/images/t4.png) 47 | 48 | ### 6. 手机和电脑的模型不通用,顾这个就顾不到那个,痛! 49 | ![t7](https://github.com/pengzhile/pandora/raw/master/doc/images/t7.png) 50 | 51 | ### 7. 蹦字慢吞吞,卡顿不流畅,不知道的甚至想换电脑。痛! 52 | ### 8. 想把 `ChatGPT` 接到其他系统,结果只能接个差强人意的 `gpt-3.5-turbo`。痛! 53 | 54 | ### _一次看完上面的噩梦,血压上来了,拳头硬了!太痛了!!!以上痛点,`Pandora` 一次全部解决。_ 55 | 56 | ## 界面截图 57 | 58 |
59 | 60 | 61 | 62 | ![alt Screenshot5](https://github.com/pengzhile/pandora/raw/master/doc/images/s05.png)
63 | ![alt Screenshot10](https://github.com/pengzhile/pandora/raw/master/doc/images/s12.jpeg) 64 | 65 |
66 | 67 | ![alt Screenshot1](https://github.com/pengzhile/pandora/raw/master/doc/images/s01.png)
68 | ![alt Screenshot2](https://github.com/pengzhile/pandora/raw/master/doc/images/s02.png)
69 | ![alt Screenshot3](https://github.com/pengzhile/pandora/raw/master/doc/images/s03.png)
70 | ![alt Screenshot4](https://github.com/pengzhile/pandora/raw/master/doc/images/s04.png)
71 | ![alt Screenshot6](https://github.com/pengzhile/pandora/raw/master/doc/images/s06.png)
72 | ![alt Screenshot11](https://github.com/pengzhile/pandora/raw/master/doc/images/s11.jpeg) 73 | 74 |
75 | 76 | ## 如何搭建运行 77 | 78 | * 访问 [doc/wiki.md](https://github.com/pengzhile/pandora/blob/master/doc/wiki.md) 获得详细指导。 79 | 80 | ## 其他说明 81 | 82 | * `开源项目可以魔改,但请保留原作者信息。确需去除,请联系作者,以免失去技术支持。` 83 | * 项目是站在其他巨人的肩膀上,感谢! 84 | * 报错、BUG之类的提出`Issue`,我会修复。 85 | * 因为之后`ChatGPT`的API变动,我可能不会跟进修复。 86 | * 喜欢的可以给颗星,都是老朋友了。 87 | * 不影响`PHP是世界上最好的编程语言!` 88 | 89 | ## 贡献者们 90 | 91 | > 感谢所有让这个项目变得更好的贡献者们! 92 | 93 | [![Star History Chart](https://contrib.rocks/image?repo=pengzhile/pandora)](https://github.com/pengzhile/pandora/graphs/contributors) 94 | 95 | ## Star历史 96 | 97 | ![Star History Chart](https://api.star-history.com/svg?repos=pengzhile/pandora&type=Date) 98 | -------------------------------------------------------------------------------- /API/talkx2api/talkx2api.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify 2 | import uuid 3 | import requests 4 | import random 5 | import time 6 | 7 | # More: https://www.blueskyxn.com/202408/7089.html 8 | 9 | app = Flask(__name__) 10 | 11 | def generate_user_agent(): 12 | os_list = [ 13 | 'Windows NT 10.0; Win64; x64', 14 | 'Macintosh; Intel Mac OS X 10_15_7', 15 | 'X11; Linux x86_64' 16 | ] 17 | 18 | browser_list = [ 19 | ('Chrome', 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{}.{}.{}.{} Safari/537.36'), 20 | ('Firefox', 'Gecko/20100101 Firefox/{}.{}.{}'), 21 | ('Safari', 'AppleWebKit/605.1.15 (KHTML, like Gecko) Version/{}.{}.{} Safari/605.1.15'), 22 | ('Edge', 'Edge/{}.{}.{}.{}') 23 | ] 24 | 25 | os_choice = random.choice(os_list) 26 | browser_name, browser_format = random.choice(browser_list) 27 | 28 | major_version = random.randint(90, 122) 29 | minor_version = random.randint(0, 9) 30 | build_version = random.randint(0, 99) 31 | patch_version = random.randint(0, 99) 32 | 33 | if browser_name == 'Chrome': 34 | user_agent = f'Mozilla/5.0 ({os_choice}) {browser_format.format(major_version, minor_version, build_version, patch_version)}' 35 | elif browser_name == 'Firefox': 36 | user_agent = f'Mozilla/5.0 ({os_choice}; rv:{major_version}.0) {browser_format.format(major_version, minor_version, build_version)}' 37 | elif browser_name == 'Safari': 38 | user_agent = f'Mozilla/5.0 ({os_choice}) {browser_format.format(major_version, minor_version, build_version)}' 39 | else: 40 | user_agent = f'Mozilla/5.0 ({os_choice}) {browser_format.format(major_version, minor_version, build_version, patch_version)}' 41 | return user_agent 42 | 43 | def get_header(): 44 | headers = { 45 | 'accept': '*/*', 46 | 'accept-language': 'zh-CN,zh;q=0.9', 47 | 'content-type': 'application/json;charset=utf-8', 48 | 'origin': 'https://web.talkx.cn', 49 | 'referer': 'https://web.talkx.cn/', 50 | 'sec-ch-ua': '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"', 51 | 'sec-ch-ua-mobile': '?0', 52 | 'sec-ch-ua-platform': '"Windows"', 53 | 'sec-fetch-dest': 'empty', 54 | 'sec-fetch-mode': 'cors', 55 | 'sec-fetch-site': 'same-site', 56 | 'talkx-token': '', # 在这里填入有效的 token 57 | 'Accept-Charset': 'utf-8', 58 | 'user-agent': generate_user_agent(), 59 | } 60 | return headers 61 | 62 | def forward_request_to_talkx(messages): 63 | json_data = { 64 | 'roleType': '0', 65 | 'productId': 0, 66 | 'sessionId': str(uuid.uuid4()), 67 | 'messages': messages, 68 | } 69 | 70 | response = requests.post('https://api.talkx.cn/gpt/chat', headers=get_header(), json=json_data) 71 | response.encoding = 'utf-8' 72 | 73 | content_type = response.headers.get('Content-Type', '') 74 | 75 | if response.status_code == 200: 76 | if 'application/json' in content_type: 77 | return response.json() 78 | else: 79 | return {"choices": [{"message": {"role": "assistant", "content": response.text}}]} 80 | else: 81 | return {"error": "Failed to fetch response from talkx API", "status_code": response.status_code, "content": response.text} 82 | 83 | @app.route("/v1/chat/completions", methods=["POST"]) 84 | def chat_completions(): 85 | openai_request = request.json 86 | messages = [{"role": message["role"], "content": message["content"]} for message in openai_request.get("messages", [])] 87 | 88 | talkx_response = forward_request_to_talkx(messages) 89 | 90 | openai_response = { 91 | "id": str(uuid.uuid4()), 92 | "object": "chat.completion", 93 | "created": int(time.time()), 94 | "model": "gpt-3.5-turbo", 95 | "choices": talkx_response.get("choices", []), 96 | "usage": { 97 | "prompt_tokens": len(openai_request.get("messages", [])), 98 | "completion_tokens": len(talkx_response.get("choices", [])), 99 | "total_tokens": len(openai_request.get("messages", [])) + len(talkx_response.get("choices", [])) 100 | } 101 | } 102 | 103 | return jsonify(openai_response) 104 | 105 | if __name__ == "__main__": 106 | app.run(host="0.0.0.0", port=5000) 107 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/migrations/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from datetime import datetime as dt 4 | 5 | from sqlalchemy import func, Column, Text, Integer 6 | from sqlalchemy.orm import DeclarativeBase 7 | 8 | from ..migrations.database import session 9 | 10 | 11 | class Base(DeclarativeBase): 12 | pass 13 | 14 | 15 | class ConversationOfficial(Base): 16 | __tablename__ = 'conversation_official' 17 | 18 | conversation_id = Column(Text, primary_key=True, autoincrement=False) 19 | title = Column(Text, nullable=False) 20 | create_time = Column(Integer, nullable=False) 21 | 22 | @staticmethod 23 | def get_list(offset, limit): 24 | total = session.query(func.count(ConversationOfficial.conversation_id)).scalar() 25 | return total, session.query(ConversationOfficial).order_by(ConversationOfficial.create_time.desc()).limit( 26 | limit).offset(offset).all() 27 | 28 | @staticmethod 29 | def get(conversation_id): 30 | return session.query(ConversationOfficial).get(conversation_id) 31 | 32 | def save(self): 33 | session.commit() 34 | return self 35 | 36 | def new(self): 37 | session.add(self) 38 | session.commit() 39 | 40 | return self 41 | 42 | @staticmethod 43 | def delete(conversation_id): 44 | session.query(ConversationOfficial).filter(ConversationOfficial.conversation_id == conversation_id).delete() 45 | session.commit() 46 | 47 | @staticmethod 48 | def clear(): 49 | session.query(ConversationOfficial).delete() 50 | session.commit() 51 | 52 | @staticmethod 53 | def new_conversation(conversation_id, title=None): 54 | conv = ConversationOfficial.get(conversation_id) 55 | 56 | if not conv: 57 | conv = ConversationOfficial() 58 | conv.conversation_id = conversation_id 59 | conv.title = title or 'New chat' 60 | conv.create_time = dt.now().timestamp() 61 | conv.new() 62 | else: 63 | conv.title = title or 'New chat' 64 | conv.save() 65 | 66 | @staticmethod 67 | def wrap_conversation_list(offset, limit): 68 | total, items = ConversationOfficial.get_list(offset, limit) 69 | 70 | stripped = [] 71 | for item in items: 72 | stripped.append({ 73 | 'id': item.conversation_id, 74 | 'title': item.title, 75 | 'create_time': dt.utcfromtimestamp(item.create_time).isoformat(), 76 | }) 77 | 78 | return {'items': stripped, 'total': total, 'limit': limit, 'offset': offset} 79 | 80 | 81 | class ConversationInfo(Base): 82 | __tablename__ = 'conversation_info' 83 | 84 | conversation_id = Column(Text, primary_key=True, autoincrement=False) 85 | title = Column(Text, nullable=False) 86 | create_time = Column(Integer, nullable=False) 87 | current_node = Column(Text, nullable=True) 88 | 89 | @staticmethod 90 | def get_list(offset, limit): 91 | total = session.query(func.count(ConversationInfo.conversation_id)).scalar() 92 | return total, session.query(ConversationInfo).order_by(ConversationInfo.create_time.desc()).limit( 93 | limit).offset(offset).all() 94 | 95 | @staticmethod 96 | def get(conversation_id): 97 | return session.query(ConversationInfo).get(conversation_id) 98 | 99 | def new(self): 100 | session.add(self) 101 | session.commit() 102 | 103 | return self 104 | 105 | @staticmethod 106 | def delete(conversation_id): 107 | session.query(ConversationInfo).filter(ConversationInfo.conversation_id == conversation_id).delete() 108 | session.commit() 109 | 110 | @staticmethod 111 | def clear(): 112 | session.query(ConversationInfo).delete() 113 | session.commit() 114 | 115 | 116 | class PromptInfo(Base): 117 | __tablename__ = 'prompt_info' 118 | 119 | prompt_id = Column(Text, primary_key=True, autoincrement=False) 120 | conversation_id = Column(Text, primary_key=True, autoincrement=False) 121 | model = Column(Text, nullable=True) 122 | parent_id = Column(Text, nullable=True) 123 | role = Column(Text, nullable=True) 124 | content = Column(Text, nullable=True) 125 | create_time = Column(Integer, nullable=False) 126 | 127 | @staticmethod 128 | def list_by_conversation_id(conversation_id): 129 | return session.query(PromptInfo).filter(PromptInfo.conversation_id == conversation_id).all() 130 | 131 | def new(self): 132 | session.add(self) 133 | session.commit() 134 | 135 | return self 136 | 137 | @staticmethod 138 | def clear(): 139 | session.query(PromptInfo).delete() 140 | session.commit() 141 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/tools/authenticator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "strings" 9 | "time" 10 | 11 | "authenticator/auth" 12 | ) 13 | 14 | type Account struct { 15 | Email string `json:"username"` 16 | Password string `json:"password"` 17 | } 18 | type Proxy struct { 19 | IP string `json:"ip"` 20 | Port string `json:"port"` 21 | User string `json:"user"` 22 | Pass string `json:"pass"` 23 | } 24 | 25 | func (p Proxy) Socks5URL() string { 26 | // Returns proxy URL (socks5) 27 | if p.User == "" && p.Pass == "" { 28 | return fmt.Sprintf("socks5://%s:%s", p.IP, p.Port) 29 | } 30 | return fmt.Sprintf("socks5://%s:%s@%s:%s", p.User, p.Pass, p.IP, p.Port) 31 | } 32 | 33 | // Read accounts.txt and create a list of accounts 34 | func readAccounts() []Account { 35 | accounts := []Account{} 36 | // Read accounts.txt and create a list of accounts 37 | file, err := os.Open("accounts.txt") 38 | if err != nil { 39 | panic(err) 40 | } 41 | defer file.Close() 42 | // Loop through each line in the file 43 | scanner := bufio.NewScanner(file) 44 | for scanner.Scan() { 45 | // Split by : 46 | line := strings.Split(scanner.Text(), ":") 47 | // Create an account 48 | account := Account{ 49 | Email: line[0], 50 | Password: line[1], 51 | } 52 | // Append to accounts 53 | accounts = append(accounts, account) 54 | } 55 | return accounts 56 | } 57 | 58 | // Read proxies from proxies.txt and create a list of proxies 59 | func readProxies() []Proxy { 60 | proxies := []Proxy{} 61 | // Read proxies.txt and create a list of proxies 62 | file, err := os.Open("proxies.txt") 63 | if err != nil { 64 | return []Proxy{} 65 | } 66 | defer file.Close() 67 | // Loop through each line in the file 68 | scanner := bufio.NewScanner(file) 69 | for scanner.Scan() { 70 | // Split by : 71 | lines := strings.Split(scanner.Text(), ":") 72 | var proxy Proxy 73 | if len(lines) == 4 { 74 | // Create a proxy 75 | proxy = Proxy{ 76 | IP: lines[0], 77 | Port: lines[1], 78 | User: lines[2], 79 | Pass: lines[3], 80 | } 81 | } else if len(lines) == 2 { 82 | proxy = Proxy{ 83 | IP: lines[0], 84 | Port: lines[1], 85 | } 86 | } else { 87 | continue 88 | } 89 | // Append to proxies 90 | proxies = append(proxies, proxy) 91 | } 92 | return proxies 93 | } 94 | 95 | func main() { 96 | // Read accounts and proxies 97 | accounts := readAccounts() 98 | proxies := readProxies() 99 | 100 | // Loop through each account 101 | for _, account := range accounts { 102 | if os.Getenv("CF_PROXY") != "" { 103 | // exec warp-cli disconnect and connect 104 | exec.Command("warp-cli", "disconnect").Run() 105 | exec.Command("warp-cli", "connect").Run() 106 | time.Sleep(5 * time.Second) 107 | } 108 | println(account.Email) 109 | println(account.Password) 110 | var proxy_url string 111 | if len(proxies) == 0 { 112 | if os.Getenv("http_proxy") != "" { 113 | proxy_url = os.Getenv("http_proxy") 114 | } 115 | } else { 116 | proxy_url = proxies[0].Socks5URL() 117 | // Push used proxy to the back of the list 118 | proxies = append(proxies[1:], proxies[0]) 119 | } 120 | println(proxy_url) 121 | authenticator := auth.NewAuthenticator(account.Email, account.Password, proxy_url) 122 | err := authenticator.Begin() 123 | if err.Error != nil { 124 | // println("Error: " + err.Details) 125 | println("Location: " + err.Location) 126 | println("Status code: " + fmt.Sprint(err.StatusCode)) 127 | println("Details: " + err.Details) 128 | println("Embedded error: " + err.Error.Error()) 129 | return 130 | } 131 | access_token, err := authenticator.GetAccessToken() 132 | if err.Error != nil { 133 | // println("Error: " + err.Details) 134 | println("Location: " + err.Location) 135 | println("Status code: " + fmt.Sprint(err.StatusCode)) 136 | println("Details: " + err.Details) 137 | println("Embedded error: " + err.Error.Error()) 138 | return 139 | } 140 | // Append access token to access_tokens.txt 141 | f, go_err := os.OpenFile("access_tokens.txt", os.O_APPEND|os.O_WRONLY, 0600) 142 | if go_err != nil { 143 | continue 144 | } 145 | defer f.Close() 146 | if _, go_err = f.WriteString(access_token + "\n"); go_err != nil { 147 | continue 148 | } 149 | // Write authenticated account to authenticated_accounts.txt 150 | f, go_err = os.OpenFile("authenticated_accounts.txt", os.O_APPEND|os.O_WRONLY, 0600) 151 | if go_err != nil { 152 | continue 153 | } 154 | defer f.Close() 155 | if _, go_err = f.WriteString(account.Email + ":" + account.Password + "\n"); go_err != nil { 156 | continue 157 | } 158 | // Remove accounts.txt 159 | os.Remove("accounts.txt") 160 | // Create accounts.txt 161 | f, go_err = os.Create("accounts.txt") 162 | if go_err != nil { 163 | continue 164 | } 165 | defer f.Close() 166 | // Remove account from accounts 167 | accounts = accounts[1:] 168 | // Write unauthenticated accounts to accounts.txt 169 | for _, acc := range accounts { 170 | // Check if account is authenticated 171 | if acc.Email == account.Email { 172 | continue 173 | } 174 | if _, go_err = f.WriteString(acc.Email + ":" + acc.Password + "\n"); go_err != nil { 175 | continue 176 | } 177 | } 178 | 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/chatgpt/health_check.go: -------------------------------------------------------------------------------- 1 | package chatgpt 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "strings" 7 | "time" 8 | 9 | "github.com/PuerkitoBio/goquery" 10 | "github.com/linweiyuan/go-chatgpt-api/api" 11 | "github.com/linweiyuan/go-chatgpt-api/util/logger" 12 | 13 | http "github.com/bogdanfinn/fhttp" 14 | ) 15 | 16 | const ( 17 | healthCheckUrl = "https://chat.openai.com/backend-api/accounts/check" 18 | readyHint = "Service go-chatgpt-api is ready." 19 | defaultCookiesApiUrl = "https://chatgpt.linweiyuan.com/cookies" 20 | errorHint403 = "If you still hit 403, do not raise new issue (will be closed directly without comment), change to a new clean IP or use legacy version first." 21 | errorHintBlock = "You have been blocked to use cookies api because your IP is detected by Cloudflare WAF." 22 | cookieName = "__cf_bm" 23 | ) 24 | 25 | //goland:noinspection GoSnakeCaseUsage 26 | var cfbm *Cookie 27 | var firstTime = true 28 | 29 | //goland:noinspection GoUnhandledErrorResult 30 | func init() { 31 | proxyUrl := os.Getenv("GO_CHATGPT_API_PROXY") 32 | if proxyUrl != "" { 33 | logger.Info("GO_CHATGPT_API_PROXY: " + proxyUrl) 34 | api.Client.SetProxy(proxyUrl) 35 | 36 | for { 37 | resp, err := healthCheck() 38 | if err != nil { 39 | // wait for proxy to be ready 40 | time.Sleep(time.Second) 41 | continue 42 | } 43 | 44 | checkHealthCheckStatus(resp) 45 | break 46 | } 47 | } else { 48 | resp, err := healthCheck() 49 | if err != nil { 50 | logger.Error("Health check failed: " + err.Error()) 51 | os.Exit(1) 52 | } 53 | 54 | checkHealthCheckStatus(resp) 55 | } 56 | } 57 | 58 | func healthCheck() (resp *http.Response, err error) { 59 | req, _ := http.NewRequest(http.MethodGet, healthCheckUrl, nil) 60 | req.Header.Set("User-Agent", api.UserAgent) 61 | if !firstTime { 62 | injectCookies(req) 63 | } 64 | resp, err = api.Client.Do(req) 65 | return 66 | } 67 | 68 | //goland:noinspection GoUnhandledErrorResult 69 | func checkHealthCheckStatus(resp *http.Response) { 70 | defer resp.Body.Close() 71 | if resp != nil && resp.StatusCode == http.StatusUnauthorized { 72 | logger.Info(readyHint) 73 | firstTime = false 74 | } else { 75 | doc, _ := goquery.NewDocumentFromReader(resp.Body) 76 | alert := doc.Find(".message").Text() 77 | if alert != "" { 78 | logger.Error(strings.TrimSpace(alert) + " by OpenAI.") 79 | time.Sleep(time.Hour) 80 | os.Exit(1) 81 | } else { 82 | getCookies() 83 | } 84 | } 85 | } 86 | 87 | func getCookiesApiUrl() string { 88 | cookiesApiUrl := os.Getenv("GO_CHATGPT_API_COOKIES_API_URL") 89 | if cookiesApiUrl == "" { 90 | cookiesApiUrl = defaultCookiesApiUrl 91 | } 92 | return cookiesApiUrl 93 | } 94 | 95 | //goland:noinspection GoUnhandledErrorResult 96 | func getCookies() { 97 | req, _ := http.NewRequest(http.MethodGet, getCookiesApiUrl(), nil) 98 | resp, err := api.Client.Do(req) 99 | if err != nil || resp.StatusCode != http.StatusOK { 100 | if resp != nil && resp.StatusCode == http.StatusForbidden { 101 | logger.Error(errorHintBlock) 102 | time.Sleep(time.Hour) 103 | os.Exit(1) 104 | } 105 | 106 | logger.Error("Failed to get cookies, please try again later.") 107 | return 108 | } 109 | 110 | defer resp.Body.Close() 111 | var cookies []*Cookie 112 | err = json.NewDecoder(resp.Body).Decode(&cookies) 113 | if err != nil { 114 | logger.Error("Failed to parse cookies, please retry later.") 115 | return 116 | } 117 | 118 | for _, cookie := range cookies { 119 | if cookie.Name == cookieName { 120 | cfbm = cookie 121 | break 122 | } 123 | } 124 | 125 | if firstTime { 126 | logger.Info(readyHint) 127 | logger.Error(errorHint403) 128 | firstTime = false 129 | 130 | go func() { 131 | keepCheckingCookies() 132 | }() 133 | } 134 | } 135 | 136 | func injectCookies(req *http.Request) { 137 | if cfbm != nil { 138 | req.Header.Set("Cookie", cookieName+"="+cfbm.Value) 139 | } 140 | } 141 | 142 | //goland:noinspection GoUnhandledErrorResult 143 | func keepCheckingCookies() { 144 | for { 145 | now := time.Now() 146 | refreshTime := now.Add(time.Minute * 5) // // refresh cookie 5 minutes before it is expired 147 | if refreshTime.Minute() == time.Unix(cfbm.Expiry, 0).Minute() { 148 | // use old cookie to get back new cookie 149 | resp, err := healthCheck() 150 | if err == nil && resp.StatusCode == http.StatusUnauthorized { 151 | oldValue := cfbm.Value 152 | for _, cookie := range resp.Cookies() { 153 | if cookie.Name == cookieName { 154 | cfbm = &Cookie{ 155 | Name: cookie.Name, 156 | Value: cookie.Value, 157 | } 158 | break 159 | } 160 | } 161 | 162 | newValue := cfbm.Value 163 | if oldValue == newValue { 164 | go func() { 165 | for { 166 | time.Sleep(time.Minute * 20) 167 | getCookies() 168 | } 169 | }() 170 | } else { 171 | // if new cfbm is set, go-chatgpt-api itself will take over the task of refreshing cookie from external cookies api 172 | go func() { 173 | for { 174 | time.Sleep(time.Minute * 25) 175 | resp, err := healthCheck() 176 | if err != nil { 177 | logger.Error("Health check failed: " + err.Error()) 178 | os.Exit(1) 179 | } 180 | 181 | for _, cookie := range resp.Cookies() { 182 | if cookie.Name == cookieName { 183 | cfbm = &Cookie{ 184 | Name: cookie.Name, 185 | Value: cookie.Value, 186 | } 187 | } 188 | } 189 | resp.Body.Close() 190 | } 191 | }() 192 | } 193 | break 194 | } 195 | } 196 | 197 | time.Sleep(time.Minute) 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /API/pandora/doc/wiki_en.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

4 |

Pandora

5 |

6 | Pandora, talking with ChatGPT in command lines, and with more surprises. 7 |
8 | Wiki in 中文 » 9 |
10 |
11 | Demo View 12 | · 13 | Bug Report 14 | · 15 | Feature Request 16 |

17 |

18 | 19 | ## Table of Contents 20 | 21 | - [Make it run](#make-it-run) 22 | - [Start parameters](#start-parameters) 23 | - [Docker](#docker) 24 | - [Access Token things](#access-token-things) 25 | - [HTTP RESTful API](#http-restful-api) 26 | - [Commands](#commands) 27 | - [Cloud mode](#cloud-mode) 28 | 29 | ## Make it run 30 | 31 | * Python version no less than `3.7` 32 | 33 | * install from `pip` 34 | 35 | ```shell 36 | pip install pandora-chatgpt 37 | pandora 38 | ``` 39 | * `gpt-3.5-turbo` mode: 40 | 41 | ```shell 42 | pip install 'pandora-chatgpt[api]' 43 | // OR 44 | pip install pandora-chatgpt[api] 45 | pandora 46 | ``` 47 | * `cloud` mode: 48 | 49 | ```shell 50 | pip install 'pandora-chatgpt[cloud]' 51 | // OR 52 | pip install pandora-chatgpt[cloud] 53 | pandora-cloud 54 | ``` 55 | 56 | * install from source 57 | 58 | ```shell 59 | pip install . 60 | pandora 61 | ``` 62 | 63 | * `gpt-3.5-turbo` mode: 64 | 65 | ```shell 66 | pip install '.[api]' 67 | // OR 68 | pip install .[api] 69 | pandora 70 | ``` 71 | 72 | * `cloud` mode: 73 | 74 | ```shell 75 | pip install '.[cloud]' 76 | // OR 77 | pip install .[cloud] 78 | pandora-cloud 79 | ``` 80 | 81 | * Docker Hub 82 | 83 | ```shell 84 | docker pull pengzhile/pandora 85 | docker run -it --rm pengzhile/pandora 86 | ``` 87 | 88 | * Docker build 89 | 90 | ```shell 91 | docker build -t pandora . 92 | docker run -it --rm pandora 93 | ``` 94 | 95 | * login with your credentials 96 | 97 | * stay simple, stay naive, stay elegant 98 | 99 | ## Start parameters 100 | 101 | * `pandora --help` for help text. 102 | * `-p` or `--proxy` for setting the proxy. the value should be`protocol://user:pass@ip:port`. 103 | * `-t` or `--token_file` for indicating the file that stores `Access Token`. You will login with access token if this option is in use. 104 | * `-s` or `--server` starts the HTTP server, by which you could open a web page and interact with it in a fancy UI. the value should be`ip:port`. 105 | * `-a` or `--api` use `gpt-3.5-turbo` API in backend. **NOTICE: you will be charged if this option is in use.** 106 | * `--tokens_file` indicating a file storing multiple `Access Token`s. The file content should be like`{"key": "token"}`. 107 | * `--threads` specify the number of server workers, default is `8`, and for cloud mode, it is `4`. 108 | * `--sentry` sending error messages to author for improving Pandora. **Sensitive information won't be leaked.** 109 | * `-v` or `--verbose` for verbose debugging messages. 110 | 111 | ## Docker 112 | 113 | These docker environment variables will override start parameters. 114 | 115 | * `PANDORA_ACCESS_TOKEN` =`Access Token` string. 116 | * `PANDORA_TOKENS_FILE` = the path of file which keeps `Access Token`s. 117 | * `PANDORA_PROXY` =`protocol://user:pass@ip:port`. 118 | * `PANDORA_SERVER` =`ip:port`. 119 | * `PANDORA_API` for using `gpt-3.5-turbo` API. **NOTICE: you will be charged if this option is in use.** 120 | * `PANDORA_SENTRY` for sending error messages to author to improve Pandora. **Sensitive information won't be leaked.** 121 | * `PANDORA_VERBOSE` for verbose debugging messages. 122 | 123 | ## Access Token things 124 | 125 | * no need for proxy if login with `Access Token`. 126 | * you could obtain your access token safely with [this service](https://ai.fakeopen.com/auth). 127 | * `Access Token` has a expiration time as `14 days`, you could save it and keep using within this period. 128 | * leaking your `Access Token` will lead to loss of your account. 129 | 130 | ## HTTP RESTFUL API 131 | 132 | * if you start Pandora with `-s`/`--server`/`PANDORA_SERVER`, you could access a web UI with `http://ip:port`. 133 | * you could switch access token by passing a different one with `http://ip:port/?token=xxx`. 134 | * API documents: [doc/HTTP-API.md](https://github.com/pengzhile/pandora/blob/master/doc/HTTP-API.md) 135 | 136 | ## Commands 137 | 138 | * **double** `Enter` to send prompt to `ChatGPT`. 139 | * `/?` for help text. 140 | * `/title` for setting the title of current conversation. 141 | * `/select` back to conversation choosing page. 142 | * `/reload` for refreshing. 143 | * `/regen` for regenerating answers if you are not satisfied with the last one. 144 | * `/continue` make `ChatGPT` to append responses. 145 | * `/edit` for editing your previous prompt. 146 | * `/new` to start a new conversation. 147 | * `/del` to delete current conversation and back to conversation choosing page. 148 | * `/token` for printing current access token. 149 | * `/copy` for copying the last response of `ChatGPT` to pasteboard. 150 | * `/copy_code` for copying the code in the last response of `ChatGPT` to pasteboard. 151 | * `/clear` for cleaning the screen. 152 | * `/version` for printing the version of Pandora. 153 | * `/exit` to exit Pandora. 154 | 155 | ## Cloud mode 156 | 157 | - setting up a service just like official `ChatGPT` website. it's so same as only jesus could tell it apart. 158 | 159 | * you need to use `pandora-cloud` instead of `pandora` to start Pandora. 160 | * enabling `PANDORA_CLOUD` if you are using Docker to start Pandora. 161 | * Other parameters are same as these guys in normal mode. 162 | -------------------------------------------------------------------------------- /API/pandora/doc/wiki.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

4 |

潘多拉 Pandora

5 |

6 | 一个不只是命令行的 "ChatGPT" 7 |
8 | Wiki in English » 9 |
10 |
11 | 查看Demo 12 | · 13 | 报告Bug 14 | · 15 | 提出新特性 16 |

17 |

18 | 19 | ## 目录 20 | 21 | - [如何运行](#如何运行) 22 | - [程序参数](#程序参数) 23 | - [Docker环境变量](#docker环境变量) 24 | - [关于 Access Token](#关于-access-token) 25 | - [HTTP服务文档](#http服务文档) 26 | - [操作命令](#操作命令) 27 | - [高阶设置](#高阶设置) 28 | - [Cloud模式](#cloud模式) 29 | - [使用Cloudflare Workers代理](#使用cloudflare-workers代理) 30 | 31 | ## 如何运行 32 | 33 | * Python版本目测起码要`3.7` 34 | 35 | * pip安装运行 36 | 37 | ```shell 38 | pip install pandora-chatgpt 39 | pandora 40 | ``` 41 | * 如果你想支持`gpt-3.5-turbo`模式: 42 | 43 | ```shell 44 | pip install 'pandora-chatgpt[api]' 45 | // 或者 46 | pip install pandora-chatgpt[api] 47 | pandora 48 | ``` 49 | * 如果你想启用`cloud`模式: 50 | 51 | ```shell 52 | pip install 'pandora-chatgpt[cloud]' 53 | // 或者 54 | pip install pandora-chatgpt[cloud] 55 | pandora-cloud 56 | ``` 57 | 58 | * 编译运行 59 | 60 | ```shell 61 | pip install . 62 | pandora 63 | ``` 64 | 65 | * 如果你想支持`gpt-3.5-turbo`模式: 66 | 67 | ```shell 68 | pip install '.[api]' 69 | // 或者 70 | pip install .[api] 71 | pandora 72 | ``` 73 | 74 | * 如果你想启用`cloud`模式: 75 | 76 | ```shell 77 | pip install '.[cloud]' 78 | // 或者 79 | pip install .[cloud] 80 | pandora-cloud 81 | ``` 82 | 83 | * Docker Hub运行 84 | 85 | ```shell 86 | docker pull pengzhile/pandora 87 | docker run -it --rm pengzhile/pandora 88 | ``` 89 | 90 | * Docker编译运行 91 | 92 | ```shell 93 | docker build -t pandora . 94 | docker run -it --rm pandora 95 | ``` 96 | 97 | * 输入用户名密码登录即可,登录密码理论上不显示出来,莫慌。 98 | * 简单而粗暴,不失优雅。 99 | 100 | ## 程序参数 101 | 102 | * 可通过 `pandora --help` 查看。 103 | * `-p` 或 `--proxy` 指定代理,格式:`protocol://user:pass@ip:port`。 104 | * `-t` 或 `--token_file` 指定一个存放`Access Token`的文件,使用`Access Token`登录。 105 | * `-s` 或 `--server` 以`http`服务方式启动,格式:`ip:port`。 106 | * `-a` 或 `--api` 使用`gpt-3.5-turbo`API请求,**你可能需要向`OpenAI`支付费用**。 107 | * `--tokens_file` 指定一个存放多`Access Token`的文件,内容为`{"key": "token"}`的形式。 108 | * `--threads` 指定服务启动的线程数,默认为 `8`,Cloud模式为 `4`。 109 | * `--sentry` 启用`sentry`框架来发送错误报告供作者查错,敏感信息**不会被发送**。 110 | * `-v` 或 `--verbose` 显示调试信息,且出错时打印异常堆栈信息,供查错使用。 111 | 112 | ## Docker环境变量 113 | 114 | * `PANDORA_ACCESS_TOKEN` 指定`Access Token`字符串。 115 | * `PANDORA_TOKENS_FILE` 指定一个存放多`Access Token`的文件路径。 116 | * `PANDORA_PROXY` 指定代理,格式:`protocol://user:pass@ip:port`。 117 | * `PANDORA_SERVER` 以`http`服务方式启动,格式:`ip:port`。 118 | * `PANDORA_API` 使用`gpt-3.5-turbo`API请求,**你可能需要向`OpenAI`支付费用**。 119 | * `PANDORA_SENTRY` 启用`sentry`框架来发送错误报告供作者查错,敏感信息**不会被发送**。 120 | * `PANDORA_VERBOSE` 显示调试信息,且出错时打印异常堆栈信息,供查错使用。 121 | * 使用Docker方式,设置环境变量即可,无视上述`程序参数`。 122 | 123 | ## 关于 Access Token 124 | 125 | * 使用`Access Token`方式登录,可以无代理直连。 126 | * [这个服务](https://ai.fakeopen.com/auth) 可以帮你安全有效拿到`Access Token`,无论是否第三方登录。 127 | * 其中`accessToken`字段的那一长串内容即是`Access Token`。 128 | * `Access Token`可以复制保存,其有效期目前为`14天`。 129 | * 不要泄露你的`Access Token`,使用它可以操纵你的账号。 130 | 131 | ## HTTP服务文档 132 | 133 | * 如果你以`http`服务方式启动,现在你可以打开一个极简版的`ChatGPT`了。通过你指定的`http://ip:port`来访问。 134 | * 通过`http://ip:port/?token=xxx`,传递一个Token的名字,可以切换到对应的`Access Token`。 135 | * API文档见:[doc/HTTP-API.md](https://github.com/pengzhile/pandora/blob/master/doc/HTTP-API.md) 136 | 137 | ## 操作命令 138 | 139 | * 对话界面**连敲两次**`Enter`发送你的输入给`ChatGPT`。 140 | * 对话界面使用`/?`可以打印支持的操作命令。 141 | * `/title` 重新设置当前对话的标题。 142 | * `/select` 回到选择会话界面。 143 | * `/reload` 重新加载当前会话所有内容,`F5`你能懂吧。 144 | * `/regen` 如果对`ChatGPT`当前回答不满意,可以让它重新回答。 145 | * `/continue` 让`ChatGPT`继续输出回复的剩余部分。 146 | * `/edit` 编辑你之前的一个提问。 147 | * `/new` 直接开启一个新会话。 148 | * `/del` 删除当前会话,回到会话选择界面。 149 | * `/token` 打印当前的`Access Token`,也许你用得上,但不要泄露。 150 | * `/copy` 复制`ChatGPT`上一次回复的内容到剪贴板。 151 | * `/copy_code` 复制`ChatGPT`上一次回复的代码到剪贴板 152 | * `/clear` 清屏,应该不用解释。 153 | * `/version` 打印`Pandora`的版本信息。 154 | * `/exit` 退出`潘多拉`。 155 | 156 | ## 高阶设置 157 | 158 | * 本部分内容不理解的朋友,**请勿擅动!** 159 | * 环境变量 `OPENAI_API_PREFIX` 可以替换OpenAI Api的前缀`https://api.openai.com`。 160 | * 环境变量 `CHATGPT_API_PREFIX` 可以替换ChatGPT Api的前缀`https://ai.fakeopen.com`。 161 | * 如果你想持久存储`Docker`中`Pandora`产生的数据,你可以挂载宿主机目录至`/data`。 162 | * 如果你在国内使用`pip`安装缓慢,可以考虑切换至腾讯的源:```pip config set global.index-url https://mirrors.cloud.tencent.com/pypi/simple``` 163 | * 镜像同步版本可能不及时,如果出现这种情况建议切换至官方源:```pip config set global.index-url https://pypi.org/simple``` 164 | * 默认使用`sqlite3`存储会话数据,如果你希望更换至`mysql`,可以这么做: 165 | * 执行```pip install PyMySQL```安装驱动。 166 | * 设置环境变量:`DATABASE_URI`为类似`mysql+pymysql://user:pass@localhost/dbname`的连接字符串。 167 | * 环境变量指定`OPENAI_EMAIL`可以替代登录输入用户名,`OPENAI_PASSWORD`则可以替代输入密码, `OPENAI_MFA_CODE`则可以替代输入二次验证。 168 | * 环境变量`API_SYSTEM_PROMPT`可以替换`api`模式下的系统`prompt`。 169 | 170 | ## Cloud模式 171 | 172 | * 搭建一个跟官方很像的`ChatGPT`服务,不能说很像,只能说一样。 173 | * 该模式使用`pandora-cloud`启动,前提是你如前面所说安装好了。 174 | * Docker环境变量:`PANDORA_CLOUD` 启动`cloud`模式。 175 | * 该模式参数含义与普通模式相同,可`--help`查看。 176 | 177 | ## 使用Cloudflare Workers代理 178 | 179 | * 如果你感觉默认的`https://ai.fakeopen.com`在你那里可能被墙了,可以使用如下方法自行代理。 180 | * 你需要一个`Cloudflare`账号,如果没有,可以[注册](https://dash.cloudflare.com/sign-up)一个。 181 | * 登录后,点击`Workers`,然后点击`Create a Worker`,填入服务名称后点击`创建服务`。 182 | * 点开你刚才创建的服务,点击`快速编辑`按钮,贴入下面的代码,然后点击`保存并部署`。 183 | 184 | ```javascript 185 | export default { 186 | async fetch(request, env) { 187 | const url = new URL(request.url); 188 | url.host = 'ai.fakeopen.com'; 189 | return fetch(new Request(url, request)) 190 | } 191 | } 192 | ``` 193 | 194 | * 点击`触发器`选项卡,可以添加自定义访问域名。 195 | * 参考`高阶设置`中的环境变量使用你的服务地址进行替换。 196 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/platform/api.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "strings" 9 | 10 | "github.com/gin-gonic/gin" 11 | "github.com/linweiyuan/go-chatgpt-api/api" 12 | 13 | http "github.com/bogdanfinn/fhttp" 14 | ) 15 | 16 | func ListModels(c *gin.Context) { 17 | handleGet(c, apiListModels) 18 | } 19 | 20 | func RetrieveModel(c *gin.Context) { 21 | model := c.Param("model") 22 | handleGet(c, fmt.Sprintf(apiRetrieveModel, model)) 23 | } 24 | 25 | //goland:noinspection GoUnhandledErrorResult 26 | func CreateCompletions(c *gin.Context) { 27 | var request CreateCompletionsRequest 28 | c.ShouldBindJSON(&request) 29 | data, _ := json.Marshal(request) 30 | resp, err := handlePost(c, apiCreateCompletions, data, request.Stream) 31 | if err != nil { 32 | return 33 | } 34 | 35 | defer resp.Body.Close() 36 | if request.Stream { 37 | api.HandleConversationResponse(c, resp) 38 | } else { 39 | io.Copy(c.Writer, resp.Body) 40 | } 41 | } 42 | 43 | //goland:noinspection GoUnhandledErrorResult 44 | func CreateChatCompletions(c *gin.Context) { 45 | var request ChatCompletionsRequest 46 | c.ShouldBindJSON(&request) 47 | data, _ := json.Marshal(request) 48 | resp, err := handlePost(c, apiCreataeChatCompletions, data, request.Stream) 49 | if err != nil { 50 | return 51 | } 52 | 53 | defer resp.Body.Close() 54 | if request.Stream { 55 | api.HandleConversationResponse(c, resp) 56 | } else { 57 | io.Copy(c.Writer, resp.Body) 58 | } 59 | } 60 | 61 | //goland:noinspection GoUnhandledErrorResult 62 | func CreateEdit(c *gin.Context) { 63 | var request CreateEditRequest 64 | c.ShouldBindJSON(&request) 65 | data, _ := json.Marshal(request) 66 | resp, err := handlePost(c, apiCreateEdit, data, false) 67 | if err != nil { 68 | return 69 | } 70 | 71 | defer resp.Body.Close() 72 | io.Copy(c.Writer, resp.Body) 73 | } 74 | 75 | //goland:noinspection GoUnhandledErrorResult 76 | func CreateImage(c *gin.Context) { 77 | var request CreateImageRequest 78 | c.ShouldBindJSON(&request) 79 | data, _ := json.Marshal(request) 80 | resp, err := handlePost(c, apiCreateImage, data, false) 81 | if err != nil { 82 | return 83 | } 84 | 85 | defer resp.Body.Close() 86 | io.Copy(c.Writer, resp.Body) 87 | } 88 | 89 | //goland:noinspection GoUnhandledErrorResult 90 | func CreateEmbeddings(c *gin.Context) { 91 | var request CreateEmbeddingsRequest 92 | c.ShouldBindJSON(&request) 93 | data, _ := json.Marshal(request) 94 | resp, err := handlePost(c, apiCreateEmbeddings, data, false) 95 | if err != nil { 96 | return 97 | } 98 | 99 | defer resp.Body.Close() 100 | io.Copy(c.Writer, resp.Body) 101 | } 102 | 103 | func ListFiles(c *gin.Context) { 104 | handleGet(c, apiListFiles) 105 | } 106 | 107 | func GetCreditGrants(c *gin.Context) { 108 | handleGet(c, apiGetCreditGrants) 109 | } 110 | 111 | //goland:noinspection GoUnhandledErrorResult 112 | func Login(c *gin.Context) { 113 | var loginInfo api.LoginInfo 114 | if err := c.ShouldBindJSON(&loginInfo); err != nil { 115 | c.AbortWithStatusJSON(http.StatusBadRequest, api.ReturnMessage(api.ParseUserInfoErrorMessage)) 116 | return 117 | } 118 | 119 | userLogin := UserLogin{ 120 | client: api.NewHttpClient(), 121 | } 122 | 123 | // hard refresh cookies 124 | resp, _ := userLogin.client.Get(auth0LogoutUrl) 125 | defer resp.Body.Close() 126 | 127 | // get authorized url 128 | authorizedUrl, statusCode, err := userLogin.GetAuthorizedUrl("") 129 | if err != nil { 130 | c.AbortWithStatusJSON(statusCode, api.ReturnMessage(err.Error())) 131 | return 132 | } 133 | 134 | // get state 135 | state, _, _ := userLogin.GetState(authorizedUrl) 136 | 137 | // check username 138 | statusCode, err = userLogin.CheckUsername(state, loginInfo.Username) 139 | if err != nil { 140 | c.AbortWithStatusJSON(statusCode, api.ReturnMessage(err.Error())) 141 | return 142 | } 143 | 144 | // check password 145 | code, statusCode, err := userLogin.CheckPassword(state, loginInfo.Username, loginInfo.Password) 146 | if err != nil { 147 | c.AbortWithStatusJSON(statusCode, api.ReturnMessage(err.Error())) 148 | return 149 | } 150 | 151 | // get access token 152 | accessToken, statusCode, err := userLogin.GetAccessToken(code) 153 | if err != nil { 154 | c.AbortWithStatusJSON(statusCode, api.ReturnMessage(err.Error())) 155 | return 156 | } 157 | 158 | // get session key 159 | var getAccessTokenResponse GetAccessTokenResponse 160 | json.Unmarshal([]byte(accessToken), &getAccessTokenResponse) 161 | req, _ := http.NewRequest(http.MethodPost, dashboardLoginUrl, strings.NewReader("{}")) 162 | req.Header.Set("Content-Type", "application/json") 163 | req.Header.Set("User-Agent", api.UserAgent) 164 | req.Header.Set("Authorization", api.GetAccessToken(getAccessTokenResponse.AccessToken)) 165 | resp, err = userLogin.client.Do(req) 166 | if err != nil { 167 | c.AbortWithStatusJSON(http.StatusInternalServerError, api.ReturnMessage(err.Error())) 168 | return 169 | } 170 | 171 | defer resp.Body.Close() 172 | if resp.StatusCode != http.StatusOK { 173 | c.AbortWithStatusJSON(resp.StatusCode, api.ReturnMessage(getSessionKeyErrorMessage)) 174 | return 175 | } 176 | 177 | io.Copy(c.Writer, resp.Body) 178 | } 179 | 180 | func GetSubscription(c *gin.Context) { 181 | handleGet(c, apiGetSubscription) 182 | } 183 | 184 | func GetApiKeys(c *gin.Context) { 185 | handleGet(c, apiGetApiKeys) 186 | } 187 | 188 | //goland:noinspection GoUnhandledErrorResult 189 | func handleGet(c *gin.Context, url string) { 190 | req, _ := http.NewRequest(http.MethodGet, url, nil) 191 | req.Header.Set("Authorization", api.GetAccessToken(c.GetHeader(api.AuthorizationHeader))) 192 | resp, _ := api.Client.Do(req) 193 | defer resp.Body.Close() 194 | io.Copy(c.Writer, resp.Body) 195 | } 196 | 197 | func handlePost(c *gin.Context, url string, data []byte, stream bool) (*http.Response, error) { 198 | req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data)) 199 | req.Header.Set("Authorization", api.GetAccessToken(c.GetHeader(api.AuthorizationHeader))) 200 | if stream { 201 | req.Header.Set("Accept", "text/event-stream") 202 | } 203 | req.Header.Set("Content-Type", "application/json") 204 | resp, err := api.Client.Do(req) 205 | if err != nil { 206 | c.AbortWithStatusJSON(http.StatusInternalServerError, api.ReturnMessage(err.Error())) 207 | return nil, err 208 | } 209 | 210 | return resp, nil 211 | } 212 | -------------------------------------------------------------------------------- /API/snova2api/snova-api.js: -------------------------------------------------------------------------------- 1 | const TARGET_URL = 'https://fast-api.snova.ai/v1/chat/completions'; 2 | const MODEL_OVERRIDE = ''; // Set this to override the model 3 | 4 | // More: https://www.blueskyxn.com/202408/7089.html 5 | // 和 https://github.com/BlueSkyXN/OpenAI-Quick-DEV/blob/main/API/snova2api/snova2api.js 的逆向API的区别有且仅有目标URL不同 6 | // 有人发的 https://github.com/GrayXu/sambanova-api-ai-proxy/blob/main/cf-worker.js 实际上连oneapi都无法过测,我不知道为什么好意思发出来,问题和 https://github.com/lingo34/sambanova-ai-proxy/blob/main/cf-worker.js 基本半斤八两 7 | 8 | export default { 9 | async fetch(request) { 10 | if (request.method === 'POST' && request.url.endsWith('/v1/chat/completions')) { 11 | try { 12 | const originalPayload = await request.json(); 13 | const isStreamMode = originalPayload.stream === true; // 检查用户是否指定了流模式 14 | 15 | // Override the model if MODEL_OVERRIDE is set 16 | if (MODEL_OVERRIDE && MODEL_OVERRIDE.trim() !== '') { 17 | originalPayload.model = MODEL_OVERRIDE; 18 | } 19 | 20 | // 强制添加 "stream": true 到目标API请求中,因为目标API只支持流模式 21 | originalPayload.stream = true; 22 | 23 | const modifiedPayload = { 24 | body: { 25 | ...originalPayload, 26 | stop: ["<|eot_id|>"] 27 | }, 28 | env_type: "tp16405b" 29 | }; 30 | 31 | const options = { 32 | method: 'POST', 33 | headers: { 34 | 'Content-Type': 'application/json' 35 | }, 36 | body: JSON.stringify(modifiedPayload) 37 | }; 38 | 39 | // 发送请求到目标API 40 | const response = await fetch(TARGET_URL, options); 41 | 42 | // 如果用户请求了流模式 43 | if (isStreamMode) { 44 | // 直接将流数据逐步传输给客户端 45 | const streamResponse = new ReadableStream({ 46 | async start(controller) { 47 | const reader = response.body.getReader(); 48 | const decoder = new TextDecoder(); 49 | 50 | while (true) { 51 | const { done, value } = await reader.read(); 52 | if (done) { 53 | controller.close(); 54 | break; 55 | } 56 | // 将流数据发送给客户端 57 | const chunk = decoder.decode(value, { stream: true }); 58 | const lines = chunk.split('\n'); 59 | for (const line of lines) { 60 | if (line.startsWith('data:')) { 61 | const data = line.replace(/^data: /, '').trim(); 62 | if (data) { 63 | controller.enqueue(new TextEncoder().encode(`data: ${data}\n\n`)); 64 | } 65 | } 66 | } 67 | } 68 | } 69 | }); 70 | 71 | return new Response(streamResponse, { 72 | status: 200, 73 | headers: { 74 | 'Content-Type': 'text/event-stream', 75 | 'Cache-Control': 'no-cache', 76 | 'Access-Control-Allow-Origin': '*', 77 | 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 78 | 'Access-Control-Allow-Headers': 'Content-Type, Authorization' 79 | } 80 | }); 81 | 82 | } else { 83 | // 非流模式:拼接流数据,并一次性返回完整响应 84 | const reader = response.body.getReader(); 85 | const decoder = new TextDecoder(); 86 | let completeResponse = ''; 87 | let isDone = false; 88 | let finishReason = null; 89 | let statistics = {}; 90 | 91 | while (!isDone) { 92 | const { done, value } = await reader.read(); 93 | if (done) break; 94 | 95 | const chunk = decoder.decode(value, { stream: true }); 96 | const lines = chunk.split('\n'); 97 | 98 | for (const line of lines) { 99 | if (line.startsWith('data:')) { 100 | const data = line.replace(/^data: /, '').trim(); 101 | 102 | if (data === '[DONE]') { 103 | isDone = true; 104 | break; 105 | } 106 | 107 | if (data) { 108 | try { 109 | const jsonChunk = JSON.parse(data); 110 | if (jsonChunk.choices && jsonChunk.choices[0].delta && jsonChunk.choices[0].delta.content) { 111 | completeResponse += jsonChunk.choices[0].delta.content; 112 | } 113 | 114 | if (jsonChunk.choices && jsonChunk.choices[0].finish_reason) { 115 | finishReason = jsonChunk.choices[0].finish_reason; 116 | } 117 | 118 | if (jsonChunk.usage) { 119 | statistics = jsonChunk.usage; 120 | } 121 | 122 | } catch (err) { 123 | console.error('Failed to parse JSON chunk:', err); 124 | } 125 | } 126 | } 127 | } 128 | } 129 | 130 | return new Response(JSON.stringify({ 131 | id: "complete-id", 132 | object: "chat.completion", 133 | created: Date.now(), 134 | model: originalPayload.model || "default-model", 135 | choices: [{ 136 | index: 0, 137 | message: { 138 | role: "assistant", 139 | content: completeResponse 140 | }, 141 | finish_reason: finishReason || "stop" 142 | }], 143 | usage: statistics 144 | }), { 145 | status: 200, 146 | headers: { 147 | 'Content-Type': 'application/json', 148 | 'Access-Control-Allow-Origin': '*', 149 | 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 150 | 'Access-Control-Allow-Headers': 'Content-Type, Authorization' 151 | } 152 | }); 153 | } 154 | 155 | } catch (error) { 156 | console.error('Error processing request:', error); 157 | return new Response(JSON.stringify({ error: 'Bad Request' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); 158 | } 159 | } else { 160 | return new Response(JSON.stringify({ error: 'Not Found' }), { status: 404, headers: { 'Content-Type': 'application/json' } }); 161 | } 162 | } 163 | }; 164 | -------------------------------------------------------------------------------- /API/snova2api/snova2api.js: -------------------------------------------------------------------------------- 1 | // 参考了 https://github.com/lingo34/sambanova-ai-proxy/blob/main/cf-worker.js 但是那玩意不可用,无法过oneapi测试,因为目标接口不支持非流模式,所以我要进行一个转换 2 | // Meta-Llama-3.1-8B-Instruct、Meta-Llama-3.1-70B-Instruct、Meta-Llama-3.1-405B-Instruct、ignos/Mistral-T5-7B-v1、v1olet/v1olet_merged_dpo_7B、macadeliccc/WestLake-7B-v2-laser-truthy-dpo、cookinai/DonutLM-v1 3 | // More: https://www.blueskyxn.com/202408/7089.html 4 | const TARGET_URL = 'https://fast.snova.ai/api/completion'; 5 | const MODEL_OVERRIDE = ''; // Set this to override the model 6 | 7 | export default { 8 | async fetch(request) { 9 | if (request.method === 'POST' && request.url.endsWith('/v1/chat/completions')) { 10 | try { 11 | const originalPayload = await request.json(); 12 | const isStreamMode = originalPayload.stream === true; // 检查用户是否指定了流模式 13 | 14 | // Override the model if MODEL_OVERRIDE is set 15 | if (MODEL_OVERRIDE && MODEL_OVERRIDE.trim() !== '') { 16 | originalPayload.model = MODEL_OVERRIDE; 17 | } 18 | 19 | // 强制添加 "stream": true 到目标API请求中,因为目标API只支持流模式 20 | originalPayload.stream = true; 21 | 22 | const modifiedPayload = { 23 | body: { 24 | ...originalPayload, 25 | stop: ["<|eot_id|>"] 26 | }, 27 | env_type: "tp16405b" 28 | }; 29 | 30 | const options = { 31 | method: 'POST', 32 | headers: { 33 | 'Content-Type': 'application/json' 34 | }, 35 | body: JSON.stringify(modifiedPayload) 36 | }; 37 | 38 | // 发送请求到目标API 39 | const response = await fetch(TARGET_URL, options); 40 | 41 | // 如果用户请求了流模式 42 | if (isStreamMode) { 43 | // 直接将流数据逐步传输给客户端 44 | const streamResponse = new ReadableStream({ 45 | async start(controller) { 46 | const reader = response.body.getReader(); 47 | const decoder = new TextDecoder(); 48 | 49 | while (true) { 50 | const { done, value } = await reader.read(); 51 | if (done) { 52 | controller.close(); 53 | break; 54 | } 55 | // 将流数据发送给客户端 56 | const chunk = decoder.decode(value, { stream: true }); 57 | const lines = chunk.split('\n'); 58 | for (const line of lines) { 59 | if (line.startsWith('data:')) { 60 | const data = line.replace(/^data: /, '').trim(); 61 | if (data) { 62 | controller.enqueue(new TextEncoder().encode(`data: ${data}\n\n`)); 63 | } 64 | } 65 | } 66 | } 67 | } 68 | }); 69 | 70 | return new Response(streamResponse, { 71 | status: 200, 72 | headers: { 73 | 'Content-Type': 'text/event-stream', 74 | 'Cache-Control': 'no-cache', 75 | 'Access-Control-Allow-Origin': '*', 76 | 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 77 | 'Access-Control-Allow-Headers': 'Content-Type, Authorization' 78 | } 79 | }); 80 | 81 | } else { 82 | // 非流模式:拼接流数据,并一次性返回完整响应 83 | const reader = response.body.getReader(); 84 | const decoder = new TextDecoder(); 85 | let completeResponse = ''; 86 | let isDone = false; 87 | let finishReason = null; 88 | let statistics = {}; 89 | 90 | while (!isDone) { 91 | const { done, value } = await reader.read(); 92 | if (done) break; 93 | 94 | const chunk = decoder.decode(value, { stream: true }); 95 | const lines = chunk.split('\n'); 96 | 97 | for (const line of lines) { 98 | if (line.startsWith('data:')) { 99 | const data = line.replace(/^data: /, '').trim(); 100 | 101 | if (data === '[DONE]') { 102 | isDone = true; 103 | break; 104 | } 105 | 106 | if (data) { 107 | try { 108 | const jsonChunk = JSON.parse(data); 109 | if (jsonChunk.choices && jsonChunk.choices[0].delta && jsonChunk.choices[0].delta.content) { 110 | completeResponse += jsonChunk.choices[0].delta.content; 111 | } 112 | 113 | if (jsonChunk.choices && jsonChunk.choices[0].finish_reason) { 114 | finishReason = jsonChunk.choices[0].finish_reason; 115 | } 116 | 117 | if (jsonChunk.usage) { 118 | statistics = jsonChunk.usage; 119 | } 120 | 121 | } catch (err) { 122 | console.error('Failed to parse JSON chunk:', err); 123 | } 124 | } 125 | } 126 | } 127 | } 128 | 129 | return new Response(JSON.stringify({ 130 | id: "complete-id", 131 | object: "chat.completion", 132 | created: Date.now(), 133 | model: originalPayload.model || "default-model", 134 | choices: [{ 135 | index: 0, 136 | message: { 137 | role: "assistant", 138 | content: completeResponse 139 | }, 140 | finish_reason: finishReason || "stop" 141 | }], 142 | usage: statistics 143 | }), { 144 | status: 200, 145 | headers: { 146 | 'Content-Type': 'application/json', 147 | 'Access-Control-Allow-Origin': '*', 148 | 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 149 | 'Access-Control-Allow-Headers': 'Content-Type, Authorization' 150 | } 151 | }); 152 | } 153 | 154 | } catch (error) { 155 | console.error('Error processing request:', error); 156 | return new Response(JSON.stringify({ error: 'Bad Request' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); 157 | } 158 | } else { 159 | return new Response(JSON.stringify({ error: 'Not Found' }), { status: 404, headers: { 'Content-Type': 'application/json' } }); 160 | } 161 | } 162 | }; 163 | -------------------------------------------------------------------------------- /API/ChatGPT-to-API/handlers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "freechatgpt/internal/chatgpt" 7 | "freechatgpt/internal/tokens" 8 | typings "freechatgpt/internal/typings" 9 | "freechatgpt/internal/typings/responses" 10 | "io" 11 | "os" 12 | "strings" 13 | 14 | "github.com/gin-gonic/gin" 15 | ) 16 | 17 | func passwordHandler(c *gin.Context) { 18 | // Get the password from the request (json) and update the password 19 | type password_struct struct { 20 | Password string `json:"password"` 21 | } 22 | var password password_struct 23 | err := c.BindJSON(&password) 24 | if err != nil { 25 | c.String(400, "password not provided") 26 | return 27 | } 28 | ADMIN_PASSWORD = password.Password 29 | // Set environment variable 30 | os.Setenv("ADMIN_PASSWORD", ADMIN_PASSWORD) 31 | c.String(200, "password updated") 32 | } 33 | 34 | func puidHandler(c *gin.Context) { 35 | // Get the password from the request (json) and update the password 36 | type puid_struct struct { 37 | PUID string `json:"puid"` 38 | } 39 | var puid puid_struct 40 | err := c.BindJSON(&puid) 41 | if err != nil { 42 | c.String(400, "puid not provided") 43 | return 44 | } 45 | // Set environment variable 46 | os.Setenv("PUID", puid.PUID) 47 | c.String(200, "puid updated") 48 | } 49 | 50 | func tokensHandler(c *gin.Context) { 51 | // Get the request_tokens from the request (json) and update the request_tokens 52 | var request_tokens []string 53 | err := c.BindJSON(&request_tokens) 54 | if err != nil { 55 | c.String(400, "tokens not provided") 56 | return 57 | } 58 | ACCESS_TOKENS = tokens.NewAccessToken(request_tokens) 59 | c.String(200, "tokens updated") 60 | } 61 | func optionsHandler(c *gin.Context) { 62 | // Set headers for CORS 63 | c.Header("Access-Control-Allow-Origin", "*") 64 | c.Header("Access-Control-Allow-Methods", "POST") 65 | c.Header("Access-Control-Allow-Headers", "*") 66 | c.JSON(200, gin.H{ 67 | "message": "pong", 68 | }) 69 | } 70 | func nightmare(c *gin.Context) { 71 | var original_request typings.APIRequest 72 | err := c.BindJSON(&original_request) 73 | if err != nil { 74 | c.JSON(400, gin.H{"error": gin.H{ 75 | "message": "Request must be proper JSON", 76 | "type": "invalid_request_error", 77 | "param": nil, 78 | "code": err.Error(), 79 | }}) 80 | } 81 | // Convert the chat request to a ChatGPT request 82 | translated_request := chatgpt.ConvertAPIRequest(original_request) 83 | 84 | authHeader := c.GetHeader("Authorization") 85 | token := ACCESS_TOKENS.GetToken() 86 | if authHeader != "" { 87 | customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1) 88 | // Check if customAccessToken starts with sk- 89 | if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9") { 90 | token = customAccessToken 91 | } 92 | } 93 | 94 | response, err := chatgpt.SendRequest(translated_request, token) 95 | if err != nil { 96 | c.JSON(response.StatusCode, gin.H{ 97 | "error": "error sending request", 98 | "message": response.Status, 99 | }) 100 | return 101 | } 102 | defer response.Body.Close() 103 | if response.StatusCode != 200 { 104 | // Try read response body as JSON 105 | var error_response map[string]interface{} 106 | err = json.NewDecoder(response.Body).Decode(&error_response) 107 | if err != nil { 108 | // Read response body 109 | body, _ := io.ReadAll(response.Body) 110 | c.JSON(500, gin.H{"error": gin.H{ 111 | "message": "Unknown error", 112 | "type": "internal_server_error", 113 | "param": nil, 114 | "code": "500", 115 | "details": string(body), 116 | }}) 117 | return 118 | } 119 | c.JSON(response.StatusCode, gin.H{"error": gin.H{ 120 | "message": error_response["detail"], 121 | "type": response.Status, 122 | "param": nil, 123 | "code": "error", 124 | }}) 125 | return 126 | } 127 | // Create a bufio.Reader from the response body 128 | reader := bufio.NewReader(response.Body) 129 | 130 | var fulltext string 131 | 132 | // Read the response byte by byte until a newline character is encountered 133 | if original_request.Stream { 134 | // Response content type is text/event-stream 135 | c.Header("Content-Type", "text/event-stream") 136 | } else { 137 | // Response content type is application/json 138 | c.Header("Content-Type", "application/json") 139 | } 140 | for { 141 | line, err := reader.ReadString('\n') 142 | if err != nil { 143 | if err == io.EOF { 144 | break 145 | } 146 | return 147 | } 148 | if len(line) < 6 { 149 | continue 150 | } 151 | // Remove "data: " from the beginning of the line 152 | line = line[6:] 153 | // Check if line starts with [DONE] 154 | if !strings.HasPrefix(line, "[DONE]") { 155 | // Parse the line as JSON 156 | var original_response responses.Data 157 | err = json.Unmarshal([]byte(line), &original_response) 158 | if err != nil { 159 | continue 160 | } 161 | if original_response.Error != nil { 162 | return 163 | } 164 | if original_response.Message.Content.Parts == nil { 165 | continue 166 | } 167 | if original_response.Message.Content.Parts[0] == "" || original_response.Message.Author.Role != "assistant" { 168 | continue 169 | } 170 | if original_response.Message.Metadata.Timestamp == "absolute" { 171 | continue 172 | } 173 | tmp_fulltext := original_response.Message.Content.Parts[0] 174 | original_response.Message.Content.Parts[0] = strings.ReplaceAll(original_response.Message.Content.Parts[0], fulltext, "") 175 | translated_response := responses.NewChatCompletionChunk(original_response.Message.Content.Parts[0]) 176 | 177 | // Stream the response to the client 178 | response_string := translated_response.String() 179 | if original_request.Stream { 180 | _, err = c.Writer.WriteString("data: " + string(response_string) + "\n\n") 181 | if err != nil { 182 | return 183 | } 184 | } 185 | 186 | // Flush the response writer buffer to ensure that the client receives each line as it's written 187 | c.Writer.Flush() 188 | fulltext = tmp_fulltext 189 | } else { 190 | if !original_request.Stream { 191 | full_response := responses.NewChatCompletion(fulltext) 192 | if err != nil { 193 | return 194 | } 195 | c.JSON(200, full_response) 196 | return 197 | } 198 | final_line := responses.StopChunk() 199 | c.Writer.WriteString("data: " + final_line.String() + "\n\n") 200 | 201 | c.String(200, "data: [DONE]\n\n") 202 | return 203 | 204 | } 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /API/go-chatgpt-api/api/chatgpt/access_token.go: -------------------------------------------------------------------------------- 1 | package chatgpt 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "strings" 9 | 10 | "github.com/PuerkitoBio/goquery" 11 | "github.com/linweiyuan/go-chatgpt-api/api" 12 | 13 | http "github.com/bogdanfinn/fhttp" 14 | ) 15 | 16 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat 17 | func (userLogin *UserLogin) GetAuthorizedUrl(csrfToken string) (string, int, error) { 18 | params := fmt.Sprintf( 19 | "callbackUrl=/&csrfToken=%s&json=true", 20 | csrfToken, 21 | ) 22 | req, err := http.NewRequest(http.MethodPost, promptLoginUrl, strings.NewReader(params)) 23 | req.Header.Set("Content-Type", api.ContentType) 24 | req.Header.Set("User-Agent", api.UserAgent) 25 | injectCookies(req) 26 | resp, err := userLogin.client.Do(req) 27 | if err != nil { 28 | return "", http.StatusInternalServerError, err 29 | } 30 | 31 | defer resp.Body.Close() 32 | if resp.StatusCode != http.StatusOK { 33 | return "", resp.StatusCode, errors.New(api.GetAuthorizedUrlErrorMessage) 34 | } 35 | 36 | responseMap := make(map[string]string) 37 | json.NewDecoder(resp.Body).Decode(&responseMap) 38 | return responseMap["url"], http.StatusOK, nil 39 | } 40 | 41 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat 42 | func (userLogin *UserLogin) GetState(authorizedUrl string) (string, int, error) { 43 | req, err := http.NewRequest(http.MethodGet, authorizedUrl, nil) 44 | req.Header.Set("Content-Type", api.ContentType) 45 | req.Header.Set("User-Agent", api.UserAgent) 46 | resp, err := userLogin.client.Do(req) 47 | if err != nil { 48 | return "", http.StatusInternalServerError, err 49 | } 50 | 51 | defer resp.Body.Close() 52 | if resp.StatusCode != http.StatusOK { 53 | return "", resp.StatusCode, errors.New(api.GetStateErrorMessage) 54 | } 55 | 56 | doc, _ := goquery.NewDocumentFromReader(resp.Body) 57 | state, _ := doc.Find("input[name=state]").Attr("value") 58 | return state, http.StatusOK, nil 59 | } 60 | 61 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat 62 | func (userLogin *UserLogin) CheckUsername(state string, username string) (int, error) { 63 | formParams := fmt.Sprintf( 64 | "state=%s&username=%s&js-available=true&webauthn-available=true&is-brave=false&webauthn-platform-available=false&action=default", 65 | state, 66 | username, 67 | ) 68 | req, _ := http.NewRequest(http.MethodPost, api.LoginUsernameUrl+state, strings.NewReader(formParams)) 69 | req.Header.Set("Content-Type", api.ContentType) 70 | req.Header.Set("User-Agent", api.UserAgent) 71 | resp, err := userLogin.client.Do(req) 72 | if err != nil { 73 | return http.StatusInternalServerError, err 74 | } 75 | 76 | defer resp.Body.Close() 77 | if resp.StatusCode != http.StatusOK { 78 | return resp.StatusCode, errors.New(api.EmailInvalidErrorMessage) 79 | } 80 | 81 | return http.StatusOK, nil 82 | } 83 | 84 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat 85 | func (userLogin *UserLogin) CheckPassword(state string, username string, password string) (string, int, error) { 86 | formParams := fmt.Sprintf( 87 | "state=%s&username=%s&password=%s&action=default", 88 | state, 89 | username, 90 | password, 91 | ) 92 | req, err := http.NewRequest(http.MethodPost, api.LoginPasswordUrl+state, strings.NewReader(formParams)) 93 | req.Header.Set("Content-Type", api.ContentType) 94 | req.Header.Set("User-Agent", api.UserAgent) 95 | userLogin.client.SetFollowRedirect(false) // make sure the cookie is injected with host chat.openai.com 96 | resp, err := userLogin.client.Do(req) 97 | if err != nil { 98 | return "", http.StatusInternalServerError, err 99 | } 100 | 101 | defer resp.Body.Close() 102 | if resp.StatusCode == http.StatusBadRequest { 103 | doc, _ := goquery.NewDocumentFromReader(resp.Body) 104 | alert := doc.Find("#prompt-alert").Text() 105 | if alert != "" { 106 | return "", resp.StatusCode, errors.New(strings.TrimSpace(alert)) 107 | } 108 | 109 | return "", resp.StatusCode, errors.New(api.EmailOrPasswordInvalidErrorMessage) 110 | } 111 | 112 | if resp.StatusCode == http.StatusFound { 113 | req, _ := http.NewRequest(http.MethodGet, api.Auth0Url+resp.Header.Get("Location"), nil) 114 | req.Header.Set("User-Agent", api.UserAgent) 115 | resp, err := userLogin.client.Do(req) 116 | if err != nil { 117 | return "", http.StatusInternalServerError, err 118 | } 119 | 120 | defer resp.Body.Close() 121 | if resp.StatusCode == http.StatusFound { 122 | location := resp.Header.Get("Location") 123 | if strings.HasPrefix(location, "/u/mfa-otp-challenge") { 124 | return "", http.StatusBadRequest, errors.New("Login with two-factor authentication enabled is not supported currently.") 125 | } 126 | 127 | req, _ := http.NewRequest(http.MethodGet, location, nil) 128 | req.Header.Set("User-Agent", api.UserAgent) 129 | injectCookies(req) // if not set this, will get 403 in some IPs 130 | resp, err := userLogin.client.Do(req) 131 | if err != nil { 132 | return "", http.StatusInternalServerError, err 133 | } 134 | 135 | defer resp.Body.Close() 136 | if resp.StatusCode == http.StatusFound { 137 | return "", http.StatusOK, nil 138 | } 139 | 140 | if resp.StatusCode == http.StatusTemporaryRedirect { 141 | errorDescription := req.URL.Query().Get("error_description") 142 | if errorDescription != "" { 143 | return "", resp.StatusCode, errors.New(errorDescription) 144 | } 145 | } 146 | 147 | return "", resp.StatusCode, errors.New(api.GetAccessTokenErrorMessage) 148 | } 149 | 150 | return "", resp.StatusCode, errors.New(api.EmailOrPasswordInvalidErrorMessage) 151 | } 152 | 153 | return "", resp.StatusCode, nil 154 | } 155 | 156 | //goland:noinspection GoUnhandledErrorResult,GoErrorStringFormat,GoUnusedParameter 157 | func (userLogin *UserLogin) GetAccessToken(code string) (string, int, error) { 158 | req, err := http.NewRequest(http.MethodGet, authSessionUrl, nil) 159 | req.Header.Set("User-Agent", api.UserAgent) 160 | injectCookies(req) 161 | resp, err := userLogin.client.Do(req) 162 | if err != nil { 163 | return "", http.StatusInternalServerError, err 164 | } 165 | 166 | defer resp.Body.Close() 167 | if resp.StatusCode != http.StatusOK { 168 | if resp.StatusCode == http.StatusTooManyRequests { 169 | responseMap := make(map[string]string) 170 | json.NewDecoder(resp.Body).Decode(&responseMap) 171 | return "", resp.StatusCode, errors.New(responseMap["detail"]) 172 | } 173 | 174 | return "", resp.StatusCode, errors.New(api.GetAccessTokenErrorMessage) 175 | } 176 | 177 | data, _ := io.ReadAll(resp.Body) 178 | return string(data), http.StatusOK, nil 179 | } 180 | -------------------------------------------------------------------------------- /API/pandora/src/pandora/turbo/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import uuid 4 | from datetime import datetime as dt 5 | 6 | 7 | class Prompt: 8 | def __init__(self, prompt_id=None, role=None, content=None, parent=None): 9 | self.prompt_id = prompt_id or str(uuid.uuid4()) 10 | self.parent_id = None 11 | self.role = role 12 | self.content = content 13 | self.children = [] 14 | self.create_time = dt.now().timestamp() 15 | 16 | if parent: 17 | self.parent_id = parent.prompt_id 18 | parent.add_child(self.prompt_id) 19 | 20 | def add_child(self, prompt_id): 21 | self.children.append(prompt_id) 22 | 23 | def get_message(self, end=True): 24 | return None 25 | 26 | def get_info(self): 27 | return { 28 | 'id': self.prompt_id, 29 | 'message': self.get_message(), 30 | 'parent': self.parent_id, 31 | 'children': self.children 32 | } 33 | 34 | 35 | class SystemPrompt(Prompt): 36 | def __init__(self, content, parent): 37 | super().__init__(role='system', content=content, parent=parent) 38 | 39 | def get_message(self, end=True): 40 | return { 41 | 'id': self.prompt_id, 42 | 'author': { 43 | 'role': self.role, 44 | 'name': None, 45 | 'metadata': {} 46 | }, 47 | 'create_time': self.create_time, 48 | 'update_time': None, 49 | 'content': { 50 | 'content_type': 'text', 51 | 'parts': [''] 52 | }, 53 | 'end_turn': True, 54 | 'weight': 1.0, 55 | 'metadata': {}, 56 | 'recipient': 'all' 57 | } 58 | 59 | 60 | class UserPrompt(Prompt): 61 | def __init__(self, prompt_id, content, parent): 62 | super().__init__(prompt_id=prompt_id, role='user', content=content, parent=parent) 63 | 64 | def get_message(self, end=True): 65 | return { 66 | 'id': self.prompt_id, 67 | 'author': { 68 | 'role': self.role, 69 | 'name': None, 70 | 'metadata': {} 71 | }, 72 | 'create_time': self.create_time, 73 | 'update_time': None, 74 | 'content': { 75 | 'content_type': 'text', 76 | 'parts': [self.content] 77 | }, 78 | 'end_turn': None, 79 | 'weight': 1.0, 80 | 'metadata': { 81 | 'timestamp_': 'absolute', 82 | 'message_type': None 83 | }, 84 | 'recipient': 'all' 85 | } 86 | 87 | 88 | class GptPrompt(Prompt): 89 | def __init__(self, parent, model): 90 | super().__init__(role='assistant', content='', parent=parent) 91 | self.model = model 92 | 93 | def append_content(self, content): 94 | self.content += content 95 | 96 | return self 97 | 98 | def get_message(self, end=True): 99 | return { 100 | 'id': self.prompt_id, 101 | 'author': { 102 | 'role': self.role, 103 | 'name': None, 104 | 'metadata': {} 105 | }, 106 | 'create_time': self.create_time, 107 | 'update_time': None, 108 | 'content': { 109 | 'content_type': 'text', 110 | 'parts': [self.content] 111 | }, 112 | 'end_turn': False if end else None, 113 | 'weight': 1.0, 114 | 'metadata': { 115 | 'message_type': None, 116 | 'model_slug': self.model, 117 | 'finish_details': { 118 | 'type': 'stop' 119 | } if end else None, 120 | 'timestamp_': 'absolute' 121 | }, 122 | 'recipient': 'all' 123 | } 124 | 125 | 126 | class Conversation: 127 | def __init__(self): 128 | self.conversation_id = str(uuid.uuid4()) 129 | self.title = 'New chat' 130 | self.create_time = dt.now().timestamp() 131 | self.current_node = None 132 | self.prompts = {} 133 | 134 | def add_prompt(self, prompt): 135 | self.prompts[prompt.prompt_id] = prompt 136 | self.current_node = prompt.prompt_id 137 | 138 | return prompt 139 | 140 | def get_prompt(self, prompt_id): 141 | return self.prompts.get(prompt_id) 142 | 143 | def get_prompts(self): 144 | return self.prompts 145 | 146 | def set_title(self, title): 147 | self.title = title 148 | 149 | def get_title(self): 150 | return self.title 151 | 152 | def get_messages_directly(self, message_id): 153 | messages = [] 154 | while True: 155 | prompt = self.get_prompt(message_id) 156 | if not prompt.parent_id: 157 | break 158 | 159 | messages.insert(0, { 160 | 'role': prompt.role, 161 | 'content': prompt.content 162 | }) 163 | message_id = prompt.parent_id 164 | 165 | return messages 166 | 167 | def get_messages(self, message_id, model): 168 | messages = [] 169 | user_prompt = None 170 | while True: 171 | prompt = self.get_prompt(message_id) 172 | if not prompt.parent_id: 173 | break 174 | 175 | if not user_prompt and isinstance(prompt, UserPrompt): 176 | user_prompt = prompt 177 | 178 | messages.insert(0, { 179 | 'role': prompt.role, 180 | 'content': prompt.content 181 | }) 182 | message_id = prompt.parent_id 183 | 184 | return user_prompt, self.add_prompt(GptPrompt(user_prompt, model)), messages 185 | 186 | def get_info(self): 187 | mapping = {} 188 | for prompt_id in self.prompts: 189 | mapping[prompt_id] = self.prompts[prompt_id].get_info() 190 | 191 | return { 192 | 'title': self.title, 193 | 'create_time': self.create_time, 194 | 'mapping': mapping, 195 | 'moderation_results': [], 196 | 'current_node': self.current_node, 197 | } 198 | 199 | 200 | class Conversations: 201 | def __init__(self): 202 | self.__data = [] 203 | 204 | def list(self, offset, limit): 205 | return len(self.__data), self.__data[offset: limit] 206 | 207 | def clear(self): 208 | self.__data = [] 209 | 210 | def delete(self, conversation): 211 | self.__data = [x for x in self.__data if conversation.conversation_id != x.conversation_id] 212 | 213 | def new(self): 214 | conversation = Conversation() 215 | self.__data.insert(0, conversation) 216 | 217 | return conversation 218 | 219 | def get(self, conversation_id): 220 | for x in self.__data: 221 | if x.conversation_id == conversation_id: 222 | return x 223 | 224 | return None 225 | 226 | def guard_get(self, conversation_id): 227 | conversation = self.get(conversation_id) 228 | if not conversation: 229 | raise Exception('Can\'t load conversation {}'.format(conversation_id)) 230 | 231 | return conversation 232 | -------------------------------------------------------------------------------- /Quick-ASK.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import threading 4 | import time 5 | from tkinter import Tk, Text, Button, StringVar, Label, Menu, Toplevel, END, Scrollbar, Entry, OptionMenu, Y, BOTH, Frame, RIGHT, LEFT 6 | 7 | def send_request(content, url, auth, model): 8 | headers = { 9 | 'Content-Type': 'application/json', 10 | 'Authorization': auth 11 | } 12 | data = { 13 | "model": model, 14 | "messages": [{"role": "user", "content": content}] 15 | } 16 | try: 17 | response = requests.post(url, headers=headers, data=json.dumps(data), timeout=150) 18 | response.raise_for_status() # 将在HTTP错误时引发异常 19 | except requests.exceptions.RequestException as err: 20 | return f"可能触发150s超时或其他原因,目前请求发送错误: {err}" 21 | 22 | try: 23 | json_response = response.json() 24 | except json.JSONDecodeError as err: 25 | return f"无法解析JSON响应: {err}" 26 | 27 | if 'choices' in json_response and json_response['choices']: 28 | return json_response['choices'][0]['message']['content'] 29 | else: 30 | return "响应中没有 'choices' 键或 'choices' 为空" 31 | 32 | 33 | 34 | def create_url_settings_window(url_var): 35 | url_settings_window = Toplevel() 36 | url_settings_window.title("设置请求URL") 37 | url_settings_window.geometry("500x200") 38 | Label(url_settings_window, text="请输入请求的URL:").pack(pady=5) 39 | Label(url_settings_window, text="默认的Endpoint端点是 /v1/chat/completions").pack(pady=5) 40 | current_url_label = Label(url_settings_window, textvariable=url_var) 41 | current_url_label.pack(pady=5) 42 | new_url_var = StringVar() 43 | url_entry = Entry(url_settings_window, textvariable=new_url_var, width=50) 44 | url_entry.pack(pady=5) 45 | Button(url_settings_window, text='提交修改', command=lambda: [url_var.set(new_url_var.get()), url_settings_window.destroy()]).pack(pady=10) 46 | 47 | 48 | def create_auth_settings_window(auth_var): 49 | auth_settings_window = Toplevel() 50 | auth_settings_window.title("设置认证信息") 51 | auth_settings_window.geometry("500x200") 52 | Label(auth_settings_window, text="请输入请求的认证信息(Authorization):").pack(pady=5) 53 | Label(auth_settings_window, text="FAKEAPI默认的认证信息是 TotallySecurePassword").pack(pady=5) 54 | current_auth_label = Label(auth_settings_window, textvariable=auth_var) 55 | current_auth_label.pack(pady=5) 56 | new_auth_var = StringVar() 57 | auth_entry = Entry(auth_settings_window, textvariable=new_auth_var, width=50) 58 | auth_entry.pack(pady=5) 59 | Button(auth_settings_window, text='提交修改', command=lambda: [auth_var.set(new_auth_var.get()), auth_settings_window.destroy()]).pack(pady=10) 60 | 61 | 62 | def create_model_settings_window(model_var): 63 | settings_window = Toplevel() 64 | settings_window.title("模型设置") 65 | settings_window.geometry("500x200") 66 | 67 | settings_window.columnconfigure(0, weight=1) # center all elements 68 | 69 | Label(settings_window, text="请选择使用的模型:").grid(row=0, padx=10, pady=10) 70 | 71 | current_model_label = Label(settings_window, textvariable=model_var) 72 | current_model_label.grid(row=1, padx=10, pady=5) 73 | 74 | model_mapping = { 75 | 'GPT-3.5': 'text-davinci-002-render-sha', 76 | 'GPT-3.5 Mobile': 'text-davinci-002-render-sha-mobile', 77 | 'GPT-4 Mobile': 'gpt-4-mobile', 78 | 'GPT-4': 'gpt-4', 79 | 'GPT-4 Browsing': 'gpt-4-browsing', 80 | 'GPT-4 Plugins': 'gpt-4-plugins', 81 | '自定义': '自定义', 82 | } 83 | 84 | # Flip the model_mapping for reverse lookup 85 | reverse_model_mapping = {v: k for k, v in model_mapping.items()} 86 | 87 | display_var = StringVar() 88 | display_var.set(reverse_model_mapping[model_var.get()]) # Load the previous setting 89 | 90 | custom_model_var = StringVar() 91 | 92 | if model_var.get() == "自定义": 93 | custom_model_var.set(model_var.get()) 94 | 95 | custom_model_entry = Entry(settings_window, textvariable=custom_model_var, width=50) 96 | custom_model_entry.grid(row=3, padx=10, pady=10) 97 | custom_model_entry.grid_remove() # Initially hide the entry box 98 | 99 | def update_entry(option): 100 | if option == '自定义': 101 | custom_model_entry.grid() 102 | model_var.set(custom_model_var.get()) 103 | else: 104 | custom_model_entry.grid_remove() 105 | model_var.set(model_mapping[option]) # Update the model name immediately 106 | 107 | model_menu = OptionMenu(settings_window, display_var, *model_mapping.keys(), command=update_entry) 108 | model_menu.grid(row=2, padx=10, pady=10) 109 | 110 | Button(settings_window, text='提交修改', command=lambda: submit_model_changes(settings_window, model_var, custom_model_var)).grid(row=4, padx=10, pady=10) 111 | 112 | 113 | def submit_model_changes(settings_window, model_var, custom_model_var): 114 | if custom_model_var.get(): 115 | model_var.set(custom_model_var.get()) 116 | settings_window.destroy() 117 | 118 | 119 | def create_window(): 120 | window = Tk() 121 | window.title("快速向GPT提问") 122 | window.geometry("600x400") # 修改一下窗口大小 123 | 124 | url_var = StringVar() 125 | url_var.set("http://127.0.0.1:31480/v1/chat/completions") 126 | auth_var = StringVar() 127 | auth_var.set("TotallySecurePassword") 128 | model_var = StringVar() 129 | model_var.set("gpt-4-mobile") 130 | 131 | title_label = Label(window, text="请输入您的问题:") 132 | title_label.pack(pady=10) 133 | entry = Text(window, width=60, height=5) 134 | entry.pack(pady=10) 135 | 136 | button_frame = Frame(window) 137 | button_frame.pack(pady=10) 138 | 139 | window.button = Button(button_frame, text='提问', command=lambda: on_button_click(window, entry, url_var.get(), auth_var.get(), model_var.get())) 140 | window.button.pack(pady=10, side=LEFT) 141 | 142 | window.time_label = Label(button_frame, text="请求耗时:") 143 | window.time_label.pack(pady=10, side=RIGHT) 144 | 145 | result_frame = Frame(window) 146 | result_frame.pack(pady=10, fill=BOTH, expand=True) 147 | 148 | scrollbar = Scrollbar(result_frame) 149 | scrollbar.pack(side=RIGHT, fill=Y) 150 | 151 | window.result_text = Text(result_frame, wrap="word", yscrollcommand=scrollbar.set) 152 | window.result_text.pack(side=LEFT, fill=BOTH, expand=True) 153 | scrollbar.config(command=window.result_text.yview) 154 | 155 | menubar = Menu(window) 156 | settings_menu = Menu(menubar, tearoff=0) 157 | settings_menu.add_command(label="更改请求URL", command=lambda: create_url_settings_window(url_var)) 158 | settings_menu.add_command(label="更改认证信息", command=lambda: create_auth_settings_window(auth_var)) 159 | settings_menu.add_command(label="自定义模型", command=lambda: create_model_settings_window(model_var)) 160 | menubar.add_cascade(label="设置", menu=settings_menu) 161 | window.config(menu=menubar) 162 | 163 | window.mainloop() 164 | 165 | 166 | 167 | def on_button_click(window, entry, url, auth, model): 168 | content = entry.get("1.0", END).strip() # 获取文本框的全部内容 169 | 170 | def update_result_text(response): 171 | window.result_text.delete("1.0", END) 172 | window.result_text.insert(END, response) 173 | 174 | def send_request_thread(): 175 | start_time = time.time() 176 | response = send_request(content, url, auth, model) 177 | formatted_response = "GPT: " + response 178 | window.after(0, update_result_text, formatted_response) 179 | window.button['text'] = "提问" # change the button text back when the request finishes 180 | 181 | # stop the timer 182 | window.is_requesting = False 183 | 184 | def timer_thread(): 185 | start_time = time.time() 186 | while window.is_requesting: 187 | elapsed_time = time.time() - start_time 188 | window.time_label['text'] = "请求耗时:{:.3f}s".format(elapsed_time) 189 | time.sleep(0.1) # update every 100ms 190 | 191 | # indicate that a request is in progress 192 | window.is_requesting = True 193 | window.button['text'] = "提问中..." 194 | 195 | threading.Thread(target=send_request_thread).start() 196 | threading.Thread(target=timer_thread).start() 197 | 198 | 199 | if __name__ == "__main__": 200 | create_window() 201 | --------------------------------------------------------------------------------