1
+ import React , { useState , useEffect } from 'react' ;
2
+
3
+ interface TagCategories {
4
+ useCases : string [ ] ;
5
+ endpoints : string [ ] ;
6
+ techStack : string [ ] ;
7
+ }
8
+
9
+ const ALL_TAGS : TagCategories = {
10
+ useCases : [
11
+ 'RAG' , 'Agents' , 'Search' , 'Embeddings' , 'Tool Use' ,
12
+ 'Reranking' , 'Fine-tuning' , 'Summarization' , 'Classification' ,
13
+ 'Text Generation' , 'Multi-step' , 'Semantic Search'
14
+ ] ,
15
+ endpoints : [ 'Chat' , 'Embed' , 'Rerank' , 'Finetuning' ] ,
16
+ techStack : [ 'Langchain' , 'LlamaIndex' , 'Pinecone' , 'Weaviate' , 'CrewAI' ]
17
+ } ;
18
+
19
+ interface Cookbook {
20
+ title : string ;
21
+ description : string ;
22
+ imageSrc : string ;
23
+ tags : {
24
+ useCases : string [ ] ;
25
+ endpoints : string [ ] ;
26
+ techStack : string [ ] ;
27
+ } ;
28
+ href : string ;
29
+ author ?: {
30
+ name : string ;
31
+ image : string ;
32
+ } ;
33
+ }
34
+
35
+ const CARD_COLORS = [ 'bg-[#EEF0EF]' , 'bg-[#FDF2F0]' , 'bg-[#F8F1F9]' , 'bg-[#F0F2FB]' ] ;
36
+
37
+ // Replace the existing tag style constants with these:
38
+ const tagButtonClass = "px-2 py-1 text-[12px] rounded-full transition-colors cursor-pointer font-normal" ;
39
+
40
+ const selectedTagClass = "bg-[#333293] text-white hover:bg-[#333293]/90" ;
41
+ const unselectedTagClass = "bg-white text-[#666666] border border-[#E5E5E5] hover:bg-gray-50" ;
42
+
43
+ export const Cookbooks : React . FC = ( ) => {
44
+ const [ searchQuery , setSearchQuery ] = useState ( '' ) ;
45
+ const [ selectedTags , setSelectedTags ] = useState < {
46
+ useCases : string [ ] ;
47
+ endpoints : string [ ] ;
48
+ techStack : string [ ] ;
49
+ } > ( {
50
+ useCases : [ ] ,
51
+ endpoints : [ ] ,
52
+ techStack : [ ]
53
+ } ) ;
54
+
55
+ // Base cookbook data
56
+ const baseCookbooks : Cookbook [ ] = [
57
+ {
58
+ title : "Agentic Multi-Stage RAG with Cohere Tools API" ,
59
+ description : "This cookbook demonstrates how to build a powerful, multi-stage agent with the Cohere platform that can retrieve documents in multiple steps." ,
60
+ imageSrc : "https://via.placeholder.com/400x200?text=Agentic+RAG" ,
61
+ tags : {
62
+ useCases : [ 'RAG' , 'Agents' , 'Tool Use' ] ,
63
+ endpoints : [ 'Chat' , 'Rerank' ] ,
64
+ techStack : [ 'Langchain' , 'Weaviate' ]
65
+ } ,
66
+ href : '/page/agentic-multi-stage-rag' ,
67
+ author : {
68
+ name : "Jason Jung" ,
69
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/0803e3d-Jason_Jung.jpg"
70
+ }
71
+ } ,
72
+ {
73
+ title : "Agentic RAG for PDFs with mixed data" ,
74
+ description : "Learn how to build a powerful, multi-step chatbot with Cohere's models that can process PDFs containing both text and tables." ,
75
+ imageSrc : "https://via.placeholder.com/400x200?text=Mixed+Data+RAG" ,
76
+ tags : {
77
+ useCases : [ 'RAG' , 'Agents' , 'Tool Use' ] ,
78
+ endpoints : [ 'Chat' , 'Embed' , 'Rerank' ] ,
79
+ techStack : [ 'LlamaIndex' , 'Pinecone' ]
80
+ } ,
81
+ href : '/page/agentic-rag-mixed-data' ,
82
+ author : {
83
+ name : "Shaan Desai" ,
84
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/d17fc44-Shaan.jpg"
85
+ }
86
+ } ,
87
+ {
88
+ title : "Analysis of Financial Forms" ,
89
+ description : "Use Cohere's large language models to build an agent able to analyze financial forms like a 10-K or a 10-Q." ,
90
+ imageSrc : "https://via.placeholder.com/400x200?text=Financial+Analysis" ,
91
+ tags : {
92
+ useCases : [ 'RAG' , 'Embeddings' , 'Classification' ] ,
93
+ endpoints : [ 'Embed' , 'Finetuning' ] ,
94
+ techStack : [ 'CrewAI' , 'Weaviate' ]
95
+ } ,
96
+ href : '/page/analysis-of-financial-forms' ,
97
+ author : {
98
+ name : "Alex Barbet" ,
99
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/bf2c763-Alex.jpg"
100
+ }
101
+ } ,
102
+ {
103
+ title : "Analyzing Hacker News with Cohere" ,
104
+ description : "Build a generative-AI powered tool to analyze headlines with Cohere's language models." ,
105
+ imageSrc : "https://via.placeholder.com/400x200?text=Hacker+News+Analysis" ,
106
+ tags : {
107
+ useCases : [ 'Embeddings' , 'Classification' , 'Summarization' ] ,
108
+ endpoints : [ 'Chat' , 'Rerank' ] ,
109
+ techStack : [ 'Langchain' , 'LlamaIndex' ]
110
+ } ,
111
+ href : '/page/analyzing-hacker-news' ,
112
+ author : {
113
+ name : "Ania Bialas" ,
114
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/c5dc5a3-Ania.jpg"
115
+ }
116
+ } ,
117
+ {
118
+ title : "Article Recommender with Text Embedding" ,
119
+ description : "Build a generative-AI tool to recommend articles with Cohere's embedding and classification capabilities." ,
120
+ imageSrc : "https://via.placeholder.com/400x200?text=Article+Recommender" ,
121
+ tags : {
122
+ useCases : [ 'Embeddings' , 'Classification' , 'Search' ] ,
123
+ endpoints : [ 'Embed' , 'Rerank' ] ,
124
+ techStack : [ 'Pinecone' , 'CrewAI' ]
125
+ } ,
126
+ href : '/page/article-recommender-with-text-embeddings' ,
127
+ author : {
128
+ name : "Giannis Chatziveroglou" ,
129
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/73153cb-giannis.jpeg"
130
+ }
131
+ } ,
132
+ {
133
+ title : "Basic Multi-Step Tool Use with Cohere" ,
134
+ description : "Create a multi-step, tool-using AI agent with Cohere's tool use functionality." ,
135
+ imageSrc : "https://via.placeholder.com/400x200?text=Multi-Step+Tool+Use" ,
136
+ tags : {
137
+ useCases : [ 'Agents' , 'Tool Use' , 'Multi-step' ] ,
138
+ endpoints : [ 'Chat' , 'Finetuning' ] ,
139
+ techStack : [ 'Weaviate' , 'Langchain' ]
140
+ } ,
141
+ href : '/page/basic-multi-step' ,
142
+ author : {
143
+ name : "Komal Teru" ,
144
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/7026fcc-komal-headshot.jpg"
145
+ }
146
+ } ,
147
+ {
148
+ title : "Basic RAG: Retrieval-Augmented Generation" ,
149
+ description : "Learn how to work with Cohere's basic retrieval-augmented generation functionality." ,
150
+ imageSrc : "https://via.placeholder.com/400x200?text=Basic+RAG" ,
151
+ tags : {
152
+ useCases : [ 'RAG' , 'Embeddings' , 'Text Generation' ] ,
153
+ endpoints : [ 'Chat' , 'Embed' ] ,
154
+ techStack : [ 'LlamaIndex' , 'Pinecone' ]
155
+ } ,
156
+ href : '/page/basic-rag' ,
157
+ author : {
158
+ name : "Youran Qi" ,
159
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/929cb1c-youran-headshot.jpg"
160
+ }
161
+ } ,
162
+ {
163
+ title : "Basic Semantic Search with Cohere Models" ,
164
+ description : "Implement basic semantic search with Cohere's embedding models." ,
165
+ imageSrc : "https://via.placeholder.com/400x200?text=Semantic+Search" ,
166
+ tags : {
167
+ useCases : [ 'Search' , 'Embeddings' , 'Semantic Search' ] ,
168
+ endpoints : [ 'Embed' , 'Rerank' ] ,
169
+ techStack : [ 'Weaviate' , 'CrewAI' ]
170
+ } ,
171
+ href : '/page/basic-semantic-search' ,
172
+ author : {
173
+ name : "Mike Mao" ,
174
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/d514b09-mike-headshot.jpg"
175
+ }
176
+ } ,
177
+ {
178
+ title : "Calendar Agent with Native Multi Step Tool" ,
179
+ description : "Use Cohere Chat API with list_calendar_events and create_calendar_event tools to book appointments." ,
180
+ imageSrc : "https://via.placeholder.com/400x200?text=Calendar+Agent" ,
181
+ tags : {
182
+ useCases : [ 'Agents' , 'Tool Use' , 'Multi-step' ] ,
183
+ endpoints : [ 'Chat' , 'Finetuning' ] ,
184
+ techStack : [ 'Langchain' , 'LlamaIndex' ]
185
+ } ,
186
+ href : '/page/calendar-agent' ,
187
+ author : {
188
+ name : "Aal Patankar" ,
189
+ image : "https://fern-image-hosting.s3.amazonaws.com/cohere/d48e622-Aal.jpg"
190
+ }
191
+ } ,
192
+ ] ;
193
+
194
+ // Create an array of 27 cookbooks by spreading the base cookbooks three times
195
+ const cookbooks : Cookbook [ ] = [
196
+ ...baseCookbooks ,
197
+ ...baseCookbooks . map ( cookbook => ( {
198
+ ...cookbook ,
199
+ href : `${ cookbook . href } -2` , // Add suffix to make hrefs unique
200
+ } ) ) ,
201
+ ...baseCookbooks . map ( cookbook => ( {
202
+ ...cookbook ,
203
+ href : `${ cookbook . href } -3` , // Add suffix to make hrefs unique
204
+ } ) )
205
+ ] ;
206
+
207
+ // Filter cookbooks based on search query and selected tags
208
+ const filteredCookbooks = cookbooks . filter ( cookbook => {
209
+ const matchesQuery = searchQuery === '' ||
210
+ cookbook . title . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ;
211
+
212
+ const matchesUseCases = selectedTags . useCases . length === 0 ||
213
+ selectedTags . useCases . every ( tag => cookbook . tags . useCases . includes ( tag ) ) ;
214
+
215
+ const matchesEndpoints = selectedTags . endpoints . length === 0 ||
216
+ selectedTags . endpoints . every ( tag => cookbook . tags . endpoints . includes ( tag ) ) ;
217
+
218
+ const matchesTechStack = selectedTags . techStack . length === 0 ||
219
+ selectedTags . techStack . every ( tag => cookbook . tags . techStack . includes ( tag ) ) ;
220
+
221
+ return matchesQuery && matchesUseCases && matchesEndpoints && matchesTechStack ;
222
+ } ) ;
223
+
224
+ // Function to get random color from array
225
+ const getRandomColor = ( index : number ) => {
226
+ return CARD_COLORS [ index % CARD_COLORS . length ] ;
227
+ } ;
228
+
229
+ // Helper function to check if a tag is selected
230
+ const isTagSelected = ( category : keyof TagCategories , tag : string ) => {
231
+ return selectedTags [ category ] . includes ( tag ) ;
232
+ } ;
233
+
234
+ // Helper function to toggle a tag
235
+ const toggleTag = ( category : keyof TagCategories , tag : string ) => {
236
+ setSelectedTags ( prev => ( {
237
+ ...prev ,
238
+ [ category ] : prev [ category ] . includes ( tag )
239
+ ? prev [ category ] . filter ( t => t !== tag )
240
+ : [ ...prev [ category ] , tag ]
241
+ } ) ) ;
242
+ } ;
243
+
244
+ return (
245
+ < div className = "w-full" >
246
+ { /* Sidebar and main content container */ }
247
+ < div className = "flex flex-col md:flex-row gap-8" >
248
+ { /* Sidebar */ }
249
+ < div className = "w-full md:w-64 flex-shrink-0" >
250
+ < div className = "sticky top-4" >
251
+ { /* Use Cases */ }
252
+ < div className = "mb-6" >
253
+ < h3 className = "text-sm font-medium mb-4" > Use Cases</ h3 >
254
+ < div className = "flex flex-wrap gap-2" >
255
+ { ALL_TAGS . useCases . map ( tag => (
256
+ < button
257
+ key = { tag }
258
+ onClick = { ( ) => toggleTag ( 'useCases' , tag ) }
259
+ className = { `${ tagButtonClass } ${
260
+ isTagSelected ( 'useCases' , tag ) ? selectedTagClass : unselectedTagClass
261
+ } `}
262
+ >
263
+ { tag }
264
+ </ button >
265
+ ) ) }
266
+ </ div >
267
+ </ div >
268
+
269
+ { /* Endpoints */ }
270
+ < div className = "mb-6" >
271
+ < h3 className = "text-sm font-medium mb-4" > Endpoints</ h3 >
272
+ < div className = "flex flex-wrap gap-2" >
273
+ { ALL_TAGS . endpoints . map ( tag => (
274
+ < button
275
+ key = { tag }
276
+ onClick = { ( ) => toggleTag ( 'endpoints' , tag ) }
277
+ className = { `${ tagButtonClass } ${
278
+ isTagSelected ( 'endpoints' , tag ) ? selectedTagClass : unselectedTagClass
279
+ } `}
280
+ >
281
+ { tag }
282
+ </ button >
283
+ ) ) }
284
+ </ div >
285
+ </ div >
286
+
287
+ { /* Tools */ }
288
+ < div className = "mb-6" >
289
+ < h3 className = "text-sm font-medium mb-4" > Tools</ h3 >
290
+ < div className = "flex flex-wrap gap-2" >
291
+ { ALL_TAGS . techStack . map ( tag => (
292
+ < button
293
+ key = { tag }
294
+ onClick = { ( ) => toggleTag ( 'techStack' , tag ) }
295
+ className = { `${ tagButtonClass } ${
296
+ isTagSelected ( 'techStack' , tag ) ? selectedTagClass : unselectedTagClass
297
+ } `}
298
+ >
299
+ { tag }
300
+ </ button >
301
+ ) ) }
302
+ </ div >
303
+ </ div >
304
+ </ div >
305
+ </ div >
306
+
307
+ { /* Main content */ }
308
+ < div className = "flex-1" >
309
+ < div className = "flex flex-col md:flex-row justify-between items-start md:items-center mb-6 gap-4" >
310
+ < div className = "w-full" >
311
+ < div className = "relative" >
312
+ < input
313
+ type = "text"
314
+ placeholder = "Search"
315
+ value = { searchQuery }
316
+ onChange = { ( e ) => setSearchQuery ( e . target . value ) }
317
+ className = "w-full px-4 py-2 pl-10 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
318
+ />
319
+ < div className = "absolute left-3 top-1/2 transform -translate-y-1/2" >
320
+ < svg xmlns = "http://www.w3.org/2000/svg" width = "16" height = "16" fill = "currentColor" className = "text-gray-400" viewBox = "0 0 16 16" >
321
+ < path d = "M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z" />
322
+ </ svg >
323
+ </ div >
324
+ </ div >
325
+ </ div >
326
+ </ div >
327
+
328
+ < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" >
329
+ { filteredCookbooks . map ( ( cookbook , index ) => (
330
+ < a
331
+ key = { index }
332
+ href = { cookbook . href }
333
+ className = { `block border border-gray-200 rounded-lg hover:shadow-md transition-shadow ${ getRandomColor ( index ) } ` }
334
+ >
335
+ < div className = "p-6" >
336
+ < h3 className = "text-base font-medium text-gray-800 mb-3" > { cookbook . title } </ h3 >
337
+
338
+ { cookbook . author && (
339
+ < div className = "flex items-center mb-4" >
340
+ < img
341
+ src = { cookbook . author . image }
342
+ alt = { cookbook . author . name }
343
+ className = "w-5 h-5 rounded-full mr-2"
344
+ />
345
+ < span className = "text-xs text-gray-600" > { cookbook . author . name } </ span >
346
+ </ div >
347
+ ) }
348
+
349
+ { /* Display only endpoint tags */ }
350
+ < div className = "flex flex-wrap gap-1.5" >
351
+ { cookbook . tags . endpoints . map ( ( tag , tagIndex ) => (
352
+ < span
353
+ key = { tagIndex }
354
+ className = "px-1.5 py-0.5 text-[10px] text-gray-600 bg-white/50 rounded-full"
355
+ >
356
+ { tag }
357
+ </ span >
358
+ ) ) }
359
+ </ div >
360
+ </ div >
361
+ </ a >
362
+ ) ) }
363
+ </ div >
364
+ </ div >
365
+ </ div >
366
+ </ div >
367
+ ) ;
368
+ } ;
0 commit comments