fix conflict
This commit is contained in:
commit
931d5a245c
43
.github/workflows/release.yml
vendored
Normal file
43
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# This workflow will build a golang project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
||||
|
||||
name: Release Workflow
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Build
|
||||
run: go build -o bin/ .
|
||||
|
||||
- name: recursively list files
|
||||
run: ls -R
|
||||
|
||||
- name: Get existing release body
|
||||
id: get_release_body
|
||||
run: |
|
||||
echo "::set-output name=body::$(curl -s -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ github.ref_path }} | jq -r '.body')"
|
||||
|
||||
- name: Upload release artifact
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
file: bin/*
|
||||
file_glob: true
|
||||
tag: ${{ github.ref }}
|
||||
body: |
|
||||
${{ steps.get_release_body.outputs.body }}
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
@ -49,6 +49,7 @@ go build
|
||||
- `PUID` - Plus账户可在`chat.openai.com`的cookies里找到,用于绕过cf的频率限制
|
||||
- `SERVER_HOST` - 默认127.0.0.1
|
||||
- `SERVER_PORT` - 默认8080
|
||||
- `ENABLE_HISTORY` - 默认true,允许网页端历史记录
|
||||
### 可选文件配置
|
||||
- `proxies.txt` - 存放代理地址的文件
|
||||
|
||||
|
@ -1,20 +1,35 @@
|
||||
package chatgpt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
chatgpt_types "freechatgpt/typings/chatgpt"
|
||||
official_types "freechatgpt/typings/official"
|
||||
"strings"
|
||||
|
||||
arkose "github.com/acheong08/funcaptcha"
|
||||
)
|
||||
|
||||
func ConvertAPIRequest(api_request official_types.APIRequest) chatgpt_types.ChatGPTRequest {
|
||||
chatgpt_request := chatgpt_types.NewChatGPTRequest()
|
||||
if strings.HasPrefix(api_request.Model, "gpt-3.5") {
|
||||
chatgpt_request.Model = "text-davinci-002-render-sha"
|
||||
}
|
||||
if strings.HasPrefix(api_request.Model, "gpt-4") {
|
||||
token, err := arkose.GetOpenAIToken()
|
||||
if err == nil {
|
||||
chatgpt_request.ArkoseToken = token
|
||||
} else {
|
||||
fmt.Println("Error getting Arkose token: ", err)
|
||||
}
|
||||
chatgpt_request.Model = "gpt-4"
|
||||
if api_request.Model == "gpt-4-browsing" || api_request.Model == "gpt-4-plugins" || api_request.Model == "gpt-4-mobile" || api_request.Model == "gpt-4-code-interpreter" {
|
||||
if api_request.Model == "gpt-4-browsing" || api_request.Model == "gpt-4-mobile" || api_request.Model == "gpt-4-code-interpreter" {
|
||||
chatgpt_request.Model = api_request.Model
|
||||
}
|
||||
}
|
||||
|
||||
if api_request.PluginIDs != nil {
|
||||
chatgpt_request.PluginIDs = api_request.PluginIDs
|
||||
chatgpt_request.Model = "gpt-4-plugins"
|
||||
}
|
||||
for _, api_message := range api_request.Messages {
|
||||
if api_message.Role == "system" {
|
||||
api_message.Role = "critic"
|
||||
|
@ -7,9 +7,11 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ConvertToString(chatgpt_response *chatgpt_types.ChatGPTResponse, previous_text *typings.StringStruct) string {
|
||||
func ConvertToString(chatgpt_response *chatgpt_types.ChatGPTResponse, previous_text *typings.StringStruct, role bool) string {
|
||||
translated_response := official_types.NewChatCompletionChunk(strings.ReplaceAll(chatgpt_response.Message.Content.Parts[0], *&previous_text.Text, ""))
|
||||
translated_response.Choices[0].Delta.Role = chatgpt_response.Message.Author.Role
|
||||
if role {
|
||||
translated_response.Choices[0].Delta.Role = chatgpt_response.Message.Author.Role
|
||||
}
|
||||
previous_text.Text = chatgpt_response.Message.Content.Parts[0]
|
||||
return "data: " + translated_response.String() + "\n\n"
|
||||
|
||||
|
3
go.mod
3
go.mod
@ -4,7 +4,8 @@ go 1.20
|
||||
|
||||
require (
|
||||
github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057
|
||||
github.com/acheong08/endless v0.0.0-20230529075213-74050cf641c8
|
||||
github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd
|
||||
github.com/acheong08/funcaptcha v0.2.1-0.20230626152808-543148a3c981
|
||||
github.com/bogdanfinn/fhttp v0.5.23
|
||||
github.com/bogdanfinn/tls-client v1.4.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
|
8
go.sum
8
go.sum
@ -1,7 +1,11 @@
|
||||
github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057 h1:AmqKpClFTUHREYekSfSy3Yn7MR/oc6WTfKtEyzB/J7o=
|
||||
github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057/go.mod h1:ES3Dh9hnbR2mDPlNTagj5e3b4nXECd4tbAjVgxggXEE=
|
||||
github.com/acheong08/endless v0.0.0-20230529075213-74050cf641c8 h1:mHtMoGlGNUfMRjsWcb5Kvd1mJfJG8Gr1TtIghE8iiN8=
|
||||
github.com/acheong08/endless v0.0.0-20230529075213-74050cf641c8/go.mod h1:0yO7neMeJLvKk/B/fq5votDY8rByrOPDubpvU+6saKo=
|
||||
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/acheong08/funcaptcha v0.2.1-0.20230626140502-adeab195a0b3 h1:3SiHkE69H/JWT19fpIvjRScPDx5DnWnzzZpR5V4vHkQ=
|
||||
github.com/acheong08/funcaptcha v0.2.1-0.20230626140502-adeab195a0b3/go.mod h1:fKxNB5i7g9h6QDTIY1YZamwFmMpAJK++wMYij5NuMm4=
|
||||
github.com/acheong08/funcaptcha v0.2.1-0.20230626152808-543148a3c981 h1:ibvQvXMdniYRTYJFDaUJvG+25BF/bQxzE3AfDtv+0Ag=
|
||||
github.com/acheong08/funcaptcha v0.2.1-0.20230626152808-543148a3c981/go.mod h1:VupbjtVAODvgyAB3Zo86fOA53G+UAmaV/Rk9jUCGuTU=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/bogdanfinn/fhttp v0.5.23 h1:4Xb5OjYArB8GpnUw4A4r5jmt8UW0/Cvey3R9nS2dC9U=
|
||||
|
38
handlers.go
38
handlers.go
@ -12,12 +12,26 @@ import (
|
||||
)
|
||||
|
||||
func openaiHandler(c *gin.Context) {
|
||||
var authorizations struct {
|
||||
OpenAI_Email string `json:"openai_email"`
|
||||
OpenAI_Password string `json:"openai_password"`
|
||||
Official_API_Key string `json:"official_api_key"`
|
||||
}
|
||||
err := c.BindJSON(&authorizations)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{"error": "JSON invalid"})
|
||||
}
|
||||
os.Setenv("OPENAI_EMAIL", authorizations.OpenAI_Email)
|
||||
os.Setenv("OPENAI_PASSWORD", authorizations.OpenAI_Password)
|
||||
if authorizations.OpenAI_Email != "" && authorizations.OpenAI_Password != "" {
|
||||
os.Setenv("OPENAI_EMAIL", authorizations.OpenAI_Email)
|
||||
os.Setenv("OPENAI_PASSWORD", authorizations.OpenAI_Password)
|
||||
}
|
||||
if authorizations.Official_API_Key != "" {
|
||||
os.Setenv("OFFICIAL_API_KEY", authorizations.Official_API_Key)
|
||||
}
|
||||
if authorizations.OpenAI_Email == "" && authorizations.OpenAI_Password == "" && authorizations.Official_API_Key == "" {
|
||||
c.JSON(400, gin.H{"error": "JSON invalid"})
|
||||
return
|
||||
}
|
||||
c.String(200, "OpenAI credentials updated")
|
||||
}
|
||||
|
||||
@ -84,6 +98,7 @@ func nightmare(c *gin.Context) {
|
||||
"param": nil,
|
||||
"code": err.Error(),
|
||||
}})
|
||||
return
|
||||
}
|
||||
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
@ -91,7 +106,7 @@ func nightmare(c *gin.Context) {
|
||||
if authHeader != "" {
|
||||
customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1)
|
||||
// Check if customAccessToken starts with sk-
|
||||
if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9") {
|
||||
if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiI") {
|
||||
token = customAccessToken
|
||||
}
|
||||
}
|
||||
@ -107,7 +122,7 @@ func nightmare(c *gin.Context) {
|
||||
// Convert the chat request to a ChatGPT request
|
||||
translated_request := chatgpt_request_converter.ConvertAPIRequest(original_request)
|
||||
|
||||
response, err := chatgpt.Send_request(translated_request, token, proxy_url)
|
||||
response, err := chatgpt.POSTconversation(translated_request, token, proxy_url)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": "error sending request",
|
||||
@ -119,7 +134,7 @@ func nightmare(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
var full_response string
|
||||
for i := 2; i > 0; i-- {
|
||||
for i := 3; i > 0; i-- {
|
||||
var continue_info *chatgpt.ContinueInfo
|
||||
var response_part string
|
||||
response_part, continue_info = chatgpt.Handler(c, response, token, translated_request, original_request.Stream)
|
||||
@ -132,7 +147,7 @@ func nightmare(c *gin.Context) {
|
||||
translated_request.Action = "continue"
|
||||
translated_request.ConversationID = continue_info.ConversationID
|
||||
translated_request.ParentMessageID = continue_info.ParentID
|
||||
response, err = chatgpt.Send_request(translated_request, token, proxy_url)
|
||||
response, err = chatgpt.POSTconversation(translated_request, token, proxy_url)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": "error sending request",
|
||||
@ -151,3 +166,14 @@ func nightmare(c *gin.Context) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func engines_handler(c *gin.Context) {
|
||||
resp, status, err := chatgpt.GETengines()
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": "error sending request",
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(status, resp)
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ var (
|
||||
jar = tls_client.NewCookieJar()
|
||||
options = []tls_client.HttpClientOption{
|
||||
tls_client.WithTimeoutSeconds(360),
|
||||
tls_client.WithClientProfile(tls_client.Safari_IOS_15_5),
|
||||
tls_client.WithClientProfile(tls_client.Safari_Ipad_15_6),
|
||||
tls_client.WithNotFollowRedirects(),
|
||||
tls_client.WithCookieJar(jar), // create cookieJar instance and pass it as argument
|
||||
// Disable SSL verification
|
||||
@ -35,7 +35,7 @@ var (
|
||||
API_REVERSE_PROXY = os.Getenv("API_REVERSE_PROXY")
|
||||
)
|
||||
|
||||
func Send_request(message chatgpt_types.ChatGPTRequest, access_token string, proxy string) (*http.Response, error) {
|
||||
func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, proxy string) (*http.Response, error) {
|
||||
if proxy != "" {
|
||||
client.SetProxy(proxy)
|
||||
}
|
||||
@ -123,6 +123,7 @@ func Handler(c *gin.Context, response *http.Response, token string, translated_r
|
||||
var finish_reason string
|
||||
var previous_text typings.StringStruct
|
||||
var original_response chatgpt_types.ChatGPTResponse
|
||||
var isRole = true
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
@ -142,8 +143,6 @@ func Handler(c *gin.Context, response *http.Response, token string, translated_r
|
||||
|
||||
err = json.Unmarshal([]byte(line), &original_response)
|
||||
if err != nil {
|
||||
println("Failed to parse JSON")
|
||||
println(line)
|
||||
continue
|
||||
}
|
||||
if original_response.Error != nil {
|
||||
@ -153,10 +152,11 @@ func Handler(c *gin.Context, response *http.Response, token string, translated_r
|
||||
if original_response.Message.Author.Role != "assistant" || original_response.Message.Content.Parts == nil {
|
||||
continue
|
||||
}
|
||||
if original_response.Message.Metadata.MessageType != "next" {
|
||||
if original_response.Message.Metadata.MessageType != "next" && original_response.Message.Metadata.MessageType != "continue" || original_response.Message.EndTurn != nil {
|
||||
continue
|
||||
}
|
||||
response_string := chatgpt_response_converter.ConvertToString(&original_response, &previous_text)
|
||||
response_string := chatgpt_response_converter.ConvertToString(&original_response, &previous_text, isRole)
|
||||
isRole = false
|
||||
if stream {
|
||||
_, err = c.Writer.WriteString(response_string)
|
||||
if err != nil {
|
||||
@ -188,3 +188,17 @@ func Handler(c *gin.Context, response *http.Response, token string, translated_r
|
||||
ParentID: original_response.Message.ID,
|
||||
}
|
||||
}
|
||||
|
||||
func GETengines() (interface{}, int, error) {
|
||||
url := "https://api.openai.com/v1/models"
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Add("Authorization", "Bearer "+os.Getenv("OFFICIAL_API_KEY"))
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var result interface{}
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
return result, resp.StatusCode, nil
|
||||
}
|
||||
|
46
main.go
46
main.go
@ -39,33 +39,29 @@ func checkProxy() {
|
||||
}
|
||||
}
|
||||
|
||||
var authorizations struct {
|
||||
OpenAI_Email string `json:"openai_email"`
|
||||
OpenAI_Password string `json:"openai_password"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
authorizations.OpenAI_Email = os.Getenv("OPENAI_EMAIL")
|
||||
authorizations.OpenAI_Password = os.Getenv("OPENAI_PASSWORD")
|
||||
if authorizations.OpenAI_Email != "" && authorizations.OpenAI_Password != "" {
|
||||
go func() {
|
||||
for {
|
||||
authenticator := auth.NewAuthenticator(authorizations.OpenAI_Email, authorizations.OpenAI_Password, os.Getenv("http_proxy"))
|
||||
err := authenticator.Begin()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
}
|
||||
puid, err := authenticator.GetPUID()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
os.Setenv("PUID", puid)
|
||||
println(puid)
|
||||
go func() {
|
||||
for {
|
||||
if os.Getenv("OPENAI_EMAIL") == "" || os.Getenv("OPENAI_PASSWORD") == "" {
|
||||
time.Sleep(24 * time.Hour * 7)
|
||||
continue
|
||||
}
|
||||
}()
|
||||
}
|
||||
authenticator := auth.NewAuthenticator(os.Getenv("OPENAI_EMAIL"), os.Getenv("OPENAI_PASSWORD"), os.Getenv("http_proxy"))
|
||||
err := authenticator.Begin()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
}
|
||||
puid, err := authenticator.GetPUID()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
os.Setenv("PUID", puid)
|
||||
println(puid)
|
||||
time.Sleep(24 * time.Hour * 7)
|
||||
}
|
||||
}()
|
||||
|
||||
HOST = os.Getenv("SERVER_HOST")
|
||||
PORT = os.Getenv("SERVER_PORT")
|
||||
if HOST == "" {
|
||||
@ -100,5 +96,7 @@ func main() {
|
||||
/// Public routes
|
||||
router.OPTIONS("/v1/chat/completions", optionsHandler)
|
||||
router.POST("/v1/chat/completions", Authorization, nightmare)
|
||||
router.GET("/v1/engines", Authorization, engines_handler)
|
||||
router.GET("/v1/models", Authorization, engines_handler)
|
||||
endless.ListenAndServe(HOST+":"+PORT, router)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
gin "github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -50,7 +51,15 @@ func Authorization(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
if len(API_KEYS) != 0 && !API_KEYS[c.Request.Header.Get("Authorization")] {
|
||||
c.String(401, "Unauthorized")
|
||||
if c.Request.Header.Get("Authorization") == "" {
|
||||
c.JSON(401, gin.H{"error": "No API key provided. Get one at https://discord.gg/9K2BvbXEHT"})
|
||||
} else if strings.HasPrefix(c.Request.Header.Get("Authorization"), "Bearer sk-") {
|
||||
c.JSON(401, gin.H{"error": "You tried to use the official API key which is not supported."})
|
||||
} else if strings.HasPrefix(c.Request.Header.Get("Authorization"), "Bearer eyJhbGciOiJSUzI1NiI") {
|
||||
return
|
||||
} else {
|
||||
c.JSON(401, gin.H{"error": "Invalid API key."})
|
||||
}
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
package chatgpt
|
||||
|
||||
import "github.com/google/uuid"
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type chatgpt_message struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
@ -24,14 +28,17 @@ type ChatGPTRequest struct {
|
||||
ConversationID string `json:"conversation_id,omitempty"`
|
||||
Model string `json:"model"`
|
||||
HistoryAndTrainingDisabled bool `json:"history_and_training_disabled"`
|
||||
ArkoseToken string `json:"arkose_token,omitempty"`
|
||||
PluginIDs []string `json:"plugin_ids,omitempty"`
|
||||
}
|
||||
|
||||
func NewChatGPTRequest() ChatGPTRequest {
|
||||
enable_history := os.Getenv("ENABLE_HISTORY") == ""
|
||||
return ChatGPTRequest{
|
||||
Action: "next",
|
||||
ParentMessageID: uuid.NewString(),
|
||||
Model: "text-davinci-002-render-sha",
|
||||
HistoryAndTrainingDisabled: true,
|
||||
HistoryAndTrainingDisabled: !enable_history,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
package official
|
||||
|
||||
type APIRequest struct {
|
||||
Messages []api_message `json:"messages"`
|
||||
Stream bool `json:"stream"`
|
||||
Model string `json:"model"`
|
||||
Messages []api_message `json:"messages"`
|
||||
Stream bool `json:"stream"`
|
||||
Model string `json:"model"`
|
||||
PluginIDs []string `json:"plugin_ids"`
|
||||
}
|
||||
|
||||
type api_message struct {
|
||||
|
@ -22,8 +22,8 @@ type Choices struct {
|
||||
}
|
||||
|
||||
type Delta struct {
|
||||
Content string `json:"content"`
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
}
|
||||
|
||||
func NewChatCompletionChunk(text string) ChatCompletionChunk {
|
||||
@ -37,7 +37,6 @@ func NewChatCompletionChunk(text string) ChatCompletionChunk {
|
||||
Index: 0,
|
||||
Delta: Delta{
|
||||
Content: text,
|
||||
Role: "assistant",
|
||||
},
|
||||
FinishReason: nil,
|
||||
},
|
||||
|
Reference in New Issue
Block a user