diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c15884f --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +ADMIN_PASSWORD= +OPENAI_EMAIL= +OPENAI_PASSWORD= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 36e2100..c7720d7 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ access_tokens.json freechatgpt chatgpttoapi tools/authenticator/.proxies.txt.swp +.env \ No newline at end of file diff --git a/go.mod b/go.mod index d919d13..27a0094 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,13 @@ go 1.20 require ( github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057 github.com/acheong08/endless v0.0.0-20230615162514-90545c7793fd - github.com/acheong08/funcaptcha v0.2.1-0.20230626152808-543148a3c981 + github.com/acheong08/funcaptcha v0.2.1-0.20230629044031-084e7dfaffef github.com/bogdanfinn/fhttp v0.5.23 github.com/bogdanfinn/tls-client v1.4.0 github.com/gin-gonic/gin v1.9.1 github.com/go-resty/resty/v2 v2.7.0 github.com/google/uuid v1.3.0 + github.com/joho/godotenv v1.5.1 github.com/tidwall/gjson v1.14.4 k8s.io/apimachinery v0.27.2 ) diff --git a/go.sum b/go.sum index 2e16abe..e0e6719 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,12 @@ github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057 h1:AmqKpClFTU github.com/acheong08/OpenAIAuth v0.0.0-20230609193408-55a0f33f1057/go.mod h1:ES3Dh9hnbR2mDPlNTagj5e3b4nXECd4tbAjVgxggXEE= 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/acheong08/funcaptcha v0.2.1-0.20230628085018-57a8c9b81bc8 h1:COt2vPM8gz+PiUjeWH1enYPfMM3FiM/HFELqU6nO2PQ= +github.com/acheong08/funcaptcha v0.2.1-0.20230628085018-57a8c9b81bc8/go.mod h1:VupbjtVAODvgyAB3Zo86fOA53G+UAmaV/Rk9jUCGuTU= +github.com/acheong08/funcaptcha v0.2.1-0.20230628154248-28b05efd8e52 h1:cZ9RUUz+A5HUXQjIf9KJzF+K90EEcVdSJyWJc8S7qds= +github.com/acheong08/funcaptcha v0.2.1-0.20230628154248-28b05efd8e52/go.mod h1:VupbjtVAODvgyAB3Zo86fOA53G+UAmaV/Rk9jUCGuTU= +github.com/acheong08/funcaptcha v0.2.1-0.20230629044031-084e7dfaffef h1:B5fq4j+Qiu/6vay/70BG9mBuBgF28CnA4MTx1+J2V+o= +github.com/acheong08/funcaptcha v0.2.1-0.20230629044031-084e7dfaffef/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= @@ -46,6 +48,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= diff --git a/handlers.go b/handlers.go index 0125c03..c9cd553 100644 --- a/handlers.go +++ b/handlers.go @@ -1,179 +1,179 @@ -package main - -import ( - chatgpt_request_converter "freechatgpt/conversion/requests/chatgpt" - chatgpt "freechatgpt/internal/chatgpt" - "freechatgpt/internal/tokens" - official_types "freechatgpt/typings/official" - "os" - "strings" - - "github.com/gin-gonic/gin" -) - -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"}) - } - 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") -} - -func passwordHandler(c *gin.Context) { - // Get the password from the request (json) and update the password - type password_struct struct { - Password string `json:"password"` - } - var password password_struct - err := c.BindJSON(&password) - if err != nil { - c.String(400, "password not provided") - return - } - ADMIN_PASSWORD = password.Password - // Set environment variable - os.Setenv("ADMIN_PASSWORD", ADMIN_PASSWORD) - c.String(200, "password updated") -} - -func puidHandler(c *gin.Context) { - // Get the password from the request (json) and update the password - type puid_struct struct { - PUID string `json:"puid"` - } - var puid puid_struct - err := c.BindJSON(&puid) - if err != nil { - c.String(400, "puid not provided") - return - } - // Set environment variable - os.Setenv("PUID", puid.PUID) - c.String(200, "puid updated") -} - -func tokensHandler(c *gin.Context) { - // Get the request_tokens from the request (json) and update the request_tokens - var request_tokens []string - err := c.BindJSON(&request_tokens) - if err != nil { - c.String(400, "tokens not provided") - return - } - ACCESS_TOKENS = tokens.NewAccessToken(request_tokens, true) - c.String(200, "tokens updated") -} -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 nightmare(c *gin.Context) { - var original_request official_types.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 - } - - authHeader := c.GetHeader("Authorization") - token := ACCESS_TOKENS.GetToken() - if authHeader != "" { - customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1) - // Check if customAccessToken starts with sk- - if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiI") { - token = customAccessToken - } - } - var proxy_url string - if len(proxies) == 0 { - proxy_url = "" - } else { - proxy_url = proxies[0] - // Push used proxy to the back of the list - proxies = append(proxies[1:], proxies[0]) - } - - // Convert the chat request to a ChatGPT request - translated_request := chatgpt_request_converter.ConvertAPIRequest(original_request) - - response, err := chatgpt.POSTconversation(translated_request, token, proxy_url) - if err != nil { - c.JSON(500, gin.H{ - "error": "error sending request", - }) - return - } - defer response.Body.Close() - if chatgpt.Handle_request_error(c, response) { - return - } - var full_response string - 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) - full_response += response_part - if continue_info == nil { - break - } - println("Continuing conversation") - translated_request.Messages = nil - translated_request.Action = "continue" - translated_request.ConversationID = continue_info.ConversationID - translated_request.ParentMessageID = continue_info.ParentID - response, err = chatgpt.POSTconversation(translated_request, token, proxy_url) - if err != nil { - c.JSON(500, gin.H{ - "error": "error sending request", - }) - return - } - defer response.Body.Close() - if chatgpt.Handle_request_error(c, response) { - return - } - } - if !original_request.Stream { - c.JSON(200, official_types.NewChatCompletion(full_response)) - } else { - c.String(200, "data: [DONE]\n\n") - } - -} - -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) -} +package main + +import ( + chatgpt_request_converter "freechatgpt/conversion/requests/chatgpt" + chatgpt "freechatgpt/internal/chatgpt" + "freechatgpt/internal/tokens" + official_types "freechatgpt/typings/official" + "os" + "strings" + + "github.com/gin-gonic/gin" +) + +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"}) + } + 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") +} + +func passwordHandler(c *gin.Context) { + // Get the password from the request (json) and update the password + type password_struct struct { + Password string `json:"password"` + } + var password password_struct + err := c.BindJSON(&password) + if err != nil { + c.String(400, "password not provided") + return + } + ADMIN_PASSWORD = password.Password + // Set environment variable + os.Setenv("ADMIN_PASSWORD", ADMIN_PASSWORD) + c.String(200, "password updated") +} + +func puidHandler(c *gin.Context) { + // Get the password from the request (json) and update the password + type puid_struct struct { + PUID string `json:"puid"` + } + var puid puid_struct + err := c.BindJSON(&puid) + if err != nil { + c.String(400, "puid not provided") + return + } + // Set environment variable + os.Setenv("PUID", puid.PUID) + c.String(200, "puid updated") +} + +func tokensHandler(c *gin.Context) { + // Get the request_tokens from the request (json) and update the request_tokens + var request_tokens []string + err := c.BindJSON(&request_tokens) + if err != nil { + c.String(400, "tokens not provided") + return + } + ACCESS_TOKENS = tokens.NewAccessToken(request_tokens, true) + c.String(200, "tokens updated") +} +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 nightmare(c *gin.Context) { + var original_request official_types.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 + } + + authHeader := c.GetHeader("Authorization") + token := ACCESS_TOKENS.GetToken() + if authHeader != "" { + customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1) + // Check if customAccessToken starts with sk- + if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiI") { + token = customAccessToken + } + } + var proxy_url string + if len(proxies) == 0 { + proxy_url = "" + } else { + proxy_url = proxies[0] + // Push used proxy to the back of the list + proxies = append(proxies[1:], proxies[0]) + } + + // Convert the chat request to a ChatGPT request + translated_request := chatgpt_request_converter.ConvertAPIRequest(original_request) + + response, err := chatgpt.POSTconversation(translated_request, token, proxy_url) + if err != nil { + c.JSON(500, gin.H{ + "error": "error sending request", + }) + return + } + defer response.Body.Close() + if chatgpt.Handle_request_error(c, response) { + return + } + var full_response string + 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) + full_response += response_part + if continue_info == nil { + break + } + println("Continuing conversation") + translated_request.Messages = nil + translated_request.Action = "continue" + translated_request.ConversationID = continue_info.ConversationID + translated_request.ParentMessageID = continue_info.ParentID + response, err = chatgpt.POSTconversation(translated_request, token, proxy_url) + if err != nil { + c.JSON(500, gin.H{ + "error": "error sending request", + }) + return + } + defer response.Body.Close() + if chatgpt.Handle_request_error(c, response) { + return + } + } + if !original_request.Stream { + c.JSON(200, official_types.NewChatCompletion(full_response)) + } else { + c.String(200, "data: [DONE]\n\n") + } + +} + +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) +} diff --git a/internal/chatgpt/request.go b/internal/chatgpt/request.go index f6a7ed8..a096f9e 100644 --- a/internal/chatgpt/request.go +++ b/internal/chatgpt/request.go @@ -10,6 +10,7 @@ import ( "os" "strings" + arkose "github.com/acheong08/funcaptcha" http "github.com/bogdanfinn/fhttp" tls_client "github.com/bogdanfinn/tls-client" "github.com/gin-gonic/gin" @@ -35,6 +36,10 @@ var ( API_REVERSE_PROXY = os.Getenv("API_REVERSE_PROXY") ) +func init() { + arkose.SetTLSClient(&client) +} + func POSTconversation(message chatgpt_types.ChatGPTRequest, access_token string, proxy string) (*http.Response, error) { if proxy != "" { client.SetProxy(proxy) diff --git a/main.go b/main.go index 83a68a8..0cd3940 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "github.com/acheong08/OpenAIAuth/auth" "github.com/acheong08/endless" "github.com/gin-gonic/gin" + "github.com/joho/godotenv" ) var HOST string @@ -40,6 +41,7 @@ func checkProxy() { } func init() { + _ = godotenv.Load(".env") go func() { for { if os.Getenv("OPENAI_EMAIL") == "" || os.Getenv("OPENAI_PASSWORD") == "" { @@ -64,6 +66,9 @@ func init() { HOST = os.Getenv("SERVER_HOST") PORT = os.Getenv("SERVER_PORT") + if PORT == "" { + PORT = os.Getenv("PORT") + } if HOST == "" { HOST = "127.0.0.1" }