Building a Web Search + AI Summary Tool

How to combine OpenAI and SERP API to create a powerful web search and AI summary tool for stock analysis and research

Introduction

In today's fast-paced financial markets, analysts need to process vast amounts of information quickly to make informed decisions. Traditional methods of manually searching the web, reading articles, and synthesizing information are time-consuming and prone to missing critical insights. This is where combining AI with web search capabilities can create a powerful tool for stock analysis.

In this blog post, I'll share how I built a web search + AI summary tool for a company's experimental stock analysis project. This tool helped analysts quickly gather and synthesize information about stocks they were researching, saving hours of manual work and providing more comprehensive insights.

The Power of Combining Web Search with AI

Before diving into the implementation, let's understand why this combination is particularly powerful:

  1. Real-time information access: SERP (Search Engine Results Page) APIs provide access to the latest information from across the web
  2. Contextual understanding: Large language models like GPT-4 can understand the context and relevance of information
  3. Synthesis capabilities: AI can summarize, extract key points, and identify trends across multiple sources
  4. Customizable analysis: The system can be tailored to focus on specific aspects of stock analysis (financials, news sentiment, market trends)

For stock analysis specifically, this combination allows analysts to:

  • Quickly gather the latest news and developments about a company
  • Analyze market sentiment across multiple sources
  • Identify potential risks or opportunities that might be buried in various articles
  • Generate comprehensive research summaries in seconds rather than hours

Implementation: Building the Tool

Let's walk through how to build this tool step by step.

1. Setting Up the Environment

First, we need to set up our environment with the necessary dependencies:

// Install required packages
npm install axios openai dotenv

// Create a .env file for API keys
OPENAI_API_KEY=your_openai_api_key
SERP_API_KEY=your_serp_api_key

2. Configuring the SERP API

We'll use a SERP API to fetch search results. There are several providers available, but for this project, I used SerpAPI which provides structured data from search engines:

const axios = require('axios')
require('dotenv').config()

async function searchWeb(query, numResults = 5) {
  try {
    const response = await axios.get('https://serpapi.com/search', {
      params: {
        q: query,
        api_key: process.env.SERP_API_KEY,
        num: numResults,
      },
    })

    // Extract the organic search results
    const searchResults = response.data.organic_results.map((result) => ({
      title: result.title,
      link: result.link,
      snippet: result.snippet,
    }))

    return searchResults
  } catch (error) {
    console.error('Error searching the web:', error)
    throw error
  }
}

3. Fetching Content from Search Results

Once we have the search results, we need to fetch the actual content from the web pages:

const axios = require('axios')
const cheerio = require('cheerio')

async function fetchContent(url) {
  try {
    const response = await axios.get(url)
    const $ = cheerio.load(response.data)

    // Remove script tags, style tags, and other non-content elements
    $('script, style, meta, link').remove()

    // Extract the main content (this is a simplified approach)
    // For production, you might want to use more sophisticated content extraction
    const content = $('body').text().replace(/\s+/g, ' ').trim()

    return content
  } catch (error) {
    console.error(`Error fetching content from ${url}:`, error)
    return '' // Return empty string if content can't be fetched
  }
}

async function fetchContentsFromSearchResults(searchResults) {
  const contents = []

  for (const result of searchResults) {
    const content = await fetchContent(result.link)
    if (content) {
      contents.push({
        title: result.title,
        url: result.link,
        content: content.substring(0, 8000), // Limit content length
      })
    }
  }

  return contents
}

4. Integrating with OpenAI API

Now, we'll use OpenAI's API to summarize and analyze the content:

const { OpenAI } = require('openai')
require('dotenv').config()

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
})

async function summarizeWithAI(stockSymbol, contents) {
  // Prepare the content for the AI
  const contentText = contents
    .map((item) => `Source: ${item.title} (${item.url})\n${item.content}\n\n`)
    .join('')

  // Create the prompt for the AI
  const prompt = `
    You are a financial analyst assistant. Below are web search results about the stock ${stockSymbol}.
    Please analyze these results and provide:
    
    1. A summary of key recent developments
    2. Analysis of market sentiment (positive, negative, neutral)
    3. Potential impact on stock price
    4. Key financial metrics mentioned
    5. Any risks or opportunities identified
    
    Make your analysis concise, factual, and focused on information that would be relevant to investors.
    
    Search Results:
    ${contentText}
  `

  try {
    const response = await openai.chat.completions.create({
      model: 'gpt-4',
      messages: [
        {
          role: 'system',
          content:
            'You are a financial analyst assistant that helps analyze stock information from web search results.',
        },
        { role: 'user', content: prompt },
      ],
      temperature: 0.2, // Lower temperature for more factual responses
      max_tokens: 1500,
    })

    return response.choices[0].message.content
  } catch (error) {
    console.error('Error generating AI summary:', error)
    throw error
  }
}

5. Putting It All Together

