Skip to content

Commit 95ea22d

Browse files
Cache AI Page Link summary (#3106)
Co-authored-by: Samy Pessé <samypesse@gmail.com>
1 parent f23023d commit 95ea22d

File tree

2 files changed

+55
-8
lines changed

2 files changed

+55
-8
lines changed

.changeset/chilly-snakes-sell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": patch
3+
---
4+
5+
Cache AI Page Link summary

packages/gitbook/src/components/Adaptive/AIPageLinkSummary.tsx

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,32 @@ import { useLanguage } from '@/intl/client';
33
import { t } from '@/intl/translate';
44
import { Icon } from '@gitbook/icons';
55
import { useEffect, useState } from 'react';
6+
import { create } from 'zustand';
67
import { useVisitedPages } from '../Insights';
78
import { usePageContext } from '../PageContext';
89
import { Loading } from '../primitives';
910
import { streamLinkPageSummary } from './server-actions/streamLinkPageSummary';
1011

12+
const useSummaries = create<{
13+
cache: Map<string, string>;
14+
setSummary: (key: string, summary: string) => void;
15+
}>((set) => ({
16+
cache: new Map(),
17+
setSummary: (key, summary) =>
18+
set((state) => {
19+
const newCache = new Map(state.cache);
20+
newCache.set(key, summary);
21+
return { cache: newCache };
22+
}),
23+
}));
24+
25+
/**
26+
* Get a unique cache key for a page summary
27+
*/
28+
function getCacheKey(targetSpaceId: string, targetPageId: string): string {
29+
return `${targetSpaceId}:${targetPageId}`;
30+
}
31+
1132
/**
1233
* Summarise a page's content for use in a link preview
1334
*/
@@ -21,15 +42,26 @@ export function AIPageLinkSummary(props: {
2142
const { targetSpaceId, targetPageId, linkPreview, linkTitle, showTrademark = true } = props;
2243

2344
const currentPage = usePageContext();
24-
2545
const language = useLanguage();
2646
const visitedPages = useVisitedPages((state) => state.pages);
27-
const [highlight, setHighlight] = useState('');
47+
const [summary, setSummary] = useState('');
48+
const cacheKey = getCacheKey(targetSpaceId, targetPageId);
49+
const { cachedSummary, setCachedSummary } = useSummaries((state) => {
50+
return {
51+
cachedSummary: state.cache.get(cacheKey) ?? '',
52+
setCachedSummary: state.setSummary,
53+
};
54+
});
2855

2956
useEffect(() => {
3057
let canceled = false;
3158

32-
setHighlight('');
59+
setSummary('');
60+
61+
if (cachedSummary) {
62+
setSummary(cachedSummary);
63+
return;
64+
}
3365

3466
(async () => {
3567
const stream = await streamLinkPageSummary({
@@ -43,9 +75,16 @@ export function AIPageLinkSummary(props: {
4375
visitedPages,
4476
});
4577

78+
let generatedSummary = '';
4679
for await (const highlight of stream) {
4780
if (canceled) return;
48-
setHighlight(highlight ?? '');
81+
generatedSummary = highlight ?? '';
82+
setSummary(generatedSummary);
83+
}
84+
85+
// Cache the complete summary
86+
if (generatedSummary) {
87+
setCachedSummary(cacheKey, generatedSummary);
4988
}
5089
})();
5190

@@ -61,6 +100,9 @@ export function AIPageLinkSummary(props: {
61100
linkPreview,
62101
linkTitle,
63102
visitedPages,
103+
cachedSummary,
104+
cacheKey,
105+
setCachedSummary,
64106
]);
65107

66108
const shimmerBlocks = [
@@ -76,14 +118,14 @@ export function AIPageLinkSummary(props: {
76118
<div className="flex flex-col gap-1">
77119
<div className="flex w-screen items-center gap-1 font-semibold text-tint text-xs uppercase leading-tight tracking-wide">
78120
{showTrademark ? (
79-
<Loading className="size-4" busy={!highlight || highlight.length === 0} />
121+
<Loading className="size-4" busy={!summary || summary.length === 0} />
80122
) : (
81123
<Icon icon="sparkle" className="size-3" />
82124
)}
83125
<h6 className="text-tint">{t(language, 'link_tooltip_ai_summary')}</h6>
84126
</div>
85-
{highlight.length > 0 ? (
86-
<p className="animate-fadeIn">{highlight}</p>
127+
{summary.length > 0 ? (
128+
<p className="animate-fadeIn">{summary}</p>
87129
) : (
88130
<div className="mt-2 flex flex-wrap gap-2">
89131
{shimmerBlocks.map((block, index) => (
@@ -94,7 +136,7 @@ export function AIPageLinkSummary(props: {
94136
))}
95137
</div>
96138
)}
97-
{highlight.length > 0 ? (
139+
{summary.length > 0 ? (
98140
<div className="animate-fadeIn text-tint-subtle text-xs">
99141
{t(language, 'link_tooltip_ai_summary_description')}
100142
</div>

0 commit comments

Comments
 (0)