Skip to content

Commit

Permalink
add tts partial simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
xqdoo00o committed May 31, 2024
1 parent e306e66 commit fae2049
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 10 deletions.
9 changes: 8 additions & 1 deletion conversion/requests/chatgpt/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func ConvertAPIRequest(api_request official_types.APIRequest, account string, se
chatgpt_request.ConversationMode.Kind = "gizmo_interaction"
chatgpt_request.ConversationMode.GizmoId = "g-" + matches[1]
}
ifMultimodel := strings.HasPrefix(api_request.Model, "gpt-4")
ifMultimodel := secret.Token != ""
for _, api_message := range api_request.Messages {
if api_message.Role == "system" {
api_message.Role = "critic"
Expand All @@ -34,3 +34,10 @@ func ConvertAPIRequest(api_request official_types.APIRequest, account string, se
}
return chatgpt_request
}

func ConvertTTSAPIRequest(input string) chatgpt_types.ChatGPTRequest {
chatgpt_request := chatgpt_types.NewChatGPTRequest()
chatgpt_request.HistoryAndTrainingDisabled = false
chatgpt_request.AddAssistantMessage(input)
return chatgpt_request
}
108 changes: 99 additions & 9 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"freechatgpt/internal/tokens"
official_types "freechatgpt/typings/official"
"os"
"strings"

"github.com/gin-gonic/gin"
"github.com/google/uuid"
Expand Down Expand Up @@ -93,15 +92,7 @@ func nightmare(c *gin.Context) {
return
}

authHeader := c.GetHeader("Authorization")
account, secret := getSecret()
if authHeader != "" {
customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1)
// Check if customAccessToken starts with sk-
if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiI") {
secret.Token = customAccessToken
}
}
var proxy_url string
if len(proxies) == 0 {
proxy_url = ""
Expand Down Expand Up @@ -195,3 +186,102 @@ func nightmare(c *gin.Context) {
}
// chatgpt.UnlockSpecConn(secret.Token+secret.TeamUserID, uid)
}

var ttsFmtMap = map[string]string{
"mp3": "mp3",
"opus": "opus",
"aac": "aac",
"flac": "aac",
"wav": "aac",
"pcm": "aac",
}

var ttsTypeMap = map[string]string{
"mp3": "audio/mpeg",
"opus": "audio/ogg",
"aac": "audio/aac",
}

var ttsVoiceMap = map[string]string{
"alloy": "cove",
"echo": "ember",
"fable": "breeze",
"onyx": "cove",
"nova": "juniper",
"shimmer": "juniper",
}

func tts(c *gin.Context) {
var original_request official_types.TTSAPIRequest
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
}

account, secret := getSecret()
if account == "" || secret.PUID == "" {
c.JSON(500, gin.H{"error": "Plus user only"})
return
}
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])
}
var deviceId = generateUUID(account)
chatgpt.SetOAICookie(deviceId)
chat_require := chatgpt.CheckRequire(&secret, deviceId, proxy_url)
if chat_require == nil {
c.JSON(500, gin.H{"error": "unable to check chat requirement"})
return
}
var proofToken string
if chat_require.Proof.Required {
proofToken = chatgpt.CalcProofToken(chat_require, proxy_url)
}
var arkoseToken string
if chat_require.Arkose.Required {
arkoseToken, err = arkose.GetOpenAIToken(4, secret.PUID, chat_require.Arkose.DX, proxy_url)
if err != nil {
println("Error getting Arkose token: ", err)
}
}
// Convert the chat request to a ChatGPT request
translated_request := chatgpt_request_converter.ConvertTTSAPIRequest(original_request.Input)

