/** * Google Gemini API - Grounding with Google Search Example * * Demonstrates how to enable grounding to connect the model to real-time * web information, reducing hallucinations and providing up-to-date responses * with citations. * * Features: * - Basic grounding with Google Search (Gemini 2.5) * - Dynamic retrieval with threshold (Gemini 1.5) * - Chat with grounding * - Combining grounding with function calling * - Checking grounding metadata and citations * * Requirements: * - @google/genai@1.27.0+ * - GEMINI_API_KEY environment variable * - Google Cloud project (grounding requires GCP project, not just API key) * * Note: Use `googleSearch` for Gemini 2.5 models (recommended) * Use `googleSearchRetrieval` for Gemini 1.5 models (legacy) */ import { GoogleGenAI, DynamicRetrievalConfigMode } from '@google/genai'; const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY! }); async function basicGrounding() { console.log('=== Basic Grounding Example (Gemini 2.5) ===\n'); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'Who won the euro 2024?', config: { tools: [{ googleSearch: {} }], }, }); console.log('Response:', response.text); // Check if grounding was used if (response.candidates[0].groundingMetadata) { console.log('\nāœ“ Search was performed!'); console.log('\nGrounding Metadata:'); console.log(JSON.stringify(response.candidates[0].groundingMetadata, null, 2)); } else { console.log('\nāœ“ Model answered from its own knowledge (no search needed)'); } console.log('\n=== Basic Grounding Complete ==='); } async function dynamicRetrievalExample() { console.log('\n=== Dynamic Retrieval Example (Gemini 1.5) ===\n'); const response = await ai.models.generateContent({ model: 'gemini-1.5-flash', contents: 'Who won the euro 2024?', config: { tools: [ { googleSearchRetrieval: { dynamicRetrievalConfig: { mode: DynamicRetrievalConfigMode.MODE_DYNAMIC, dynamicThreshold: 0.7, // Search only if confidence < 70% }, }, }, ], }, }); console.log('Response:', response.text); if (response.candidates[0].groundingMetadata) { console.log('\nāœ“ Search performed (confidence < 70%)'); } else { console.log('\nāœ“ Answered from knowledge (confidence >= 70%)'); } console.log('\n=== Dynamic Retrieval Complete ==='); } async function chatWithGrounding() { console.log('\n=== Chat with Grounding Example ===\n'); const chat = await ai.chats.create({ model: 'gemini-2.5-flash', config: { tools: [{ googleSearch: {} }], }, }); // First message console.log('User: What are the latest developments in quantum computing?'); let response = await chat.sendMessage('What are the latest developments in quantum computing?'); console.log(`\nAssistant: ${response.text}`); // Check and display sources if (response.candidates[0].groundingMetadata) { const sources = response.candidates[0].groundingMetadata.webPages || []; console.log(`\nšŸ“š Sources used: ${sources.length}`); sources.forEach((source, i) => { console.log(`${i + 1}. ${source.title}`); console.log(` ${source.url}`); }); } // Follow-up question console.log('\n\nUser: Which company made the biggest breakthrough?'); response = await chat.sendMessage('Which company made the biggest breakthrough?'); console.log(`\nAssistant: ${response.text}`); if (response.candidates[0].groundingMetadata) { const sources = response.candidates[0].groundingMetadata.webPages || []; console.log(`\nšŸ“š Sources used: ${sources.length}`); sources.forEach((source, i) => { console.log(`${i + 1}. ${source.title} - ${source.url}`); }); } console.log('\n=== Chat with Grounding Complete ==='); } async function groundingWithFunctionCalling() { console.log('\n=== Grounding + Function Calling Example ===\n'); // Define weather function const weatherFunction = { name: 'get_current_weather', description: 'Get current weather for a location', parametersJsonSchema: { type: 'object', properties: { location: { type: 'string', description: 'City name' }, unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }, }, required: ['location'], }, }; const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'What is the weather like in the city that won Euro 2024?', config: { tools: [{ googleSearch: {} }, { functionDeclarations: [weatherFunction] }], }, }); console.log('User query: What is the weather like in the city that won Euro 2024?'); console.log('\nModel will:'); console.log('1. Use Google Search to find Euro 2024 winner'); console.log('2. Call get_current_weather function with the city'); console.log('3. Combine both results in response\n'); // Check for function calls const functionCall = response.candidates[0].content.parts.find((part) => part.functionCall); if (functionCall) { console.log('āœ“ Function call detected:'); console.log(` Function: ${functionCall.functionCall?.name}`); console.log(` Arguments:`, functionCall.functionCall?.args); } if (response.candidates[0].groundingMetadata) { console.log('\nāœ“ Grounding was used'); const sources = response.candidates[0].groundingMetadata.webPages || []; console.log(` Sources: ${sources.length} web pages`); } console.log('\n=== Grounding + Function Calling Complete ==='); } async function checkingGroundingUsage() { console.log('\n=== Checking Grounding Usage Example ===\n'); // Query that doesn't need search console.log('Query 1: What is 2+2? (Should NOT need search)'); const response1 = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'What is 2+2?', config: { tools: [{ googleSearch: {} }], }, }); console.log(`Answer: ${response1.text}`); console.log( `Grounding used: ${response1.candidates[0].groundingMetadata ? 'YES' : 'NO'}\n` ); // Query that needs current information console.log('Query 2: What happened in the news today? (Should need search)'); const response2 = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'What are the top news headlines today?', config: { tools: [{ googleSearch: {} }], }, }); console.log(`Answer: ${response2.text}`); console.log(`Grounding used: ${response2.candidates[0].groundingMetadata ? 'YES' : 'NO'}`); if (response2.candidates[0].groundingMetadata) { console.log('\nSearch queries performed:'); const queries = response2.candidates[0].groundingMetadata.searchQueries || []; queries.forEach((q, i) => { console.log(`${i + 1}. ${q.text || q}`); }); } console.log('\n=== Checking Grounding Usage Complete ==='); } async function citationsExample() { console.log('\n=== Citations Example ===\n'); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'Tell me about the recent Mars rover discoveries', config: { tools: [{ googleSearch: {} }], }, }); console.log('Response:', response.text); if (response.candidates[0].groundingMetadata) { const metadata = response.candidates[0].groundingMetadata; console.log('\nšŸ“š Web Pages:'); const webPages = metadata.webPages || []; webPages.forEach((page, i) => { console.log(`\n${i + 1}. ${page.title}`); console.log(` URL: ${page.url}`); if (page.snippet) { console.log(` Snippet: ${page.snippet.substring(0, 100)}...`); } }); console.log('\nšŸ”— Citations:'); const citations = metadata.citations || []; citations.forEach((citation, i) => { console.log(`\n${i + 1}. Position: ${citation.startIndex}-${citation.endIndex}`); console.log(` Source: ${citation.uri}`); }); } console.log('\n=== Citations Example Complete ==='); } // Run all examples async function main() { await basicGrounding(); await dynamicRetrievalExample(); await chatWithGrounding(); await groundingWithFunctionCalling(); await checkingGroundingUsage(); await citationsExample(); } main().catch((error) => { console.error('Error:', error.message); if (error.message.includes('Google Cloud project')) { console.error( '\nNote: Grounding requires a Google Cloud project, not just an API key.' ); } process.exit(1); });