> ## Documentation Index
> Fetch the complete documentation index at: https://docs.perplexity.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Cookbook

> Guides, runnable examples, and community projects for building with the Perplexity Agent, Search, and Embeddings APIs. Search or filter by product and category.

export const COOKBOOK_LABELS = {
  "products": {
    "agent-api": "Agent API",
    "search-api": "Search API",
    "sonar-api": "Sonar API",
    "embeddings-api": "Embeddings API"
  },
  "categories": {
    "finance": "Finance",
    "people": "People",
    "sandbox": "Sandbox",
    "multimodal": "Multimodal",
    "rag": "RAG",
    "deep-research": "Deep Research",
    "structured-outputs": "Structured Outputs",
    "function-calling": "Function Calling",
    "streaming": "Streaming",
    "memory": "Memory",
    "search-filtering": "Search Filtering",
    "orchestration": "Orchestration",
    "integrations": "Integrations",
    "mcp": "MCP"
  },
  "type": {
    "guide": "Guide",
    "example": "Example",
    "showcase": "Showcase"
  }
};

export const COOKBOOK_FACETS = {
  "products": ["agent-api", "search-api", "sonar-api", "embeddings-api"],
  "categories": ["finance", "people", "sandbox", "multimodal", "rag", "deep-research", "structured-outputs", "function-calling", "streaming", "memory", "search-filtering", "orchestration", "integrations", "mcp"],
  "type": ["guide", "example", "showcase"]
};

