diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md
new file mode 100644
index 0000000000000000000000000000000000000000..6375290f61ffdb9c45e35f41374b4a2b6ecca373
--- /dev/null
+++ b/.chglog/CHANGELOG.tpl.md
@@ -0,0 +1,42 @@
+{{ range .Versions }}
+
+## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
+{{ range .CommitGroups -}}
+### {{ .Title }}
+{{ range .Commits -}}
+- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
+{{ end }}
+{{ end -}}
+
+{{- if .RevertCommits -}}
+### Reverts
+{{ range .RevertCommits -}}
+- {{ .Revert.Header }}
+{{ end }}
+{{ end -}}
+
+{{- if .MergeCommits -}}
+### Pull Requests
+{{ range .MergeCommits -}}
+- {{ .Header }}
+{{ end }}
+{{ end -}}
+
+{{- if .NoteGroups -}}
+{{ range .NoteGroups -}}
+### {{ .Title }}
+{{ range .Notes }}
+{{ .Body }}
+{{ end }}
+{{ end -}}
+{{ end -}}
+{{ end -}}
+
+{{- if .Versions }}
+[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
+{{ range .Versions -}}
+{{ if .Tag.Previous -}}
+[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
+{{ end -}}
+{{ end -}}
+{{ end -}}
\ No newline at end of file
diff --git a/.chglog/config.yml b/.chglog/config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0bc4b1fc36c7f2e9331c0bc9d35dfa1d03ec269c
--- /dev/null
+++ b/.chglog/config.yml
@@ -0,0 +1,28 @@
+style: github
+template: CHANGELOG.tpl.md
+info:
+ title: CHANGELOG
+ repository_url: https://github.com/aurorax-neo/free-gpt3.5-2api
+options:
+ commits:
+ # filters:
+ # Type:
+ # - feat
+ # - fix
+ # - perf
+ # - refactor
+ commit_groups:
+ # title_maps:
+ # feat: Features
+ # fix: Bug Fixes
+ # perf: Performance Improvements
+ # refactor: Code Refactoring
+ header:
+ pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$"
+ pattern_maps:
+ - Type
+ - Scope
+ - Subject
+ notes:
+ keywords:
+ - BREAKING CHANGE
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 9345012e258b899cb78ba1e88801a34fc5a2367e..0000000000000000000000000000000000000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-*.html linguist-language=Go
diff --git a/.github/workflows/Auto Release.yml b/.github/workflows/Auto Release.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9c10051b3f89830b978c59bac4059f0cf57cde79
--- /dev/null
+++ b/.github/workflows/Auto Release.yml
@@ -0,0 +1,89 @@
+name: Auto Release
+
+on:
+ push:
+ tags:
+ - 'release-v*'
+
+env:
+ APP_NAME: free-gpt3.5-2api
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: 'stable'
+ check-latest: true
+
+ - name: Build Binary
+ run: |
+ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o ${{ env.APP_NAME }} -a -ldflags '-s -w -extldflags "-static"' . && rm -rf artifact && mkdir -p artifact && cp ${{ env.APP_NAME }} artifact/${{ env.APP_NAME }} && cd artifact && tar -czvf ../${{ env.APP_NAME }}-linux-amd64.tar.gz * && cd ..
+ GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o ${{ env.APP_NAME }} -a -ldflags '-s -w -extldflags "-static"' . && rm -rf artifact && mkdir -p artifact && cp ${{ env.APP_NAME }} artifact/${{ env.APP_NAME }} && cd artifact && tar -czvf ../${{ env.APP_NAME }}-darwin-amd64.tar.gz * && cd ..
+ GOOS=freebsd GOARCH=amd64 CGO_ENABLED=0 go build -o ${{ env.APP_NAME }} -a -ldflags '-s -w -extldflags "-static"' . && rm -rf artifact && mkdir -p artifact && cp ${{ env.APP_NAME }} artifact/${{ env.APP_NAME }} && cd artifact && tar -czvf ../${{ env.APP_NAME }}-freebsd-amd64.tar.gz * && cd ..
+ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o ${{ env.APP_NAME }} -a -ldflags '-s -w -extldflags "-static"' . && rm -rf artifact && mkdir -p artifact && cp ${{ env.APP_NAME }} artifact/${{ env.APP_NAME }}.exe && cd artifact && tar -czvf ../${{ env.APP_NAME }}-windows-amd64.tar.gz * && cd ..
+
+ - name: Upload Artifact
+ uses: actions/upload-artifact@main
+ with:
+ name: ${{ env.APP_NAME }}-pre-built.zip
+ path: |
+ ${{ env.APP_NAME }}-windows-amd64.tar.gz
+ ${{ env.APP_NAME }}-linux-amd64.tar.gz
+ ${{ env.APP_NAME }}-darwin-amd64.tar.gz
+ ${{ env.APP_NAME }}-freebsd-amd64.tar.gz
+
+ - name: Get Release Name
+ shell: bash
+ id: grn
+ run: echo "tag=$(echo $GITHUB_REF | sed 's|refs/tags/||')" >> $GITHUB_OUTPUT
+
+ - name: Generate Changelog
+ id: changelog
+ run: |
+ export PATH=$PATH:$HOME/go/bin
+ go install github.com/git-chglog/git-chglog/cmd/git-chglog@latest
+ git-chglog -o CHANGELOG.md ${{ steps.grn.outputs.tag }}
+
+ - name: Release
+ id: release
+ uses: softprops/action-gh-release@v2
+ if: startsWith(github.ref, 'refs/tags/')
+ env:
+ # GITHUB_TOKEN
+ GITHUB_TOKEN: ${{ secrets.GB_TOKEN }}
+ with:
+ # tag_name: 使用 tag
+ tag_name: ${{ github.ref }}
+ # release_name: 使用 tag
+ name: ${{ steps.grn.outputs.tag }}
+ # body: 使用 changelog
+ body_path: CHANGELOG.md
+ # 草稿
+ draft: false
+ # 预发布
+ prerelease: false
+ # 自动生成 release notes
+ generate_release_notes: true
+ # 上传文件
+ files: |
+ ${{ env.APP_NAME }}-linux-amd64.tar.gz
+ ${{ env.APP_NAME }}-windows-amd64.tar.gz
+ ${{ env.APP_NAME }}-darwin-amd64.tar.gz
+ ${{ env.APP_NAME }}-freebsd-amd64.tar.gz
+
+ - name: Delete Workflow Runs
+ uses: Mattraks/delete-workflow-runs@v2
+ with:
+ token: ${{ secrets.GB_TOKEN }}
+ repository: ${{ github.repository }}
+ retain_days: 1
+ keep_minimum_runs: 8
\ No newline at end of file
diff --git a/.github/workflows/Build Docker Image.yml b/.github/workflows/Build Docker Image.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a40045ca687da43a4d01c0edfb51d511ab009a09
--- /dev/null
+++ b/.github/workflows/Build Docker Image.yml
@@ -0,0 +1,67 @@
+name: Build Docker Image
+
+on:
+ push:
+ tags:
+ - 'release-v*'
+ workflow_dispatch:
+
+env:
+ GHCR_REPO: ghcr.io/aurorax-neo/free-gpt3.5-2api
+
+jobs:
+ main:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Get Docker Image Tag
+ shell: bash
+ id: get_docker_image_tag
+ run: echo "tag=$(echo $GITHUB_REF | sed 's|refs/tags/release-v||')" >> $GITHUB_OUTPUT
+
+ - name: Set Up QEMU
+ uses: docker/setup-qemu-action@v3
+
+ - name: Set Up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Login To GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GB_TOKEN }}
+
+ - name: Cache Docker Layers
+ uses: actions/cache@v4
+ with:
+ path: /tmp/.buildx-cache
+ key: "${{ runner.os }}-buildx-${{ github.sha }}"
+ restore-keys: |
+ ${{ runner.os }}-buildx-
+
+ - name: Build Docker Image And Push To GHCR
+ uses: docker/build-push-action@v5
+ with:
+ push: true
+ context: .
+ platforms: linux/amd64,linux/arm64
+ file: Dockerfile
+ tags: |
+ ${{ env.GHCR_REPO }}:latest
+ ${{ env.GHCR_REPO }}:${{ steps.get_docker_image_tag.outputs.tag }}
+ ${{ env.GHCR_REPO }}:${{ github.sha }}
+ cache-from: type=local,src=/tmp/.buildx-cache
+ cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
+
+ - name: Delete Workflow Runs
+ uses: Mattraks/delete-workflow-runs@v2
+ with:
+ token: ${{ secrets.GB_TOKEN }}
+ repository: ${{ github.repository }}
+ retain_days: 1
+ keep_minimum_runs: 8
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a9d06f8848e799707645633d5b2783de52397cf5..bc9ddb2fb07ed1babe95a6299513d7bbbed3f3c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,185 @@
-tools/authenticator/100-ACCOUNTS_COMPILED.txt
-tools/authenticator/accounts.txt
-tools/authenticator/proxies.txt
-tools/authenticator/authenticated_accounts.txt
-tools/authenticator/access_tokens.txt
-*.txt
-aurora
-chatgpttoapi
-tools/authenticator/.proxies.txt.swp
-.env
-*.har
-.idea/
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Go template
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
+
+### GoLand template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
/logs/
+/.env
/target/
-/bin/
+/CHANGELOG.md
diff --git a/Dockerfile b/Dockerfile
index 64e0b01281731f117aa519d4c78bc1f8ca5169f8..b6ae84c81107f21fb62e5bbe9960f52492324b16 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,30 +1,21 @@
-# 使用 Go 1.21 官方镜像作为构建环境
FROM golang:1.21 AS builder
-# 禁用 CGO
ENV CGO_ENABLED=0
-# 设置工作目录
WORKDIR /app
-# 复制 go.mod 和 go.sum 并下载依赖
COPY go.mod go.sum ./
RUN go mod download
-# 复制源代码并构建应用
COPY . .
-RUN go build -ldflags "-s -w" -o /app/duck2api .
+RUN go build -o /app/free-gpt3.5-2api .
-# 使用 Alpine Linux 作为最终镜像
FROM alpine:latest
-# 设置工作目录
WORKDIR /app
-# 从构建阶段复制编译好的应用和资源
-COPY --from=builder /app/duck2api /app/duck2api
+COPY --from=builder /app/free-gpt3.5-2api /app/free-gpt3.5-2api
-# 暴露端口
-EXPOSE 8080
+EXPOSE 3040
-CMD ["/app/duck2api"]
+CMD [ "./free-gpt3.5-2api" ]
diff --git a/FreeGpt35/FreeGpt35.go b/FreeGpt35/FreeGpt35.go
new file mode 100644
index 0000000000000000000000000000000000000000..790720dd1ffa41c102ee3ee470974eba0480f2b4
--- /dev/null
+++ b/FreeGpt35/FreeGpt35.go
@@ -0,0 +1,231 @@
+package FreeGpt35
+
+import (
+ "encoding/json"
+ "fmt"
+ ProofWork2 "free-gpt3.5-2api/ProofWork"
+ "free-gpt3.5-2api/ProxyPool"
+ "free-gpt3.5-2api/RequestClient"
+ "free-gpt3.5-2api/common"
+ "free-gpt3.5-2api/config"
+ "free-gpt3.5-2api/constant"
+ "github.com/aurorax-neo/go-logger"
+ fhttp "github.com/bogdanfinn/fhttp"
+ "github.com/google/uuid"
+ "io"
+)
+
+var (
+ BaseUrl = config.BaseUrl
+ ChatUrl = BaseUrl + "/backend-anon/conversation"
+ AuthUrl = BaseUrl + "/backend-anon/sentinel/chat-requirements"
+ OfficialBaseURLS = []string{"https://chat.openai.com", "https://chatgpt.com"}
+)
+
+// NewFreeAuthType 定义一个枚举类型
+type NewFreeAuthType int
+
+const (
+ NewFreeAuthNormal NewFreeAuthType = 0 //正常获取
+ NewFreeAuthRefresh NewFreeAuthType = 1 // 刷新获取
+)
+
+type FreeGpt35 struct {
+ RequestClient RequestClient.RequestClient
+ Proxy *ProxyPool.Proxy
+ MaxUseCount int
+ ExpiresAt int64
+ FreeAuth *freeAuth
+ Ua string
+ Cookies []*fhttp.Cookie
+}
+
+type freeAuth struct {
+ OaiDeviceId string `json:"-"`
+ Persona string `json:"persona"`
+ Arkose arkose `json:"arkose"`
+ Turnstile turnstile `json:"turnstile"`
+ ProofWork ProofWork2.ProofWork `json:"proofofwork"`
+ Token string `json:"token"`
+}
+
+type arkose struct {
+ Required bool `json:"required"`
+ Dx string `json:"dx"`
+}
+
+type turnstile struct {
+ Required bool `json:"required"`
+}
+
+// NewFreeGpt35 创建 FreeGpt35 实例 0 无论网络是否被标记限制都获取 1 在网络未标记时才能获取
+func NewFreeGpt35(newType NewFreeAuthType, maxUseCount int, expiresAt int64) *FreeGpt35 {
+ // 创建 FreeGpt35 实例
+ freeGpt35 := &FreeGpt35{
+ MaxUseCount: maxUseCount,
+ ExpiresAt: expiresAt,
+ FreeAuth: &freeAuth{},
+ }
+ // 获取请求客户端
+ err := freeGpt35.newRequestClient()
+ if err != nil {
+ logger.Logger.Debug(err.Error())
+ return nil
+ }
+ // 获取并设置代理
+ err = freeGpt35.getProxy(newType)
+ if err != nil {
+ logger.Logger.Debug(err.Error())
+ return nil
+ }
+ // 获取cookies
+ if common.IsStrInArray(BaseUrl, OfficialBaseURLS) {
+ err = freeGpt35.getCookies()
+ if err != nil {
+ logger.Logger.Debug(err.Error())
+ return nil
+ }
+ }
+ // 获取 FreeAuth
+ err = freeGpt35.newFreeAuth(newType)
+ if err != nil {
+ logger.Logger.Debug(err.Error())
+ return nil
+ }
+ return freeGpt35
+}
+
+func (FG *FreeGpt35) NewRequest(method, url string, body io.Reader) (*fhttp.Request, error) {
+ request, err := RequestClient.NewRequest(method, url, body)
+ if err != nil {
+ return nil, err
+ }
+ request.Header.Set("accept", "*/*")
+ request.Header.Set("accept-language", "zh-CN,zh;q=0.9,zh-Hans;q=0.8,en;q=0.7")
+ for _, cookie := range FG.Cookies {
+ request.AddCookie(cookie)
+ }
+ request.Header.Set("oai-language", "en-US")
+ request.Header.Set("origin", common.GetOrigin(url))
+ request.Header.Set("referer", common.GetOrigin(url))
+ request.Header.Set("sec-ch-ua", `"Microsoft Edge";v="123", "Not:A-Brand";v="8", "Chromium";v="123"`)
+ request.Header.Set("sec-ch-ua-mobile", "?0")
+ request.Header.Set("sec-ch-ua-platform", `"Windows"`)
+ request.Header.Set("sec-fetch-dest", "empty")
+ request.Header.Set("sec-fetch-mode", "cors")
+ request.Header.Set("sec-fetch-site", "same-origin")
+ request.Header.Set("user-agent", FG.Ua)
+ return request, nil
+}
+
+func (FG *FreeGpt35) newRequestClient() error {
+ // 请求客户端
+ FG.RequestClient = RequestClient.NewTlsClient(300, constant.ClientProfile)
+ if FG.RequestClient == nil {
+ errStr := fmt.Sprint("RequestClient is nil")
+ logger.Logger.Debug(errStr)
+ return fmt.Errorf(errStr)
+ }
+ return nil
+}
+
+func (FG *FreeGpt35) getProxy(newFreeAuthType NewFreeAuthType) error {
+ // 获取代理池
+ ProxyPoolInstance := ProxyPool.GetProxyPoolInstance()
+ // 获取代理
+ FG.Proxy = ProxyPoolInstance.GetProxy()
+ // 判断代理是否可用
+ if FG.Proxy.CanUseAt > common.GetTimestampSecond(0) && newFreeAuthType == NewFreeAuthRefresh {
+ errStr := fmt.Sprint(FG.Proxy.Link, ": Proxy restricted, Reuse at ", FG.Proxy.CanUseAt)
+ return fmt.Errorf(errStr)
+ }
+ // Ua
+ FG.Ua = FG.Proxy.Ua
+ // 补全cookies
+ FG.Cookies = append(FG.Cookies, FG.Proxy.Cookies...)
+ // 设置代理
+ err := FG.RequestClient.SetProxy(FG.Proxy.Link.String())
+ if err != nil {
+ errStr := fmt.Sprint("SetProxy Error: ", err)
+ logger.Logger.Debug(errStr)
+ }
+ return nil
+}
+
+func (FG *FreeGpt35) getCookies() error {
+ // 获取cookies
+ request, err := FG.NewRequest("GET", fmt.Sprint(BaseUrl, "/?oai-dm=1"), nil)
+ if err != nil {
+ return err
+ }
+ // 设置请求头
+ request.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
+ // 发送 GET 请求
+ response, err := FG.RequestClient.Do(request)
+ if err != nil {
+ return err
+ }
+ defer func(Body io.ReadCloser) {
+ _ = Body.Close()
+ }(response.Body)
+ if response.StatusCode != 200 {
+ return fmt.Errorf("StatusCode: %d", response.StatusCode)
+ }
+ // 获取cookies
+ cookies := response.Cookies()
+ for i, cookie := range cookies {
+ if cookie.Name == "oai-did" {
+ FG.FreeAuth.OaiDeviceId = cookie.Value
+ cookies = append(cookies[:i], cookies[i+1:]...)
+ }
+ if cookie.Name == "__Secure-next-auth.callback-url" {
+ cookie.Value = BaseUrl
+ }
+ }
+ // 设置cookies
+ FG.Cookies = append(FG.Cookies, cookies...)
+ return nil
+}
+
+func (FG *FreeGpt35) newFreeAuth(newFreeAuthType NewFreeAuthType) error {
+ // 生成新的设备 ID
+ if FG.FreeAuth.OaiDeviceId == "" {
+ FG.FreeAuth.OaiDeviceId = uuid.New().String()
+ }
+ // 创建请求
+ request, err := FG.NewRequest("POST", AuthUrl, nil)
+ if err != nil {
+ return err
+ }
+ // 设置请求头
+ request.Header.Set("Content-Type", "application/json")
+ request.Header.Set("oai-device-id", FG.FreeAuth.OaiDeviceId)
+ // 发送 POST 请求
+ response, err := FG.RequestClient.Do(request)
+ if err != nil {
+ return err
+ }
+ if response.StatusCode != 200 {
+ logger.Logger.Debug(fmt.Sprint("newFreeAuth: StatusCode: ", response.StatusCode))
+ if (response.StatusCode == 429 || response.StatusCode == 403) && newFreeAuthType == NewFreeAuthRefresh {
+ FG.Proxy.CanUseAt = common.GetTimestampSecond(300)
+ logger.Logger.Debug(fmt.Sprint("newFreeAuth: Proxy(", FG.Proxy.Link, ")restricted, Reuse at ", FG.Proxy.CanUseAt))
+ }
+ return fmt.Errorf("StatusCode: %d", response.StatusCode)
+ } else if newFreeAuthType == 0 {
+ // 成功后更新代理的可用时间
+ FG.Proxy.CanUseAt = common.GetTimestampSecond(0)
+ logger.Logger.Debug(fmt.Sprint("newFreeAuth: Proxy(", FG.Proxy.Link, ")Reuse at ", FG.Proxy.CanUseAt))
+ }
+ defer func(Body io.ReadCloser) {
+ _ = Body.Close()
+ }(response.Body)
+ if err := json.NewDecoder(response.Body).Decode(&FG.FreeAuth); err != nil {
+ return err
+ }
+ // ProofWork
+ if FG.FreeAuth.ProofWork.Required {
+ FG.FreeAuth.ProofWork.Ospt = ProofWork2.CalcProofToken(FG.FreeAuth.ProofWork.Seed, FG.FreeAuth.ProofWork.Difficulty, request.Header.Get("User-Agent"))
+ }
+ return nil
+}
diff --git a/FreeGpt35Pool/FreeGpt35Pool.go b/FreeGpt35Pool/FreeGpt35Pool.go
new file mode 100644
index 0000000000000000000000000000000000000000..8d5c27d271f406e33fc9ec6dbcd2d002f9b1b9f7
--- /dev/null
+++ b/FreeGpt35Pool/FreeGpt35Pool.go
@@ -0,0 +1,128 @@
+package FreeGpt35Pool
+
+import (
+ "fmt"
+ "free-gpt3.5-2api/FreeGpt35"
+ "free-gpt3.5-2api/common"
+ "free-gpt3.5-2api/config"
+ "free-gpt3.5-2api/queue"
+ "github.com/aurorax-neo/go-logger"
+ "sync"
+ "time"
+)
+
+var (
+ instance *FreeGpt35Pool
+ once sync.Once
+)
+
+type FreeGpt35Pool struct {
+ queue *queue.Queue
+ capacity int // 队列容量
+}
+
+func newFreeGpt35Pool(capacity int) *FreeGpt35Pool {
+ return &FreeGpt35Pool{
+ queue: queue.New(),
+ capacity: capacity,
+ }
+}
+
+func GetFreeGpt35PoolInstance() *FreeGpt35Pool {
+ once.Do(func() {
+ logger.Logger.Info(fmt.Sprint("Init FreeGpt35Pool..."))
+ // 初始化 FreeGpt35Pool
+ instance = newFreeGpt35Pool(config.PoolMaxCount)
+ // 定时刷新 FreeGpt35Pool
+ instance.refreshFreeGpt35Pool(time.Millisecond * 256)
+ //
+ logger.Logger.Info(fmt.Sprint("Init FreeGpt35Pool Success", ", PoolMaxCount: ", config.PoolMaxCount, ", AuthExpirationDate: ", config.AuthED))
+ })
+ return instance
+}
+
+func (G *FreeGpt35Pool) refreshFreeGpt35Pool(sleep time.Duration) {
+ // 检测 FreeGpt35Pool 是否已满
+ common.AsyncLoopTask(sleep, func() {
+ // 判断 FreeGpt35Pool 是否已满
+ if G.IsFull() {
+ return
+ }
+ // 获取新 FreeGpt35 实例
+ gpt35 := FreeGpt35.NewFreeGpt35(FreeGpt35.NewFreeAuthRefresh, 1, common.GetTimestampSecond(config.AuthED))
+ // 判断 FreeGpt35 实例是否有效
+ if G.isLiveGpt35(gpt35) {
+ // 入队新 FreeGpt35 实例
+ G.AddFreeGpt35(gpt35)
+ }
+ })
+ // 检测并移除无效 FreeGpt35 实例
+ common.AsyncLoopTask(sleep, func() {
+ // 遍历队列中的所有元素
+ G.queue.Traverse(func(n *queue.Node) {
+ // 判断是否为无效 FreeGpt35 实例
+ if !G.isLiveGpt35(n.Value.(*FreeGpt35.FreeGpt35)) {
+ // 移除无效 FreeGpt35 实例
+ G.queue.Remove(n)
+ }
+ })
+ })
+}
+
+func (G *FreeGpt35Pool) isLiveGpt35(gpt35 *FreeGpt35.FreeGpt35) bool {
+ //判断是否为空
+ if gpt35 == nil ||
+ gpt35.MaxUseCount <= 0 || //无可用次数
+ gpt35.ExpiresAt <= common.GetTimestampSecond(0) {
+ return false
+ }
+ return true
+}
+
+func (G *FreeGpt35Pool) GetFreeGpt35(retry int) *FreeGpt35.FreeGpt35 {
+ // 获取 FreeGpt35 实例
+ n := G.queue.Peek()
+ if n != nil {
+ gpt35 := n.Value.(*FreeGpt35.FreeGpt35)
+ if G.isLiveGpt35(gpt35) { //有缓存
+ // 深拷贝
+ gpt35_ := common.DeepCopyStruct(gpt35).(*FreeGpt35.FreeGpt35)
+ // 减少 FreeGpt35 实例的最大使用次数
+ gpt35.MaxUseCount--
+ // 判断 FreeGpt35 实例是否有效 无效则移除
+ if !G.isLiveGpt35(gpt35) {
+ G.queue.Dequeue()
+ }
+ return gpt35_
+ } else if retry > 0 {
+ time.Sleep(time.Millisecond * 128)
+ return G.GetFreeGpt35(retry - 1)
+ }
+ }
+ // 缓存内无可用 FreeGpt35 实例,返回新 FreeGpt35 实例
+ return FreeGpt35.NewFreeGpt35(FreeGpt35.NewFreeAuthNormal, 1, common.GetTimestampSecond(config.AuthED))
+}
+
+// GetSize 获取队列当前元素个数
+func (G *FreeGpt35Pool) GetSize() int {
+ return G.queue.Len()
+}
+
+// GetCapacity 获取队列容量
+func (G *FreeGpt35Pool) GetCapacity() int {
+ return G.capacity
+}
+
+// IsFull 检查队列是否已满
+func (G *FreeGpt35Pool) IsFull() bool {
+ return G.GetSize() == G.capacity
+}
+
+// AddFreeGpt35 入队
+func (G *FreeGpt35Pool) AddFreeGpt35(v *FreeGpt35.FreeGpt35) bool {
+ if G.IsFull() || v == nil {
+ return false
+ }
+ G.queue.Enqueue(v)
+ return true
+}
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index d322e6dbf9a9471b0de438b2a539c4c9f4752a55..0000000000000000000000000000000000000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2024 aurora-develop
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/Procfile b/Procfile
deleted file mode 100644
index ae76712ac18a1eac1744a2e4bd74b805e45d9286..0000000000000000000000000000000000000000
--- a/Procfile
+++ /dev/null
@@ -1 +0,0 @@
-web: aurora
\ No newline at end of file
diff --git a/ProofWork/ProofWork.go b/ProofWork/ProofWork.go
new file mode 100644
index 0000000000000000000000000000000000000000..12d5cc363e1630f22cc3b3825b3abc8ea23b03e8
--- /dev/null
+++ b/ProofWork/ProofWork.go
@@ -0,0 +1,55 @@
+package ProofWork
+
+import (
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/json"
+ "golang.org/x/crypto/sha3"
+ "math/rand"
+ "time"
+)
+
+var (
+ numberCollisions = 100000
+ cores = []int{8, 12, 16, 24}
+ screens = []int{3000, 4000, 6000}
+ timeLayout = "Mon Jan 2 2006 15:04:05"
+)
+
+type ProofWork struct {
+ Difficulty string `json:"difficulty,omitempty"`
+ Required bool `json:"required"`
+ Seed string `json:"seed,omitempty"`
+ Ospt string `json:"-"`
+}
+
+func getParseTime() string {
+ now := time.Now()
+ return now.Format(timeLayout) + " GMT" + now.Format("-0700 MST (MST)")
+}
+
+func getConfig(userAgent string) []interface{} {
+ rand.New(rand.NewSource(time.Now().UnixNano()))
+ core := cores[rand.Intn(4)]
+ rand.New(rand.NewSource(time.Now().UnixNano()))
+ screen := screens[rand.Intn(3)]
+ return []interface{}{core + screen, getParseTime(), int64(4294705152), 0, userAgent}
+
+}
+
+func CalcProofToken(seed string, diff string, userAgent string) string {
+ config := getConfig(userAgent)
+ hasher := sha3.New512()
+ for i := 0; i < numberCollisions; i++ {
+ config[3] = i
+ jsonStr, _ := json.Marshal(config)
+ base := base64.StdEncoding.EncodeToString(jsonStr)
+ hasher.Write([]byte(seed + base))
+ hash := hasher.Sum(nil)
+ hasher.Reset()
+ if hex.EncodeToString(hash[:len(diff)]) <= diff {
+ return "gAAAAAB" + base
+ }
+ }
+ return "gAAAAABwQ8Lk5FbGpA2NcR9dShT6gYjU7VxZ4D" + base64.StdEncoding.EncodeToString([]byte(`"`+seed+`"`))
+}
diff --git a/ProxyPool/ProxyPool.go b/ProxyPool/ProxyPool.go
new file mode 100644
index 0000000000000000000000000000000000000000..c512968654b22c9e069714ad4caca8640664149f
--- /dev/null
+++ b/ProxyPool/ProxyPool.go
@@ -0,0 +1,87 @@
+package ProxyPool
+
+import (
+ "fmt"
+ "free-gpt3.5-2api/common"
+ "free-gpt3.5-2api/config"
+ "free-gpt3.5-2api/constant"
+ "github.com/aurorax-neo/go-logger"
+ fhttp "github.com/bogdanfinn/fhttp"
+ "net/url"
+ "sync"
+ "time"
+)
+
+var (
+ Instance *ProxyPool
+ Once sync.Once
+)
+
+type ProxyPool struct {
+ Proxies []*Proxy
+ Index int
+}
+
+type Proxy struct {
+ Link *url.URL
+ CanUseAt int64
+ Ua string
+ Cookies []*fhttp.Cookie
+}
+
+func GetProxyPoolInstance() *ProxyPool {
+ Once.Do(func() {
+ logger.Logger.Info(fmt.Sprint("Init ProxyPool..."))
+ // 初始化 ProxyPool
+ Instance = NewProxyPool(nil)
+ // 遍历配置文件中的代理 添加到代理池
+ for _, px := range config.Proxy {
+ proxy := NewProxy(px, common.GetTimestampSecond(0), constant.Ua)
+ _ = proxy.getCookies()
+ Instance.AddProxy(proxy)
+ }
+ //定时刷新代理cookies
+ common.AsyncLoopTask(1*time.Minute, func() {
+ for _, proxy := range Instance.Proxies {
+ _ = proxy.getCookies()
+ }
+ })
+ logger.Logger.Info(fmt.Sprint("Init ProxyPool Success"))
+ })
+ return Instance
+}
+
+func NewProxyPool(proxies []*Proxy) *ProxyPool {
+ proxy := NewProxy("", common.GetTimestampSecond(0), constant.Ua)
+ _ = proxy.getCookies()
+ return &ProxyPool{
+ Proxies: append([]*Proxy{proxy}, proxies...),
+ Index: 0,
+ }
+}
+
+func (PP *ProxyPool) GetProxy() *Proxy {
+ PP.Index = (PP.Index + 1) % len(PP.Proxies)
+ // 如果配置了代理 不会使用无代理
+ if PP.Index == 0 && len(PP.Proxies) > 1 {
+ PP.Index = 1
+ }
+ // 返回代理
+ return PP.Proxies[PP.Index]
+}
+
+func (PP *ProxyPool) AddProxy(proxy *Proxy) {
+ PP.Proxies = append(PP.Proxies, proxy)
+}
+
+func NewProxy(link string, cannotUseTime int64, ua string) *Proxy {
+ return &Proxy{
+ Link: common.ParseUrl(link),
+ CanUseAt: cannotUseTime,
+ Ua: ua,
+ }
+}
+
+func (P *Proxy) getCookies() error {
+ return nil
+}
diff --git a/README.md b/README.md
index e0990e7cae55755151cb993efaa4504877768e4c..ff4a049f8f28a69e6000db27ee70a158a7ad76d3 100644
--- a/README.md
+++ b/README.md
@@ -1,90 +1,94 @@
-# duck2api
+# [free-gpt3.5-2api](https://github.com/aurorax-neo/free-gpt3.5-2api)
+## 接口
+#### /v1/tokens
-# 交流群
-https://t.me/aurora_develop
-
-# Web端
-
-访问http://你的服务器ip:8080/web
-
-
+```
+curl --location --request GET 'http://127.0.0.1:9846/v1/tokens' \
+--header 'Authorization: Bearer abc'
+```
-## Deploy
+返回示例说明:`count`为授权池中可用授权数,如果`count` 为 `0`请检查`ip`是否支持 `openai`
+```
+{
+ "count": 0
+}
+```
-### Render部署
-[](https://render.com/deploy)
+#### /v1/chat/completions
-### 编译部署
+###### 支持返回stream和json
-```bash
-git clone https://github.com/aurora-develop/duck2api
-cd duck2api
-go build -o duck2api
-chmod +x ./duck2api
-./duck2api
+```
+http://:/v1/chat/completions
```
-### Docker部署
-## Docker部署
-您需要安装Docker和Docker Compose。
+##### 示例
-```bash
-docker run -d \
- --name duck2api \
- -p 8080:8080 \
- ghcr.io/aurora-develop/duck2api:latest
```
-
-## Docker Compose部署
-创建一个新的目录,例如duck2api,并进入该目录:
-```bash
-mkdir duck2api
-cd duck2api
+curl http://127.0.0.1:9846
```
-在此目录中下载库中的docker-compose.yml文件:
-```bash
-docker-compose up -d
```
-
-## Usage
-
-```bash
-curl --location 'http://你的服务器ip:8080/v1/chat/completions' \
+curl --location --request POST 'http://127.0.0.1:9846/v1/chat/completions' \
+--header 'Authorization: Bearer abc' \
--header 'Content-Type: application/json' \
---data '{
- "model": "gpt-3.5-turbo",
- "messages": [{"role": "user", "content": "Say this is a test!"}],
- "stream": true
- }'
+--data-raw '{
+ "model": "gpt-3.5-turbo",
+ "messages": [
+ {
+ "role": "user",
+ "content": "西红柿炒钢丝球怎么做?"
+ }
+ ],
+ "stream": false
+}'
```
-支持claude和gpt-3.5-turbo
-## 高级设置
-默认情况不需要设置,除非你有需求
+## 配置
### 环境变量
+
+```
+LOG_LEVEL=info # debug, info, warn, error
+LOG_PATH= # 日志文件路径,默认为空(不生成日志文件)
+BIND=0.0.0.0 # 127.0.0.1
+PORT=3040
+PROXY= # http://127.0.0.1:7890,http://127.0.0.1:7890 已支持多个代理(英文 "," 分隔)
+AUTHORIZATIONS= # abc,bac (英文 "," 分隔)
+BASE_URL= # 默认:https://chat.openai.com
+POOL_MAX_COUNT=64 # max number of connections to keep in the pool 默认:64
+AUTH_ED=600 # expiration time for the authorization in seconds 默认:600
```
-Authorization=your_authorization 用户认证 key。
-TLS_CERT=path_to_your_tls_cert 存储TLS(传输层安全协议)证书的路径。
-TLS_KEY=path_to_your_tls_key 存储TLS(传输层安全协议)证书的路径。
-PROXY_URL=your_proxy_url 添加代理池来。
+###### 也可使用与程序同目录下 `.env` 文件配置上述字段
+
+
+### docker部署
+
+##### 1 .创建文件夹
+
+```
+mkdir -p $PWD/free-gpt3.5-2api
```
-## 鸣谢
+##### 2.拉取镜像启动
-感谢各位大佬的pr支持,感谢。
+```
+docker run -itd --name=free-gpt3.5-2api -p 9846:3040 ghcr.io/aurorax-neo/free-gpt3.5-2api
+```
+##### 3.更新容器
-## 参考项目
+```
+docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower -cR free-gpt3.5-2api --debug
+```
+### Koyeb部署
-https://github.com/xqdoo00o/ChatGPT-to-API
+###### 注意:`Regions`请选择支持`openai`免登的区域!!!
-## License
+[](https://app.koyeb.com/deploy?type=docker&name=free-gpt3-5-2api®ion=par&ports=3040;http;/&image=ghcr.io/aurorax-neo/free-gpt3.5-2api)
-MIT License
diff --git a/RequestClient/RequestClient.go b/RequestClient/RequestClient.go
new file mode 100644
index 0000000000000000000000000000000000000000..6038a6bdc16c62396a2bc434b36caaeaeec37e16
--- /dev/null
+++ b/RequestClient/RequestClient.go
@@ -0,0 +1,10 @@
+package RequestClient
+
+import (
+ fhttp "github.com/bogdanfinn/fhttp"
+)
+
+type RequestClient interface {
+ Do(req *fhttp.Request) (*fhttp.Response, error)
+ SetProxy(link string) error
+}
diff --git a/RequestClient/TlsClient.go b/RequestClient/TlsClient.go
new file mode 100644
index 0000000000000000000000000000000000000000..c9662ced147072107af5a0804b9bf9f68238d605
--- /dev/null
+++ b/RequestClient/TlsClient.go
@@ -0,0 +1,77 @@
+package RequestClient
+
+import (
+ fhttp "github.com/bogdanfinn/fhttp"
+ tlsClient "github.com/bogdanfinn/tls-client"
+ "github.com/bogdanfinn/tls-client/profiles"
+ "io"
+ "math/rand"
+ "time"
+)
+
+type TlsClient struct {
+ client tlsClient.HttpClient
+}
+
+func NewTlsClient(timeoutSeconds int, clientProfile profiles.ClientProfile) *TlsClient {
+ jar := tlsClient.NewCookieJar()
+ options := []tlsClient.HttpClientOption{
+ tlsClient.WithTimeoutSeconds(timeoutSeconds),
+ tlsClient.WithClientProfile(clientProfile),
+ tlsClient.WithNotFollowRedirects(),
+ tlsClient.WithCookieJar(jar),
+ }
+ client, err := tlsClient.NewHttpClient(tlsClient.NewNoopLogger(), options...)
+ if err != nil {
+ return nil
+ }
+ return &TlsClient{
+ client: client,
+ }
+}
+
+func RandomClientProfile() profiles.ClientProfile {
+ // 初始化随机数生成器
+ seed := time.Now().UnixNano()
+ rng := rand.New(rand.NewSource(seed))
+ clientProfiles := []profiles.ClientProfile{
+ profiles.Firefox_102,
+ profiles.Safari_15_6_1,
+ profiles.Safari_16_0,
+ profiles.Chrome_110,
+ profiles.Okhttp4Android13,
+ profiles.CloudflareCustom,
+ profiles.Firefox_117,
+ }
+ // 随机选择一个
+ randomIndex := rng.Intn(len(clientProfiles))
+ return clientProfiles[randomIndex]
+}
+
+func NewRequest(method, url string, body io.Reader) (*fhttp.Request, error) {
+ request, err := fhttp.NewRequest(method, url, body)
+ if err != nil {
+ return nil, err
+ }
+ return request, nil
+
+}
+
+func (T *TlsClient) Do(req *fhttp.Request) (*fhttp.Response, error) {
+ response, err := T.client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ return response, nil
+}
+
+func (T *TlsClient) SetProxy(link string) error {
+ if link == "" {
+ return nil
+ }
+ err := T.client.SetProxy(link)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/VERSION b/VERSION
deleted file mode 100644
index 227cea215648b1af34a87c9acf5b707fe02d2072..0000000000000000000000000000000000000000
--- a/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-2.0.0
diff --git a/api/router.go b/api/router.go
deleted file mode 100644
index 481e8ebd3bbfbd70bd3f450d8673256007d8b1f6..0000000000000000000000000000000000000000
--- a/api/router.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package api
-
-import (
- "aurora/initialize"
- "github.com/gin-gonic/gin"
- "net/http"
-)
-
-var router *gin.Engine
-
-func init() {
- // 初始化gin
- router = initialize.RegisterRouter()
-}
-
-func Listen(w http.ResponseWriter, r *http.Request) {
- router.ServeHTTP(w, r)
-}
diff --git a/build.sh b/build.sh
deleted file mode 100644
index 3ccae9aeeb4d087bac5c84a7b51689d09966544e..0000000000000000000000000000000000000000
--- a/build.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-
-export GOPROXY=https://goproxy.io
-
-go get
-
-export CGO_ENABLED=0
-PKG=aurora
-
-targets=(
- "windows/amd64"
- "linux/amd64"
- "darwin/amd64"
- "windows/386"
- "linux/386"
- "darwin/386"
- "linux/arm"
- "linux/arm64"
- "linux/s390x"
-)
-
-upxPath=$(command -v upx)
-
-for target in "${targets[@]}"; do
- GOOS=${target%/*}
- GOARCH=${target#*/}
- outputDir="bin/${GOOS}_${GOARCH}"
- outputFile="${outputDir}/${PKG}"
- archiveName="${PKG}-${GOOS}-${GOARCH}.tar.gz"
- mkdir -p $(dirname ${outputFile})
- GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-s -w -extldflags '-static'" -o ${outputFile} *.go
- if [ -n "$upxPath" ]; then
- $upxPath -9 ${outputFile}
- fi
- # Archive the binary
- if [ "$GOOS" = "windows" ]; then
- zip -j "${outputDir}/${PKG}-${GOOS}-${GOARCH}.zip" "${outputFile}"
- else
- tar -C "${outputDir}" -czf "${outputDir}/${archiveName}" "${PKG}"
- fi
-done
diff --git a/common/common.go b/common/common.go
new file mode 100644
index 0000000000000000000000000000000000000000..429b192fe274742fad1febe24bf9a4d3178497ef
--- /dev/null
+++ b/common/common.go
@@ -0,0 +1,285 @@
+package common
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ fhttp "github.com/bogdanfinn/fhttp"
+ "github.com/bogdanfinn/fhttp/httputil"
+ "github.com/gin-gonic/gin"
+ jsoniter "github.com/json-iterator/go"
+ "math/rand"
+ "net/url"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "time"
+)
+
+func ErrorResponse(c *gin.Context, code int, msg interface{}, err interface{}) {
+ c.AbortWithStatusJSON(code, gin.H{
+ "detail": struct {
+ Code int `json:"code"`
+ Msg interface{} `json:"msg"`
+ Error interface{} `json:"error"`
+ }{
+ Code: code,
+ Msg: msg,
+ Error: err,
+ },
+ })
+ return
+}
+
+// GetTimestampSecond 获取当前时间戳 + 指定 秒
+func GetTimestampSecond(second int) int64 {
+ return time.Now().Add(time.Second * time.Duration(second)).Unix()
+}
+
+func ParseUrl(link string) *url.URL {
+ if link == "" {
+ return &url.URL{}
+ }
+ u, err := url.Parse(link)
+ if err != nil {
+ return &url.URL{}
+ }
+ return u
+}
+
+func GetOrigin(link string) string {
+ u := ParseUrl(link)
+ if u == nil {
+ return ""
+ }
+ return u.Scheme + "://" + u.Host
+}
+
+func Struct2BytesBuffer(v interface{}) (*bytes.Buffer, error) {
+ data := new(bytes.Buffer)
+ err := json.NewEncoder(data).Encode(v)
+ if err != nil {
+ return nil, err
+ }
+ return data, nil
+}
+
+func Struct2Bytes(v interface{}) ([]byte, error) {
+ // 创建一个jsonIter的Encoder
+ configCompatibleWithStandardLibrary := jsoniter.ConfigCompatibleWithStandardLibrary
+ // 将结构体转换为JSON文本并保持顺序
+ bytes_, err := configCompatibleWithStandardLibrary.Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ return bytes_, nil
+}
+
+func SplitAndAddBearer(authTokens string) []string {
+ var authTokenList []string
+ for _, v := range strings.Split(authTokens, ",") {
+ authTokenList = append(authTokenList, "Bearer "+v)
+ }
+ return authTokenList
+}
+
+func GetRand() rand.Rand {
+ // 初始化随机数生成器
+ seed := time.Now().UnixNano()
+ rng := rand.New(rand.NewSource(seed))
+ return *rng
+}
+
+func RandomLanguage() string {
+ // 初始化随机数生成器
+ rng := GetRand()
+ // 语言列表
+ languages := []string{"af", "am", "ar-sa", "as", "az-Latn", "be", "bg", "bn-BD", "bn-IN", "bs", "ca", "ca-ES-valencia", "cs", "cy", "da", "de", "de-de", "el", "en-GB", "en-US", "es", "es-ES", "es-US", "es-MX", "et", "eu", "fa", "fi", "fil-Latn", "fr", "fr-FR", "fr-CA", "ga", "gd-Latn", "gl", "gu", "ha-Latn", "he", "hi", "hr", "hu", "hy", "id", "ig-Latn", "is", "it", "it-it", "ja", "ka", "kk", "km", "kn", "ko", "kok", "ku-Arab", "ky-Cyrl", "lb", "lt", "lv", "mi-Latn", "mk", "ml", "mn-Cyrl", "mr", "ms", "mt", "nb", "ne", "nl", "nl-BE", "nn", "nso", "or", "pa", "pa-Arab", "pl", "prs-Arab", "pt-BR", "pt-PT", "qut-Latn", "quz", "ro", "ru", "rw", "sd-Arab", "si", "sk", "sl", "sq", "sr-Cyrl-BA", "sr-Cyrl-RS", "sr-Latn-RS", "sv", "sw", "ta", "te", "tg-Cyrl", "th", "ti", "tk-Latn", "tn", "tr", "tt-Cyrl", "ug-Arab", "uk", "ur", "uz-Latn", "vi", "wo", "xh", "yo-Latn", "zh-Hans", "zh-Hant", "zu"}
+ // 随机选择一个语言
+ randomIndex := rng.Intn(len(languages))
+ return languages[randomIndex]
+}
+
+// GetAbsPathAndGenerate 获取绝对路径并生成文件或文件夹
+func GetAbsPathAndGenerate(path string, isFilePath bool, content string) string {
+ // 获取绝对路径
+ path = GetAbsPath(path)
+ if isFilePath {
+ // 判断文件是否存在
+ if isExist := fileIsExistAndCreat(path, content); isExist {
+ return path
+ }
+ } else {
+ // 判断文件夹是否存在
+ if isExist := dirIsExistAndMkdir(path, false); isExist {
+ return path
+ }
+ }
+ return path
+}
+
+// GetAbsPath 获取绝对路径
+func GetAbsPath(path string) string {
+ if !filepath.IsAbs(path) {
+ absPath, err := filepath.Abs(path)
+ if err != nil {
+ return ""
+ }
+ return absPath
+ }
+ return path
+}
+
+func dirIsExistAndMkdir(dirPath string, isFile bool) bool {
+ // 判断路径是否存在
+ _, err := os.Stat(dirPath)
+ dir := dirPath
+ if err != nil {
+ if isFile {
+ dir = filepath.Dir(dirPath)
+ }
+ // 创建路径
+ err := os.MkdirAll(dir, os.ModePerm)
+ if err != nil {
+ return false
+ }
+ }
+ return true
+}
+
+func fileIsExistAndCreat(filePath string, content string) bool {
+ //判断文件是否存在
+ _, err := os.Stat(filePath)
+ if err != nil {
+ // 判断文件夹是否存在
+ if isExist := dirIsExistAndMkdir(filePath, true); !isExist {
+ return false
+ }
+ // 创建文件
+ _, err := os.Create(filePath)
+ if err != nil {
+ return false
+ }
+ if content != "" {
+ // 写入content
+ file, _ := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0777)
+ _, _ = file.Write([]byte(content))
+ defer func(file *os.File) {
+ _ = file.Close()
+ }(file)
+ }
+ }
+ return true
+}
+
+// AsyncTimingTask 定时任务 参数含函数
+func AsyncTimingTask(nanosecond time.Duration, fun func()) {
+ go func() {
+ timerChan := time.After(nanosecond)
+ // 使用for循环阻塞等待定时器的信号
+ for {
+ // 通过select语句监听定时器通道和其他事件
+ select {
+ case <-timerChan:
+ fun()
+ // 重新设置定时器,以便下一次执行
+ timerChan = time.After(nanosecond)
+ }
+ time.Sleep(time.Millisecond * 100)
+ }
+ }()
+}
+
+// AsyncLoopTask AsyncTimingTask 定时任务 参数含函数
+func AsyncLoopTask(sleep time.Duration, fun func()) {
+ go func() {
+ for {
+ fun()
+ time.Sleep(sleep)
+ }
+ }()
+}
+
+// DeepCopyStruct 深拷贝函数
+func DeepCopyStruct(src interface{}) interface{} {
+ // 获取源对象的类型信息
+ srcType := reflect.TypeOf(src)
+ // 创建目标对象
+ dst := reflect.New(srcType).Elem()
+
+ // 深拷贝过程
+ deepCopyValue(reflect.ValueOf(src), dst)
+
+ return dst.Interface()
+}
+
+// 递归进行深拷贝
+func deepCopyValue(src, dst reflect.Value) {
+ switch src.Kind() {
+ case reflect.Ptr:
+ if src.IsNil() {
+ dst.Set(src)
+ return
+ }
+ // 递归处理指针指向的内容
+ newDst := reflect.New(src.Elem().Type())
+ deepCopyValue(src.Elem(), newDst.Elem())
+ dst.Set(newDst)
+ case reflect.Struct:
+ for i := 0; i < src.NumField(); i++ {
+ // 递归处理结构体的字段
+ deepCopyValue(src.Field(i), dst.Field(i))
+ }
+ default:
+ // 检查目标值是否支持设置
+ if dst.CanSet() {
+ // 处理基本类型和数组、切片、映射等
+ dst.Set(src)
+ }
+ }
+}
+
+func RandomHexadecimalString() string {
+ rng := GetRand()
+ const charset = "0123456789abcdef"
+ const length = 16 // The length of the string you want to generate
+ b := make([]byte, length)
+ for i := range b {
+ b[i] = charset[rng.Intn(len(charset))]
+ }
+ return string(b)
+}
+
+// OutRequest 打印请求.
+func OutRequest(req *fhttp.Request) {
+ dump, err := httputil.DumpRequestOut(req, true)
+ if err != nil {
+ fmt.Println("Error dumping request:", err)
+ } else {
+ fmt.Println(string(dump))
+ }
+}
+
+// OutResponse 打印响应.
+func OutResponse(res *fhttp.Response) {
+ dump, err := httputil.DumpResponse(res, true)
+ if err != nil {
+ fmt.Println("Error dumping response:", err)
+ } else {
+ fmt.Println(string(dump))
+ }
+}
+
+func IsStrInArray(str string, strS []string) bool {
+ // 如果 strS 为空,直接返回 true
+ if len(strS) == 0 {
+ return true
+ }
+ for _, v := range strS {
+ if v == str {
+ return true
+ }
+ }
+ return false
+}
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000000000000000000000000000000000000..d55b16169cf5eaeca9bd42e25361b3f28e63d68b
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,74 @@
+package config
+
+import (
+ "free-gpt3.5-2api/common"
+ "github.com/joho/godotenv"
+ "os"
+ "strconv"
+ "strings"
+)
+
+var (
+ Bind string
+ Port string
+ Proxy []string
+ AUTHORIZATIONS []string
+ BaseUrl string
+ PoolMaxCount int
+ AuthED int
+)
+
+func init() {
+ _ = godotenv.Load()
+ // Bind
+ Bind = os.Getenv("BIND")
+ if Bind == "" {
+ Bind = "0.0.0.0"
+ }
+ // PORT
+ Port = os.Getenv("PORT")
+ if Port == "" {
+ Port = "3040"
+ }
+ // PROXY
+ proxy := os.Getenv("PROXY")
+ if proxy != "" {
+ Proxy = strings.Split(proxy, ",")
+ }
+ // AUTH_TOKEN
+ authorizations := os.Getenv("AUTHORIZATIONS")
+ if authorizations == "" {
+ AUTHORIZATIONS = []string{}
+ } else {
+ //以,分割 AUTH_TOKEN 并且为每个AUTH_TOKEN前面加上Bearer
+ AUTHORIZATIONS = common.SplitAndAddBearer(authorizations)
+ }
+ // BASE_URL
+ BaseUrl = os.Getenv("BASE_URL")
+ if BaseUrl == "" {
+ BaseUrl = "https://chatgpt.com"
+ } else {
+ BaseUrl = strings.TrimRight(BaseUrl, "/")
+ }
+ // POOL_MAX_COUNT
+ poolMaxCount := os.Getenv("POOL_MAX_COUNT")
+ var err error
+ if poolMaxCount == "" {
+ PoolMaxCount = 64
+ } else {
+ PoolMaxCount, err = strconv.Atoi(poolMaxCount)
+ if err != nil {
+ PoolMaxCount = 64
+ }
+ }
+ // AUTH_ED
+ authED := os.Getenv("AUTH_ED")
+ if authED == "" {
+ AuthED = 600
+ } else {
+ AuthED, err = strconv.Atoi(authED)
+ if err != nil {
+ AuthED = 600
+ }
+ }
+}
diff --git a/constant/constant.go b/constant/constant.go
new file mode 100644
index 0000000000000000000000000000000000000000..c48f636394f9d0dc75d351565950584dde8a0e7c
--- /dev/null
+++ b/constant/constant.go
@@ -0,0 +1,11 @@
+package constant
+
+import "github.com/bogdanfinn/tls-client/profiles"
+
+var (
+ ClientProfile = profiles.Safari_15_6_1
+)
+
+const (
+ Ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
+)
diff --git a/conversion/requests/duckgo/convert.go b/conversion/requests/duckgo/convert.go
deleted file mode 100644
index 65768fa07570bb24870c79c3cc52528b3b08670f..0000000000000000000000000000000000000000
--- a/conversion/requests/duckgo/convert.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package duckgo
-
-import (
- duckgotypes "aurora/typings/duckgo"
- officialtypes "aurora/typings/official"
- "strings"
-)
-
-func ConvertAPIRequest(api_request officialtypes.APIRequest) duckgotypes.ApiRequest {
- // 默认模型3.5
- duckgo_request := duckgotypes.NewApiRequest("gpt-3.5-turbo-0125")
- // 检查并更新模型为 claude- 开头的情况
- if strings.HasPrefix(strings.ToLower(api_request.Model), "claude") {
- duckgo_request.Model = "claude-3-haiku-20240307"
- }
- content := buildContent(&api_request)
- duckgo_request.AddMessage("user", content)
- return duckgo_request
-}
-
-func buildContent(api_request *officialtypes.APIRequest) string {
- var content strings.Builder
- for _, apiMessage := range api_request.Messages {
- role := apiMessage.Role
- if role == "user" || role == "system" || role == "assistant" {
- content.WriteString(role + ":" + apiMessage.Content + ";\r\n")
- }
- }
- return content.String()
-}
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 397ea764b629fc6facd5371f1b146793a1525d76..0000000000000000000000000000000000000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-version: '3'
-
-services:
- app:
- image: ghcr.io/aurora-develop/duck2api:latest
- container_name: duck2api
- restart: unless-stopped
- ports:
- - '8080:8080'
diff --git a/env.template b/env.template
index a2e8c296a49f33756ea10b0317d212977d861d2c..44eaccf392a457fcd400c55e53f6a020f7bbd8b9 100644
--- a/env.template
+++ b/env.template
@@ -1,8 +1,8 @@
-SERVER_HOST=0.0.0.0
-SERVER_PORT=8080
-FREE_ACCOUNTS=true
-FREE_ACCOUNTS_NUM=1024
-Authorization=
-TLS_CERT=
-TLS_KEY=
-PROXY_URL=
+LOG_LEVEL=info # debug, info, warn, error
+BIND=127.0.0.1 #
+PORT=8080
+PROXY=
+AUTHORIZATIONS=
+POOL_MAX_COUNT=5 # max number of connections to keep in the pool
+AUTH_ED=180 # expiration time for the authorization in seconds
+AUTH_USE_COUNT=5 # number of times an authorization can be used
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 5953626748dfe7dba946891b2489d710b3efa99a..34f61c1cbf861598141a55311139e5669a90391b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,56 +1,50 @@
-module aurora
+module free-gpt3.5-2api
go 1.21
require (
- github.com/EDDYCJY/fake-useragent v0.2.0
- github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd
- github.com/bogdanfinn/fhttp v0.5.27
+ github.com/aurorax-neo/go-logger v0.0.0-20240421094709-1eb4bda786d5
+ github.com/bogdanfinn/fhttp v0.5.28
github.com/bogdanfinn/tls-client v1.7.2
github.com/gin-gonic/gin v1.9.1
- github.com/go-resty/resty/v2 v2.12.0
github.com/google/uuid v1.6.0
- github.com/gorilla/websocket v1.5.1
github.com/joho/godotenv v1.5.1
- github.com/pkoukk/tiktoken-go v0.1.6
- github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c
+ github.com/json-iterator/go v1.1.12
+ github.com/launchdarkly/eventsource v1.7.1
+ golang.org/x/crypto v0.21.0
)
require (
- github.com/PuerkitoBio/goquery v1.9.1 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
- github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/bogdanfinn/utls v1.6.1 // indirect
- github.com/bytedance/sonic v1.10.1 // indirect
- github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
- github.com/chenzhuoyu/iasm v0.9.0 // indirect
- github.com/cloudflare/circl v1.3.6 // indirect
- github.com/dlclark/regexp2 v1.10.0 // indirect
+ github.com/bytedance/sonic v1.9.1 // indirect
+ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
+ github.com/cloudflare/circl v1.3.7 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.15.4 // indirect
+ github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
- github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/compress v1.17.0 // indirect
- github.com/klauspost/cpuid/v2 v2.2.5 // indirect
- github.com/kr/text v0.2.0 // indirect
+ github.com/klauspost/compress v1.16.7 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/pelletier/go-toml/v2 v2.1.0 // indirect
- github.com/quic-go/quic-go v0.37.4 // indirect
+ github.com/pelletier/go-toml/v2 v2.0.8 // indirect
+ github.com/quic-go/quic-go v0.42.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
- golang.org/x/arch v0.5.0 // indirect
- golang.org/x/crypto v0.21.0 // indirect
+ go.uber.org/multierr v1.11.0 // indirect
+ go.uber.org/zap v1.27.0 // indirect
+ golang.org/x/arch v0.3.0 // indirect
+ golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 11946d433b86d704d95ba8c95d51976ad462765a..47f6cdf813f5959f59c70c9a5ac9c6b5dd7fe86c 100644
--- a/go.sum
+++ b/go.sum
@@ -1,37 +1,24 @@
-github.com/EDDYCJY/fake-useragent v0.2.0 h1:Jcnkk2bgXmDpX0z+ELlUErTkoLb/mxFBNd2YdcpvJBs=
-github.com/EDDYCJY/fake-useragent v0.2.0/go.mod h1:5wn3zzlDxhKW6NYknushqinPcAqZcAPHy8lLczCdJdc=
-github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI=
-github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY=
-github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd h1:oIpfrRhD7Jus41dotbK+SQjWSFRnf1cLZUYCZpF/o/4=
-github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd/go.mod h1:0yO7neMeJLvKk/B/fq5votDY8rByrOPDubpvU+6saKo=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
-github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
-github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
-github.com/bogdanfinn/fhttp v0.5.27 h1:+glR3k8v5nxfUSk7+J3M246zEQ2yadhS0vLq1utK71A=
-github.com/bogdanfinn/fhttp v0.5.27/go.mod h1:oJiYPG3jQTKzk/VFmogH8jxjH5yiv2rrOH48Xso2lrE=
+github.com/aurorax-neo/go-logger v0.0.0-20240421094709-1eb4bda786d5 h1:L1ei0BPLvE/ld4KAh4bKVAn5tDYOdJz0SuxlbuzfKzQ=
+github.com/aurorax-neo/go-logger v0.0.0-20240421094709-1eb4bda786d5/go.mod h1:BJsRG1ECcXTHwiz2zaMYxFkeXh+MpQVs6nWYphLT244=
+github.com/bogdanfinn/fhttp v0.5.28 h1:G6thT8s8v6z1IuvXMUsX9QKy3ZHseTQTzxuIhSiaaAw=
+github.com/bogdanfinn/fhttp v0.5.28/go.mod h1:oJiYPG3jQTKzk/VFmogH8jxjH5yiv2rrOH48Xso2lrE=
github.com/bogdanfinn/tls-client v1.7.2 h1:vpL5qBYUfT9ueygEf1yLfymrXyUEZQatL25amfqGV8M=
github.com/bogdanfinn/tls-client v1.7.2/go.mod h1:pOGa2euqTbEkGNqE5idx5jKKfs9ytlyn3fwEw8RSP+g=
github.com/bogdanfinn/utls v1.6.1 h1:dKDYAcXEyFFJ3GaWaN89DEyjyRraD1qb4osdEK89ass=
github.com/bogdanfinn/utls v1.6.1/go.mod h1:VXIbRZaiY/wHZc6Hu+DZ4O2CgTzjhjCg/Ou3V4r/39Y=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
-github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc=
-github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
+github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
+github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
-github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
-github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
-github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
-github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
-github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg=
-github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
+github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
-github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@@ -46,16 +33,12 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs=
-github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
-github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
-github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
+github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
+github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -63,22 +46,23 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
-github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
-github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
+github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
-github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
-github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
+github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/launchdarkly/eventsource v1.7.1 h1:StoRQeiPyrcQIXjlQ7b5jWMzHW4p+GGczN2r2oBhujg=
+github.com/launchdarkly/eventsource v1.7.1/go.mod h1:LHxSeb4OnqznNZxCSXbFghxS/CjIQfzHovNoAqbO/Wk=
+github.com/launchdarkly/go-test-helpers/v2 v2.2.0 h1:L3kGILP/6ewikhzhdNkHy1b5y4zs50LueWenVF0sBbs=
+github.com/launchdarkly/go-test-helpers/v2 v2.2.0/go.mod h1:L7+th5govYp5oKU9iN7To5PgznBuIjBPn+ejqKR0avw=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
@@ -92,102 +76,64 @@ github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
-github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
-github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
-github.com/pkoukk/tiktoken-go v0.1.6 h1:JF0TlJzhTbrI30wCvFuiw6FzP2+/bR+FIxUdgEAcUsw=
-github.com/pkoukk/tiktoken-go v0.1.6/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg=
+github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
+github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/quic-go/quic-go v0.37.4 h1:ke8B73yMCWGq9MfrCCAw0Uzdm7GaViC3i39dsIdDlH4=
-github.com/quic-go/quic-go v0.37.4/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU=
+github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
+github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc=
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c h1:nj17XsSTwprsZUDXLldOUZmqz7VlHsLCeXXFOE6Q+Mk=
-github.com/xqdoo00o/funcaptcha v0.0.0-20240403090732-1b604d808f6c/go.mod h1:7aCyoW5MHDUsoooMVLqKe0F7W9HMPUvDG3bXqw++8XA=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y=
-golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
+golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
+golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
-golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
-golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
-golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/httpclient/Iaurorahttpclient.go b/httpclient/Iaurorahttpclient.go
deleted file mode 100644
index 91f3beb800e1a44ad4fc8075bd587032f4e85c5b..0000000000000000000000000000000000000000
--- a/httpclient/Iaurorahttpclient.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package httpclient
-
-import (
- "io"
- "net/http"
-)
-
-type AuroraHttpClient interface {
- Request(method HttpMethod, url string, headers AuroraHeaders, cookies []*http.Cookie, body io.Reader) (*http.Response, error)
- SetProxy(url string) error
-}
-
-type HttpMethod string
-
-const (
- GET HttpMethod = "GET"
- POST HttpMethod = "POST"
- PUT HttpMethod = "PUT"
- HEAD HttpMethod = "HEAD"
- DELETE HttpMethod = "DELETE"
- OPTIONS HttpMethod = "OPTIONS"
-)
-
-type AuroraHeaders map[string]string
-
-func (a AuroraHeaders) Set(key, value string) {
- a[key] = value
-}
diff --git a/httpclient/bogdanfinn/tls_client.go b/httpclient/bogdanfinn/tls_client.go
deleted file mode 100644
index 7f8e53b887306b0107db6564a33a1d8b0f8b7e01..0000000000000000000000000000000000000000
--- a/httpclient/bogdanfinn/tls_client.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package bogdanfinn
-
-import (
- "aurora/httpclient"
- "io"
- "net/http"
-
- fhttp "github.com/bogdanfinn/fhttp"
- tls_client "github.com/bogdanfinn/tls-client"
- "github.com/bogdanfinn/tls-client/profiles"
-)
-
-type TlsClient struct {
- Client tls_client.HttpClient
- ReqBefore handler
-}
-
-type handler func(r *fhttp.Request) error
-
-func NewStdClient() *TlsClient {
- client, _ := tls_client.NewHttpClient(tls_client.NewNoopLogger(), []tls_client.HttpClientOption{
- tls_client.WithCookieJar(tls_client.NewCookieJar()),
- tls_client.WithTimeoutSeconds(600),
- tls_client.WithClientProfile(profiles.Safari_15_6_1),
- }...)
-
- stdClient := &TlsClient{Client: client}
- return stdClient
-}
-
-func convertResponse(resp *fhttp.Response) *http.Response {
- response := &http.Response{
- Status: resp.Status,
- StatusCode: resp.StatusCode,
- Proto: resp.Proto,
- ProtoMajor: resp.ProtoMajor,
- ProtoMinor: resp.ProtoMinor,
- Header: http.Header(resp.Header),
- Body: resp.Body,
- ContentLength: resp.ContentLength,
- TransferEncoding: resp.TransferEncoding,
- Close: resp.Close,
- Uncompressed: resp.Uncompressed,
- Trailer: http.Header(resp.Trailer),
- }
- return response
-}
-
-func (t *TlsClient) handleHeaders(req *fhttp.Request, headers httpclient.AuroraHeaders) {
- if headers == nil {
- return
- }
- for k, v := range headers {
- req.Header.Set(k, v)
- }
-}
-
-func (t *TlsClient) handleCookies(req *fhttp.Request, cookies []*http.Cookie) {
- if cookies == nil {
- return
- }
- for _, c := range cookies {
- req.AddCookie(&fhttp.Cookie{
- Name: c.Name,
- Value: c.Value,
- Path: c.Path,
- Domain: c.Domain,
- Expires: c.Expires,
- RawExpires: c.RawExpires,
- MaxAge: c.MaxAge,
- Secure: c.Secure,
- HttpOnly: c.HttpOnly,
- SameSite: fhttp.SameSite(c.SameSite),
- Raw: c.Raw,
- Unparsed: c.Unparsed,
- })
- }
-}
-
-func (t *TlsClient) Request(method httpclient.HttpMethod, url string, headers httpclient.AuroraHeaders, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
- req, err := fhttp.NewRequest(string(method), url, body)
- if err != nil {
- return nil, err
- }
- t.handleHeaders(req, headers)
- t.handleCookies(req, cookies)
- if t.ReqBefore != nil {
- if err := t.ReqBefore(req); err != nil {
- return nil, err
- }
- }
- do, err := t.Client.Do(req)
- if err != nil {
- return nil, err
- }
- return convertResponse(do), nil
-}
-
-func (t *TlsClient) SetProxy(url string) error {
- return t.Client.SetProxy(url)
-}
diff --git a/httpclient/bogdanfinn/tls_client_test.go b/httpclient/bogdanfinn/tls_client_test.go
deleted file mode 100644
index 50794f0a48cfab9d4db89eb7d16ab03c94f8b19d..0000000000000000000000000000000000000000
--- a/httpclient/bogdanfinn/tls_client_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package bogdanfinn
-
-import (
- "aurora/httpclient"
- "fmt"
- "io"
- "net/http"
- "os"
- "strings"
- "testing"
-
- "github.com/joho/godotenv"
-)
-
-var BaseURL string
-
-func init() {
- _ = godotenv.Load(".env")
- BaseURL = os.Getenv("BASE_URL")
- if BaseURL == "" {
- BaseURL = "https://chat.openai.com/backend-anon"
- }
-}
-func TestTlsClient_Request(t *testing.T) {
- client := NewStdClient()
- userAgent := "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
- proxy := "http://127.0.0.1:7990"
- client.SetProxy(proxy)
-
- apiUrl := BaseURL + "/sentinel/chat-requirements"
- payload := strings.NewReader(`{"conversation_mode_kind":"primary_assistant"}`)
- header := make(httpclient.AuroraHeaders)
- header.Set("Content-Type", "application/json")
- header.Set("User-Agent", userAgent)
- header.Set("Accept", "*/*")
- header.Set("oai-language", "en-US")
- header.Set("origin", "https://chat.openai.com")
- header.Set("referer", "https://chat.openai.com/")
- header.Set("oai-device-id", "c83b24f0-5a9e-4c43-8915-3f67d4332609")
- response, err := client.Request(http.MethodPost, apiUrl, header, nil, payload)
- if err != nil {
- return
- }
- defer response.Body.Close()
- fmt.Println(response.StatusCode)
- if response.StatusCode != 200 {
- fmt.Println("Error: ", response.StatusCode)
- }
-}
-
-func TestChatGPTModel(t *testing.T) {
- client := NewStdClient()
- userAgent := "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
- proxy := "http://127.0.0.1:7990"
- client.SetProxy(proxy)
- apiUrl := "https://chat.openai.com/backend-anon/models"
-
- header := make(httpclient.AuroraHeaders)
- header.Set("Content-Type", "application/json")
- header.Set("User-Agent", userAgent)
- header.Set("Accept", "*/*")
- header.Set("oai-language", "en-US")
- header.Set("origin", "https://chat.openai.com")
- header.Set("referer", "https://chat.openai.com/")
- header.Set("oai-device-id", "c83b24f0-5a9e-4c43-8915-3f67d4332609")
- response, err := client.Request(http.MethodGet, apiUrl, header, nil, nil)
- if err != nil {
- return
- }
- defer response.Body.Close()
- fmt.Println(response.StatusCode)
- if response.StatusCode != 200 {
- fmt.Println("Error: ", response.StatusCode)
- body, _ := io.ReadAll(response.Body)
- fmt.Println(string(body))
- return
- }
-
- type EnginesData struct {
- Models []struct {
- Slug string `json:"slug"`
- MaxTokens int `json:"max_tokens"`
- Title string `json:"title"`
- Description string `json:"description"`
- Tags []string `json:"tags"`
- Capabilities struct {
- } `json:"capabilities,omitempty"`
- ProductFeatures struct {
- } `json:"product_features,omitempty"`
- } `json:"models"`
- Categories []struct {
- Category string `json:"category"`
- HumanCategoryName string `json:"human_category_name"`
- SubscriptionLevel string `json:"subscription_level"`
- DefaultModel string `json:"default_model"`
- CodeInterpreterModel string `json:"code_interpreter_model,omitempty"`
- PluginsModel string `json:"plugins_model"`
- } `json:"categories"`
- }
-
-}
diff --git a/httpclient/resty/resty_client.go b/httpclient/resty/resty_client.go
deleted file mode 100644
index 36b0cd485055e158781801f568925a1e5edfe7e3..0000000000000000000000000000000000000000
--- a/httpclient/resty/resty_client.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package resty
-
-import (
- "aurora/util"
- "crypto/tls"
- browser "github.com/EDDYCJY/fake-useragent"
- "github.com/go-resty/resty/v2"
- "net/http"
- "time"
-)
-
-type RestyClient struct {
- Client *resty.Client
-}
-
-func NewStdClient() *RestyClient {
- client := &RestyClient{
- Client: resty.NewWithClient(&http.Client{
- Transport: &http.Transport{
- // 禁用长连接
- DisableKeepAlives: true,
- // 配置TLS设置,跳过证书验证
- TLSClientConfig: &tls.Config{
- InsecureSkipVerify: true,
- },
- },
- }),
- }
- client.Client.SetBaseURL("https://chat.openai.com")
- client.Client.SetRetryCount(3)
- client.Client.SetRetryWaitTime(5 * time.Second)
- client.Client.SetRetryMaxWaitTime(20 * time.Second)
-
- client.Client.SetTimeout(600 * time.Second)
- client.Client.SetHeader("user-agent", browser.Random()).
- SetHeader("accept", "*/*").
- SetHeader("accept-language", "en-US,en;q=0.9").
- SetHeader("cache-control", "no-cache").
- SetHeader("content-type", "application/json").
- SetHeader("oai-language", util.RandomLanguage()).
- SetHeader("pragma", "no-cache").
- SetHeader("sec-ch-ua", `"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"`).
- SetHeader("sec-ch-ua-mobile", "?0").
- SetHeader("sec-ch-ua-platform", "Windows").
- SetHeader("sec-fetch-dest", "empty").
- SetHeader("sec-fetch-mode", "cors").
- SetHeader("sec-fetch-site", "same-origin")
- return client
-}
-
-//func (c *RestyClient) Request(method string, url string, headers map[string]string, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
-//}
-
-//func (c *RestyClient) Post(url string, headers map[string]string, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
-//}
-//
-//func (c *RestyClient) Get(url string, headers map[string]string, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
-//}
-//
-//func (c *RestyClient) Head(url string, headers map[string]string, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
-//}
-//
-//func (c *RestyClient) Options(url string, headers map[string]string, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
-//}
-//
-//func (c *RestyClient) Put(url string, headers map[string]string, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
-//}
-//
-//func (c *RestyClient) Delete(url string, headers map[string]string, cookies []*http.Cookie, body io.Reader) (*http.Response, error) {
-//}
-//
-//func (c *RestyClient) SetProxy(url string) error {}
diff --git a/initialize/handlers.go b/initialize/handlers.go
deleted file mode 100644
index c49b97d0cb1d86cdcdc75b1de681cc0d8ec78775..0000000000000000000000000000000000000000
--- a/initialize/handlers.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package initialize
-
-import (
- duckgoConvert "aurora/conversion/requests/duckgo"
- "aurora/httpclient/bogdanfinn"
- "aurora/internal/duckgo"
- "aurora/internal/proxys"
- officialtypes "aurora/typings/official"
-
- "github.com/gin-gonic/gin"
-)
-
-type Handler struct {
- proxy *proxys.IProxy
-}
-
-func NewHandle(proxy *proxys.IProxy) *Handler {
- return &Handler{proxy: proxy}
-}
-
-func optionsHandler(c *gin.Context) {
- // Set headers for CORS
- c.Header("Access-Control-Allow-Origin", "*")
- c.Header("Access-Control-Allow-Methods", "POST")
- c.Header("Access-Control-Allow-Headers", "*")
- c.JSON(200, gin.H{
- "message": "pong",
- })
-}
-
-func (h *Handler) duckduckgo(c *gin.Context) {
- var original_request officialtypes.APIRequest
- err := c.BindJSON(&original_request)
- if err != nil {
- c.JSON(400, gin.H{"error": gin.H{
- "message": "Request must be proper JSON",
- "type": "invalid_request_error",
- "param": nil,
- "code": err.Error(),
- }})
- return
- }
- proxyUrl := h.proxy.GetProxyIP()
- client := bogdanfinn.NewStdClient()
- token, err := duckgo.InitXVQD(client, proxyUrl)
- if err != nil {
- c.JSON(500, gin.H{
- "error": err.Error(),
- })
- return
- }
-
- translated_request := duckgoConvert.ConvertAPIRequest(original_request)
- response, err := duckgo.POSTconversation(client, translated_request, token, proxyUrl)
- if err != nil {
- c.JSON(500, gin.H{
- "error": "request conversion error",
- })
- return
- }
-
- defer response.Body.Close()
- if duckgo.Handle_request_error(c, response) {
- return
- }
- var response_part string
- response_part = duckgo.Handler(c, response, translated_request, original_request.Stream)
- if c.Writer.Status() != 200 {
- return
- }
- if !original_request.Stream {
- c.JSON(200, officialtypes.NewChatCompletionWithModel(response_part, translated_request.Model))
- } else {
- c.String(200, "data: [DONE]\n\n")
- }
-}
-
-func (h *Handler) engines(c *gin.Context) {
- type ResData struct {
- ID string `json:"id"`
- Object string `json:"object"`
- Created int `json:"created"`
- OwnedBy string `json:"owned_by"`
- }
-
- type JSONData struct {
- Object string `json:"object"`
- Data []ResData `json:"data"`
- }
-
- modelS := JSONData{
- Object: "list",
- }
- var resModelList []ResData
-
- resModelList = append(resModelList, ResData{
- ID: "gpt-3.5-turbo-0125",
- Object: "model",
- Created: 1685474247,
- OwnedBy: "duckgo",
- })
- resModelList = append(resModelList, ResData{
- ID: "claude-3-haiku-20240307",
- Object: "model",
- Created: 1685474247,
- OwnedBy: "duckgo",
- })
- modelS.Data = resModelList
- c.JSON(200, modelS)
-}
diff --git a/initialize/proxy.go b/initialize/proxy.go
deleted file mode 100644
index f343a0916512400df78004cf00a27f7743d5b1f1..0000000000000000000000000000000000000000
--- a/initialize/proxy.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package initialize
-
-import (
- "aurora/internal/proxys"
- "bufio"
- "log/slog"
- "net/url"
- "os"
-)
-
-func checkProxy() *proxys.IProxy {
- var proxies []string
- proxyUrl := os.Getenv("PROXY_URL")
- if proxyUrl != "" {
- proxies = append(proxies, proxyUrl)
- }
-
- if _, err := os.Stat("proxies.txt"); err == nil {
- file, _ := os.Open("proxies.txt")
- defer file.Close()
- scanner := bufio.NewScanner(file)
- for scanner.Scan() {
- proxy := scanner.Text()
- parsedURL, err := url.Parse(proxy)
- if err != nil {
- slog.Warn("proxy url is invalid", "url", proxy, "err", err)
- continue
- }
-
- // 如果缺少端口信息,不是完整的代理链接
- if parsedURL.Port() != "" {
- proxies = append(proxies, proxy)
- } else {
- continue
- }
- }
- }
-
- if len(proxies) == 0 {
- proxy := os.Getenv("http_proxy")
- if proxy != "" {
- proxies = append(proxies, proxy)
- }
- }
-
- proxyIP := proxys.NewIProxyIP(proxies)
- return &proxyIP
-}
diff --git a/initialize/router.go b/initialize/router.go
deleted file mode 100644
index 3ecae947b2b5f8fc06eeb014f477dfde37b4219f..0000000000000000000000000000000000000000
--- a/initialize/router.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package initialize
-
-import (
- "aurora/middlewares"
-
- "github.com/gin-gonic/gin"
-)
-
-func RegisterRouter() *gin.Engine {
- handler := NewHandle(
- checkProxy(),
- )
-
- router := gin.Default()
- router.Use(middlewares.Cors)
-
- router.GET("/", func(c *gin.Context) {
- c.JSON(200, gin.H{
- "message": "Hello, world!",
- })
- })
-
- router.GET("/ping", func(c *gin.Context) {
- c.JSON(200, gin.H{
- "message": "pong",
- })
- })
-
- router.OPTIONS("/v1/chat/completions", optionsHandler)
- router.OPTIONS("/v1/chat/models", optionsHandler)
- authGroup := router.Group("").Use(middlewares.Authorization)
- authGroup.POST("/v1/chat/completions", handler.duckduckgo)
- authGroup.GET("/v1/models", handler.engines)
- return router
-}
diff --git a/internal/duckgo/request.go b/internal/duckgo/request.go
deleted file mode 100644
index 19cfdc7af3cc89ee10909ec3981a2fea7fbf157c..0000000000000000000000000000000000000000
--- a/internal/duckgo/request.go
+++ /dev/null
@@ -1,188 +0,0 @@
-package duckgo
-
-import (
- "aurora/httpclient"
- duckgotypes "aurora/typings/duckgo"
- officialtypes "aurora/typings/official"
- "bufio"
- "bytes"
- "encoding/json"
- "errors"
- "github.com/gin-gonic/gin"
- "io"
- "net/http"
- "strings"
- "sync"
- "time"
-)
-
-var (
- Token *XqdgToken
- UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
-)
-
-type XqdgToken struct {
- Token string `json:"token"`
- M sync.Mutex `json:"-"`
- ExpireAt time.Time `json:"expire"`
-}
-
-func InitXVQD(client httpclient.AuroraHttpClient, proxyUrl string) (string, error) {
- if Token == nil {
- Token = &XqdgToken{
- Token: "",
- M: sync.Mutex{},
- }
- }
- Token.M.Lock()
- defer Token.M.Unlock()
- if Token.Token == "" || Token.ExpireAt.Before(time.Now()) {
- status, err := postStatus(client, proxyUrl)
- if err != nil {
- return "", err
- }
- defer status.Body.Close()
- token := status.Header.Get("x-vqd-4")
- if token == "" {
- return "", errors.New("no x-vqd-4 token")
- }
- Token.Token = token
- Token.ExpireAt = time.Now().Add(time.Minute * 5)
- }
-
- return Token.Token, nil
-}
-
-func postStatus(client httpclient.AuroraHttpClient, proxyUrl string) (*http.Response, error) {
- if proxyUrl != "" {
- client.SetProxy(proxyUrl)
- }
- header := createHeader()
- header.Set("accept", "*/*")
- header.Set("x-vqd-accept", "1")
- response, err := client.Request(httpclient.GET, "https://duckduckgo.com/duckchat/v1/status", header, nil, nil)
- if err != nil {
- return nil, err
- }
- return response, nil
-}
-
-func POSTconversation(client httpclient.AuroraHttpClient, request duckgotypes.ApiRequest, token string, proxyUrl string) (*http.Response, error) {
- if proxyUrl != "" {
- client.SetProxy(proxyUrl)
- }
- body_json, err := json.Marshal(request)
- if err != nil {
- return &http.Response{}, err
- }
- header := createHeader()
- header.Set("accept", "text/event-stream")
- header.Set("x-vqd-4", token)
- response, err := client.Request(httpclient.POST, "https://duckduckgo.com/duckchat/v1/chat", header, nil, bytes.NewBuffer(body_json))
- if err != nil {
- return nil, err
- }
- return response, nil
-}
-
-func Handle_request_error(c *gin.Context, response *http.Response) bool {
- if response.StatusCode != 200 {
- // Try read response body as JSON
- var error_response map[string]interface{}
- err := json.NewDecoder(response.Body).Decode(&error_response)
- if err != nil {
- // Read response body
- body, _ := io.ReadAll(response.Body)
- c.JSON(response.StatusCode, gin.H{"error": gin.H{
- "message": "Unknown error",
- "type": "internal_server_error",
- "param": nil,
- "code": "500",
- "details": string(body),
- }})
- return true
- }
- c.JSON(response.StatusCode, gin.H{"error": gin.H{
- "message": error_response["detail"],
- "type": response.Status,
- "param": nil,
- "code": "error",
- }})
- return true
- }
- return false
-}
-
-func createHeader() httpclient.AuroraHeaders {
- header := make(httpclient.AuroraHeaders)
- header.Set("accept-language", "zh-CN,zh;q=0.9")
- header.Set("content-type", "application/json")
- header.Set("origin", "https://duckduckgo.com")
- header.Set("referer", "https://duckduckgo.com/")
- header.Set("sec-ch-ua", `"Chromium";v="120", "Google Chrome";v="120", "Not-A.Brand";v="99"`)
- header.Set("sec-ch-ua-mobile", "?0")
- header.Set("sec-ch-ua-platform", `"Windows"`)
- header.Set("user-agent", UA)
- return header
-}
-
-func Handler(c *gin.Context, response *http.Response, oldRequest duckgotypes.ApiRequest, stream bool) string {
- reader := bufio.NewReader(response.Body)
- if stream {
- // Response content type is text/event-stream
- c.Header("Content-Type", "text/event-stream")
- } else {
- // Response content type is application/json
- c.Header("Content-Type", "application/json")
- }
-
- var previousText strings.Builder
- for {
- line, err := reader.ReadString('\n')
- if err != nil {
- if err == io.EOF {
- break
- }
- return ""
- }
- if len(line) < 6 {
- continue
- }
- line = line[6:]
- if !strings.HasPrefix(line, "[DONE]") {
- var originalResponse duckgotypes.ApiResponse
- err = json.Unmarshal([]byte(line), &originalResponse)
- if err != nil {
- continue
- }
- if originalResponse.Action != "success" {
- c.JSON(500, gin.H{"error": "Error"})
- return ""
- }
- responseString := ""
- if originalResponse.Message != "" {
- previousText.WriteString(originalResponse.Message)
- translatedResponse := officialtypes.NewChatCompletionChunkWithModel(originalResponse.Message, originalResponse.Model)
- responseString = "data: " + translatedResponse.String() + "\n\n"
- }
-
- if responseString == "" {
- continue
- }
-
- if stream {
- _, err = c.Writer.WriteString(responseString)
- if err != nil {
- return ""
- }
- c.Writer.Flush()
- }
- } else {
- if stream {
- final_line := officialtypes.StopChunkWithModel("stop", oldRequest.Model)
- c.Writer.WriteString("data: " + final_line.String() + "\n\n")
- }
- }
- }
- return previousText.String()
-}
diff --git a/internal/proxys/proxys.go b/internal/proxys/proxys.go
deleted file mode 100644
index 8ee40d222f0509c892ee53ff649c6cb06b3bebde..0000000000000000000000000000000000000000
--- a/internal/proxys/proxys.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package proxys
-
-import "sync"
-
-type IProxy struct {
- ips []string
- lock sync.Mutex
-}
-
-func NewIProxyIP(ips []string) IProxy {
- return IProxy{
- ips: ips,
- }
-}
-
-func (p *IProxy) GetIPS() int {
- return len(p.ips)
-}
-
-func (p *IProxy) GetProxyIP() string {
- if p == nil {
- return ""
- }
-
- p.lock.Lock()
- defer p.lock.Unlock()
-
- if len(p.ips) == 0 {
- return ""
- }
-
- proxyIp := p.ips[0]
- p.ips = append(p.ips[1:], proxyIp)
- return proxyIp
-}
diff --git a/main.go b/main.go
index 1edf89a1192b4f228140831fd176b5b251c444e8..38b09a0413cb0bde2eef30dede5e502476aeb161 100644
--- a/main.go
+++ b/main.go
@@ -1,50 +1,35 @@
package main
import (
- "aurora/initialize"
- "embed"
- "io/fs"
- "log"
- "net/http"
- "os"
-
+ "fmt"
+ "free-gpt3.5-2api/FreeGpt35Pool"
+ "free-gpt3.5-2api/ProxyPool"
+ "free-gpt3.5-2api/config"
+ "free-gpt3.5-2api/router"
+ "github.com/aurorax-neo/go-logger"
"github.com/gin-gonic/gin"
-
- "github.com/acheong08/endless"
- "github.com/joho/godotenv"
)
-//go:embed web/*
-var staticFiles embed.FS
+func Init() {
+ ProxyPool.GetProxyPoolInstance()
+ FreeGpt35Pool.GetFreeGpt35PoolInstance()
+}
func main() {
+ // Init
+ Init()
+ // Initialize HTTP server
gin.SetMode(gin.ReleaseMode)
- router := initialize.RegisterRouter()
- subFS, err := fs.Sub(staticFiles, "web")
- if err != nil {
- log.Fatal(err)
- }
- router.StaticFS("/web", http.FS(subFS))
-
- _ = godotenv.Load(".env")
- host := os.Getenv("SERVER_HOST")
- port := os.Getenv("SERVER_PORT")
- tlsCert := os.Getenv("TLS_CERT")
- tlsKey := os.Getenv("TLS_KEY")
-
- if host == "" {
- host = "0.0.0.0"
- }
- if port == "" {
- port = os.Getenv("PORT")
- if port == "" {
- port = "8080"
- }
- }
-
- if tlsCert != "" && tlsKey != "" {
- _ = endless.ListenAndServeTLS(host+":"+port, tlsCert, tlsKey, router)
- } else {
- _ = endless.ListenAndServe(host+":"+port, router)
+ server := gin.New()
+ server.Use(gin.Recovery())
+ // 设置路由
+ router.SetRouter(server)
+ // 提示服务启动
+ host := config.Bind
+ if config.Bind == "0.0.0.0" {
+ host = "127.0.0.1"
}
+ logger.Logger.Info(fmt.Sprint("Server started on http://", host, ":", config.Port))
+ // 启动 HTTP 服务器
+ _ = server.Run(fmt.Sprint(config.Bind, ":", config.Port))
}
diff --git a/middlewares/auth.go b/middlewares/auth.go
deleted file mode 100644
index f67e5198e5fdf9043a79520910d839569e1516f4..0000000000000000000000000000000000000000
--- a/middlewares/auth.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package middlewares
-
-import (
- "github.com/gin-gonic/gin"
- "os"
- "strings"
-)
-
-func Authorization(c *gin.Context) {
- customer_key := os.Getenv("Authorization")
- if customer_key != "" {
- authHeader := c.GetHeader("Authorization")
- if authHeader == "" {
- c.JSON(401, gin.H{"error": "Unauthorized"})
- c.Abort()
- return
- }
- tokenParts := strings.Split(strings.Replace(authHeader, "Bearer ", "", 1)," ")
- customAccessToken := tokenParts[0]
- if customer_key != customAccessToken {
- c.JSON(401, gin.H{"error": "Unauthorized"})
- c.Abort()
- return
- }
- if len(tokenParts) > 1 {
- openaiAccessToken := tokenParts[1]
- c.Request.Header.Set("Authorization", "Bearer " + openaiAccessToken)
- }
- }
- c.Next()
-}
diff --git a/middlewares/cors.go b/middlewares/cors.go
deleted file mode 100644
index 8818637675f48b98abf5211570750767f5ad1232..0000000000000000000000000000000000000000
--- a/middlewares/cors.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package middlewares
-
-import "github.com/gin-gonic/gin"
-
-func Cors(c *gin.Context) {
- c.Header("Access-Control-Allow-Origin", "*")
- c.Header("Access-Control-Allow-Methods", "*")
- c.Header("Access-Control-Allow-Headers", "*")
- c.Next()
-}
diff --git a/queue/queue.go b/queue/queue.go
new file mode 100644
index 0000000000000000000000000000000000000000..3278488734b16abfdd1ae43c0f33bd2a0cbdbf4d
--- /dev/null
+++ b/queue/queue.go
@@ -0,0 +1,106 @@
+package queue
+
+type (
+ Queue struct {
+ start, end *Node
+ length int
+ }
+ Node struct {
+ Value interface{}
+ next *Node
+ }
+)
+
+// New 新建一个队列
+func New() *Queue {
+ return &Queue{nil, nil, 0}
+}
+
+// Dequeue 出队
+func (Q *Queue) Dequeue() *Node {
+ if Q.length == 0 {
+ return nil
+ }
+ n := Q.start
+ if Q.length == 1 {
+ Q.start = nil
+ Q.end = nil
+ } else {
+ Q.start = Q.start.next
+ }
+ Q.length--
+ return n
+}
+
+// Enqueue 入队
+func (Q *Queue) Enqueue(value interface{}) {
+ n := &Node{value, nil}
+ if Q.length == 0 {
+ Q.start = n
+ Q.end = n
+ } else {
+ Q.end.next = n
+ Q.end = n
+ }
+ Q.length++
+}
+
+// Len 获取队列长度
+func (Q *Queue) Len() int {
+ return Q.length
+}
+
+// Peek 返回队列的第一个元素
+func (Q *Queue) Peek() *Node {
+ if Q.length == 0 {
+ return nil
+ }
+ return Q.start
+}
+
+// Remove 移除指定节点
+func (Q *Queue) Remove(n *Node) {
+ if Q.length == 0 || n == nil {
+ return
+ }
+
+ // 如果移除的是队列的第一个元素
+ if n == Q.start {
+ Q.start = Q.start.next
+ if Q.start == nil {
+ // 如果移除后队列为空,则end也应该设置为nil
+ Q.end = nil
+ }
+ Q.length--
+ return
+ }
+
+ // 找到n的前一个节点
+ prevNode := Q.start
+ for prevNode != nil && prevNode.next != n {
+ prevNode = prevNode.next
+ }
+
+ if prevNode == nil {
+ // 没有找到n的前一个节点(n不在队列中)
+ return
+ }
+
+ // 移除节点n
+ prevNode.next = n.next
+ // 如果移除的是最后一个元素,更新end指针
+ if n.next == nil {
+ Q.end = prevNode
+ }
+ Q.length--
+}
+
+// Traverse 遍历队列
+func (Q *Queue) Traverse(cb func(n *Node)) {
+ if Q.length == 0 {
+ return
+ }
+ for n := Q.start; n != nil; n = n.next {
+ cb(n)
+ }
+}
diff --git a/release.bat b/release.bat
index b7b5ac8dfe996ac4c5f7d1fc8e58bea8c205515b..dc1200192f647440b9a60db8438b2cbfc5d08565 100644
--- a/release.bat
+++ b/release.bat
@@ -5,10 +5,10 @@ REM 指定编码为 UTF-8
chcp 65001
REM 设置要生成的可执行文件的名称
-set OUTPUT_NAME=aurora
+set OUTPUT_NAME=free-gpt3.5-2api
REM 设置 Go 源文件的名称
-SET GOFILE=aurora
+SET GOFILE=main.go
REM 设置输出目录
SET OUTPUTDIR=target
diff --git a/render.yaml b/render.yaml
deleted file mode 100644
index 2593b666e39d9a6893b8cea0b279112aeffeda92..0000000000000000000000000000000000000000
--- a/render.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-services:
- - type: web
- name: duck2api
- env: docker
- dockerfilePath: ./Dockerfile
- plan: free
-
diff --git a/router/middleware.go b/router/middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..93c0e4e8b710f9ba03b605b12560a2df6c47b862
--- /dev/null
+++ b/router/middleware.go
@@ -0,0 +1,63 @@
+package router
+
+import (
+ "fmt"
+ "free-gpt3.5-2api/common"
+ "free-gpt3.5-2api/config"
+ "github.com/aurorax-neo/go-logger"
+ "github.com/gin-gonic/gin"
+)
+
+// Ping 测试接口
+func Ping(c *gin.Context) {
+ c.JSON(200, gin.H{
+ "message": "pong",
+ })
+}
+
+// V1Cors 跨域中间件
+func V1Cors(c *gin.Context) {
+ // 允许跨域
+ c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
+ c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
+ c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
+ c.Writer.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept")
+ c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
+ // 如果是OPTIONS请求,直接返回
+ if c.Request.Method == "OPTIONS" {
+ c.AbortWithStatus(204)
+ return
+ }
+ c.Next()
+}
+
+// V1Request 请求中间件
+func V1Request(c *gin.Context) {
+ // 打印请求摘要 方法 url ip - user-agent 格式化输出
+ infoStr := fmt.Sprint(" -> ", c.Request.Method, " ", c.Request.URL.String(), " - ", c.ClientIP(), " - ", c.Request.Header.Get("User-Agent"))
+ logger.Logger.Info(infoStr)
+ c.Next()
+}
+
+// V1Auth 验证v1 api 的token
+func V1Auth(c *gin.Context) {
+ authToken := c.Request.Header.Get("Authorization")
+ if authToken == "" && len(config.AUTHORIZATIONS) > 0 {
+ common.ErrorResponse(c, 401, "You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY)", nil)
+ return
+ }
+ // 判断 authToken 是否在 config.CONFIG.AUTHORIZATIONS 列表
+ if !common.IsStrInArray(authToken, config.AUTHORIZATIONS) {
+ common.ErrorResponse(c, 401, "Incorrect API key provided: sk-4yNZz***************************************6mjw.", nil)
+ return
+ }
+ c.Next()
+}
+
+// V1Response 响应中间件
+func V1Response(c *gin.Context) {
+ c.Next()
+ // 打印响应摘要 方法 url 状态码
+ infoStr := fmt.Sprint(" <- ", c.Request.Method, " ", c.Request.URL.String(), " - ", c.Writer.Status())
+ logger.Logger.Info(infoStr)
+}
diff --git a/router/router.go b/router/router.go
new file mode 100644
index 0000000000000000000000000000000000000000..9aff77691a9921828c63e6140e28ea0cc2f06dde
--- /dev/null
+++ b/router/router.go
@@ -0,0 +1,25 @@
+package router
+
+import (
+ v1 "free-gpt3.5-2api/service/v1"
+ "free-gpt3.5-2api/service/v1Chat"
+ "github.com/gin-gonic/gin"
+ "net/http"
+)
+
+func SetRouter(router *gin.Engine) {
+ router.GET("/", Index)
+ router.GET("/ping", Ping)
+ v1Router := router.Group("/v1")
+ v1Router.Use(V1Cors)
+ v1Router.Use(V1Request)
+ v1Router.Use(V1Response)
+ v1Router.Use(V1Auth)
+ v1Router.GET("/tokens", v1.Tokens)
+ v1Router.OPTIONS("/chat/completions", nil)
+ v1Router.POST("/chat/completions", v1Chat.Completions)
+}
+
+func Index(c *gin.Context) {
+ c.String(http.StatusOK, "Hello,This is free-gpt3.5-2api.")
+}
diff --git a/service/v1/tokens.go b/service/v1/tokens.go
new file mode 100644
index 0000000000000000000000000000000000000000..b576c184401eabe468ea04dee1de63a4c8698423
--- /dev/null
+++ b/service/v1/tokens.go
@@ -0,0 +1,20 @@
+package v1
+
+import (
+ "fmt"
+ "free-gpt3.5-2api/FreeGpt35Pool"
+ "github.com/aurorax-neo/go-logger"
+ "github.com/gin-gonic/gin"
+)
+
+type TokensResp struct {
+ Count int `json:"count"`
+}
+
+func Tokens(c *gin.Context) {
+ resp := &TokensResp{
+ Count: FreeGpt35Pool.GetFreeGpt35PoolInstance().GetSize(),
+ }
+ logger.Logger.Info(fmt.Sprint("FreeGpt35Pool Tokens: ", resp.Count))
+ c.JSON(200, resp)
+}
diff --git a/service/v1/util.go b/service/v1/util.go
new file mode 100644
index 0000000000000000000000000000000000000000..358e84e457c7137e344a27af7f96a697563475e7
--- /dev/null
+++ b/service/v1/util.go
@@ -0,0 +1,65 @@
+package v1
+
+import (
+ "free-gpt3.5-2api/service/v1Chat/reqModel"
+ "github.com/google/uuid"
+ "math/rand"
+)
+
+func MappingModel(model string) string {
+ var modelMapping = map[string]string{
+ "gpt-3.5-turbo": "text-davinci-002-render-sha",
+ "gpt-3.5-turbo-16k": "text-davinci-002-render-sha",
+ "gpt-3.5-turbo-16k-0613": "text-davinci-002-render-sha",
+ "gpt-3.5-turbo-0301": "text-davinci-002-render-sha",
+ "gpt-3.5-turbo-0613": "text-davinci-002-render-sha",
+ "gpt-3.5-turbo-1106": "text-davinci-002-render-sha",
+ }
+ if model == "" {
+ return "text-davinci-002-render-sha"
+ }
+ if v, ok := modelMapping[model]; ok {
+ return v
+ }
+ return "text-davinci-002-render-sha"
+}
+
+func GenerateID(length int) string {
+ const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ id := "chatcmpl-"
+ for i := 0; i < length; i++ {
+ id += string(charset[rand.Intn(len(charset))])
+ }
+ return id
+}
+
+func ApiReq2ChatReq35(apiReq *reqModel.ApiReq) (chatReq *reqModel.ChatReq35) {
+ messages := make([]reqModel.ChatMessages, 0)
+ for _, apiMessage := range apiReq.Messages {
+ chatMessage := reqModel.ChatMessages{
+ Author: reqModel.ChatAuthor{
+ Role: apiMessage.Role,
+ },
+ Content: reqModel.ChatContent{
+ ContentType: "text",
+ Parts: []string{apiMessage.Content},
+ },
+ }
+ messages = append(messages, chatMessage)
+ }
+
+ chatReq = &reqModel.ChatReq35{
+ Action: "next",
+ Messages: messages,
+ ParentMessageId: uuid.New().String(),
+ Model: MappingModel(apiReq.Model),
+ TimeZoneOffsetMin: -180,
+ Suggestions: make([]string, 0),
+ HistoryAndTrainingDisabled: true,
+ ConversationMode: reqModel.ChatConversationMode{
+ Kind: "primary_assistant",
+ },
+ WebsocketRequestId: uuid.New().String(),
+ }
+ return chatReq
+}
diff --git a/service/v1Chat/completions.go b/service/v1Chat/completions.go
new file mode 100644
index 0000000000000000000000000000000000000000..434834a6513424ed52d5632b0532c0ab47ad87fb
--- /dev/null
+++ b/service/v1Chat/completions.go
@@ -0,0 +1,19 @@
+package v1Chat
+
+import (
+ "free-gpt3.5-2api/common"
+ "free-gpt3.5-2api/service/v1Chat/reqModel"
+ "github.com/gin-gonic/gin"
+ "net/http"
+)
+
+func Completions(c *gin.Context) {
+ // 从请求中获取参数
+ apiReq := &reqModel.ApiReq{}
+ err := c.BindJSON(apiReq)
+ if err != nil {
+ common.ErrorResponse(c, http.StatusBadRequest, "Invalid parameter", nil)
+ return
+ }
+ Gpt35Completions(c, apiReq)
+}
diff --git a/service/v1Chat/gpt35Completions.go b/service/v1Chat/gpt35Completions.go
new file mode 100644
index 0000000000000000000000000000000000000000..650cc0b5d37cc6cd8498ceb1dc2106acf250971e
--- /dev/null
+++ b/service/v1Chat/gpt35Completions.go
@@ -0,0 +1,231 @@
+package v1Chat
+
+import (
+ "encoding/json"
+ "fmt"
+ "free-gpt3.5-2api/FreeGpt35"
+ "free-gpt3.5-2api/FreeGpt35Pool"
+ "free-gpt3.5-2api/common"
+ "free-gpt3.5-2api/service/v1"
+ "free-gpt3.5-2api/service/v1Chat/reqModel"
+ "free-gpt3.5-2api/service/v1Chat/respModel"
+ "github.com/aurorax-neo/go-logger"
+ fhttp "github.com/bogdanfinn/fhttp"
+ "github.com/gin-gonic/gin"
+ "github.com/launchdarkly/eventsource"
+ "io"
+ "net/http"
+ "strings"
+)
+
+func Gpt35Completions(c *gin.Context, apiReq *reqModel.ApiReq) {
+ // 获取 FreeGpt35 实例
+ ChatGpt35 := FreeGpt35Pool.GetFreeGpt35PoolInstance().GetFreeGpt35(3)
+ if ChatGpt35 == nil {
+ errStr := "please restart the program、change the IP address、use a proxy to try again."
+ logger.Logger.Error(errStr)
+ common.ErrorResponse(c, http.StatusUnauthorized, errStr, nil)
+ return
+ }
+ // 转换请求
+ ChatReq35 := v1.ApiReq2ChatReq35(apiReq)
+ // 请求参数
+ body, err := common.Struct2BytesBuffer(ChatReq35)
+ if err != nil {
+ logger.Logger.Error(err.Error())
+ common.ErrorResponse(c, http.StatusInternalServerError, "", err)
+ return
+
+ }
+ // 生成请求
+ request, err := ChatGpt35.NewRequest(fhttp.MethodPost, FreeGpt35.ChatUrl, body)
+ if err != nil || request == nil {
+ errStr := "Request is nil or error"
+ logger.Logger.Error("Request is nil or error")
+ common.ErrorResponse(c, http.StatusInternalServerError, errStr, err)
+ return
+ }
+ // 设置请求头
+ request.Header.Set("Content-Type", "application/json")
+ request.Header.Set("oai-device-id", ChatGpt35.FreeAuth.OaiDeviceId)
+ request.Header.Set("openai-sentinel-chat-requirements-token", ChatGpt35.FreeAuth.Token)
+ if ChatGpt35.FreeAuth.ProofWork.Required {
+ request.Header.Set("Openai-Sentinel-Proof-Token", ChatGpt35.FreeAuth.ProofWork.Ospt)
+ }
+ // 发送请求
+ response, err := ChatGpt35.RequestClient.Do(request)
+ if err != nil {
+ errStr := "RequestClient Do error"
+ logger.Logger.Error(fmt.Sprint(errStr, " ", err))
+ common.ErrorResponse(c, http.StatusInternalServerError, errStr, err)
+ return
+ }
+ defer func(Body io.ReadCloser) {
+ _ = Body.Close()
+ }(response.Body)
+ if response.StatusCode != http.StatusOK {
+ errStr := "Request error"
+ logger.Logger.Error(fmt.Sprint(errStr, " ", response.StatusCode))
+ common.ErrorResponse(c, response.StatusCode, errStr, nil)
+ return
+ }
+ // 流式返回
+ if apiReq.Stream {
+ __CompletionsStream(c, apiReq, response)
+ } else { // 非流式回应
+ __CompletionsNoStream(c, apiReq, response)
+ }
+}
+
+func __CompletionsStream(c *gin.Context, apiReq *reqModel.ApiReq, resp *fhttp.Response) {
+ defer func(Body io.ReadCloser) {
+ _ = Body.Close()
+ }(resp.Body)
+ messageTemp := ""
+ decoder := eventsource.NewDecoder(resp.Body)
+ // 响应id
+ id := v1.GenerateID(29)
+ handlingSigns := false
+ for {
+ event, err := decoder.Decode()
+ if err != nil {
+ logger.Logger.Error(err.Error())
+ common.ErrorResponse(c, http.StatusInternalServerError, "", err)
+ break
+ }
+ name := event.Event()
+ data := event.Data()
+ // 空白数据不处理
+ if data == "" {
+ continue
+ }
+ // 结束标志
+ if data == "[DONE]" {
+ // 生成响应 stream
+ apiRespStream := respModel.NewApiRespStream(id, apiReq.Model, "", "stop")
+ // 生成响应 bytes
+ bytes, err := common.Struct2Bytes(apiRespStream)
+ if err != nil {
+ logger.Logger.Error(err.Error())
+ continue
+ }
+ // 发送响应
+ c.SSEvent(name, fmt.Sprint(" ", string(bytes)))
+ // 结束
+ c.SSEvent(name, " [DONE]")
+ return
+ }
+ chatResp35 := &respModel.ChatResp35{}
+ err = json.Unmarshal([]byte(data), chatResp35)
+ if chatResp35.Error != nil && !handlingSigns {
+ logger.Logger.Error(fmt.Sprint(chatResp35.Error))
+ common.ErrorResponse(c, http.StatusInternalServerError, "", chatResp35.Error)
+ return
+ }
+ // 脏数据不处理
+ if err != nil {
+ continue
+ }
+ // 被block
+ if contentIsBlocked(chatResp35) {
+ // 返回响应
+ common.ErrorResponse(c, http.StatusBadRequest, "content is blocked.", "")
+ return
+ }
+ // 仅处理assistant的消息
+ if chatResp35.Message.Author.Role == "assistant" && (chatResp35.Message.Status == "in_progress" || handlingSigns) {
+ // handlingSigns 置为 true
+ handlingSigns = true
+ // 仅处理第一个part
+ parts := chatResp35.Message.Content.Parts[0]
+ // 去除重复数据
+ content := strings.Replace(parts, messageTemp, "", 1)
+ messageTemp = parts
+ // 空白数据不处理
+ if content == "" {
+ continue
+ }
+ // 生成响应 stream
+ apiRespStream := respModel.NewApiRespStream(id, apiReq.Model, content, "")
+ // 生成响应 bytes
+ bytes, err := common.Struct2Bytes(apiRespStream)
+ if err != nil {
+ logger.Logger.Error(err.Error())
+ continue
+ }
+ // 发送响应
+ c.SSEvent(name, fmt.Sprint(" ", string(bytes)))
+ // 继续
+ continue
+ }
+ }
+}
+
+func __CompletionsNoStream(c *gin.Context, apiReq *reqModel.ApiReq, resp *fhttp.Response) {
+ defer func(Body io.ReadCloser) {
+ _ = Body.Close()
+ }(resp.Body)
+ content := ""
+ decoder := eventsource.NewDecoder(resp.Body)
+ handlingSigns := false
+ for {
+ event, err := decoder.Decode()
+ if err != nil {
+ logger.Logger.Error(err.Error())
+ common.ErrorResponse(c, http.StatusInternalServerError, "", err)
+ return
+ }
+ data := event.Data()
+ // 空白数据不处理
+ if data == "" {
+ continue
+ }
+ // 结束标志
+ if data == "[DONE]" {
+ apiRespObj := respModel.NewApiRespJson(v1.GenerateID(29), apiReq.Model, content)
+ // 返回响应
+ c.JSON(http.StatusOK, apiRespObj)
+ return
+ }
+ chatResp35 := &respModel.ChatResp35{}
+ err = json.Unmarshal([]byte(data), chatResp35)
+ if chatResp35.Error != nil && !handlingSigns {
+ logger.Logger.Error(fmt.Sprint(chatResp35.Error))
+ common.ErrorResponse(c, http.StatusInternalServerError, "", chatResp35.Error)
+ return
+ }
+ // 被block
+ if contentIsBlocked(chatResp35) {
+ // 返回响应
+ common.ErrorResponse(c, http.StatusBadRequest, "content is blocked.", "")
+ return
+ }
+ // 脏数据不处理
+ if err != nil {
+ continue
+ }
+ // 仅处理assistant的消息
+ if chatResp35.Message.Author.Role == "assistant" && (chatResp35.Message.Status == "in_progress" || handlingSigns) {
+ // handlingSigns 置为 true
+ handlingSigns = true
+ // 如果不包含上一次的数据则不处理
+ if !strings.Contains(chatResp35.Message.Content.Parts[0], content) {
+ continue
+ }
+ // 仅处理第一个part
+ content = chatResp35.Message.Content.Parts[0]
+ // 空白数据不处理
+ if content == "" {
+ continue
+ }
+ continue
+ }
+ }
+}
+
+func contentIsBlocked(chatResp35 *respModel.ChatResp35) bool {
+ if !chatResp35.IsCompletion && chatResp35.ModerationResponse.Blocked {
+ return true
+ }
+ return false
+}
diff --git a/service/v1Chat/reqModel/apiReq.go b/service/v1Chat/reqModel/apiReq.go
new file mode 100644
index 0000000000000000000000000000000000000000..3363f3638603fb56147f7fabeddab70d372912e4
--- /dev/null
+++ b/service/v1Chat/reqModel/apiReq.go
@@ -0,0 +1,14 @@
+package reqModel
+
+type ApiReq struct {
+ Messages []ApiMessage `json:"messages"`
+ Model string `json:"model"`
+ Stream bool `json:"stream"`
+ PluginIds []string `json:"plugin_ids"`
+ NewMessages string `json:"-"`
+}
+
+type ApiMessage struct {
+ Role string `json:"role"`
+ Content string `json:"content"`
+}
diff --git a/service/v1Chat/reqModel/chatReq.go b/service/v1Chat/reqModel/chatReq.go
new file mode 100644
index 0000000000000000000000000000000000000000..41e7c34df62d734d8dd76c0f1b43ab21548fdf55
--- /dev/null
+++ b/service/v1Chat/reqModel/chatReq.go
@@ -0,0 +1,31 @@
+package reqModel
+
+type ChatAuthor struct {
+ Role string `json:"role"`
+}
+
+type ChatContent struct {
+ ContentType string `json:"content_type"`
+ Parts []string `json:"parts"`
+}
+
+type ChatMessages struct {
+ Author ChatAuthor `json:"author"`
+ Content ChatContent `json:"content"`
+}
+
+type ChatConversationMode struct {
+ Kind string `json:"kind"`
+}
+
+type ChatReq35 struct {
+ Action string `json:"action"`
+ Messages []ChatMessages `json:"messages"`
+ ParentMessageId string `json:"parent_message_id"`
+ Model string `json:"model"`
+ TimeZoneOffsetMin int `json:"timezone_offset_min"`
+ Suggestions []string `json:"suggestions"`
+ HistoryAndTrainingDisabled bool `json:"history_and_training_disabled"`
+ ConversationMode ChatConversationMode `json:"conversation_mode"`
+ WebsocketRequestId string `json:"websocket_request_id"`
+}
diff --git a/service/v1Chat/respModel/apiRespJson.go b/service/v1Chat/respModel/apiRespJson.go
new file mode 100644
index 0000000000000000000000000000000000000000..e6ca66afb59e7cd923ffb5885cb0a37274564992
--- /dev/null
+++ b/service/v1Chat/respModel/apiRespJson.go
@@ -0,0 +1,54 @@
+package respModel
+
+import "time"
+
+type ApiRespJson struct {
+ ID string `json:"id"`
+ Object string `json:"object"`
+ Created int64 `json:"created"`
+ Model string `json:"model"`
+ Usage ApiRespJsonUsage `json:"usage"`
+ Choices []ApiRespJsonChoice `json:"choices"`
+}
+
+type ApiRespJsonMessage struct {
+ Role string `json:"role"`
+ Content string `json:"content"`
+}
+
+type ApiRespJsonChoice struct {
+ Message ApiRespJsonMessage `json:"message"`
+ FinishReason string `json:"finish_reason"`
+ Index int `json:"index"`
+}
+
+type ApiRespJsonUsage struct {
+ PromptTokens int `json:"prompt_tokens"`
+ CompletionTokens int `json:"completion_tokens"`
+ TotalTokens int `json:"total_tokens"`
+}
+
+func NewApiRespJson(id string, model string, content string) *ApiRespJson {
+ apiRespObj := &ApiRespJson{
+ ID: id,
+ Created: time.Now().Unix(),
+ Object: "chat.completion",
+ Model: model,
+ Usage: ApiRespJsonUsage{
+ PromptTokens: 0,
+ CompletionTokens: 0,
+ TotalTokens: 0,
+ },
+ Choices: []ApiRespJsonChoice{
+ {
+ Message: ApiRespJsonMessage{
+ Role: "assistant",
+ Content: content,
+ },
+ FinishReason: "stop",
+ Index: 0,
+ },
+ },
+ }
+ return apiRespObj
+}
\ No newline at end of file
diff --git a/service/v1Chat/respModel/apiRespStream.go b/service/v1Chat/respModel/apiRespStream.go
new file mode 100644
index 0000000000000000000000000000000000000000..fad990741116fbedf3c76d9b990b04453db35808
--- /dev/null
+++ b/service/v1Chat/respModel/apiRespStream.go
@@ -0,0 +1,43 @@
+package respModel
+
+import "time"
+
+// ApiRespStream represents the JSON structure
+type ApiRespStream struct {
+ ID string `json:"id"`
+ Object string `json:"object"`
+ Created int64 `json:"created"`
+ Model string `json:"model"`
+ Choices []ApiStreamChoice `json:"choices"`
+}
+
+// ApiStreamChoice represents the nested "choices" object in the JSON
+type ApiStreamChoice struct {
+ Delta ApiStreamDelta `json:"delta"`
+ Index int `json:"index"`
+ FinishReason string `json:"finish_reason"`
+}
+
+// ApiStreamDelta represents the nested "delta" object in the JSON
+type ApiStreamDelta struct {
+ Content string `json:"content"`
+}
+
+func NewApiRespStream(id string, model string, content string, finishReason string) *ApiRespStream {
+ // 生成响应 model
+ apiRespStream := &ApiRespStream{
+ ID: id,
+ Created: time.Now().Unix(),
+ Object: "chat.completion.chunk",
+ Model: model,
+ Choices: []ApiStreamChoice{
+ {
+ Delta: ApiStreamDelta{
+ Content: content,
+ },
+ FinishReason: finishReason,
+ },
+ },
+ }
+ return apiRespStream
+}
diff --git a/service/v1Chat/respModel/chatResp.go b/service/v1Chat/respModel/chatResp.go
new file mode 100644
index 0000000000000000000000000000000000000000..b54ccd01e79b3ba87968e7db9b46ea2142ff5ff5
--- /dev/null
+++ b/service/v1Chat/respModel/chatResp.go
@@ -0,0 +1,44 @@
+package respModel
+
+type ChatResp35 struct {
+ Message struct {
+ Id string `json:"id"`
+ Author struct {
+ Role string `json:"role"`
+ Name interface{} `json:"name"`
+ Metadata struct {
+ } `json:"metadata"`
+ } `json:"author"`
+ CreateTime float64 `json:"create_time"`
+ UpdateTime interface{} `json:"update_time"`
+ Content struct {
+ ContentType string `json:"content_type"`
+ Parts []string `json:"parts"`
+ } `json:"content"`
+ Status string `json:"status"`
+ EndTurn interface{} `json:"end_turn"`
+ Weight float64 `json:"weight"`
+ Metadata struct {
+ Citations []interface{} `json:"citations"`
+ GizmoId interface{} `json:"gizmo_id"`
+ MessageType string `json:"message_type"`
+ ModelSlug string `json:"model_slug"`
+ DefaultModelSlug string `json:"default_model_slug"`
+ Pad string `json:"pad"`
+ ParentId string `json:"parent_id"`
+ } `json:"metadata"`
+ Recipient string `json:"recipient"`
+ } `json:"message"`
+ ConversationId string `json:"conversation_id"`
+ Error interface{} `json:"error"`
+ // 审核
+ Type string `json:"type"`
+ MessageId string `json:"message_id"`
+ IsCompletion bool `json:"is_completion"`
+ ModerationResponse struct {
+ Flagged bool `json:"flagged"`
+ Disclaimers []interface{} `json:"disclaimers"`
+ Blocked bool `json:"blocked"`
+ ModerationId string `json:"moderation_id"`
+ } `json:"moderation_response"`
+}
diff --git a/typings/duckgo/request.go b/typings/duckgo/request.go
deleted file mode 100644
index b901d1c7f37ff3ee588c989ce66232e55a79fa25..0000000000000000000000000000000000000000
--- a/typings/duckgo/request.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package duckgo
-
-type ApiRequest struct {
- Model string `json:"model"`
- Messages []messages `json:"messages"`
-}
-type messages struct {
- Role string `json:"role"`
- Content string `json:"content"`
-}
-
-func (a *ApiRequest) AddMessage(role string, content string) {
- a.Messages = append(a.Messages, messages{
- Role: role,
- Content: content,
- })
-}
-
-func NewApiRequest(model string) ApiRequest {
- return ApiRequest{
- Model: model,
- }
-}
diff --git a/typings/duckgo/response.go b/typings/duckgo/response.go
deleted file mode 100644
index 010bea4db4aa17f374ecde33455f85c3548f4953..0000000000000000000000000000000000000000
--- a/typings/duckgo/response.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package duckgo
-
-type ApiResponse struct {
- Message string `json:"message"`
- Created int `json:"created"`
- Id string `json:"id"`
- Action string `json:"action"`
- Model string `json:"model"`
-}
diff --git a/typings/official/request.go b/typings/official/request.go
deleted file mode 100644
index 43ee3ea74b825ae54d5e33b1b886ba723ed25bd1..0000000000000000000000000000000000000000
--- a/typings/official/request.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package official
-
-type APIRequest struct {
- Messages []api_message `json:"messages"`
- Stream bool `json:"stream"`
- Model string `json:"model"`
- PluginIDs []string `json:"plugin_ids"`
-}
-
-type api_message struct {
- Role string `json:"role"`
- Content string `json:"content"`
-}
-
-type OpenAISessionToken struct {
- SessionToken string `json:"session_token"`
-}
-
-type OpenAIRefreshToken struct {
- RefreshToken string `json:"refresh_token"`
-}
diff --git a/typings/official/response.go b/typings/official/response.go
deleted file mode 100644
index 67624c2b42ec5ac326c68e858711936d4c625ded..0000000000000000000000000000000000000000
--- a/typings/official/response.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package official
-
-import "encoding/json"
-
-type ChatCompletionChunk struct {
- ID string `json:"id"`
- Object string `json:"object"`
- Created int64 `json:"created"`
- Model string `json:"model"`
- Choices []Choices `json:"choices"`
-}
-
-func (chunk *ChatCompletionChunk) String() string {
- resp, _ := json.Marshal(chunk)
- return string(resp)
-}
-
-type Choices struct {
- Delta Delta `json:"delta"`
- Index int `json:"index"`
- FinishReason interface{} `json:"finish_reason"`
-}
-
-type Delta struct {
- Content string `json:"content,omitempty"`
- Role string `json:"role,omitempty"`
-}
-
-func NewChatCompletionChunk(text string) ChatCompletionChunk {
- return ChatCompletionChunk{
- ID: "chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK",
- Object: "chat.completion.chunk",
- Created: 0,
- Model: "gpt-3.5-turbo-0301",
- Choices: []Choices{
- {
- Index: 0,
- Delta: Delta{
- Content: text,
- },
- FinishReason: nil,
- },
- },
- }
-}
-
-func NewChatCompletionChunkWithModel(text string, model string) ChatCompletionChunk {
- return ChatCompletionChunk{
- ID: "chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK",
- Object: "chat.completion.chunk",
- Created: 0,
- Model: model,
- Choices: []Choices{
- {
- Index: 0,
- Delta: Delta{
- Content: text,
- },
- FinishReason: nil,
- },
- },
- }
-}
-
-func StopChunkWithModel(reason string, model string) ChatCompletionChunk {
- return ChatCompletionChunk{
- ID: "chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK",
- Object: "chat.completion.chunk",
- Created: 0,
- Model: model,
- Choices: []Choices{
- {
- Index: 0,
- FinishReason: reason,
- },
- },
- }
-}
-
-func StopChunk(reason string) ChatCompletionChunk {
- return ChatCompletionChunk{
- ID: "chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK",
- Object: "chat.completion.chunk",
- Created: 0,
- Model: "gpt-3.5-turbo-0125",
- Choices: []Choices{
- {
- Index: 0,
- FinishReason: reason,
- },
- },
- }
-}
-
-type ChatCompletion struct {
- ID string `json:"id"`
- Object string `json:"object"`
- Created int64 `json:"created"`
- Model string `json:"model"`
- Usage usage `json:"usage"`
- Choices []Choice `json:"choices"`
-}
-type Msg struct {
- Role string `json:"role"`
- Content string `json:"content"`
-}
-type Choice struct {
- Index int `json:"index"`
- Message Msg `json:"message"`
- FinishReason interface{} `json:"finish_reason"`
-}
-type usage struct {
- PromptTokens int `json:"prompt_tokens"`
- CompletionTokens int `json:"completion_tokens"`
- TotalTokens int `json:"total_tokens"`
-}
-
-func NewChatCompletionWithModel(text string, model string) ChatCompletion {
- return ChatCompletion{
- ID: "chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK",
- Object: "chat.completion",
- Created: int64(0),
- Model: model,
- Usage: usage{
- PromptTokens: 0,
- CompletionTokens: 0,
- TotalTokens: 0,
- },
- Choices: []Choice{
- {
- Message: Msg{
- Content: text,
- Role: "assistant",
- },
- Index: 0,
- },
- },
- }
-}
-
-func NewChatCompletion(full_test string, input_tokens, output_tokens int) ChatCompletion {
- return ChatCompletion{
- ID: "chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK",
- Object: "chat.completion",
- Created: int64(0),
- Model: "gpt-3.5-turbo-0125",
- Usage: usage{
- PromptTokens: input_tokens,
- CompletionTokens: output_tokens,
- TotalTokens: input_tokens + output_tokens,
- },
- Choices: []Choice{
- {
- Message: Msg{
- Content: full_test,
- Role: "assistant",
- },
- Index: 0,
- },
- },
- }
-}
diff --git a/typings/typings.go b/typings/typings.go
deleted file mode 100644
index 044a5ead907fcea53649191a71cc78b58ff62cf0..0000000000000000000000000000000000000000
--- a/typings/typings.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package typings
-
-type GenericResponseLine struct {
- Line string `json:"line"`
- Error string `json:"error"`
-}
-
-type StringStruct struct {
- Text string `json:"text"`
-}
diff --git a/util/util.go b/util/util.go
deleted file mode 100644
index 367b56307c3f8bce7a1ab66c0672520ffad98307..0000000000000000000000000000000000000000
--- a/util/util.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package util
-
-import (
- "github.com/pkoukk/tiktoken-go"
- "log/slog"
- "math/rand"
- "time"
-)
-
-func RandomLanguage() string {
- // 初始化随机数生成器
- rand.Seed(time.Now().UnixNano())
- // 语言列表
- languages := []string{"af", "am", "ar-sa", "as", "az-Latn", "be", "bg", "bn-BD", "bn-IN", "bs", "ca", "ca-ES-valencia", "cs", "cy", "da", "de", "de-de", "el", "en-GB", "en-US", "es", "es-ES", "es-US", "es-MX", "et", "eu", "fa", "fi", "fil-Latn", "fr", "fr-FR", "fr-CA", "ga", "gd-Latn", "gl", "gu", "ha-Latn", "he", "hi", "hr", "hu", "hy", "id", "ig-Latn", "is", "it", "it-it", "ja", "ka", "kk", "km", "kn", "ko", "kok", "ku-Arab", "ky-Cyrl", "lb", "lt", "lv", "mi-Latn", "mk", "ml", "mn-Cyrl", "mr", "ms", "mt", "nb", "ne", "nl", "nl-BE", "nn", "nso", "or", "pa", "pa-Arab", "pl", "prs-Arab", "pt-BR", "pt-PT", "qut-Latn", "quz", "ro", "ru", "rw", "sd-Arab", "si", "sk", "sl", "sq", "sr-Cyrl-BA", "sr-Cyrl-RS", "sr-Latn-RS", "sv", "sw", "ta", "te", "tg-Cyrl", "th", "ti", "tk-Latn", "tn", "tr", "tt-Cyrl", "ug-Arab", "uk", "ur", "uz-Latn", "vi", "wo", "xh", "yo-Latn", "zh-Hans", "zh-Hant", "zu"}
- // 随机选择一个语言
- randomIndex := rand.Intn(len(languages))
- return languages[randomIndex]
-}
-
-func RandomHexadecimalString() string {
- rand.Seed(time.Now().UnixNano())
- const charset = "0123456789abcdef"
- const length = 16 // The length of the string you want to generate
- b := make([]byte, length)
- for i := range b {
- b[i] = charset[rand.Intn(len(charset))]
- }
- return string(b)
-}
-func CountToken(input string) int {
- encoding := "gpt-3.5-turbo"
- tkm, err := tiktoken.EncodingForModel(encoding)
- if err != nil {
- slog.Warn("tiktoken.EncodingForModel error:", err)
- return 0
- }
- token := tkm.Encode(input, nil, nil)
- return len(token)
-}
diff --git a/util/utils_test.go b/util/utils_test.go
deleted file mode 100644
index be2a0d9a7a515492d65893fa5c0de29a110d550a..0000000000000000000000000000000000000000
--- a/util/utils_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package util
-
-import (
- "fmt"
- "testing"
-)
-
-func TestRandomHexadecimalString(t *testing.T) {
- var str = RandomHexadecimalString()
- fmt.Println(str)
-}
diff --git a/vercel.json b/vercel.json
deleted file mode 100644
index 15103b0d4c6b439a6568160fcbc0eb03ec1bf9cc..0000000000000000000000000000000000000000
--- a/vercel.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "routes": [
- {
- "src": "/.*",
- "dest": "/api/router.go"
- }
- ]
-}
diff --git a/web/avatar.png b/web/avatar.png
deleted file mode 100644
index 0d65fe7c5d9b508416b34ac8a08e50e5616a46cc..0000000000000000000000000000000000000000
Binary files a/web/avatar.png and /dev/null differ
diff --git a/web/icon.png b/web/icon.png
deleted file mode 100644
index 5730de9c25af4ab0082e4f81f222da76bd1ab9a9..0000000000000000000000000000000000000000
Binary files a/web/icon.png and /dev/null differ
diff --git a/web/index.html b/web/index.html
deleted file mode 100644
index 80e5d4fafd726d9779a5b9df4bfa602b9d11eb9e..0000000000000000000000000000000000000000
--- a/web/index.html
+++ /dev/null
@@ -1,7005 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ChatGPT
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
UI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-