package google import ( "encoding/json" "fmt" "net/http" "net/url" "time" "git.linuxforward.com/byom/byom-trends/config" "git.linuxforward.com/byom/byom-trends/logger" "github.com/sirupsen/logrus" ) type Client struct { httpClient *http.Client apiKey string baseURL string logger *logrus.Entry } type TrendResult struct { Keyword string `json:"keyword"` TimeRange string `json:"time_range"` Interest []InterestPoint `json:"interest"` RelatedTopics []RelatedTopic `json:"related_topics"` RegionalInterest map[string]int `json:"regional_interest"` } type InterestPoint struct { Date time.Time `json:"date"` Value int `json:"value"` } type RelatedTopic struct { Title string `json:"title"` Type string `json:"type"` Value int `json:"value"` } func NewClient(cfg *config.GoogleConfig) *Client { return &Client{ httpClient: &http.Client{ Timeout: time.Second * 10, }, apiKey: cfg.TrendsAPIKey, baseURL: cfg.BaseURL, logger: logger.NewLogger("google-trends-client"), } } func (c *Client) GetTrends(keyword string, timeRange string) (*TrendResult, error) { params := url.Values{} params.Add("keyword", keyword) params.Add("time_range", timeRange) params.Add("key", c.apiKey) url := fmt.Sprintf("%s/dailytrends?%s", c.baseURL, params.Encode()) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("create request: %w", err) } resp, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("do request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) } var result TrendResult if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("decode response: %w", err) } return &result, nil } func (c *Client) CompareKeywords(keywords []string, timeRange string) (map[string]*TrendResult, error) { results := make(map[string]*TrendResult) for _, keyword := range keywords { result, err := c.GetTrends(keyword, timeRange) if err != nil { return nil, fmt.Errorf("get trends for %s: %w", keyword, err) } results[keyword] = result } return results, nil } func (c *Client) GetRelatedTopics(keyword string) ([]RelatedTopic, error) { params := url.Values{} params.Add("keyword", keyword) params.Add("key", c.apiKey) url := fmt.Sprintf("%s/relatedTopics?%s", c.baseURL, params.Encode()) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("create request: %w", err) } resp, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("do request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) } var topics []RelatedTopic if err := json.NewDecoder(resp.Body).Decode(&topics); err != nil { return nil, fmt.Errorf("decode response: %w", err) } return topics, nil } func (c *Client) GetRegionalInterest(keyword string, region string) (map[string]int, error) { params := url.Values{} params.Add("keyword", keyword) params.Add("region", region) params.Add("key", c.apiKey) url := fmt.Sprintf("%s/regionalInterest?%s", c.baseURL, params.Encode()) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("create request: %w", err) } resp, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("do request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) } var interest map[string]int if err := json.NewDecoder(resp.Body).Decode(&interest); err != nil { return nil, fmt.Errorf("decode response: %w", err) } return interest, nil }