@@ -3,11 +3,32 @@ import { useLanguage } from '@/intl/client';
3
3
import { t } from '@/intl/translate' ;
4
4
import { Icon } from '@gitbook/icons' ;
5
5
import { useEffect , useState } from 'react' ;
6
+ import { create } from 'zustand' ;
6
7
import { useVisitedPages } from '../Insights' ;
7
8
import { usePageContext } from '../PageContext' ;
8
9
import { Loading } from '../primitives' ;
9
10
import { streamLinkPageSummary } from './server-actions/streamLinkPageSummary' ;
10
11
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
+
11
32
/**
12
33
* Summarise a page's content for use in a link preview
13
34
*/
@@ -21,15 +42,26 @@ export function AIPageLinkSummary(props: {
21
42
const { targetSpaceId, targetPageId, linkPreview, linkTitle, showTrademark = true } = props ;
22
43
23
44
const currentPage = usePageContext ( ) ;
24
-
25
45
const language = useLanguage ( ) ;
26
46
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
+ } ) ;
28
55
29
56
useEffect ( ( ) => {
30
57
let canceled = false ;
31
58
32
- setHighlight ( '' ) ;
59
+ setSummary ( '' ) ;
60
+
61
+ if ( cachedSummary ) {
62
+ setSummary ( cachedSummary ) ;
63
+ return ;
64
+ }
33
65
34
66
( async ( ) => {
35
67
const stream = await streamLinkPageSummary ( {
@@ -43,9 +75,16 @@ export function AIPageLinkSummary(props: {
43
75
visitedPages,
44
76
} ) ;
45
77
78
+ let generatedSummary = '' ;
46
79
for await ( const highlight of stream ) {
47
80
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 ) ;
49
88
}
50
89
} ) ( ) ;
51
90
@@ -61,6 +100,9 @@ export function AIPageLinkSummary(props: {
61
100
linkPreview ,
62
101
linkTitle ,
63
102
visitedPages ,
103
+ cachedSummary ,
104
+ cacheKey ,
105
+ setCachedSummary ,
64
106
] ) ;
65
107
66
108
const shimmerBlocks = [
@@ -76,14 +118,14 @@ export function AIPageLinkSummary(props: {
76
118
< div className = "flex flex-col gap-1" >
77
119
< div className = "flex w-screen items-center gap-1 font-semibold text-tint text-xs uppercase leading-tight tracking-wide" >
78
120
{ showTrademark ? (
79
- < Loading className = "size-4" busy = { ! highlight || highlight . length === 0 } />
121
+ < Loading className = "size-4" busy = { ! summary || summary . length === 0 } />
80
122
) : (
81
123
< Icon icon = "sparkle" className = "size-3" />
82
124
) }
83
125
< h6 className = "text-tint" > { t ( language , 'link_tooltip_ai_summary' ) } </ h6 >
84
126
</ div >
85
- { highlight . length > 0 ? (
86
- < p className = "animate-fadeIn" > { highlight } </ p >
127
+ { summary . length > 0 ? (
128
+ < p className = "animate-fadeIn" > { summary } </ p >
87
129
) : (
88
130
< div className = "mt-2 flex flex-wrap gap-2" >
89
131
{ shimmerBlocks . map ( ( block , index ) => (
@@ -94,7 +136,7 @@ export function AIPageLinkSummary(props: {
94
136
) ) }
95
137
</ div >
96
138
) }
97
- { highlight . length > 0 ? (
139
+ { summary . length > 0 ? (
98
140
< div className = "animate-fadeIn text-tint-subtle text-xs" >
99
141
{ t ( language , 'link_tooltip_ai_summary_description' ) }
100
142
</ div >
0 commit comments