In this step, we’ll implement Summary, which provide a concise, AI-generated summary to user queries. This feature is useful for delivering immediate insights to users without requiring them to sift through multiple search results.
To fetch a summary, use the Raffle API’s /summary endpoint. This requires a uid and a query parameter.
/summary
uid
query
Here’s the function to fetch a summary from the Raffle API:
export const fetchSummary = async (query) => { const response = await fetch( `https://api.raffle.ai/v2/summary?uid=$YOUR_RAFFLE_UID&query=${encodeURIComponent(query)}` ); const data = await response.json(); return data; };
This function sends a GET request to the summary endpoint using the user’s query and returns the summary response.
GET
summary
dangerouslySetInnerHTML
status
success
no-relevant-results
index
[1]
title
url
We’ll integrate the summary feature using React Query’s useMutation. This will handle the fetching of a summary dynamically when a search is triggered.
useMutation
import { useState } from "react"; import { useMutation } from "@tanstack/react-query"; import { fetchSummary } from "./api"; export const Search = () => { const [query, setQuery] = useState(""); const { data: summary, isPending: isLoadingSummary, mutate: handleFetchSummary, } = useMutation({ mutationKey: ["summary"], mutationFn: fetchSummary, }); const handleSearch = () => { if (query.trim()) { handleFetchSummary(query.trim()); } }; return ( <div> <h1>Search API - React Example</h1> <div> <input type="text" value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Enter your query..." /> <button onClick={handleSearch}>Search</button> </div> <div> <h2>Summary</h2> {isLoadingSummary ? ( <p>Loading...</p> ) : summary?.status === "success" ? ( <div> <div dangerouslySetInnerHTML={{ __html: summary.summary }} /> {summary.references.length > 0 && ( <div> <h3>References</h3> <ul> {summary.references.map((ref) => ( <li key={ref.index}> {ref.url ? ( <a href={ref.url} target="_blank" rel="noopener noreferrer" > {ref.title} </a> ) : ( ref.title )} </li> ))} </ul> </div> )} </div> ) : ( <p>No summary available for this query.</p> )} </div> </div> ); };
fetchSummary
This step integrates the summary seamlessly into the UI, providing users with instant insights while maintaining a smooth and efficient experience.
At this stage, your full code should look like this:
import { useEffect, useState } from "react"; import { useMutation, useQuery } from "@tanstack/react-query"; import { useDebounce } from "@uidotdev/usehooks"; import { fetchSuggestions, fetchSummary, fetchTopQuestions } from "./api"; export const Search = () => { const [query, setQuery] = useState(""); const debouncedQuery = useDebounce(query, 500); // Debounce with 500ms delay const { data: topQuestions = [], isLoading } = useQuery({ queryKey: ["topQuestions"], queryFn: fetchTopQuestions, }); const { data: suggestions = [], mutate: handleFetchSuggestions } = useMutation({ mutationKey: ["suggestions", debouncedQuery], mutationFn: (q) => fetchSuggestions(q, 5), }); const { data: summary, isPending: isLoadingSummary, mutate: handleFetchSummary, } = useMutation({ mutationKey: ["summary"], mutationFn: fetchSummary, }); // Trigger suggestions when debouncedQuery is at least 3 characters long useEffect(() => { if (debouncedQuery.length >= 3) { handleFetchSuggestions(debouncedQuery); } }, [debouncedQuery, handleFetchSuggestions]); const handleSearch = () => { if (query.trim()) { handleFetchSummary(query.trim()); } }; return ( <div> <h1>Search API - React Example</h1> <div> <input type="text" value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Enter your query..." /> <button onClick={handleSearch}>Search</button> </div> <div> <h2>Top Questions</h2> {isLoading ? ( <p>Loading top questions...</p> ) : ( <ul> {topQuestions.map(({ question }) => ( <li key={question} onClick={() => setQuery(question)}> {question} </li> ))} </ul> )} </div> <div> <h2>Suggestions</h2> <ul> {suggestions.map(({ suggestion }, index) => ( <li key={index} onClick={() => { setQuery(suggestion); handleSearch(); }} > {suggestion} </li> ))} </ul> </div> <div> <h2>Summary</h2> {isLoadingSummary ? ( <p>Loading...</p> ) : summary?.status === "success" ? ( <div> <div dangerouslySetInnerHTML={{ __html: summary.summary }} /> {summary.references.length > 0 && ( <div> <h3>References</h3> <ul> {summary.references.map((ref) => ( <li key={ref.index}> {ref.url ? ( <a href={ref.url} target="_blank" rel="noopener noreferrer" > {ref.title} </a> ) : ( ref.title )} </li> ))} </ul> </div> )} </div> ) : ( <p>No summary available for this query.</p> )} </div> <div> <h2>Search Results</h2> <p>Search results will appear here...</p> </div> </div> ); };
5 - Add Search Results