Finally, let's create the main function that ties everything together:

async function analyzeStock(stockSymbol) {
  try {
    console.log(`Analyzing stock: ${stockSymbol}...`)

    // Step 1: Search for recent information about the stock
    const searchQuery = `${stockSymbol} stock news financial analysis recent developments`
    const searchResults = await searchWeb(searchQuery, 8)

    // Step 2: Fetch content from search results
    const contents = await fetchContentsFromSearchResults(searchResults)

    // Step 3: Generate AI summary and analysis
    const analysis = await summarizeWithAI(stockSymbol, contents)

    return {
      stockSymbol,
      searchResults,
      analysis,
    }
  } catch (error) {
    console.error(`Error analyzing stock ${stockSymbol}:`, error)
    throw error
  }
}

// Example usage
analyzeStock('AAPL')
  .then((result) => {
    console.log('Analysis complete:')
    console.log(result.analysis)
  })
  .catch((error) => {
    console.error('Analysis failed:', error)
  })

Real-World Application: Stock Analysis Dashboard

For our company's experimental project, we integrated this functionality into a dashboard that allowed analysts to:

  1. Input multiple stock symbols for analysis
  2. Customize the search parameters (time range, focus areas)
  3. Compare AI-generated summaries side by side
  4. Save and track analyses over time to identify trends

The dashboard looked something like this:

// React component example (simplified)
function StockAnalysisDashboard() {
  const [stocks, setStocks] = useState([])
  const [loading, setLoading] = useState({})
  const [analyses, setAnalyses] = useState({})

  const addStock = (symbol) => {
    if (!stocks.includes(symbol)) {
      setStocks([...stocks, symbol])
      analyzeStockAndUpdateState(symbol)
    }
  }

  const analyzeStockAndUpdateState = async (symbol) => {
    setLoading((prev) => ({ ...prev, [symbol]: true }))
    try {
      const result = await analyzeStock(symbol)
      setAnalyses((prev) => ({ ...prev, [symbol]: result }))
    } catch (error) {
      console.error(`Error analyzing ${symbol}:`, error)
    } finally {
      setLoading((prev) => ({ ...prev, [symbol]: false }))
    }
  }

  return (
    <div className="dashboard">
      <h1>Stock Analysis Dashboard</h1>

      <div className="stock-input">
        <input
          type="text"
          placeholder="Enter stock symbol (e.g., AAPL)"
          onKeyPress={(e) => e.key === 'Enter' && addStock(e.target.value)}
        />
      </div>

      <div className="stock-analyses">
        {stocks.map((symbol) => (
          <div key={symbol} className="stock-card">
            <h2>{symbol}</h2>
            {loading[symbol] ? (
              <p>Loading analysis...</p>
            ) : analyses[symbol] ? (
              <div>
                <h3>AI Analysis</h3>
                <div className="analysis-content">{analyses[symbol].analysis}</div>
                <h3>Sources</h3>
                <ul>
                  {analyses[symbol].searchResults.map((result, i) => (
                    <li key={i}>
                      <a href={result.link} target="_blank" rel="noopener noreferrer">
                        {result.title}
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
            ) : (
              <p>No analysis available</p>
            )}
          </div>
        ))}
      </div>
    </div>
  )
}

Challenges and Considerations

While building this tool, we encountered several challenges worth noting:

1. API Rate Limits and Costs

Both SERP APIs and OpenAI's API have rate limits and usage costs. For a production system, you'll need to:

  • Implement caching to avoid redundant searches
  • Set up usage monitoring and alerts
  • Consider batch processing for multiple stocks

2. Content Extraction Quality

Extracting meaningful content from web pages can be challenging due to:

  • Paywalls on financial news sites
  • Dynamic content loaded via JavaScript
  • Varied page structures across different sites

We improved our content extraction by:

  • Using more sophisticated libraries like
    mozilla/readability
  • Implementing site-specific extractors for common financial news sources
  • Falling back to meta descriptions when full content wasn't available

3. Ensuring Analysis Quality

To improve the quality of AI-generated analyses:

  • We fine-tuned prompts based on feedback from financial analysts
  • Implemented fact-checking by cross-referencing key claims
  • Added source attribution to make it clear where information came from

Conclusion

Combining web search capabilities with AI summarization creates a powerful tool for stock analysis that can save hours of research time and provide more comprehensive insights. The implementation we've outlined here is just a starting point—there are many ways to extend and improve this system.

Some potential extensions include:

  • Adding sentiment analysis specifically tuned for financial news
  • Incorporating historical stock price data for correlation analysis
  • Expanding to include social media sentiment from platforms like Twitter/X
  • Creating alerts for significant news that might impact stock prices

As AI capabilities continue to advance, tools like this will become increasingly sophisticated and valuable for financial analysis and decision-making.

Have you built similar tools or have ideas for improvements? I'd love to hear about your experiences in the comments!