answer/pkg/search/duckduckgo.go
Steve Dudenhoeffer 6c30fdf4d8 Add DuckDuckGo support and refactor caching system
Introduced DuckDuckGo as a new search provider alongside Google. Implemented a flexible caching system with in-memory, file-based, and no-op cache options to improve modularity. Updated dependencies and revised the project structure for improved maintainability.
2025-02-21 18:40:25 -05:00

84 lines
1.5 KiB
Go

package search
import (
"answer/pkg/cache"
"context"
"fmt"
"time"
"gitea.stevedudenhoeffer.com/steve/go-extractor"
"gitea.stevedudenhoeffer.com/steve/go-extractor/sites/duckduckgo"
)
type duckDuckGo struct {
Cache cache.Cache
Browser extractor.Browser
}
func NewDuckDuckGo(c cache.Cache) (Search, error) {
timeout := 60 * time.Second
browser, err := extractor.NewPlayWrightBrowser(extractor.PlayWrightBrowserOptions{Timeout: &timeout})
if err != nil {
return nil, fmt.Errorf("failed to create browser: %w", err)
}
return duckDuckGo{
Cache: c,
Browser: browser,
}, nil
}
var _ Search = duckDuckGo{}
func (d duckDuckGo) Search(ctx context.Context, search string) ([]Result, error) {
var res []Result
key := "duckduckgo:" + search
err := d.Cache.GetJSON(key, &res)
if err == nil {
return res, nil
}
results, err := d.searchDuckDuckGo(ctx, search)
if err != nil {
return nil, err
}
for _, r := range results {
res = append(res, Result{
Title: r.Title,
URL: r.URL,
Description: r.Description,
})
}
_ = d.Cache.SetJSON(key, res)
return res, nil
}
func (d duckDuckGo) searchDuckDuckGo(ctx context.Context, search string) ([]Result, error) {
cfg := duckduckgo.DefaultConfig
r, err := cfg.Search(ctx, d.Browser, search)
if err != nil {
return nil, err
}
res := make([]Result, len(r))
for i, v := range r {
res[i] = Result{
URL: v.URL,
Title: v.Title,
Description: v.Description,
}
}
return res, nil
}