> ## 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": "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": "Perplexity Discord Bot",
  "description": "A simple discord.py bot that integrates Perplexity's Sonar API to bring AI answers to your Discord server.",
  "href": "/docs/cookbook/examples/discord-py-bot/README",
  "type": "example",
  "products": ["sonar-api"],
  "categories": ["integrations"],
  "date": "Aug 2025",
  "dateSort": "2025-08-15T22:52:20Z"
}, {
  "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"
}, {
  "title": "Financial News Tracker",
  "description": "A real-time financial news monitoring tool that fetches and analyzes market news using Perplexity's Sonar API",
  "href": "/docs/cookbook/examples/financial-news-tracker/README",
  "type": "example",
  "products": ["sonar-api"],
  "categories": ["finance", "structured-outputs"],
  "date": "Jul 2025",
  "dateSort": "2025-07-29T19:02:34Z"
}, {
  "title": "Academic Research Finder CLI",
  "description": "A command-line tool that uses Perplexity's Sonar API to find and summarize academic literature",
  "href": "/docs/cookbook/examples/research-finder/README",
  "type": "example",
  "products": ["sonar-api"],
  "categories": ["structured-outputs"],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}, {
  "title": "Chat Summary Memory Buffer",
  "description": "Token-aware conversation memory using summarization with LlamaIndex and Perplexity Sonar API",
  "href": "/docs/cookbook/articles/memory-management/chat-summary-memory-buffer/README",
  "type": "guide",
  "products": ["sonar-api"],
  "categories": ["memory", "integrations"],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}, {
  "title": "Daily Knowledge Bot",
  "description": "A Python application that delivers interesting facts about rotating topics using the Perplexity AI API",
  "href": "/docs/cookbook/examples/daily-knowledge-bot/README",
  "type": "example",
  "products": ["sonar-api"],
  "categories": [],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}, {
  "title": "Disease Information App",
  "description": "An interactive browser-based application that provides structured information about diseases using Perplexity's Sonar API",
  "href": "/docs/cookbook/examples/disease-qa/README",
  "type": "example",
  "products": ["sonar-api"],
  "categories": ["structured-outputs"],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}, {
  "title": "Fact Checker CLI",
  "description": "A command-line tool that identifies false or misleading claims in articles or statements using Perplexity's Sonar API",
  "href": "/docs/cookbook/examples/fact-checker-cli/README",
  "type": "example",
  "products": ["sonar-api"],
  "categories": ["structured-outputs"],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}, {
  "title": "Memory Management",
  "description": "Advanced conversation memory solutions using LlamaIndex for persistent, context-aware applications",
  "href": "/docs/cookbook/articles/memory-management/README",
  "type": "guide",
  "products": ["sonar-api"],
  "categories": ["rag", "memory", "integrations"],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}, {
  "title": "OpenAI Agents Integration",
  "description": "Complete guide for integrating Perplexity's Sonar API with the OpenAI Agents SDK",
  "href": "/docs/cookbook/articles/openai-agents-integration/README",
  "type": "guide",
  "products": ["sonar-api"],
  "categories": ["function-calling", "streaming", "integrations"],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}, {
  "title": "Persistent Chat Memory",
  "description": "Long-term conversation memory using LanceDB vector storage and Perplexity Sonar API",
  "href": "/docs/cookbook/articles/memory-management/chat-with-persistence/README",
  "type": "guide",
  "products": ["sonar-api"],
  "categories": ["rag", "memory", "integrations"],
  "date": "Jul 2025",
  "dateSort": "2025-07-24T00:04:17+01:00"
}];

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 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" 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 -translate-y-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">
              <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 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} />
