feature/gemini-web-provider #1
|
|
@ -132,58 +132,89 @@ func SelectModel(page *rod.Page, model string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendPrompt(page *rod.Page, prompt string) error {
|
func SendPrompt(page *rod.Page, prompt string) error {
|
||||||
|
fmt.Printf("[GeminiWeb] Finding input field...\n")
|
||||||
|
|
||||||
// 嘗試多種可能的輸入框選擇器
|
// 嘗試多種可能的輸入框選擇器
|
||||||
selectors := []string{
|
selectors := []string{
|
||||||
`textarea[aria-label*="message" i]`,
|
|
||||||
`textarea[placeholder*="message" i]`,
|
|
||||||
`textarea`,
|
`textarea`,
|
||||||
`[contenteditable="true"]`,
|
`[contenteditable="true"]`,
|
||||||
`[role="textbox"]`,
|
`[role="textbox"]`,
|
||||||
|
`div[contenteditable="true"]`,
|
||||||
|
`div[role="textbox"]`,
|
||||||
|
`.ql-editor`,
|
||||||
`rich-textarea`,
|
`rich-textarea`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var textarea *rod.Element
|
var textarea *rod.Element
|
||||||
var err error
|
var err error
|
||||||
for _, sel := range selectors {
|
for _, sel := range selectors {
|
||||||
|
fmt.Printf(" Trying selector: %s\n", sel)
|
||||||
textarea, err = page.Element(sel)
|
textarea, err = page.Element(sel)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
fmt.Printf(" Found with: %s\n", sel)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("input field not found after trying selectors %v: %w", selectors, err)
|
return fmt.Errorf("input field not found after trying all selectors: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("[GeminiWeb] Typing prompt (%d chars)...\n", len(prompt))
|
||||||
if err := textarea.Input(prompt); err != nil {
|
if err := textarea.Input(prompt); err != nil {
|
||||||
return fmt.Errorf("failed to input prompt: %w", err)
|
return fmt.Errorf("failed to input prompt: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(300 * time.Millisecond)
|
fmt.Printf("[GeminiWeb] Finding send button...\n")
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
|
||||||
// 嘗試多種可能的發送按鈕選擇器
|
// 嘗試多種可能的發送按鈕選擇器
|
||||||
btnSelectors := []string{
|
btnSelectors := []string{
|
||||||
|
`button[type="submit"]`,
|
||||||
`button[aria-label*="Send" i]`,
|
`button[aria-label*="Send" i]`,
|
||||||
`button[aria-label*="submit" i]`,
|
`button[aria-label*="submit" i]`,
|
||||||
`button[type="submit"]`,
|
`button:has(svg)`,
|
||||||
`button svg`,
|
`button`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendBtn *rod.Element
|
var sendBtn *rod.Element
|
||||||
for _, sel := range btnSelectors {
|
for _, sel := range btnSelectors {
|
||||||
|
fmt.Printf(" Trying button selector: %s\n", sel)
|
||||||
sendBtn, err = page.Element(sel)
|
sendBtn, err = page.Element(sel)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
// 檢查是否是發送按鈕(不是其他按鈕)
|
||||||
|
ariaLabel, _ := sendBtn.Attribute("aria-label")
|
||||||
|
text, _ := sendBtn.Text()
|
||||||
|
if ariaLabel != nil || text != "" {
|
||||||
|
fmt.Printf(" Found button with aria-label=%v text=%s\n", ariaLabel, truncate(text, 20))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf(" Found send button with: %s\n", sel)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("send button not found: %w", err)
|
// 嘗試按 Enter 鍵發送
|
||||||
|
fmt.Printf("[GeminiWeb] No send button found, trying Enter key...\n")
|
||||||
|
if err := page.Keyboard.Press('\n'); err != nil {
|
||||||
|
return fmt.Errorf("failed to press Enter: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("[GeminiWeb] Clicking send button...\n")
|
||||||
return sendBtn.Click(proto.InputMouseButtonLeft, 1)
|
return sendBtn.Click(proto.InputMouseButtonLeft, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func truncate(s string, max int) string {
|
||||||
|
if len(s) <= max {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return s[:max] + "..."
|
||||||
|
}
|
||||||
|
|
||||||
func WaitForResponse(page *rod.Page, onChunk func(text string), onThinking func(thinking string), onComplete func()) error {
|
func WaitForResponse(page *rod.Page, onChunk func(text string), onThinking func(thinking string), onComplete func()) error {
|
||||||
lastText := ""
|
lastText := ""
|
||||||
lastThinking := ""
|
lastThinking := ""
|
||||||
|
|
|
||||||
|
|
@ -113,34 +113,26 @@ func (p *Provider) Generate(ctx context.Context, model string, messages []apityp
|
||||||
fmt.Printf("[GeminiWeb] Not logged in - continuing without login\n")
|
fmt.Printf("[GeminiWeb] Not logged in - continuing without login\n")
|
||||||
|
|
||||||
if visible {
|
if visible {
|
||||||
// 開啟可見瀏覽器,提示使用者可以登入
|
// 如果瀏覽器可見,提示使用者可以登入,但繼續執行不等待
|
||||||
fmt.Println("\n========================================")
|
fmt.Println("\n========================================")
|
||||||
fmt.Println("Browser is now open. You can:")
|
fmt.Println("Browser is open. You can:")
|
||||||
fmt.Println("1. Log in to Gemini (to use your account)")
|
fmt.Println("1. Log in to Gemini now (to use your account)")
|
||||||
fmt.Println("2. Or continue without login (limited functionality)")
|
fmt.Println("2. Continue without login")
|
||||||
fmt.Println("\nPress Enter when ready to continue...")
|
fmt.Println("\nThe request will proceed without waiting.")
|
||||||
|
fmt.Println("If you log in during this session, cookies will be saved automatically.")
|
||||||
fmt.Println("========================================\n")
|
fmt.Println("========================================\n")
|
||||||
|
|
||||||
// 等待使用者按 Enter
|
// 異步保存 cookies(如果使用者登入了)
|
||||||
var input string
|
go func() {
|
||||||
fmt.Scanln(&input)
|
time.Sleep(30 * time.Second) // 給使用者 30 秒登入
|
||||||
|
|
||||||
// 檢查是否已登入
|
|
||||||
if IsLoggedIn(page) {
|
if IsLoggedIn(page) {
|
||||||
fmt.Printf("[GeminiWeb] Login detected! Saving cookies for future use...\n")
|
|
||||||
cookies, err := GetPageCookies(page)
|
cookies, err := GetPageCookies(page)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
fmt.Printf("[GeminiWeb] Warning: could not get cookies: %v\n", err)
|
SaveCookiesToFile(cookies, session.CookieFile)
|
||||||
} else {
|
fmt.Printf("[GeminiWeb] Saved %d cookies for future use\n", len(cookies))
|
||||||
if err := SaveCookiesToFile(cookies, session.CookieFile); err != nil {
|
|
||||||
fmt.Printf("[GeminiWeb] Warning: could not save cookies: %v\n", err)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("[GeminiWeb] Saved %d cookies to %s\n", len(cookies), session.CookieFile)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}()
|
||||||
fmt.Printf("[GeminiWeb] Continuing without login\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue