- Updated .env.example to include new configuration options for the UltiAI branding and API endpoints. - Enhanced Nginx configuration to support new API routes for the MCP and WebSocket connections. - Introduced sub-filters for branding adjustments in Nginx responses. - Added new JavaScript patch for API endpoint adjustments. - Implemented tests for new API functionalities and improved error handling in the AI gateway.
101 lines
2.3 KiB
Go
101 lines
2.3 KiB
Go
package websearch
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
func (c *Client) searchCustom(ctx context.Context, provider Provider, query string, count int) ([]Result, error) {
|
|
endpoint := strings.TrimSpace(provider.BaseURL)
|
|
if endpoint == "" {
|
|
return nil, fmt.Errorf("custom search base url is required")
|
|
}
|
|
|
|
endpoint = strings.NewReplacer(
|
|
"{query}", url.QueryEscape(query),
|
|
"{count}", fmt.Sprintf("%d", count),
|
|
).Replace(endpoint)
|
|
|
|
reqURL, err := url.Parse(endpoint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !strings.Contains(provider.BaseURL, "{query}") {
|
|
q := reqURL.Query()
|
|
q.Set(queryParamName(provider), query)
|
|
if !strings.Contains(provider.BaseURL, "{count}") {
|
|
q.Set("count", fmt.Sprintf("%d", count))
|
|
}
|
|
reqURL.RawQuery = q.Encode()
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL.String(), nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Accept", "application/json")
|
|
if apiKey := strings.TrimSpace(provider.APIKey); apiKey != "" {
|
|
header := strings.TrimSpace(provider.AuthHeader)
|
|
switch {
|
|
case header != "":
|
|
if strings.EqualFold(header, "Authorization") {
|
|
req.Header.Set(header, "Bearer "+apiKey)
|
|
} else {
|
|
req.Header.Set(header, apiKey)
|
|
}
|
|
case strings.Contains(reqURL.RawQuery, "api_key="):
|
|
// key already in URL
|
|
default:
|
|
q := reqURL.Query()
|
|
q.Set("api_key", apiKey)
|
|
reqURL.RawQuery = q.Encode()
|
|
req.URL = reqURL
|
|
}
|
|
}
|
|
|
|
body, status, err := c.doRequest(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if status >= 400 {
|
|
return nil, fmt.Errorf("custom search failed (%d): %s", status, string(body))
|
|
}
|
|
|
|
root, err := decodeJSONBody(body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items, ok := resultsArray(root, provider.ResultsPath)
|
|
if !ok {
|
|
return []Result{}, nil
|
|
}
|
|
|
|
descField := strings.TrimSpace(provider.DescField)
|
|
if descField == "" {
|
|
descField = "description"
|
|
}
|
|
|
|
limit := count
|
|
if len(items) < limit {
|
|
limit = len(items)
|
|
}
|
|
results := make([]Result, 0, limit)
|
|
for _, item := range items[:limit] {
|
|
title := jsonFieldString(item, provider.TitleField)
|
|
link := jsonFieldString(item, provider.URLField)
|
|
desc := jsonFieldString(item, descField)
|
|
if title == "" && link == "" {
|
|
continue
|
|
}
|
|
results = append(results, Result{
|
|
Title: title,
|
|
URL: link,
|
|
Description: desc,
|
|
})
|
|
}
|
|
return results, nil
|
|
}
|