export const COOKBOOK_RECIPES = [{
  "title": "Search as Code for coding agents",
  "description": "Use the Perplexity Search SDK to build a source-backed dependency migration packet that any coding agent can inspect before it edits code.",
  "href": "/docs/cookbook/articles/search-as-code-coding-agents/README",
  "type": "guide",
  "products": ["search-api"],
  "categories": ["search-filtering", "orchestration"],
  "date": "Sep 2026",
  "dateSort": "2026-09-15T15:19:29-07:00"
}, {
  "title": "Build an incident responder with Profiles, Skills, and Managed Connectors",
  "description": "Combine a saved Profile, an Incident Response Skill, Sandbox, and Datadog, GitHub, and Slack managed connectors, then launch the custom agent with the Agent API.",
  "href": "/docs/cookbook/articles/incident-responder/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["orchestration", "integrations"],
  "date": "Sep 2026",
  "dateSort": "2026-09-09T13:56:05-07:00"
}, {
  "title": "Enrich Customer Data with Agent API",
  "description": "Use Agent API with people_search to enrich a ClickHouse customer data row and append the result to the table.",
  "href": "/docs/cookbook/examples/customer-enrichment-agent-api/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["people", "function-calling"],
  "date": "Sep 2026",
  "dateSort": "2026-09-01T15:43:29-07:00"
}, {
  "title": "GitHub investigation agent using managed connectors",
  "description": "Use managed Slack and GitHub connectors to investigate a linked bug report and reply in its Slack thread.",
  "href": "/docs/cookbook/examples/triage-bug-report-connectors/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["sandbox", "orchestration", "integrations"],
  "date": "Aug 2026",
  "dateSort": "2026-08-27T17:59:07-07:00"
}, {
  "title": "Customizing Presets",
  "description": "",
  "href": "/docs/cookbook/examples/agent-api-presets/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": [],
  "date": "Aug 2026",
  "dateSort": "2026-08-19T16:47:06-07:00"
}, {
  "title": "Grounded Data Story with Kimi K3",
  "description": "Turn any topic into a self-contained, source-linked interactive HTML report using Kimi K3, live web search, and the Agent API.",
  "href": "/docs/cookbook/examples/data-story-kimi-k3/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["deep-research", "orchestration"],
  "date": "Aug 2026",
  "dateSort": "2026-08-07T10:56:38-07:00"
}, {
  "title": "Daily News Digest with LLM Deduplication",
  "description": "Build a daily news digest that reports each story once. One Agent API request runs code in the sandbox to fetch the day's news, groups coverage into stories, and delivers the digest and a story registry as files.",
  "href": "/docs/cookbook/articles/news-dedupe-digest/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["sandbox", "orchestration"],
  "date": "Jul 2026",
  "dateSort": "2026-07-20T21:01:18-07:00"
}, {
  "title": "Daily AI Stock News PDF with Skills",
  "description": "Generate a daily one-page AI-industry stock news PDF with the Agent API using the built-in office skill and an inline design skill.",
  "href": "/docs/cookbook/articles/agent-skills/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["sandbox", "orchestration"],
  "date": "Jul 2026",
  "dateSort": "2026-07-17T12:40:41Z"
}, {
  "title": "Model Picker",
  "description": "Describe a task and get a grounded shortlist of open models to use. One Agent API request combines the Hugging Face MCP server with web search to find, verify, and recommend a model.",
  "href": "/docs/cookbook/examples/model-picker/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["mcp", "integrations"],
  "date": "Jul 2026",
  "dateSort": "2026-07-05T16:24:31+02:00"
}, {
  "title": "Talent Sourcer",
  "description": "Build a vetted engineer sourcing shortlist with one Agent API request. The model works in a Python sandbox - segmenting the brief, calling people_search across sub-segments, verifying each candidate's role, location, and tenure with web_search, collecting GitHub, social, and publication links, scoring and de-duplicating in code, then rendering an HTML shortlist and sharing it with share_file.",
  "href": "/docs/cookbook/examples/talent-sourcer/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["people", "sandbox"],
  "date": "Jun 2026",
  "dateSort": "2026-06-20T00:18:16+02:00"
}, {
  "title": "Competitor Buzz Tracker",
  "description": "Turn a basket of searches and keyword rules into a one-page share-of-voice chart (PDF) with two chained Agent API requests. The first searches and counts inside the sandbox and returns a structured-output JSON contract. The second renders the bar chart and shares it as a downloadable file.",
  "href": "/docs/cookbook/examples/competitor-buzz-tracker/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["sandbox", "structured-outputs"],
  "date": "Jun 2026",
  "dateSort": "2026-06-18T21:16:39+02:00"
}, {
  "title": "VC Investment Memo Agent with LangGraph",
  "description": "Build an auditable, citation-grounded VC research agent with LangGraph and the Perplexity Agent API, and pick the best search provider with a LangSmith eval harness.",
  "href": "/docs/cookbook/articles/langchain-vc-memo-agent/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["finance", "deep-research", "orchestration", "integrations"],
  "date": "Jun 2026",
  "dateSort": "2026-06-11T12:27:53-07:00"
}, {
  "title": "Multi-Provider Orchestration",
  "description": "Route between OpenAI, Anthropic, Google, and xAI models through Perplexity's Agent API with zero markup, build fallback chains, and compare providers side-by-side",
  "href": "/docs/cookbook/articles/multi-provider-orchestration/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["function-calling", "orchestration"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:46:59+08:00"
}, {
  "title": "Function Calling End-to-End",
  "description": "Complete multi-turn function calling patterns for the Perplexity Agent API, including orchestration, web search integration, error handling, and parallel calls",
  "href": "/docs/cookbook/articles/function-calling-e2e/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["function-calling", "orchestration"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:45:38+08:00"
}, {
  "title": "RAG with Perplexity Embeddings",
  "description": "Build an end-to-end retrieval-augmented generation pipeline using Perplexity's standard and contextualized embedding models.",
  "href": "/docs/cookbook/articles/embeddings-rag/README",
  "type": "guide",
  "products": ["agent-api", "embeddings-api"],
  "categories": ["rag"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:44:55+08:00"
}, {
  "title": "Structured Output Extraction",
  "description": "Get typed, schema-validated JSON responses from the Agent API using response_format with JSON schemas for data extraction, pipelines, and structured research",
  "href": "/docs/cookbook/articles/structured-output-extraction/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["structured-outputs", "function-calling"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:44:55+08:00"
}, {
  "title": "Academic and Scholarly Search",
  "description": "Use the Agent API's domain filtering to restrict search to academic sources, extract DOIs and paper metadata, build citation chains, and create research summaries with proper attribution",
  "href": "/docs/cookbook/articles/academic-search/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["structured-outputs", "search-filtering"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:42:27+08:00"
}, {
  "title": "Search Domain Filtering Patterns",
  "description": "Use search_domain_filter for focused search — allowlist patterns for trusted sources, denylist for excluding domains, and practical patterns for news, government, and competitive intelligence",
  "href": "/docs/cookbook/articles/search-domain-filtering/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["search-filtering"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:42:27+08:00"
}, {
  "title": "Streaming Citation Parsing",
  "description": "Consume streaming responses from the Agent API and extract, validate, and display citations in real-time as chunks arrive",
  "href": "/docs/cookbook/articles/streaming-citations/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["streaming", "integrations"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:42:27+08:00"
}, {
  "title": "TypeScript Agent CLI",
  "description": "An interactive TypeScript CLI with streaming responses, model selection, and web search using the Perplexity Agent API",
  "href": "/docs/cookbook/examples/typescript-agent-cli/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["streaming", "memory"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:42:27+08:00"
}, {
  "title": "Agent Research Assistant",
  "description": "A CLI tool that uses Perplexity's Agent API with the medium preset to conduct multi-step web research and produce structured reports",
  "href": "/docs/cookbook/examples/agent-research-assistant/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["deep-research", "structured-outputs"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:24:39+08:00"
}, {
  "title": "Multi-Provider Model Comparison",
  "description": "A CLI tool that sends the same prompt to multiple AI models via Perplexity's Agent API and compares response quality, latency, and cost",
  "href": "/docs/cookbook/examples/model-comparison/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["orchestration"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:24:39+08:00"
}, {
  "title": "Search News Monitor",
  "description": "A CLI tool that uses Perplexity's Search API to monitor real-time news across multiple configurable topics with domain and recency filtering",
  "href": "/docs/cookbook/examples/search-news-monitor/README",
  "type": "example",
  "products": ["search-api"],
  "categories": ["search-filtering"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:24:39+08:00"
}, {
  "title": "Document Q&A",
  "description": "Load documents and ask questions about them via the Agent API — text extraction, web search enrichment, multi-turn Q&A, and structured output extraction",
  "href": "/docs/cookbook/examples/file-attachment-qa/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["structured-outputs", "function-calling", "memory"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:18:41+08:00"
}, {
  "title": "Document Q&A with Embeddings",
  "description": "A self-contained RAG system that ingests documents, generates contextualized embeddings, and answers questions using the Agent API",
  "href": "/docs/cookbook/examples/document-qa/README",
  "type": "example",
  "products": ["agent-api", "embeddings-api"],
  "categories": ["rag"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:18:41+08:00"
}, {
  "title": "Image Analysis",
  "description": "Vision-powered image analysis with web search for context-enriched results using the Perplexity Agent API",
  "href": "/docs/cookbook/examples/image-analysis/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["multimodal", "function-calling"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:18:41+08:00"
}, {
  "title": "SEC Filing Search",
  "description": "Use search domain filtering to query SEC.gov and EDGAR for financial filings, extract key financial data, and build structured financial summaries",
  "href": "/docs/cookbook/examples/sec-filing-search/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["finance", "structured-outputs", "search-filtering"],
  "date": "May 2026",
  "dateSort": "2026-05-16T06:18:41+08:00"
}, {
  "title": "Deep Research Workflows",
  "description": "Use the Agent API medium preset for comprehensive, multi-step research tasks — synchronous usage, batch concurrency, result processing, and production patterns",
  "href": "/docs/cookbook/articles/async-deep-research/README",
  "type": "guide",
  "products": ["agent-api"],
  "categories": ["deep-research", "search-filtering"],
  "date": "May 2026",
  "dateSort": "2026-05-16T05:22:03+08:00"
}, {
  "title": "Equity Research Brief",
  "description": "Generate institutional-grade equity research briefs from any public ticker using the Perplexity Agent API and the built-in finance_search tool.",
  "href": "/docs/cookbook/examples/equity-research-brief/README",
  "type": "example",
  "products": ["agent-api"],
  "categories": ["finance", "function-calling"],
  "date": "May 2026",
  "dateSort": "2026-05-07T12:20:38Z"
}, {
  "title": "Perplexity Client | Desktop AI Chat Interface with API Controls",
  "description": "An Electron-based desktop client for Perplexity API with advanced features like model selection, custom system prompts, and API debugging mode",
  "href": "/docs/cookbook/showcase/perplexity-client",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["streaming"],
  "date": "Dec 2025",
  "dateSort": "2025-12-17T15:00:49Z"
}, {
  "title": "StarPlex | AI-Powered Startup Intelligence Platform",
  "description": "An AI-powered startup intelligence platform that helps entrepreneurs validate their business ideas and find the right resources to succeed",
  "href": "/docs/cookbook/showcase/starplex",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["rag", "structured-outputs", "streaming"],
  "date": "Oct 2025",
  "dateSort": "2025-10-21T11:25:18Z"
}, {
  "title": "TruthTracer | AI-Powered Misinformation Detection Platform",
  "description": "A comprehensive misinformation detection platform that uses Perplexity's Sonar API to analyze claims, trace trust chains, and provide Socratic reasoning for fact verification",
  "href": "/docs/cookbook/showcase/truth-tracer",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["orchestration"],
  "date": "Aug 2025",
  "dateSort": "2025-08-23T02:18:21Z"
}, {
  "title": "PerplexiCart | AI-Powered Value-Aligned Shopping Assistant",
  "description": "An AI shopping assistant that uses Perplexity Sonar to deliver structured research, value-aligned recommendations, and transparent citations across the web",
  "href": "/docs/cookbook/showcase/perplexicart",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["structured-outputs"],
  "date": "Aug 2025",
  "dateSort": "2025-08-19T15:41:48Z"
}, {
  "title": "UnCovered | Real-Time Fact-Checking Chrome Extension",
  "description": "A Chrome extension that brings real-time fact-checking to anything you see online in just 2 clicks, powered by Perplexity's Sonar API for instant verification",
  "href": "/docs/cookbook/showcase/uncovered",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal", "deep-research"],
  "date": "Aug 2025",
  "dateSort": "2025-08-17T16:18:57Z"
}, {
  "title": "Daily News Briefing | AI-Powered News Summaries for Obsidian",
  "description": "An Obsidian plugin that delivers AI-powered daily news summaries directly to your vault using Perplexity's Sonar API for intelligent content curation",
  "href": "/docs/cookbook/showcase/daily-news-briefing",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["search-filtering"],
  "date": "Aug 2025",
  "dateSort": "2025-08-17T16:15:53Z"
}, {
  "title": "PosterLens | Scientific Poster Scanner & Research Assistant",
  "description": "An iOS app that transforms static scientific posters into interactive insights using OCR and Perplexity's Sonar Pro API for semantic search and context",
  "href": "/docs/cookbook/showcase/posterlens",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal"],
  "date": "Aug 2025",
  "dateSort": "2025-08-17T16:12:36Z"
}, {
  "title": "Sonar Chromium Browser | Native Search Omnibox and Context Menu",
  "description": "Chromium browser patch with native Perplexity Sonar API integration providing omnibox answers and context-menu summarization",
  "href": "/docs/cookbook/showcase/sonar-chromium-browser",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": [],
  "date": "Aug 2025",
  "dateSort": "2025-08-17T16:01:59Z"
}, {
  "title": "Greenify | Localized community-driven greenification/plantation solution with AI",
  "description": "A mobile application that analyzes photos and location data to suggest suitable plants and build sustainable communities using Perplexity Sonar API",
  "href": "/docs/cookbook/showcase/greenify",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal", "structured-outputs"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T19:51:39Z"
}, {
  "title": "Perplexity Lens | AI-Powered Knowledge Graph Browser Extension",
  "description": "A browser extension that builds personalized knowledge graphs using Perplexity AI for smart text selection, webpage summarization, and contextual insights",
  "href": "/docs/cookbook/showcase/perplexity-lens",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["rag"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T19:35:49Z"
}, {
  "title": "Flow & Focus | Personalized News for Genuine Understanding",
  "description": "A personalized news app combining vertical feed discovery with AI-powered deep dives using Perplexity Sonar Pro and Deep Research models",
  "href": "/docs/cookbook/showcase/flow-and-focus",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["deep-research", "memory"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T19:28:39Z"
}, {
  "title": "Executive Intelligence | AI-Powered Strategic Decision Platform",
  "description": "A comprehensive Perplexity Sonar-powered application that provides executives and board members with instant, accurate, and credible intelligence for strategic decision-making",
  "href": "/docs/cookbook/showcase/executive-intelligence",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["memory"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T19:18:20Z"
}, {
  "title": "MVP LifeLine | AI Youth Empowerment Platform",
  "description": "A multilingual, offline-first AI platform that helps underserved youth Earn, Heal, and Grow using real-time AI and holistic tools",
  "href": "/docs/cookbook/showcase/mvp-lifeline-ai-app",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": [],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T18:15:26Z"
}, {
  "title": "4Point Hoops | AI Basketball Analytics Platform",
  "description": "Advanced NBA analytics platform that combines live Basketball-Reference data with Perplexity Sonar to deliver deep-dive player stats, cross-season comparisons and expert-grade AI explanations",
  "href": "/docs/cookbook/showcase/4point-Hoops",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": [],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T18:12:37Z"
}, {
  "title": "BazaarAISaathi | AI-Powered Indian Stock Market Assistant",
  "description": "An AI-powered platform for Indian stock market analysis, portfolio optimization, and investment strategies using Perplexity Sonar API",
  "href": "/docs/cookbook/showcase/bazaar-ai-saathi",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["finance", "multimodal"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T18:07:14Z"
}, {
  "title": "FirstPrinciples | AI Learning Roadmap Generator",
  "description": "An AI-powered learning roadmap generator that uses conversational AI to help users identify specific learning topics and provides personalized step-by-step learning plans",
  "href": "/docs/cookbook/showcase/first-principle",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["memory", "orchestration", "integrations"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T17:11:48Z"
}, {
  "title": "Ellipsis | One-Click Podcast Generation Agent",
  "description": "A next-gen podcast generation agent that brings human-like, high-quality audio content to life on any topic with just one click",
  "href": "/docs/cookbook/showcase/Ellipsis",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["streaming"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T16:49:32Z"
}, {
  "title": "Monday – Voice-First AI Learning Assistant",
  "description": "An accessible, multimodal AI learning companion that delivers contextual reasoning, 3D visualizations, and curated educational content via natural voice interaction.",
  "href": "/docs/cookbook/showcase/monday",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal", "deep-research"],
  "date": "Aug 2025",
  "dateSort": "2025-08-16T16:43:22Z"
}, {
  "title": "FlameGuardAI | AI-powered wildfire prevention",
  "description": "AI-powered wildfire prevention using OpenAI Vision + Perplexity Sonar API",
  "href": "/docs/cookbook/showcase/flameguardai",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal", "deep-research"],
  "date": "Aug 2025",
  "dateSort": "2025-08-05T22:37:05Z"
}, {
  "title": "CycleSyncAI | Personalized Health Plans Powered by Sonar API",
  "description": "iOS app that delivers personalized diet and workout recommendations for women, powered by Apple HealthKit and Perplexity's Sonar Pro API.",
  "href": "/docs/cookbook/showcase/cycle-sync-ai",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": [],
  "date": "Aug 2025",
  "dateSort": "2025-08-05T17:52:20Z"
}, {
  "title": "Valetudo AI | Trusted Medical Answer Assistant",
  "description": "Sonar-powered medical assistant for fast, science-backed answers.",
  "href": "/docs/cookbook/showcase/valetudo-ai",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal", "search-filtering"],
  "date": "Aug 2025",
  "dateSort": "2025-08-05T17:32:52Z"
}, {
  "title": "PerplexiGrid | Interactive Analytics Dashboards",
  "description": "Instantly generate analytics dashboards from natural language using live data via Perplexity Sonar API.",
  "href": "/docs/cookbook/showcase/perplexigrid",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["structured-outputs"],
  "date": "Aug 2025",
  "dateSort": "2025-08-02T16:40:52Z"
}, {
  "title": "CityPulse | AI-Powered Geospatial Discovery Search",
  "description": "Real-time local discovery search using Perplexity AI for personalized location insights and recommendations",
  "href": "/docs/cookbook/showcase/citypulse-ai-search",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["structured-outputs"],
  "date": "Aug 2025",
  "dateSort": "2025-08-02T16:09:19Z"
}, {
  "title": "Fact Dynamics | Real-time Fact-Checking Flutter App",
  "description": "Cross-platform app for real-time fact-checking of debates, speeches, and images using Perplexity's Sonar API",
  "href": "/docs/cookbook/showcase/fact-dynamics",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal", "structured-outputs", "streaming", "memory"],
  "date": "Aug 2025",
  "dateSort": "2025-08-02T15:55:27Z"
}, {
  "title": "Perplexity Dart & Flutter SDKs",
  "description": "Lightweight, type-safe SDKs for seamless Perplexity API integration in Dart and Flutter applications",
  "href": "/docs/cookbook/showcase/perplexity-flutter",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["multimodal", "streaming", "search-filtering"],
  "date": "Aug 2025",
  "dateSort": "2025-08-02T15:52:07Z"
}, {
  "title": "Briefo | Perplexity Powered News & Finance Social App",
  "description": "AI curated newsfeed, social discussion, and deep research reports built on the Sonar API",
  "href": "/docs/cookbook/showcase/briefo",
  "type": "showcase",
  "products": ["sonar-api"],
  "categories": ["finance", "deep-research"],
  "date": "Jul 2025",
  "dateSort": "2025-07-30T17:23:07Z"
}];

export const CookbookGallery = ({recipes = [], facets = {}, labels = {}} = {}) => {
  const label = value => labels.products && labels.products[value] || labels.categories && labels.categories[value] || labels.type && labels.type[value] || value;
  const pillStyle = (facet, value) => {
    const k = facet === 'products' ? value : facet === 'type' ? 'type' : 'category';
    return {
      color: `var(--cb-${k}-fg)`,
      backgroundColor: `var(--cb-${k}-bg)`
    };
  };
  const renderPill = (facet, value, key) => <span key={key} className="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium whitespace-nowrap" style={pillStyle(facet, value)}>
      {label(value)}
    </span>;
  const products = facets.products || [];
  const flatOptions = [...products, ...facets.categories || [], ...facets.type || []];
  const CHIP_EXCLUDE = new Set(['sonar-api']);
  const chipProducts = products.filter(p => !CHIP_EXCLUDE.has(p));
  const CAT_PARAM = 'category';
  const SEARCH_PARAM = 'q';
  const [searchText, setSearchText] = useState('');
  const [selected, setSelected] = useState(() => new Set());
  const [dropdownOpen, setDropdownOpen] = useState(false);
  const dropdownRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const params = new URLSearchParams(window.location.search);
    const q = params.get(SEARCH_PARAM);
    if (q) setSearchText(q);
    const valid = new Set(flatOptions);
    const fromUrl = params.getAll(CAT_PARAM).filter(v => valid.has(v));
    if (fromUrl.length) setSelected(new Set(fromUrl));
  }, []);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const params = new URLSearchParams(window.location.search);
    params.delete(SEARCH_PARAM);
    params.delete(CAT_PARAM);
    const q = searchText.trim();
    if (q) params.set(SEARCH_PARAM, q);
    [...selected].forEach(v => params.append(CAT_PARAM, v));
    const qs = params.toString();
    window.history.replaceState(null, '', qs ? `?${qs}` : window.location.pathname);
  }, [selected, searchText]);
  useEffect(() => {
    if (!dropdownOpen) return undefined;
    const onClick = e => {
      if (dropdownRef.current && !dropdownRef.current.contains(e.target)) setDropdownOpen(false);
    };
    const onKey = e => {
      if (e.key === 'Escape') setDropdownOpen(false);
    };
    document.addEventListener('mousedown', onClick);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onClick);
      document.removeEventListener('keydown', onKey);
    };
  }, [dropdownOpen]);
  const toggle = value => {
    setSelected(prev => {
      const next = new Set(prev);
      if (next.has(value)) next.delete(value); else next.add(value);
      return next;
    });
  };
  const query = searchText.trim().toLowerCase();
  const filtered = recipes.filter(r => {
    if (query) {
      const hay = [r.title, r.description, ...(r.products || []).map(label), ...(r.categories || []).map(label), r.type ? label(r.type) : ''].join(' ').toLowerCase();
      if (!hay.includes(query)) return false;
    }
    if (selected.size > 0) {
      const tags = [...r.products || [], ...r.categories || [], r.type].filter(Boolean);
      if (!tags.some(t => selected.has(t))) return false;
    }
    return true;
  });
  const clearAll = () => setSelected(new Set());
  const checkIcon = <svg className="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <polyline points="20 6 9 17 4 12" />
    </svg>;
  return <div className="not-prose w-full" style={{
    boxSizing: 'border-box'
  }}>
      {}
      <div className="flex flex-col gap-4 max-w-3xl mx-auto">
      {}
      <div className="flex flex-col sm:flex-row gap-3 order-2 sm:order-1">
        <div className="relative flex-1">
          <svg className="absolute left-4 top-1/2 h-4 w-4 text-muted-foreground pointer-events-none" style={{
    transform: 'translateY(-50%)'
  }} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
            <circle cx="11" cy="11" r="7" />
            <line x1="21" y1="21" x2="16.65" y2="16.65" />
          </svg>
          <input type="text" value={searchText} onChange={e => setSearchText(e.target.value)} placeholder="Search recipes…" aria-label="Search recipes" className="w-full rounded-full border pl-11 pr-10 py-2.5 text-sm bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2" style={{
    borderColor: 'var(--color-border)'
  }} />
          {searchText && <button type="button" onClick={() => setSearchText('')} aria-label="Clear search" className="absolute right-3 top-1/2 flex h-5 w-5 items-center justify-center rounded-full text-muted-foreground hover:text-foreground hover:bg-[var(--cb-hover)] transition-colors" style={{
    transform: 'translateY(-50%)'
  }}>
              <svg className="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" aria-hidden="true">
                <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
              </svg>
            </button>}
        </div>

        <div className="relative" ref={dropdownRef}>
          <button type="button" onClick={() => setDropdownOpen(v => !v)} aria-expanded={dropdownOpen} aria-haspopup="true" className="inline-flex items-center gap-2 rounded-full border px-4 py-2.5 text-sm font-medium text-foreground hover:bg-[var(--color-card)] transition-colors whitespace-nowrap" style={{
    borderColor: 'var(--color-border)'
  }}>
            <svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
              <line x1="4" y1="6" x2="20" y2="6" /><line x1="7" y1="12" x2="17" y2="12" /><line x1="10" y1="18" x2="14" y2="18" />
            </svg>
            {selected.size > 0 ? `${selected.size} ${selected.size === 1 ? 'Category' : 'Categories'}` : 'Categories'}
            <svg className="h-3.5 w-3.5 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true"><polyline points="6 9 12 15 18 9" /></svg>
          </button>

          {dropdownOpen && <div className="absolute right-0 z-50 mt-2 w-64 max-h-[400px] overflow-y-auto rounded-lg border p-2 shadow-lg" style={{
    backgroundColor: 'var(--cb-popover-bg)',
    borderColor: 'var(--cb-popover-border)'
  }} role="dialog" aria-label="Filter by category">
              <div className="flex justify-between items-center mb-2 px-2 pb-2 border-b" style={{
    borderColor: 'var(--cb-popover-border)'
  }}>
                <span className="text-sm font-medium text-foreground">Categories</span>
                {selected.size > 0 && <button type="button" onClick={clearAll} className="text-xs font-medium" style={{
    color: 'var(--cb-accent-fg)'
  }}>
                    Clear all
                  </button>}
              </div>
              <div className="space-y-0.5">
                {flatOptions.map(value => {
    const checked = selected.has(value);
    return <label key={value} className="flex items-center gap-2.5 px-2 py-1.5 rounded cursor-pointer hover:bg-[var(--color-card)]">
                      <input type="checkbox" className="sr-only" checked={checked} onChange={() => toggle(value)} />
                      <span className="shrink-0 w-4 h-4 flex items-center justify-center border rounded transition-colors" style={checked ? {
      backgroundColor: 'var(--cb-accent-fg)',
      borderColor: 'var(--cb-accent-fg)',
      color: 'var(--cb-popover-bg)'
    } : {
      backgroundColor: 'transparent',
      borderColor: 'var(--color-border)'
    }}>
                        {checked && checkIcon}
                      </span>
                      <span className="text-sm text-foreground">{label(value)}</span>
                    </label>;
  })}
              </div>
            </div>}
        </div>
      </div>

      {}
      {!query && <div className="flex flex-wrap justify-center gap-2 order-1 sm:order-2">
          {chipProducts.map(p => <button key={p} type="button" onClick={() => setSearchText(label(p))} className="cb-chip inline-flex items-center rounded-full border px-3.5 py-1.5 text-sm font-medium text-foreground transition-colors" style={{
    borderColor: 'var(--color-border)'
  }}>
              {label(p)}
            </button>)}
        </div>}
      </div>

      {}
      <div className="max-w-3xl mx-auto mt-8 mb-3 px-1 text-sm text-muted-foreground" aria-live="polite">
        {filtered.length} {filtered.length === 1 ? 'recipe' : 'recipes'}
      </div>

      {}
      <div className="max-w-3xl mx-auto">
        {filtered.length === 0 ? <div className="text-center py-16 text-muted-foreground">No recipes match your filters.</div> : <ul className="flex flex-col divide-y" style={{
    borderColor: 'var(--color-border)'
  }}>
            {filtered.map(r => <li key={r.href}>
                <a href={r.href} className="group cookbook-card flex flex-col gap-2 py-5 px-1 transition-colors hover:bg-[var(--color-card)] rounded-lg sm:px-3 -mx-1 sm:-mx-3">
                  <div className="flex items-baseline justify-between gap-4">
                    <h3 className="text-base font-semibold text-foreground group-hover:underline">{r.title}</h3>
                    {r.date && <span className="shrink-0 text-xs text-muted-foreground whitespace-nowrap tabular-nums">{r.date}</span>}
                  </div>
                  {r.description && <p className="text-sm text-muted-foreground line-clamp-2">{r.description}</p>}
                  <div className="flex flex-wrap gap-1.5 pt-0.5">
                    {(r.products || []).map(v => renderPill('products', v, `p-${v}`))}
                    {(r.categories || []).map(v => renderPill('categories', v, `c-${v}`))}
                    {r.type && renderPill('type', r.type, `ty-${r.type}`)}
                  </div>
                </a>
              </li>)}
          </ul>}
      </div>
    </div>;
};

<CookbookGallery recipes={COOKBOOK_RECIPES} facets={COOKBOOK_FACETS} labels={COOKBOOK_LABELS} />
