Skip to content

Commit

Permalink
fix: fix related queries
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaoroger committed Nov 30, 2024
1 parent 58f1597 commit 67d7168
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 107 deletions.
6 changes: 3 additions & 3 deletions docs/core_docs/docs/integrations/tools/google_trends.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import CodeBlock from "@theme/CodeBlock";

# Google Trends Tool

The Google Trends Tool allows your agent to utilize the Google Trends API from Serp API to retrieve and analyze search interest data.
The Google Trends Tool allows your agent to utilize the Google Trends API from Serp API to retrieve and analyze search interest data.
This can be useful for understanding trending topics, regional search interest, and historical popularity of search terms.

## Setup

To use this tool, you'll need to configure access to the Google Trends API. The integration relies on the unofficial
To use this tool, you'll need to configure access to the Google Trends API. The integration relies on the unofficial
Google Trends library, as Google does not provide a formal API for accessing trends data.

Get an API key from [SERPApi](https://serpapi.com/users/sign_in)
Expand All @@ -34,4 +34,4 @@ import ToolExample from "@examples/tools/google_trends.ts";

## Related

- Tool [https://serpapi.com/google-trends-api]
- Tool [https://serpapi.com/google-trends-api]
5 changes: 2 additions & 3 deletions examples/src/tools/google_trends.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { GoogleTrendsAPI } from "@langchain/community/tools/google_trends";

export async function run() {

const tool = new GoogleTrendsAPI();
const tool = new GoogleTrendsAPI();

const res = await tool._call("Monster");

console.log(res);
}
}
218 changes: 121 additions & 97 deletions libs/langchain-community/src/tools/google_trends.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,113 +5,137 @@ import { Tool } from "@langchain/core/tools";
* Interface for parameters required by GoogleTrendsAPI class.
*/
export interface GoogleTrendsAPIParams {
apiKey?: string;
}

apiKey?: string;
}

/**
* Tool that queries the Google Trends API
* Tool that queries the Google Trends API. Uses default interest over time.
*/
export class GoogleTrendsAPI extends Tool {
static lc_name() {
return "GoogleTrendsAPI";
}

get lc_secrets(): { [key: string]: string } | undefined {
return {
apiKey: "SERPAPI_API_KEY",
};
}

name = "google_trends";

protected apiKey: string;
static lc_name() {
return "GoogleTrendsAPI";
}

description = `A wrapper around Google Trends API. Useful for analyzing and retrieving trending search data based on keywords,
get lc_secrets(): { [key: string]: string } | undefined {
return {
apiKey: "SERPAPI_API_KEY",
};
}

name = "google_trends";

protected apiKey: string;

description = `A wrapper around Google Trends API. Useful for analyzing and retrieving trending search data based on keywords,
categories, or regions. Input should be a search query or specific parameters for trends analysis.`;

constructor(fields?: GoogleTrendsAPIParams) {
super(...arguments);
const apiKey =
fields?.apiKey ?? getEnvironmentVariable("SERPAPI_API_KEY");
if (apiKey === undefined) {
throw new Error(
`Google Trends API key not set. You can set it as "SERPAPI_API_KEY" in your environment variables.`
);
constructor(fields?: GoogleTrendsAPIParams) {
super(...arguments);
const apiKey = fields?.apiKey ?? getEnvironmentVariable("SERPAPI_API_KEY");
if (apiKey === undefined) {
throw new Error(
`Google Trends API key not set. You can set it as "SERPAPI_API_KEY" in your environment variables.`
);
}
this.apiKey = apiKey;
}

async _call(query: string): Promise<string> {
/**
* Related queries only accepts one at a time, and multiple
* queries at once on interest over time (default) is effectively the same as
* each query one by one.
*/
if (query.split(",").length > 1) {
throw new Error("Please do one query at a time");
}
const serpapiApiKey = this.apiKey;
const params = new URLSearchParams({
engine: "google_trends",
api_key: serpapiApiKey,
q: query,
});

const res = await fetch(
`https://serpapi.com/search.json?${params.toString()}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
this.apiKey = apiKey;
);

if (!res.ok) {
throw new Error(`Error fetching data from SerpAPI: ${res.statusText}`);
}

const clientDict = await res.json();
const totalResults = clientDict.interest_over_time?.timeline_data ?? [];

if (totalResults.length === 0) {
return "No good Trend Result was found";
}

async _call(query: string): Promise<string> {
const serpapiApiKey = this.apiKey;
const params = new URLSearchParams({
engine: "google_trends",
api_key: serpapiApiKey,
q: query,
});

const res = await fetch(`https://serpapi.com/search.json?${params.toString()}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

if (!res.ok) {
throw new Error(`Error fetching data from SerpAPI: ${res.statusText}`);
}

const clientDict = await res.json();
const totalResults = clientDict.interest_over_time?.timeline_data ?? [];

if (totalResults.length === 0) {
return "No good Trend Result was found";
}

const startDate = totalResults[0].date.split(" ");
const endDate = totalResults[totalResults.length - 1].date.split(" ");
const values = totalResults.map((result: any) => result.values[0].extracted_value);
const minValue = Math.min(...values);
const maxValue = Math.max(...values);
const avgValue = values.reduce((a: number, b: number) => a + b, 0) / values.length;
const percentageChange = ((values[values.length - 1] - values[0]) / (values[0] || 1)) * 100;

// const relatedParams = new URLSearchParams({
// engine: "google_trends",
// api_key: serpapiApiKey,
// data_type: "RELATED_TOPICS",
// q: query,
// });

// const relatedRes = await fetch(`https://serpapi.com/search.json?${relatedParams.toString()}`, {
// method: "GET",
// headers: {
// "Content-Type": "application/json",
// },
// });

// if (!relatedRes.ok) {
// throw new Error(`Error fetching related queries from SerpAPI: ${relatedRes.statusText}`);
// }

// const relatedDict = await relatedRes.json();
// const rising = relatedDict.related_queries?.rising?.map((result: any) => result.query) ?? [];
// const top = relatedDict.related_queries?.top?.map((result: any) => result.query) ?? [];

const doc = [
`Query: ${query}`,
`Date From: ${startDate[0]} ${startDate[1]}, ${startDate[2]}`,
`Date To: ${endDate[0]} ${endDate[1]} ${endDate[2]}`,
`Min Value: ${minValue}`,
`Max Value: ${maxValue}`,
`Average Value: ${avgValue}`,
`Percent Change: ${percentageChange.toFixed(2)}%`,
// `Trend values: ${values.join(", ")}`,
// `Rising Related Queries: ${rising.join(", ")}`,
// `Top Related Queries: ${top.join(", ")}`,
];

return doc.join("\n\n");
const startDate = totalResults[0].date.split(" ");
const endDate = totalResults[totalResults.length - 1].date.split(" ");
const values = totalResults.map(
(result: any) => result.values[0].extracted_value
);
const minValue = Math.min(...values);
const maxValue = Math.max(...values);
const avgValue =
values.reduce((a: number, b: number) => a + b, 0) / values.length;
const percentageChange =
((values[values.length - 1] - values[0]) / (values[0] || 1)) * 100;

const relatedParams = new URLSearchParams({
engine: "google_trends",
api_key: serpapiApiKey,
data_type: "RELATED_QUERIES",
q: query,
});

const relatedRes = await fetch(
`https://serpapi.com/search.json?${relatedParams.toString()}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);

let rising = [];
let top = [];
if (!relatedRes.ok) {
console.error(
`Error fetching related queries from SerpAPI: ${relatedRes.statusText}`
);
} else {
const relatedDict = await relatedRes.json();
rising =
relatedDict.related_queries?.rising?.map(
(result: any) => result.query
) ?? [];
top =
relatedDict.related_queries?.top?.map((result: any) => result.query) ??
[];
}

const doc = [
`Query: ${query}`,
`Date From: ${startDate[0]} ${startDate[1]}, ${startDate[2]}`,
`Date To: ${endDate[0]} ${endDate[1]} ${endDate[2]}`,
`Min Value: ${minValue}`,
`Max Value: ${maxValue}`,
`Average Value: ${avgValue}`,
`Percent Change: ${percentageChange.toFixed(2)}%`,
`Trend values: ${values.join(", ")}`,
`Rising Related Queries: ${rising.join(", ")}`,
`Top Related Queries: ${top.join(", ")}`,
];

return doc.join("\n\n");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ describe("GoogleTrendsAPI", () => {
expect(result).toContain("Max Value:");
expect(result).toContain("Average Value:");
expect(result).toContain("Percent Change:");
// expect(result).toContain("Trend values:");
// expect(result).toContain("Rising Related Queries:");
// expect(result).toContain("Top Related Queries:");
expect(result).toContain("Trend values:");
expect(result).toContain("Rising Related Queries:");
expect(result).toContain("Top Related Queries:");
});

test("GoogleTrendsAPI returns 'No good Trend Result was found' for a non-existent query", async () => {
const tool = new GoogleTrendsAPI();

const result = await tool._call("hhdhbfsjbfwl");
const result = await tool._call("earghajgpajrpgjaprgag");

expect(result).toBe("No good Trend Result was found");
});
Expand Down

0 comments on commit 67d7168

Please sign in to comment.