Skip to content

AI Summary

This page documents Deckly's AI Summary feature as it exists today: how it is triggered from the UI, how the Supabase edge function resolves scope and generates summaries, what models are used, what data is persisted, and what secrets must be configured for the feature to work.


Summary

AI Summary adds two capabilities to Deckly:

  • a scoped summary for a deck, data room, or room folder
  • follow-up chat that stays anchored to the current summary and retrieved document snippets

The implementation is split between the React app and the ai-summary Supabase edge function. The browser is responsible for opening the summary panel and sending requests; the edge function owns authentication, scope resolution, caching, quota checks, retrieval, generation, and chat persistence.

Current provider/model choices:

  • Embeddings: text-embedding-3-small
  • Summary generation: gpt-4o-mini
  • Follow-up chat: gpt-4o-mini

Deckly calls OpenAI directly from the edge function today. We are not using Vercel AI Gateway in the current implementation.


User Flow

Entry points

The summary panel can be opened from:

  • the Summarize button in the deck viewer
  • the Summarize action in the content library deck table
  • the Summarize with AI action in saved decks
  • the Summarize action in data room detail views and folder cards

What happens when a user clicks summarize

  1. The UI opens the AI Summary sidebar.
  2. The browser calls the ai-summary edge function with the requested scope.
  3. The edge function resolves the scope, checks quota, and looks up any existing cache entry.
  4. If a fresh summary exists, it is returned from cache.
  5. If no cached summary exists, the edge function gathers document chunks, generates a summary, writes the cache row, and returns the result.
  6. Signed-in users can continue with follow-up chat against the current summary.

Guest behavior

Guests can summarize deck scopes only. Guest follow-up chat is locked, and the UI prompts sign-in before continuing the conversation.


Backend Architecture

The supabase/functions/ai-summary/index.ts function is the orchestration layer.

It performs these steps:

  • authenticates the caller from the request header when a signed-in summary or chat is requested
  • loads the user tier from profiles
  • resolves the scope into document records
  • builds a stable content hash for cache keys
  • checks summary cache state
  • enforces guest and signed-in quotas
  • generates summary text through OpenAI
  • persists summary cache rows and chat session/message rows
  • performs lightweight retrieval for follow-up chat

The key service layers behind it are:

  • src/services/aiSummaryInitialOrchestrator.ts for cache-aware summary generation
  • src/services/aiChatSessionService.ts for chat session management and message persistence
  • src/services/aiRetrievalQueryService.ts for snippet selection
  • src/services/aiSummaryCacheCore.ts for cache lookup and cache row lifecycle
  • src/services/aiSummaryQuotaPolicy.ts for guest and signed-in limits

Data Model

The AI feature stores its own tables in Supabase:

  • ai_summary_cache
    • one row per scope/content-hash/model combination
    • stores summary text, status, metadata, timestamps, and cache freshness
  • ai_chat_sessions
    • one row per signed-in chat session
    • tracks the scope, content hash, summary cache reference, and session lifecycle
  • ai_chat_messages
    • stores user and assistant messages for each chat session
    • includes retrieval context and model metadata
  • ai_guest_usage
    • tracks guest summary usage by IP address and date
    • enforces the daily guest limit
  • ai_chunk_embeddings
    • stores chunk text and embeddings used for retrieval
    • keyed by scope, content hash, embedding model, and model version

The foundation migration for these tables is:

  • supabase/migrations/20260502160000_add_ai_summary_foundations.sql

Model Strategy

Why the models are split

Summary generation, chat, and embeddings do different jobs.

  • Embeddings should be optimized for retrieval quality and cost.
  • Summary generation should be optimized for concise synthesis.
  • Chat should be optimized for follow-up conversation grounded in the summary and retrieved snippets.

Current model choices

  • text-embedding-3-small is used for document retrieval embeddings.
  • gpt-4o-mini is used for initial summaries.
  • gpt-4o-mini is also used for follow-up chat.

What is not split yet

The current chat and summary generation both use the same chat model. That is intentional for now. If the team later wants to test another chat provider or a gateway, the model boundary already exists in the service layer and edge function.


Cache and Quota Behavior

Cache key

Summary cache entries are keyed by:

  • scope type
  • scope id
  • content hash
  • model identifier
  • model version

This means a summary is reused only when the underlying content and the model settings match.

Freshness behavior

  • cached summaries are reopened without regenerating
  • stale or content-changed summaries are regenerated
  • no-content scopes are cached separately so repeated requests do not re-run generation

Quotas

Current quota policy is defined in src/constants/tiers.ts and enforced by the AI quota service:

  • guest: 1 summary per 24 hours per IP
  • FREE: 2 summaries per 24 hours
  • PRO: 10 summaries per 24 hours
  • PRO_PLUS: 50 summaries per 24 hours

The edge function returns quota-limited responses that the UI maps to sign-in or upgrade prompts.


Supabase function secrets

The ai-summary edge function requires:

  • OPENAI_API_KEY
  • SUPABASE_SERVICE_ROLE_KEY or PROJECT_SECRET_KEY

The function also expects the Supabase runtime to expose:

  • SUPABASE_URL

The same Supabase project URL and anon key used by the frontend are reused by the function runtime. The browser app does not need the service-role secret.

What you do not need for AI Summary

These are not required for AI Summary specifically:

  • CONVERT_API_SECRET
  • CRON_SECRET

Those belong to other edge functions in the repo.


Troubleshooting

503 Service Unavailable from ai-summary

This usually means the edge function failed to boot. Check:

  • OPENAI_API_KEY exists in Supabase function secrets
  • SUPABASE_SERVICE_ROLE_KEY or PROJECT_SECRET_KEY exists in Supabase function secrets
  • the ai-summary function was deployed successfully
  • the ai_summary_foundations migration has been applied

OPENAI_API_KEY is not configured

The edge function reads OPENAI_API_KEY directly from the function runtime. Adding the key only to the browser .env.local is not enough.

Empty summary or no_content

The current document set may not have extractable text yet. This can happen when:

  • the deck has not been indexed into chunk embeddings
  • the room/folder contains only unsupported or empty documents
  • the content was filtered out during extraction

Chat is locked

Guest chat is intentionally disabled. Sign in to continue the conversation.


Files of Interest

  • supabase/functions/ai-summary/index.ts
  • src/services/aiSummaryInitialOrchestrator.ts
  • src/services/aiChatSessionService.ts
  • src/services/aiRetrievalQueryService.ts
  • src/services/aiSummaryCacheCore.ts
  • src/services/aiSummaryQuotaPolicy.ts
  • src/components/viewer/AiSummarySidebar.tsx
  • src/hooks/useAiSummaryPanel.ts
  • src/pages/Viewer.tsx
  • src/pages/DataRoomViewer.tsx
  • src/pages/OwnerDeckPreview.tsx
  • src/components/dashboard/DecksTable.tsx
  • src/components/saved-decks/DocumentRow.tsx
  • src/components/saved-decks/LibraryActionMenu.tsx

Developer Note

The current implementation uses OpenAI directly from the Supabase edge function. If we later move to a gateway or alternate provider, the best place to change that is inside supabase/functions/ai-summary/index.ts, because the rest of the app already treats summaries, retrieval, and chat as separate responsibilities.

Built with ❤️ for Founders