package websearch import ( "context" "encoding/json" "fmt" "net/http" "net/url" "strings" ) type bingSearchResponse struct { WebPages *struct { Value []struct { Name string `json:"name"` URL string `json:"url"` Snippet string `json:"snippet"` } `json:"value"` } `json:"webPages"` } func (c *Client) searchBing(ctx context.Context, provider Provider, query string, count int) ([]Result, error) { apiKey := strings.TrimSpace(provider.APIKey) if apiKey == "" { return nil, fmt.Errorf("bing api key is required") } endpoint := strings.TrimSpace(provider.BaseURL) if endpoint == "" { endpoint = bingSearchURL } u, err := url.Parse(endpoint) if err != nil { return nil, err } q := u.Query() q.Set(queryParamName(provider), query) q.Set("count", fmt.Sprintf("%d", count)) u.RawQuery = q.Encode() req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) if err != nil { return nil, err } req.Header.Set("Accept", "application/json") header := strings.TrimSpace(provider.AuthHeader) if header == "" { header = "Ocp-Apim-Subscription-Key" } req.Header.Set(header, apiKey) body, status, err := c.doRequest(req) if err != nil { return nil, err } if status >= 400 { return nil, fmt.Errorf("bing search failed (%d): %s", status, string(body)) } var parsed bingSearchResponse if err := json.Unmarshal(body, &parsed); err != nil { return nil, err } if parsed.WebPages == nil || len(parsed.WebPages.Value) == 0 { return []Result{}, nil } results := make([]Result, 0, len(parsed.WebPages.Value)) for _, item := range parsed.WebPages.Value { results = append(results, Result{ Title: strings.TrimSpace(item.Name), URL: strings.TrimSpace(item.URL), Description: strings.TrimSpace(item.Snippet), }) } if len(results) > count { results = results[:count] } return results, nil }