Skip to content

Commit

Permalink
impl captcha solving interface
Browse files Browse the repository at this point in the history
  • Loading branch information
juzeon committed Feb 6, 2024
1 parent e1db516 commit f4afc0a
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 10 deletions.
1 change: 1 addition & 0 deletions app_chatbot.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func (a *App) createSydney() (*sydney.Sydney, error) {
CreateConversationURL: a.settings.config.CreateConversationURL,
NoSearch: currentWorkspace.NoSearch,
GPT4Turbo: currentWorkspace.GPT4Turbo,
BypassServer: a.settings.config.BypassServer,
}), nil
}

Expand Down
1 change: 1 addition & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type Config struct {
CreateConversationURL string `json:"create_conversation_url"`
ThemeColor string `json:"theme_color"`
DisableNoSearchLoader bool `json:"disable_no_search_loader"`
BypassServer string `json:"bypass_server"`
}

func fillDefault[T comparable](pointer *T, defaultValue T) {
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/pages/SettingsPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ function onRevokeReplyCountChanged(v: string) {
v-model="config.create_conversation_url"></v-autocomplete>
</template>
</v-tooltip>
<v-tooltip text="Full URL of the CAPTCHA-bypass server."
location="bottom">
<template #activator="{props}">
<v-text-field color="primary" label="CAPTCHA Bypass Server" v-model="config.bypass_server"
v-bind="props" hint="Leave empty to disable CAPTCHA bypass"></v-text-field>
</template>
</v-tooltip>
</v-card-text>
</v-card>
<v-card title="Display" class="my-3">
Expand Down
2 changes: 2 additions & 0 deletions frontend/wailsjs/go/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ export namespace main {
create_conversation_url: string;
theme_color: string;
disable_no_search_loader: boolean;
bypass_server: string;

static createFrom(source: any = {}) {
return new Config(source);
Expand Down Expand Up @@ -223,6 +224,7 @@ export namespace main {
this.create_conversation_url = source["create_conversation_url"];
this.theme_color = source["theme_color"];
this.disable_no_search_loader = source["disable_no_search_loader"];
this.bypass_server = source["bypass_server"];
}

convertValues(a: any, classs: any, asMap: boolean = false): any {
Expand Down
7 changes: 4 additions & 3 deletions sydney/captcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/go-resty/resty/v2"
"github.com/google/uuid"
"log/slog"
Expand Down Expand Up @@ -33,14 +34,14 @@ func (o *Sydney) BypassCaptcha(
slog.Debug("Bypass CAPTCHA request", "v", req)
resp, err := client.R().SetContext(stopCtx).SetBody(req).Post(o.bypassServer)
if err != nil {
return nil, err
return nil, fmt.Errorf("cannot communicate with captcha bypass server: %w", err)
}
slog.Debug("Bypass captcha response body", "v", string(resp.Body()))
var response BypassCaptchaResponse
err = json.Unmarshal(resp.Body(), &response)
if err != nil {
return nil, err
return nil, fmt.Errorf("cannot unmarshal json from captcha bypass server: %w", err)
}
slog.Debug("Bypass captcha response", "v", response)
if response.Error != "" {
return nil, errors.New("bypass captcha error: " + response.Error)
}
Expand Down
52 changes: 46 additions & 6 deletions sydney/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

func (o *Sydney) AskStream(options AskStreamOptions) (<-chan Message, error) {
out := make(chan Message)
options.messageID = uuid.New().String()
conversation, ch, err := o.AskStreamRaw(options)
if err != nil {
return nil, err
Expand All @@ -46,22 +47,61 @@ func (o *Sydney) AskStream(options AskStreamOptions) (<-chan Message, error) {
for msg := range ch {
if msg.Error != nil {
slog.Error("Ask stream message", "error", msg.Error)
if strings.Contains(msg.Error.Error(), "CAPTCHA") && o.bypassServer != "" {
if strings.Contains(msg.Error.Error(), "CAPTCHA") {
if o.bypassServer == "" {
err0 := errors.New("encountered CAPTCHA challenge; " +
"please resolve it manually on Bing's website or configure a Bypass Server")
out <- Message{
Type: MessageTypeError,
Text: err0.Error(),
Error: err0,
}
return
}
if options.disableCaptchaBypass {
err0 := errors.New("infinite CAPTCHA detected; " +
"please resolve it manually on Bing's website")
out <- Message{
Type: MessageTypeError,
Text: err0.Error(),
Error: err0,
}
return
}
slog.Info("Start to bypass the captcha", "server", o.bypassServer)
out <- Message{
Type: MessageTypeSolvingCaptcha,
Text: "Please wait patiently while we are solving the CAPTCHA...",
}
cookies, err := o.BypassCaptcha(options.StopCtx, conversation.ConversationId,
options.MessageID)
options.messageID)
if err != nil {
out <- Message{
Type: MessageTypeError,
Text: msg.Error.Error(),
Error: msg.Error,
Text: err.Error(),
Error: err,
}
return
}
slog.Info("New Cookie", "v", cookies) // TODO persist this cookie
for k, v := range cookies { // keep the map pointer
o.cookies[k] = v
}
newOptions := options
newOptions.disableCaptchaBypass = true
newOptions.messageID = ""
newCh, err := o.AskStream(newOptions)
if err != nil {
out <- Message{
Type: MessageTypeError,
Text: err.Error(),
Error: err,
}
return
}
for newMsg := range newCh { // proxy messages from recursive AskStream
out <- newMsg
}
slog.Info("New Cookie", "v", cookies) // TODO resend conversation
return
} else {
out <- Message{
Expand Down Expand Up @@ -271,7 +311,7 @@ func (o *Sydney) AskStreamRaw(options AskStreamOptions) (CreateConversationRespo
}
return
}
messageID := options.MessageID
messageID := options.messageID
if messageID == "" {
msgID, err := uuid.NewUUID()
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion sydney/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ type AskStreamOptions struct {
WebpageContext string
ImageURL string

MessageID string // A random uuid. Optional.
messageID string // A random uuid. Optional.
disableCaptchaBypass bool
}
type UploadImagePayload struct {
ImageInfo map[string]any `json:"imageInfo"`
Expand Down

0 comments on commit f4afc0a

Please sign in to comment.