Spaces:
Runtime error
Runtime error
akashyadav758
Harden monitor (gate all routes), swap ChatGPT backend to free-Chatgpt-api, clean repo
5c7f4b5 | package main | |
| import ( | |
| "log" | |
| "os" | |
| "regexp" | |
| "strings" | |
| "time" | |
| ) | |
| var fileIDRegexp = regexp.MustCompile(`(file_[0-9a-fA-F]{32}|file-[a-zA-Z0-9_-]{24,36})`) | |
| func sendChat(prompt string) (string, string, error) { | |
| return sendChatWithConversation(prompt, "", cfg.DefaultModel, cfg.DefaultThinkingEffort) | |
| } | |
| func sendChatWithConversation(prompt, conversationID, model, thinkingEffort string) (string, string, error) { | |
| return sendChatWithConversationAndAttachments(prompt, conversationID, model, thinkingEffort, nil) | |
| } | |
| func sendChatWithConversationAndAttachments(prompt, conversationID, model, thinkingEffort string, attachments []FileAttachment) (string, string, error) { | |
| var response, rawText, newConvID string | |
| var err error | |
| // βββ Try 1: Direct Go HTTP call using synced cookies (fastest, no extension needed) βββ | |
| if HasCookies() && len(attachments) == 0 { | |
| log.Println("[chat] Attempting direct API call using synced cookies...") | |
| response, rawText, newConvID, err = SendChatDirect(prompt, conversationID, model, thinkingEffort) | |
| if err == nil { | |
| log.Println("[chat] β Direct API call succeeded!") | |
| return processResponse(response, rawText, newConvID, prompt, attachments) | |
| } | |
| log.Printf("[chat] β οΈ Direct API call failed: %v β falling back to extension", err) | |
| } | |
| // βββ Try 2: Extension full_conversation method (browser-based) βββ | |
| log.Println("[chat] Using extension full_conversation method...") | |
| response, rawText, newConvID, err = sendChatViaFullConversation(prompt, conversationID, model, thinkingEffort, attachments...) | |
| if err != nil { | |
| return "", "", err | |
| } | |
| return processResponse(response, rawText, newConvID, prompt, attachments) | |
| } | |
| // processResponse handles post-processing: auto-download images, poll for async images | |
| func processResponse(response, rawText, newConvID, prompt string, attachments []FileAttachment) (string, string, error) { | |
| // Auto-download any files found in the rawText or response | |
| var rawFileIDs []string | |
| rawFileIDs = append(rawFileIDs, fileIDRegexp.FindAllString(rawText, -1)...) | |
| rawFileIDs = append(rawFileIDs, fileIDRegexp.FindAllString(response, -1)...) | |
| // Dedup and filter file IDs (excluding any attachment IDs we uploaded) | |
| uploadedIDs := make(map[string]bool) | |
| for _, att := range attachments { | |
| uploadedIDs[att.ID] = true | |
| } | |
| seen := make(map[string]bool) | |
| var fileIDs []string | |
| for _, id := range rawFileIDs { | |
| if !seen[id] && !uploadedIDs[id] { | |
| seen[id] = true | |
| fileIDs = append(fileIDs, id) | |
| } | |
| } | |
| log.Printf("[chat] Found %d new file ID(s) to download: %v", len(fileIDs), fileIDs) | |
| if len(fileIDs) > 0 { | |
| for _, id := range fileIDs { | |
| registerFilePrompt(id, prompt) | |
| name := getPromptFilename(prompt, id) | |
| log.Printf("[auto-download] Detected image %s (%s) in response, downloading...", id, name) | |
| // Retry download up to 10 times because the image might still be generating/saving on OpenAI backend | |
| var data []byte | |
| var err error | |
| for attempt := 1; attempt <= 10; attempt++ { | |
| data, err = downloadChatGPTFile(id) | |
| if err == nil { | |
| break | |
| } | |
| log.Printf("[auto-download] Image %s not ready yet, retrying in 2 seconds... (attempt %d/10)", id, attempt) | |
| time.Sleep(2 * time.Second) | |
| } | |
| if err == nil { | |
| _ = os.MkdirAll("output", 0755) | |
| localPath := "output/" + name + ".png" | |
| err = os.WriteFile(localPath, data, 0644) | |
| if err != nil { | |
| log.Printf("[auto-download] Error saving file %s: %v", localPath, err) | |
| } else { | |
| log.Printf("[auto-download] Successfully saved image to %s", localPath) | |
| } | |
| } else { | |
| log.Printf("[auto-download] Error downloading image %s: %v", id, err) | |
| } | |
| } | |
| } | |
| shouldPoll := newConvID != "" && (strings.Contains(response, "Processing image") || | |
| strings.Contains(response, "creating images") || | |
| strings.Contains(response, "generating your image") || | |
| len(attachments) > 0 || | |
| isPromptForImage(prompt)) | |
| if shouldPoll { | |
| log.Printf("[chat] detected async image generation/edit in conversation %s, starting poll...", newConvID) | |
| var excludeIDs []string | |
| for _, att := range attachments { | |
| excludeIDs = append(excludeIDs, att.ID) | |
| } | |
| polledResponse, pollErr := pollForImage(prompt, newConvID, 150*time.Second, excludeIDs...) | |
| if pollErr == nil { | |
| return polledResponse, newConvID, nil | |
| } | |
| log.Printf("[chat] image poll failed: %v, returning original response", pollErr) | |
| } | |
| return response, newConvID, nil | |
| } | |
| func isPromptForImage(prompt string) bool { | |
| p := strings.ToLower(prompt) | |
| keywords := []string{ | |
| "generate", "create", "draw", "make", "edit", "add", "remove", | |
| "change", "modify", "paint", "cartoon", "3d", "render", | |
| "picture", "photo", "illustration", "dall-e", "dalle", | |
| } | |
| for _, kw := range keywords { | |
| if strings.Contains(p, kw) { | |
| return true | |
| } | |
| } | |
| return false | |
| } | |