From 90d675e82ac6d79422cbfcd61d556e8849181033 Mon Sep 17 00:00:00 2001 From: Antonio Cheong Date: Wed, 12 Apr 2023 10:31:44 +0800 Subject: [PATCH] Docker (#2) Co-authored-by: huangzt <378627710@qq.com> --- .github/workflows/build_docker.yml | 41 +++++++++++++++++++++++++ Dockerfile | 26 ++++++++++++++++ README.md | 49 ++++++++++++++++++++++++++++++ docker-compose.yml | 18 +++++++++++ handlers.go | 15 ++++++++- internal/chatgpt/request.go | 18 +++++++++-- 6 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/build_docker.yml create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 docker-compose.yml diff --git a/.github/workflows/build_docker.yml b/.github/workflows/build_docker.yml new file mode 100644 index 0000000..e0eb3c6 --- /dev/null +++ b/.github/workflows/build_docker.yml @@ -0,0 +1,41 @@ +name: build_docker + +on: + push: + branches: [master] + release: + types: [created] # 表示在创建新的 Release 时触发 + +jobs: + build_docker: + name: Build docker + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - run: | + echo "本次构建的版本为:${GITHUB_REF_NAME} (但是这个变量目前上下文中无法获取到)" + echo 本次构建的版本为:${{ github.ref_name }} + env + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push + id: docker_build + uses: docker/build-push-action@v4 + with: + context: . + push: true + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + tags: | + ${{ secrets.DOCKERHUB_USERNAME }}/chatgpt-to-api:${{ github.ref_name }} + ${{ secrets.DOCKERHUB_USERNAME }}/chatgpt-to-api:latest diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..525e696 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# 设置基础镜像为 Golang 官方镜像 +FROM golang:1.20.3-alpine + +# 设置环境变量 +# Reverse Proxy - Available on accessToken +# Default: https://bypass.churchless.tech/api/conversation +ENV API_REVERSE_PROXY 'https://bypass.churchless.tech/api/conversation' +ENV SERVER_HOST '0.0.0.0' + +# 设置工作目录为 /app +WORKDIR /app + +# 将本地应用程序复制到容器中 +COPY . . + +# 下载应用程序所需的依赖项 +RUN go mod download + +# 构建应用程序二进制文件 +RUN go build -o app + +# 暴露应用程序运行的端口 +EXPOSE 8080 + +# 启动应用程序 +CMD ["./app"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..dd560ad --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# ChatGPT-to-API +Create a fake API using ChatGPT's website + +**API endpoint: http://127.0.0.1:8080/v1/chat/completions.** + +**When calling the API, you must include the authorization parameter in the request header: `'Authorization':'Bearer ' + accessToken`.** + +**You can get your accessToken from the following link: [ChatGPT](https://chat.openai.com/api/auth/session)** + +**This API can be used with the project [BetterChatGPT](https://github.com/huangzt/BetterChatGPT)** + +## Docker build & Run + +```bash +docker build -t chatgpt-to-api . + +# Running the API +docker run --name chatgpttoapi -d -p 127.0.0.1:8080:8080 chatgpt-to-api + +# API path +http://127.0.0.1:8080/v1/chat/completions + +``` + +## Docker compose + +[Hub address](https://hub.docker.com/repository/docker/acheong08/chatgpt-to-api/general) + +```yml +version: '3' + +services: + app: + image: acheong08/chatgpt-to-api # Use latest tag + container_name: chatgpttoapi + restart: unless-stopped + ports: + - '8080:8080' + environment: + SERVER_HOST: 0.0.0.0 + SERVER_PORT: 8080 + ADMIN_PASSWORD: TotallySecurePassword + # Reverse Proxy - Available on accessToken + API_REVERSE_PROXY: https://bypass.churchless.tech/api/conversation + # 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. + # You can get your PUID for Plus account from the following link: https://chat.openai.com/api/auth/session. + PUID: xxx + +``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c410aad --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3' + +services: + app: + image: acheong08/chatgpt-to-api # 总是使用latest,更新时重新pull该tag镜像即可 + container_name: chatgpttoapi + restart: unless-stopped + ports: + - '8080:8080' + environment: + SERVER_HOST: 0.0.0.0 + SERVER_PORT: 8080 + ADMIN_PASSWORD: TotallySecurePassword + # Reverse Proxy - Available on accessToken + API_REVERSE_PROXY: https://bypass.churchless.tech/api/conversation + # 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. + # You can get your PUID for Plus account from the following link: https://chat.openai.com/api/auth/session. + PUID: xxx diff --git a/handlers.go b/handlers.go index 93aa7b6..765e89c 100644 --- a/handlers.go +++ b/handlers.go @@ -74,7 +74,20 @@ func nightmare(c *gin.Context) { // Convert the chat request to a ChatGPT request chatgpt_request := chatgpt.ConvertAPIRequest(chat_request) // c.JSON(200, chatgpt_request) - response, err := chatgpt.SendRequest(chatgpt_request, &PUID, ACCESS_TOKENS.GetToken()) + + authHeader := c.GetHeader("Authorization") + token := ACCESS_TOKENS.GetToken() + if authHeader != "" { + // 如果Authorization头不为空,则提取其中的token + // 首先将Bearer前缀替换为空字符串 + customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1) + if customAccessToken != "" { + token = customAccessToken + println("customAccessToken set:" + customAccessToken) + } + } + + response, err := chatgpt.SendRequest(chatgpt_request, &PUID, token) if err != nil { c.JSON(500, gin.H{ "error": "error sending request", diff --git a/internal/chatgpt/request.go b/internal/chatgpt/request.go index 8ac97b9..5fc7c6d 100644 --- a/internal/chatgpt/request.go +++ b/internal/chatgpt/request.go @@ -3,6 +3,7 @@ package chatgpt import ( "bytes" "encoding/json" + "os" typings "freechatgpt/internal/typings" @@ -18,17 +19,30 @@ var ( tls_client.WithNotFollowRedirects(), tls_client.WithCookieJar(jar), // create cookieJar instance and pass it as argument } - client, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) + client, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) + http_proxy = os.Getenv("http_proxy") + API_REVERSE_PROXY = os.Getenv("API_REVERSE_PROXY") ) func SendRequest(message typings.ChatGPTRequest, puid *string, access_token string) (*http.Response, error) { + if http_proxy != "" { + client.SetProxy(http_proxy) + println("Proxy set:" + http_proxy) + } + + apiUrl := "https://chat.openai.com/backend-api/conversation" + if API_REVERSE_PROXY != "" { + apiUrl = API_REVERSE_PROXY + println("API_REVERSE_PROXY set:" + API_REVERSE_PROXY) + } + // JSONify the body and add it to the request body_json, err := json.Marshal(message) if err != nil { return &http.Response{}, err } - request, err := http.NewRequest(http.MethodPost, "https://chat.openai.com/backend-api/conversation", bytes.NewBuffer(body_json)) + request, err := http.NewRequest(http.MethodPost, apiUrl, bytes.NewBuffer(body_json)) if err != nil { return &http.Response{}, err }