fix: Add proper page ready check before finding input

Key improvements:
- Wait for page to fully load (SPA needs time)
- Wait for input field to be visible before typing
- Check login status only after page is ready
- Add fallback wait (3 seconds) if first attempt fails
- Properly handle error messages

Based on project-golem's PageInteractor.waitForReady()
This commit is contained in:
王性驊 2026-04-03 01:26:43 +08:00
parent 3d5f2d91c0
commit 104e55d613
1 changed files with 61 additions and 24 deletions

View File

@ -132,10 +132,15 @@ func (p *PlaywrightProvider) Generate(ctx context.Context, model string, message
}); err != nil {
return fmt.Errorf("failed to navigate: %w", err)
}
time.Sleep(2 * time.Second)
}
// 3. 檢查登入狀態
// 3. 等待頁面完全載入project-golem 策略)
fmt.Println("[GeminiWeb] Waiting for page to be ready...")
if err := p.waitForPageReady(); err != nil {
fmt.Printf("[GeminiWeb] Warning: %v\n", err)
}
// 4. 檢查登入狀態
fmt.Println("[GeminiWeb] Checking login status...")
loggedIn := p.isLoggedIn()
if !loggedIn {
@ -151,11 +156,6 @@ func (p *PlaywrightProvider) Generate(ctx context.Context, model string, message
fmt.Println("[GeminiWeb] Logged in")
}
// 4. 等待頁面就緒
if err := p.waitForReady(); err != nil {
fmt.Printf("[GeminiWeb] Warning: %v\n", err)
}
// 5. 建構提示詞
prompt := buildPromptFromMessagesPlaywright(messages)
fmt.Printf("[GeminiWeb] Typing prompt (%d chars)...\n", len(prompt))
@ -201,6 +201,58 @@ func (p *PlaywrightProvider) Close() error {
return nil
}
// waitForPageReady 等待頁面完全就緒project-golem 策略)
func (p *PlaywrightProvider) waitForPageReady() error {
fmt.Println("[GeminiWeb] Checking for ready state...")
// 1. 等待停止按鈕消失(如果存在)
_, _ = p.page.WaitForSelector("button[aria-label*='Stop'], button[aria-label*='停止']", playwright.PageWaitForSelectorOptions{
State: playwright.WaitForSelectorStateDetached,
Timeout: playwright.Float(5000),
})
// 2. 等待輸入框出現(關鍵!)
inputSelectors := []string{
".ProseMirror",
"rich-textarea",
"div[role='textbox']",
"div[contenteditable='true']",
"textarea",
}
var lastErr error
for _, sel := range inputSelectors {
fmt.Printf(" Checking for: %s\n", sel)
locator := p.page.Locator(sel)
if err := locator.WaitFor(playwright.LocatorWaitForOptions{
Timeout: playwright.Float(10000),
State: playwright.WaitForSelectorStateVisible,
}); err == nil {
fmt.Printf(" ✓ Input field found: %s\n", sel)
return nil
} else {
lastErr = err
}
}
// 3. 如果都找不到,給頁面更多時間
fmt.Println("[GeminiWeb] Input not found immediately, waiting longer...")
time.Sleep(3 * time.Second)
for _, sel := range inputSelectors {
locator := p.page.Locator(sel)
if err := locator.WaitFor(playwright.LocatorWaitForOptions{
Timeout: playwright.Float(5000),
State: playwright.WaitForSelectorStateVisible,
}); err == nil {
fmt.Printf(" ✓ Input field found after wait: %s\n", sel)
return nil
}
}
return fmt.Errorf("input field not ready: %w", lastErr)
}
// isLoggedIn 檢查是否已登入
func (p *PlaywrightProvider) isLoggedIn() bool {
// 嘗試找輸入框(登入狀態的主要特徵)
@ -213,29 +265,14 @@ func (p *PlaywrightProvider) isLoggedIn() bool {
}
for _, sel := range selectors {
if _, err := p.page.WaitForSelector(sel, playwright.PageWaitForSelectorOptions{
Timeout: playwright.Float(3000),
}); err == nil {
locator := p.page.Locator(sel)
if count, _ := locator.Count(); count > 0 {
return true
}
}
return false
}
// waitForReady 等待頁面就緒
func (p *PlaywrightProvider) waitForReady() error {
fmt.Println("[GeminiWeb] Checking if page is ready...")
// 等待停止按鈕消失(如果存在)
_, _ = p.page.WaitForSelector("button[aria-label*='Stop']", playwright.PageWaitForSelectorOptions{
State: playwright.WaitForSelectorStateDetached,
Timeout: playwright.Float(5000),
})
fmt.Println("[GeminiWeb] Page is ready")
return nil
}
// typeInput 輸入文字(使用 Playwright 的 Auto-wait
func (p *PlaywrightProvider) typeInput(text string) error {
fmt.Println("[GeminiWeb] Looking for input field...")