response, err := chatgpt.POSTconversation(translated_request, &secret, deviceId, chat_require.Token, arkoseToken, proofToken, 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
}
msgId, convId := chatgpt.HandlerTTS(response, original_request.Input)
format := ttsFmtMap[original_request.Format]
if format == "" {
format = "aac"
}
voice := ttsVoiceMap[original_request.Voice]
if voice == "" {
voice = "cove"
}
apiUrl := "https://chatgpt.com/backend-api/synthesize?message_id=" + msgId + "&conversation_id=" + convId + "&voice=" + voice + "&format=" + format
data := chatgpt.GetTTS(&secret, deviceId, apiUrl, proxy_url)
if data != nil {
c.Data(200, ttsTypeMap[format], data)
}
chatgpt.RemoveConversation(&secret, deviceId, convId, proxy_url)
}
88 changes: 88 additions & 0 deletions internal/chatgpt/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -777,3 +777,91 @@ func Handler(c *gin.Context, response *http.Response, secret *tokens.Secret, pro
ParentID: original_response.Message.ID,
}
}

func HandlerTTS(response *http.Response, input string) (string, string) {
// Create a bufio.Reader from the response body
reader := bufio.NewReader(response.Body)

var original_response chatgpt_types.ChatGPTResponse
var convId string

for {
var line string
var err error
line, err = reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
return "", ""
}
if len(line) < 6 {
continue
}
// Remove "data: " from the beginning of the line
line = line[6:]
// Check if line starts with [DONE]
if !strings.HasPrefix(line, "[DONE]") {
// Parse the line as JSON
original_response.Message.ID = ""
err = json.Unmarshal([]byte(line), &original_response)
if err != nil {
continue
}
if original_response.Error != nil {
return "", ""
}
if original_response.Message.ID == "" {
continue
}
if original_response.ConversationID != convId {
if convId == "" {
convId = original_response.ConversationID
} else {
continue
}
}
if original_response.Message.Author.Role == "assistant" && original_response.Message.Content.Parts[0].(string) == input {
return original_response.Message.ID, convId
}
}
}
return "", ""
}

func GetTTS(secret *tokens.Secret, deviceId string, url string, proxy string) []byte {
if proxy != "" {
client.SetProxy(proxy)
}
request, err := newRequest(http.MethodGet, url, nil, secret, deviceId)
if err != nil {
return nil
}
response, err := client.Do(request)
if err != nil {
return nil
}
defer response.Body.Close()
blob, err := io.ReadAll(response.Body)
if err != nil {
return nil
}
return blob
}

func RemoveConversation(secret *tokens.Secret, deviceId string, id string, proxy string) {
if proxy != "" {
client.SetProxy(proxy)
}
url := "https://chatgpt.com/backend-api/conversation/" + id
request, err := newRequest(http.MethodPatch, url, bytes.NewBuffer([]byte(`{"is_visible":false}`)), secret, deviceId)
request.Header.Set("Content-Type", "application/json")
if err != nil {
return
}
response, err := client.Do(request)
if err != nil {
return
}
response.Body.Close()
}
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ func main() {
/// Public routes
router.OPTIONS("/v1/chat/completions", optionsHandler)
router.POST("/v1/chat/completions", Authorization, nightmare)
router.OPTIONS("/v1/audio/speech", optionsHandler)
router.POST("/v1/audio/speech", Authorization, tts)
router.OPTIONS("/v1/models", optionsHandler)
router.GET("/v1/models", Authorization, simulateModel)
endless.ListenAndServe(HOST+":"+PORT, router)
}
10 changes: 10 additions & 0 deletions typings/chatgpt/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,3 +471,13 @@ func (c *ChatGPTRequest) AddMessage(role string, content interface{}, multimodal
}
c.Messages = append(c.Messages, msg)
}

func (c *ChatGPTRequest) AddAssistantMessage(input string) {
var msg = chatgpt_message{
ID: uuid.New(),
Author: chatgpt_author{Role: "assistant"},
Content: chatgpt_content{ContentType: "text", Parts: []interface{}{input}},
Metadata: nil,
}
c.Messages = append(c.Messages, msg)
}
6 changes: 6 additions & 0 deletions typings/official/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ type api_message struct {
Role string `json:"role"`
Content interface{} `json:"content"`
}

type TTSAPIRequest struct {
Input string `json:"input"`
Voice string `json:"voice"`
Format string `json:"response_format"`
}

0 comments on commit fae2049

Please sign in to comment.