fix: Always save diagnostics on any error
- Add saveDiagnostics method - Use defer in Generate to catch all errors - Simplify typeInput error handling - Automatic screenshot and HTML dump on failure
This commit is contained in:
parent
e245558f3d
commit
3fec6e55eb
|
|
@ -114,7 +114,15 @@ func (p *PlaywrightProvider) launchIfNeeded() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate 生成回應
|
// Generate 生成回應
|
||||||
func (p *PlaywrightProvider) Generate(ctx context.Context, model string, messages []apitypes.Message, tools []apitypes.Tool, cb func(apitypes.StreamChunk)) error {
|
func (p *PlaywrightProvider) Generate(ctx context.Context, model string, messages []apitypes.Message, tools []apitypes.Tool, cb func(apitypes.StreamChunk)) (err error) {
|
||||||
|
// 確保在返回錯誤時保存診斷
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[GeminiWeb] Error occurred, saving diagnostics...")
|
||||||
|
_ = p.saveDiagnostics()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
fmt.Printf("[GeminiWeb] Starting generation with model: %s\n", model)
|
fmt.Printf("[GeminiWeb] Starting generation with model: %s\n", model)
|
||||||
|
|
||||||
// 1. 確保瀏覽器已啟動
|
// 1. 確保瀏覽器已啟動
|
||||||
|
|
@ -237,6 +245,36 @@ func (p *PlaywrightProvider) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// saveDiagnostics 保存診斷信息
|
||||||
|
func (p *PlaywrightProvider) saveDiagnostics() error {
|
||||||
|
if p.page == nil {
|
||||||
|
return fmt.Errorf("no page available")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 截圖
|
||||||
|
screenshotPath := "/tmp/gemini-debug.png"
|
||||||
|
if _, err := p.page.Screenshot(playwright.PageScreenshotOptions{
|
||||||
|
Path: playwright.String(screenshotPath),
|
||||||
|
}); err == nil {
|
||||||
|
fmt.Printf("[GeminiWeb] Screenshot saved: %s\n", screenshotPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML
|
||||||
|
htmlPath := "/tmp/gemini-debug.html"
|
||||||
|
if html, err := p.page.Content(); err == nil {
|
||||||
|
if err := os.WriteFile(htmlPath, []byte(html), 0644); err == nil {
|
||||||
|
fmt.Printf("[GeminiWeb] HTML saved: %s\n", htmlPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 輸出頁面信息
|
||||||
|
url := p.page.URL()
|
||||||
|
title, _ := p.page.Title()
|
||||||
|
fmt.Printf("[GeminiWeb] Diagnostics: URL=%s, Title=%s\n", url, title)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// waitForPageReady 等待頁面完全就緒(project-golem 策略)
|
// waitForPageReady 等待頁面完全就緒(project-golem 策略)
|
||||||
func (p *PlaywrightProvider) waitForPageReady() error {
|
func (p *PlaywrightProvider) waitForPageReady() error {
|
||||||
fmt.Println("[GeminiWeb] Checking for ready state...")
|
fmt.Println("[GeminiWeb] Checking for ready state...")
|
||||||
|
|
@ -393,61 +431,10 @@ func (p *PlaywrightProvider) typeInput(text string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
// 保存診斷信息
|
// 錯誤會被 Generate 的 defer 捕獲並保存診斷
|
||||||
screenshotPath := "/tmp/gemini-debug.png"
|
|
||||||
htmlPath := "/tmp/gemini-debug.html"
|
|
||||||
|
|
||||||
// 截圖
|
|
||||||
if _, err := p.page.Screenshot(playwright.PageScreenshotOptions{
|
|
||||||
Path: playwright.String(screenshotPath),
|
|
||||||
}); err == nil {
|
|
||||||
fmt.Printf("[GeminiWeb] Screenshot saved: %s\n", screenshotPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTML
|
|
||||||
if html, err := p.page.Content(); err == nil {
|
|
||||||
if err := os.WriteFile(htmlPath, []byte(html), 0644); err == nil {
|
|
||||||
fmt.Printf("[GeminiWeb] HTML saved: %s\n", htmlPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 輸出調試信息
|
|
||||||
url := p.page.URL()
|
url := p.page.URL()
|
||||||
title, _ := p.page.Title()
|
title, _ := p.page.Title()
|
||||||
fmt.Printf("[GeminiWeb] DEBUG: URL=%s\n", url)
|
return fmt.Errorf("input field not found (URL=%s, Title=%s). Diagnostics will be saved to /tmp/", url, title)
|
||||||
fmt.Printf("[GeminiWeb] DEBUG: Title=%s\n", title)
|
|
||||||
|
|
||||||
// 嘗試用 JavaScript 找輸入框
|
|
||||||
fmt.Println("[GeminiWeb] Trying JavaScript element search...")
|
|
||||||
_, _ = p.page.Evaluate(`
|
|
||||||
() => {
|
|
||||||
console.log('=== DEBUG: Looking for input elements ===');
|
|
||||||
const selectors = [
|
|
||||||
'.ProseMirror',
|
|
||||||
'rich-textarea',
|
|
||||||
'div[role="textbox"]',
|
|
||||||
'div[contenteditable="true"]',
|
|
||||||
'textarea',
|
|
||||||
'input'
|
|
||||||
];
|
|
||||||
for (const sel of selectors) {
|
|
||||||
const els = document.querySelectorAll(sel);
|
|
||||||
if (els.length > 0) {
|
|
||||||
console.log('Found', els.length, 'elements for:', sel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 檢查頁面中所有可交互元素
|
|
||||||
const interactable = document.querySelectorAll('div[contenteditable="true"], textarea, input[type="text"], [role="textbox"]');
|
|
||||||
console.log('Total interactable elements:', interactable.length);
|
|
||||||
|
|
||||||
return { found: false };
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
// 顯示最後的URL和標題
|
|
||||||
return fmt.Errorf("input field not found (URL=%s, Title=%s). Screenshot saved to %s, HTML saved to %s",
|
|
||||||
url, title, screenshotPath, htmlPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus 並填充(Playwright 自動等待)
|
// Focus 並填充(Playwright 自動等待)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue