mszel commited on
Commit
98383bd
·
1 Parent(s): 48202b3

adding FAQ chatbot

Browse files
examples/LynxScribe FAQ Chatbot Builder.lynxkite.json ADDED
@@ -0,0 +1,605 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "edges": [
3
+ {
4
+ "id": "LynxScribe FAQ to RAG 1 LynxScribe RAG Graph Chatbot Builder 1",
5
+ "source": "LynxScribe FAQ to RAG 1",
6
+ "sourceHandle": "output",
7
+ "target": "LynxScribe RAG Graph Chatbot Builder 1",
8
+ "targetHandle": "rag_graph"
9
+ },
10
+ {
11
+ "id": "LynxScribe RAG Graph Chatbot Builder 1 LynxScribe RAG Graph Chatbot Backend 1",
12
+ "source": "LynxScribe RAG Graph Chatbot Builder 1",
13
+ "sourceHandle": "output",
14
+ "target": "LynxScribe RAG Graph Chatbot Backend 1",
15
+ "targetHandle": "knowledge_base"
16
+ },
17
+ {
18
+ "id": "Chat processor 1 LynxScribe RAG Graph Chatbot Backend 1",
19
+ "source": "Chat processor 1",
20
+ "sourceHandle": "output",
21
+ "target": "LynxScribe RAG Graph Chatbot Backend 1",
22
+ "targetHandle": "chat_processor"
23
+ },
24
+ {
25
+ "id": "Truncate history 1 Chat processor 1",
26
+ "source": "Truncate history 1",
27
+ "sourceHandle": "output",
28
+ "target": "Chat processor 1",
29
+ "targetHandle": "processor"
30
+ },
31
+ {
32
+ "id": "LynxScribe RAG Graph Chatbot Backend 1 Test Chat API 1",
33
+ "source": "LynxScribe RAG Graph Chatbot Backend 1",
34
+ "sourceHandle": "output",
35
+ "target": "Test Chat API 1",
36
+ "targetHandle": "chat_api"
37
+ },
38
+ {
39
+ "id": "Input chat 1 Test Chat API 1",
40
+ "source": "Input chat 1",
41
+ "sourceHandle": "output",
42
+ "target": "Test Chat API 1",
43
+ "targetHandle": "message"
44
+ },
45
+ {
46
+ "id": "Test Chat API 1 View 1",
47
+ "source": "Test Chat API 1",
48
+ "sourceHandle": "output",
49
+ "target": "View 1",
50
+ "targetHandle": "input"
51
+ }
52
+ ],
53
+ "env": "LynxScribe",
54
+ "nodes": [
55
+ {
56
+ "data": {
57
+ "__execution_delay": 0.0,
58
+ "collapsed": false,
59
+ "display": null,
60
+ "error": null,
61
+ "input_metadata": null,
62
+ "meta": {
63
+ "inputs": {},
64
+ "name": "LynxScribe FAQ to RAG",
65
+ "outputs": {
66
+ "output": {
67
+ "name": "output",
68
+ "position": "right",
69
+ "type": {
70
+ "type": "None"
71
+ }
72
+ }
73
+ },
74
+ "params": {
75
+ "faq_excel_path": {
76
+ "default": "uploads/organon_demo/organon_en_copy.xlsx",
77
+ "name": "faq_excel_path",
78
+ "type": {
79
+ "type": "<class 'str'>"
80
+ }
81
+ },
82
+ "scenario_cluster_distance_pct": {
83
+ "default": 30.0,
84
+ "name": "scenario_cluster_distance_pct",
85
+ "type": {
86
+ "type": "<class 'float'>"
87
+ }
88
+ },
89
+ "text_embedder_interface": {
90
+ "default": "openai",
91
+ "name": "text_embedder_interface",
92
+ "type": {
93
+ "type": "<class 'str'>"
94
+ }
95
+ },
96
+ "text_embedder_model_name_or_path": {
97
+ "default": "text-embedding-3-large",
98
+ "name": "text_embedder_model_name_or_path",
99
+ "type": {
100
+ "type": "<class 'str'>"
101
+ }
102
+ },
103
+ "vdb_collection_name": {
104
+ "default": "lynx",
105
+ "name": "vdb_collection_name",
106
+ "type": {
107
+ "type": "<class 'str'>"
108
+ }
109
+ },
110
+ "vdb_num_dimensions": {
111
+ "default": 3072.0,
112
+ "name": "vdb_num_dimensions",
113
+ "type": {
114
+ "type": "<class 'int'>"
115
+ }
116
+ },
117
+ "vdb_provider_name": {
118
+ "default": "faiss",
119
+ "name": "vdb_provider_name",
120
+ "type": {
121
+ "type": "<class 'str'>"
122
+ }
123
+ }
124
+ },
125
+ "type": "basic"
126
+ },
127
+ "params": {
128
+ "faq_excel_path": "uploads/organon_demo/organon_en_copy.xlsx",
129
+ "scenario_cluster_distance_pct": "30",
130
+ "text_embedder_interface": "openai",
131
+ "text_embedder_model_name_or_path": "text-embedding-3-large",
132
+ "vdb_collection_name": "lynx",
133
+ "vdb_num_dimensions": 3072.0,
134
+ "vdb_provider_name": "faiss"
135
+ },
136
+ "status": "done",
137
+ "title": "LynxScribe FAQ to RAG"
138
+ },
139
+ "dragHandle": ".bg-primary",
140
+ "height": 620.0,
141
+ "id": "LynxScribe FAQ to RAG 1",
142
+ "position": {
143
+ "x": -1180.0,
144
+ "y": -76.0
145
+ },
146
+ "type": "basic",
147
+ "width": 415.0
148
+ },
149
+ {
150
+ "data": {
151
+ "__execution_delay": 0.0,
152
+ "collapsed": false,
153
+ "display": null,
154
+ "error": null,
155
+ "input_metadata": null,
156
+ "meta": {
157
+ "inputs": {
158
+ "rag_graph": {
159
+ "name": "rag_graph",
160
+ "position": "left",
161
+ "type": {
162
+ "type": "<class 'inspect._empty'>"
163
+ }
164
+ }
165
+ },
166
+ "name": "LynxScribe RAG Graph Chatbot Builder",
167
+ "outputs": {
168
+ "output": {
169
+ "name": "output",
170
+ "position": "top",
171
+ "type": {
172
+ "type": "None"
173
+ }
174
+ }
175
+ },
176
+ "params": {
177
+ "node_types": {
178
+ "default": "intent_cluster",
179
+ "name": "node_types",
180
+ "type": {
181
+ "type": "<class 'str'>"
182
+ }
183
+ },
184
+ "scenario_file": {
185
+ "default": "uploads/lynx_chatbot_scenario_selector.yaml",
186
+ "name": "scenario_file",
187
+ "type": {
188
+ "type": "<class 'str'>"
189
+ }
190
+ },
191
+ "scenario_meta_name": {
192
+ "default": "scenario_name",
193
+ "name": "scenario_meta_name",
194
+ "type": {
195
+ "type": "<class 'str'>"
196
+ }
197
+ }
198
+ },
199
+ "position": {
200
+ "x": 1569.0,
201
+ "y": 528.0
202
+ },
203
+ "type": "basic"
204
+ },
205
+ "params": {
206
+ "node_types": "intent_cluster",
207
+ "scenario_file": "uploads/organon_demo/backend-scenarios-en.yaml",
208
+ "scenario_meta_name": "scenario_name"
209
+ },
210
+ "status": "done",
211
+ "title": "LynxScribe RAG Graph Chatbot Builder"
212
+ },
213
+ "dragHandle": ".bg-primary",
214
+ "height": 296.0,
215
+ "id": "LynxScribe RAG Graph Chatbot Builder 1",
216
+ "position": {
217
+ "x": -591.0,
218
+ "y": 86.0
219
+ },
220
+ "type": "basic",
221
+ "width": 547.0
222
+ },
223
+ {
224
+ "data": {
225
+ "__execution_delay": 0.0,
226
+ "collapsed": null,
227
+ "display": null,
228
+ "error": null,
229
+ "input_metadata": null,
230
+ "meta": {
231
+ "inputs": {
232
+ "chat_processor": {
233
+ "name": "chat_processor",
234
+ "position": "bottom",
235
+ "type": {
236
+ "type": "<class 'inspect._empty'>"
237
+ }
238
+ },
239
+ "knowledge_base": {
240
+ "name": "knowledge_base",
241
+ "position": "bottom",
242
+ "type": {
243
+ "type": "<class 'inspect._empty'>"
244
+ }
245
+ }
246
+ },
247
+ "name": "LynxScribe RAG Graph Chatbot Backend",
248
+ "outputs": {
249
+ "output": {
250
+ "name": "output",
251
+ "position": "top",
252
+ "type": {
253
+ "type": "None"
254
+ }
255
+ }
256
+ },
257
+ "params": {
258
+ "llm_interface": {
259
+ "default": "openai",
260
+ "name": "llm_interface",
261
+ "type": {
262
+ "type": "<class 'str'>"
263
+ }
264
+ },
265
+ "llm_model_name": {
266
+ "default": "gpt-4o",
267
+ "name": "llm_model_name",
268
+ "type": {
269
+ "type": "<class 'str'>"
270
+ }
271
+ },
272
+ "negative_answer": {
273
+ "default": "I'm sorry, but the data I've been trained on does not contain any information related to your question.",
274
+ "name": "negative_answer",
275
+ "type": {
276
+ "type": "<class 'str'>"
277
+ }
278
+ },
279
+ "retriever_limits_by_type": {
280
+ "default": "{}",
281
+ "name": "retriever_limits_by_type",
282
+ "type": {
283
+ "type": "<class 'str'>"
284
+ }
285
+ },
286
+ "retriever_max_iterations": {
287
+ "default": 3.0,
288
+ "name": "retriever_max_iterations",
289
+ "type": {
290
+ "type": "<class 'int'>"
291
+ }
292
+ },
293
+ "retriever_overall_chunk_limit": {
294
+ "default": 20.0,
295
+ "name": "retriever_overall_chunk_limit",
296
+ "type": {
297
+ "type": "<class 'int'>"
298
+ }
299
+ },
300
+ "retriever_overall_token_limit": {
301
+ "default": 3000.0,
302
+ "name": "retriever_overall_token_limit",
303
+ "type": {
304
+ "type": "<class 'int'>"
305
+ }
306
+ },
307
+ "retriever_strict_limits": {
308
+ "default": true,
309
+ "name": "retriever_strict_limits",
310
+ "type": {
311
+ "type": "<class 'bool'>"
312
+ }
313
+ }
314
+ },
315
+ "position": {
316
+ "x": 1280.0,
317
+ "y": 450.0
318
+ },
319
+ "type": "basic"
320
+ },
321
+ "params": {
322
+ "llm_interface": "openai",
323
+ "llm_model_name": "gpt-4o",
324
+ "negative_answer": "I'm sorry, but the data I've been trained on does not contain any information related to your question.",
325
+ "retriever_limits_by_type": "{\"faq_question\": [0, 0], \"faq_answer\": [3, 3]}",
326
+ "retriever_max_iterations": "3",
327
+ "retriever_overall_chunk_limit": "3",
328
+ "retriever_overall_token_limit": "30000",
329
+ "retriever_strict_limits": true
330
+ },
331
+ "status": "done",
332
+ "title": "LynxScribe RAG Graph Chatbot Backend"
333
+ },
334
+ "dragHandle": ".bg-primary",
335
+ "height": 382.0,
336
+ "id": "LynxScribe RAG Graph Chatbot Backend 1",
337
+ "position": {
338
+ "x": -427.131476508498,
339
+ "y": -465.1194966607713
340
+ },
341
+ "type": "basic",
342
+ "width": 791.0
343
+ },
344
+ {
345
+ "data": {
346
+ "display": null,
347
+ "error": null,
348
+ "input_metadata": null,
349
+ "meta": {
350
+ "inputs": {
351
+ "processor": {
352
+ "name": "processor",
353
+ "position": "bottom",
354
+ "type": {
355
+ "type": "<class 'inspect._empty'>"
356
+ }
357
+ }
358
+ },
359
+ "name": "Chat processor",
360
+ "outputs": {
361
+ "output": {
362
+ "name": "output",
363
+ "position": "top",
364
+ "type": {
365
+ "type": "None"
366
+ }
367
+ }
368
+ },
369
+ "params": {},
370
+ "position": {
371
+ "x": 1291.0,
372
+ "y": 718.0
373
+ },
374
+ "type": "basic"
375
+ },
376
+ "params": {},
377
+ "status": "done",
378
+ "title": "Chat processor"
379
+ },
380
+ "dragHandle": ".bg-primary",
381
+ "height": 200.0,
382
+ "id": "Chat processor 1",
383
+ "position": {
384
+ "x": 252.7291107206022,
385
+ "y": 81.86852349150202
386
+ },
387
+ "type": "basic",
388
+ "width": 200.0
389
+ },
390
+ {
391
+ "data": {
392
+ "display": null,
393
+ "error": null,
394
+ "input_metadata": null,
395
+ "meta": {
396
+ "inputs": {},
397
+ "name": "Truncate history",
398
+ "outputs": {
399
+ "output": {
400
+ "name": "output",
401
+ "position": "top",
402
+ "type": {
403
+ "type": "None"
404
+ }
405
+ }
406
+ },
407
+ "params": {
408
+ "max_tokens": {
409
+ "default": 10000.0,
410
+ "name": "max_tokens",
411
+ "type": {
412
+ "type": "<class 'int'>"
413
+ }
414
+ }
415
+ },
416
+ "position": {
417
+ "x": 1440.0,
418
+ "y": 936.0
419
+ },
420
+ "type": "basic"
421
+ },
422
+ "params": {
423
+ "max_tokens": 10000.0
424
+ },
425
+ "status": "done",
426
+ "title": "Truncate history"
427
+ },
428
+ "dragHandle": ".bg-primary",
429
+ "height": 200.0,
430
+ "id": "Truncate history 1",
431
+ "position": {
432
+ "x": 253.59374153502728,
433
+ "y": 386.4661577036063
434
+ },
435
+ "type": "basic",
436
+ "width": 200.0
437
+ },
438
+ {
439
+ "data": {
440
+ "__execution_delay": 0.0,
441
+ "collapsed": null,
442
+ "display": null,
443
+ "error": null,
444
+ "input_metadata": null,
445
+ "meta": {
446
+ "inputs": {},
447
+ "name": "Input chat",
448
+ "outputs": {
449
+ "output": {
450
+ "name": "output",
451
+ "position": "right",
452
+ "type": {
453
+ "type": "None"
454
+ }
455
+ }
456
+ },
457
+ "params": {
458
+ "chat": {
459
+ "default": null,
460
+ "name": "chat",
461
+ "type": {
462
+ "type": "<class 'str'>"
463
+ }
464
+ }
465
+ },
466
+ "position": {
467
+ "x": 449.0,
468
+ "y": 172.0
469
+ },
470
+ "type": "basic"
471
+ },
472
+ "params": {
473
+ "chat": "I had headache after taking the pill"
474
+ },
475
+ "status": "done",
476
+ "title": "Input chat"
477
+ },
478
+ "dragHandle": ".bg-primary",
479
+ "height": 204.0,
480
+ "id": "Input chat 1",
481
+ "position": {
482
+ "x": -1115.7774404622555,
483
+ "y": -747.1320865489535
484
+ },
485
+ "type": "basic",
486
+ "width": 552.0
487
+ },
488
+ {
489
+ "data": {
490
+ "__execution_delay": 0.0,
491
+ "collapsed": null,
492
+ "display": null,
493
+ "error": null,
494
+ "input_metadata": null,
495
+ "meta": {
496
+ "inputs": {
497
+ "chat_api": {
498
+ "name": "chat_api",
499
+ "position": "bottom",
500
+ "type": {
501
+ "type": "<class 'inspect._empty'>"
502
+ }
503
+ },
504
+ "message": {
505
+ "name": "message",
506
+ "position": "left",
507
+ "type": {
508
+ "type": "<class 'inspect._empty'>"
509
+ }
510
+ }
511
+ },
512
+ "name": "Test Chat API",
513
+ "outputs": {
514
+ "output": {
515
+ "name": "output",
516
+ "position": "right",
517
+ "type": {
518
+ "type": "None"
519
+ }
520
+ }
521
+ },
522
+ "params": {
523
+ "show_details": {
524
+ "default": false,
525
+ "name": "show_details",
526
+ "type": {
527
+ "type": "<class 'bool'>"
528
+ }
529
+ }
530
+ },
531
+ "position": {
532
+ "x": 937.0,
533
+ "y": 213.0
534
+ },
535
+ "type": "basic"
536
+ },
537
+ "params": {
538
+ "show_details": false
539
+ },
540
+ "status": "done",
541
+ "title": "Test Chat API"
542
+ },
543
+ "dragHandle": ".bg-primary",
544
+ "height": 200.0,
545
+ "id": "Test Chat API 1",
546
+ "position": {
547
+ "x": -131.54900620226195,
548
+ "y": -745.4660726292032
549
+ },
550
+ "type": "basic",
551
+ "width": 200.0
552
+ },
553
+ {
554
+ "data": {
555
+ "display": {
556
+ "dataframes": {
557
+ "df": {
558
+ "columns": [
559
+ "answer"
560
+ ],
561
+ "data": [
562
+ [
563
+ "I'm not equipped to handle adverse events or other product-related queries. Your safety is important to us, and we want to ensure you receive the appropriate support. Please report any adverse events or concerns to our dedicated support team. They can be reached at [email protected]. If you have any questions related to contraceptives or women's health, please feel free to ask, and I'll provide you with the information you need.\n"
564
+ ]
565
+ ]
566
+ }
567
+ }
568
+ },
569
+ "error": null,
570
+ "input_metadata": null,
571
+ "meta": {
572
+ "inputs": {
573
+ "input": {
574
+ "name": "input",
575
+ "position": "left",
576
+ "type": {
577
+ "type": "<class 'inspect._empty'>"
578
+ }
579
+ }
580
+ },
581
+ "name": "View",
582
+ "outputs": {},
583
+ "params": {},
584
+ "position": {
585
+ "x": 1547.0,
586
+ "y": 222.0
587
+ },
588
+ "type": "table_view"
589
+ },
590
+ "params": {},
591
+ "status": "done",
592
+ "title": "View"
593
+ },
594
+ "dragHandle": ".bg-primary",
595
+ "height": 483.0,
596
+ "id": "View 1",
597
+ "position": {
598
+ "x": 540.6544350347407,
599
+ "y": -886.065865503576
600
+ },
601
+ "type": "table_view",
602
+ "width": 707.0
603
+ }
604
+ ]
605
+ }
examples/LynxScribe RAG Chatbot.lynxkite.json CHANGED
@@ -7,20 +7,6 @@
7
  "target": "LynxScribe Text RAG Loader 1",
8
  "targetHandle": "file_urls"
9
  },
10
- {
11
- "id": "LynxScribe Text RAG Loader 1 LynxScribe RAG Graph Chatbot Builder 1",
12
- "source": "LynxScribe Text RAG Loader 1",
13
- "sourceHandle": "output",
14
- "target": "LynxScribe RAG Graph Chatbot Builder 1",
15
- "targetHandle": "rag_graph"
16
- },
17
- {
18
- "id": "LynxScribe RAG Graph Chatbot Builder 1 LynxScribe RAG Graph Chatbot Backend 1",
19
- "source": "LynxScribe RAG Graph Chatbot Builder 1",
20
- "sourceHandle": "output",
21
- "target": "LynxScribe RAG Graph Chatbot Backend 1",
22
- "targetHandle": "knowledge_base"
23
- },
24
  {
25
  "id": "Truncate history 1 Chat processor 1",
26
  "source": "Truncate history 1",
@@ -62,6 +48,20 @@
62
  "sourceHandle": "output",
63
  "target": "View 1",
64
  "targetHandle": "input"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
  ],
67
  "env": "LynxScribe",
@@ -112,10 +112,6 @@
112
  }
113
  }
114
  },
115
- "position": {
116
- "x": 530.0,
117
- "y": 350.0
118
- },
119
  "type": "basic"
120
  },
121
  "params": {
@@ -210,10 +206,6 @@
210
  }
211
  }
212
  },
213
- "position": {
214
- "x": 1048.0,
215
- "y": 762.0
216
- },
217
  "type": "basic"
218
  },
219
  "params": {
@@ -237,70 +229,6 @@
237
  "type": "basic",
238
  "width": 290.0
239
  },
240
- {
241
- "data": {
242
- "display": null,
243
- "error": null,
244
- "input_metadata": null,
245
- "meta": {
246
- "inputs": {
247
- "rag_graph": {
248
- "name": "rag_graph",
249
- "position": "left",
250
- "type": {
251
- "type": "<class 'inspect._empty'>"
252
- }
253
- }
254
- },
255
- "name": "LynxScribe RAG Graph Chatbot Builder",
256
- "outputs": {
257
- "output": {
258
- "name": "output",
259
- "position": "top",
260
- "type": {
261
- "type": "None"
262
- }
263
- }
264
- },
265
- "params": {
266
- "node_types": {
267
- "default": "intent_cluster",
268
- "name": "node_types",
269
- "type": {
270
- "type": "<class 'str'>"
271
- }
272
- },
273
- "scenario_file": {
274
- "default": "uploads/lynx_chatbot_scenario_selector.yaml",
275
- "name": "scenario_file",
276
- "type": {
277
- "type": "<class 'str'>"
278
- }
279
- }
280
- },
281
- "position": {
282
- "x": 1451.0,
283
- "y": 752.0
284
- },
285
- "type": "basic"
286
- },
287
- "params": {
288
- "node_types": "intent_cluster",
289
- "scenario_file": "uploads/lynx_chatbot_scenario_selector.yaml"
290
- },
291
- "status": "done",
292
- "title": "LynxScribe RAG Graph Chatbot Builder"
293
- },
294
- "dragHandle": ".bg-primary",
295
- "height": 208.0,
296
- "id": "LynxScribe RAG Graph Chatbot Builder 1",
297
- "position": {
298
- "x": 245.0,
299
- "y": 421.0
300
- },
301
- "type": "basic",
302
- "width": 407.0
303
- },
304
  {
305
  "data": {
306
  "__execution_delay": 0.0,
@@ -393,10 +321,6 @@
393
  }
394
  }
395
  },
396
- "position": {
397
- "x": 1658.0,
398
- "y": 587.0
399
- },
400
  "type": "basic"
401
  },
402
  "params": {
@@ -404,7 +328,7 @@
404
  "llm_model_name": "gpt-4o",
405
  "negative_answer": "I'm sorry, but the data I've been trained on does not contain any information related to your question.",
406
  "retriever_limits_by_type": "{\"information\": [1, 5], \"summary\": [0, 2], \"template_qna\": [1, 3], \"QnA question\": [0, 0]}",
407
- "retriever_max_iterations": 3.0,
408
  "retriever_overall_chunk_limit": 20.0,
409
  "retriever_overall_token_limit": 3000.0,
410
  "retriever_strict_limits": true
@@ -448,10 +372,6 @@
448
  }
449
  },
450
  "params": {},
451
- "position": {
452
- "x": 1742.0,
453
- "y": 847.0
454
- },
455
  "type": "basic"
456
  },
457
  "params": {},
@@ -462,8 +382,8 @@
462
  "height": 220.0,
463
  "id": "Chat processor 1",
464
  "position": {
465
- "x": 921.2787659034059,
466
- "y": 431.57233488216445
467
  },
468
  "type": "basic",
469
  "width": 387.0
@@ -494,10 +414,6 @@
494
  }
495
  }
496
  },
497
- "position": {
498
- "x": 1991.0,
499
- "y": 1042.0
500
- },
501
  "type": "basic"
502
  },
503
  "params": {
@@ -565,10 +481,6 @@
565
  }
566
  }
567
  },
568
- "position": {
569
- "x": 2003.0,
570
- "y": 1053.0
571
- },
572
  "type": "basic"
573
  },
574
  "params": {
@@ -618,10 +530,6 @@
618
  }
619
  }
620
  },
621
- "position": {
622
- "x": 2012.0,
623
- "y": 475.0
624
- },
625
  "type": "basic"
626
  },
627
  "params": {
@@ -683,10 +591,6 @@
683
  }
684
  }
685
  },
686
- "position": {
687
- "x": 1238.0,
688
- "y": 211.0
689
- },
690
  "type": "basic"
691
  },
692
  "params": {
@@ -715,7 +619,7 @@
715
  ],
716
  "data": [
717
  [
718
- "The CEO of Lynx Analytics is Gyorgy Lajtai. He co-founded the company in 2010 and has a background in CRM, marketing automation, and systems."
719
  ]
720
  ]
721
  }
@@ -736,10 +640,6 @@
736
  "name": "View",
737
  "outputs": {},
738
  "params": {},
739
- "position": {
740
- "x": 1746.0,
741
- "y": 232.0
742
- },
743
  "type": "table_view"
744
  },
745
  "params": {},
@@ -755,6 +655,80 @@
755
  },
756
  "type": "table_view",
757
  "width": 995.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758
  }
759
  ]
760
  }
 
7
  "target": "LynxScribe Text RAG Loader 1",
8
  "targetHandle": "file_urls"
9
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  {
11
  "id": "Truncate history 1 Chat processor 1",
12
  "source": "Truncate history 1",
 
48
  "sourceHandle": "output",
49
  "target": "View 1",
50
  "targetHandle": "input"
51
+ },
52
+ {
53
+ "id": "LynxScribe Text RAG Loader 1 LynxScribe RAG Graph Chatbot Builder 1",
54
+ "source": "LynxScribe Text RAG Loader 1",
55
+ "sourceHandle": "output",
56
+ "target": "LynxScribe RAG Graph Chatbot Builder 1",
57
+ "targetHandle": "rag_graph"
58
+ },
59
+ {
60
+ "id": "LynxScribe RAG Graph Chatbot Builder 1 LynxScribe RAG Graph Chatbot Backend 1",
61
+ "source": "LynxScribe RAG Graph Chatbot Builder 1",
62
+ "sourceHandle": "output",
63
+ "target": "LynxScribe RAG Graph Chatbot Backend 1",
64
+ "targetHandle": "knowledge_base"
65
  }
66
  ],
67
  "env": "LynxScribe",
 
112
  }
113
  }
114
  },
 
 
 
 
115
  "type": "basic"
116
  },
117
  "params": {
 
206
  }
207
  }
208
  },
 
 
 
 
209
  "type": "basic"
210
  },
211
  "params": {
 
229
  "type": "basic",
230
  "width": 290.0
231
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  {
233
  "data": {
234
  "__execution_delay": 0.0,
 
321
  }
322
  }
323
  },
 
 
 
 
324
  "type": "basic"
325
  },
326
  "params": {
 
328
  "llm_model_name": "gpt-4o",
329
  "negative_answer": "I'm sorry, but the data I've been trained on does not contain any information related to your question.",
330
  "retriever_limits_by_type": "{\"information\": [1, 5], \"summary\": [0, 2], \"template_qna\": [1, 3], \"QnA question\": [0, 0]}",
331
+ "retriever_max_iterations": "3",
332
  "retriever_overall_chunk_limit": 20.0,
333
  "retriever_overall_token_limit": 3000.0,
334
  "retriever_strict_limits": true
 
372
  }
373
  },
374
  "params": {},
 
 
 
 
375
  "type": "basic"
376
  },
377
  "params": {},
 
382
  "height": 220.0,
383
  "id": "Chat processor 1",
384
  "position": {
385
+ "x": 907.3546850533578,
386
+ "y": 381.09754180073975
387
  },
388
  "type": "basic",
389
  "width": 387.0
 
414
  }
415
  }
416
  },
 
 
 
 
417
  "type": "basic"
418
  },
419
  "params": {
 
481
  }
482
  }
483
  },
 
 
 
 
484
  "type": "basic"
485
  },
486
  "params": {
 
530
  }
531
  }
532
  },
 
 
 
 
533
  "type": "basic"
534
  },
535
  "params": {
 
591
  }
592
  }
593
  },
 
 
 
 
594
  "type": "basic"
595
  },
596
  "params": {
 
619
  ],
620
  "data": [
621
  [
622
+ "The CEO of Lynx Analytics is Gyorgy Lajtai. He is also a co-founder of the company and has a rich background in CRM, marketing automation, and systems."
623
  ]
624
  ]
625
  }
 
640
  "name": "View",
641
  "outputs": {},
642
  "params": {},
 
 
 
 
643
  "type": "table_view"
644
  },
645
  "params": {},
 
655
  },
656
  "type": "table_view",
657
  "width": 995.0
658
+ },
659
+ {
660
+ "data": {
661
+ "__execution_delay": 0.0,
662
+ "collapsed": null,
663
+ "display": null,
664
+ "error": null,
665
+ "input_metadata": null,
666
+ "meta": {
667
+ "inputs": {
668
+ "rag_graph": {
669
+ "name": "rag_graph",
670
+ "position": "left",
671
+ "type": {
672
+ "type": "<class 'inspect._empty'>"
673
+ }
674
+ }
675
+ },
676
+ "name": "LynxScribe RAG Graph Chatbot Builder",
677
+ "outputs": {
678
+ "output": {
679
+ "name": "output",
680
+ "position": "top",
681
+ "type": {
682
+ "type": "None"
683
+ }
684
+ }
685
+ },
686
+ "params": {
687
+ "node_types": {
688
+ "default": "intent_cluster",
689
+ "name": "node_types",
690
+ "type": {
691
+ "type": "<class 'str'>"
692
+ }
693
+ },
694
+ "scenario_file": {
695
+ "default": "uploads/lynx_chatbot_scenario_selector.yaml",
696
+ "name": "scenario_file",
697
+ "type": {
698
+ "type": "<class 'str'>"
699
+ }
700
+ },
701
+ "scenario_meta_name": {
702
+ "default": "scenario_name",
703
+ "name": "scenario_meta_name",
704
+ "type": {
705
+ "type": "<class 'str'>"
706
+ }
707
+ }
708
+ },
709
+ "position": {
710
+ "x": 1121.0,
711
+ "y": 813.0
712
+ },
713
+ "type": "basic"
714
+ },
715
+ "params": {
716
+ "node_types": "intent_cluster",
717
+ "scenario_file": "uploads/lynx_chatbot_scenario_selector.yaml",
718
+ "scenario_meta_name": ""
719
+ },
720
+ "status": "done",
721
+ "title": "LynxScribe RAG Graph Chatbot Builder"
722
+ },
723
+ "dragHandle": ".bg-primary",
724
+ "height": 297.0,
725
+ "id": "LynxScribe RAG Graph Chatbot Builder 1",
726
+ "position": {
727
+ "x": 328.41755532473496,
728
+ "y": 378.2277574498554
729
+ },
730
+ "type": "basic",
731
+ "width": 396.0
732
  }
733
  ]
734
  }
lynxkite-lynxscribe/src/lynxkite_lynxscribe/lynxscribe_ops.py CHANGED
@@ -9,6 +9,7 @@ from enum import Enum
9
  import asyncio
10
  import pandas as pd
11
  import joblib
 
12
 
13
  import pathlib
14
  from lynxscribe.core.llm.base import get_llm_engine
@@ -16,6 +17,7 @@ from lynxscribe.core.vector_store.base import get_vector_store
16
  from lynxscribe.common.config import load_config
17
  from lynxscribe.components.text.embedder import TextEmbedder
18
  from lynxscribe.core.models.embedding import Embedding
 
19
 
20
  from lynxscribe.components.rag.rag_graph import RAGGraph
21
  from lynxscribe.components.rag.knowledge_base_graph import PandasKnowledgeBaseGraph
@@ -27,6 +29,7 @@ from lynxscribe.components.chat.processors import (
27
  )
28
  from lynxscribe.components.chat.api import ChatAPI
29
  from lynxscribe.core.models.prompts import ChatCompletionPrompt
 
30
 
31
  from lynxkite.core import ops
32
  import json
@@ -53,6 +56,60 @@ class RAGVersion(Enum):
53
  V2 = "v2"
54
 
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  @op("Cloud-sourced File Listing")
57
  def cloud_file_loader(
58
  *,
@@ -397,14 +454,102 @@ def ls_text_rag_loader(
397
  return {"rag_graph": rag_graph}
398
 
399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  @output_on_top
401
  @op("LynxScribe RAG Graph Chatbot Builder")
402
- @mem.cache
403
  def ls_rag_chatbot_builder(
404
  rag_graph,
405
  *,
406
  scenario_file: str = "uploads/lynx_chatbot_scenario_selector.yaml",
407
  node_types: str = "intent_cluster",
 
408
  ):
409
  """
410
  Builds up a RAG Graph-based chatbot (basically the loaded RAG graph +
@@ -422,11 +567,15 @@ def ls_rag_chatbot_builder(
422
  # rag_graph = rag_graph[0]["rag_graph"] TODO: check why is it bad
423
  rag_graph = rag_graph["rag_graph"]
424
 
 
 
 
 
 
 
 
425
  # loading the scenarios
426
- scenario_selector = ScenarioSelector(
427
- scenarios=[Scenario(**scenario) for scenario in scenarios],
428
- node_types=node_types,
429
- )
430
 
431
  # TODO: later we should unify this "knowledge base" object across the functions
432
  # this could be always an input of a RAG Chatbot, but also for other apps.
@@ -554,7 +703,12 @@ async def test_chat_api(message, chat_api, *, show_details=False):
554
  messages=[{"role": "user", "content": message["text"]}],
555
  )
556
  response = await chat_api.answer(request, stream=False)
557
- answer = response.choices[0].message.content
 
 
 
 
 
558
  if show_details:
559
  return {"answer": answer, **response.__dict__}
560
  else:
 
9
  import asyncio
10
  import pandas as pd
11
  import joblib
12
+ from pydantic import BaseModel, ConfigDict
13
 
14
  import pathlib
15
  from lynxscribe.core.llm.base import get_llm_engine
 
17
  from lynxscribe.common.config import load_config
18
  from lynxscribe.components.text.embedder import TextEmbedder
19
  from lynxscribe.core.models.embedding import Embedding
20
+ from lynxscribe.components.embedding_clustering import FclusterBasedClustering
21
 
22
  from lynxscribe.components.rag.rag_graph import RAGGraph
23
  from lynxscribe.components.rag.knowledge_base_graph import PandasKnowledgeBaseGraph
 
29
  )
30
  from lynxscribe.components.chat.api import ChatAPI
31
  from lynxscribe.core.models.prompts import ChatCompletionPrompt
32
+ from lynxscribe.components.rag.loaders import FAQTemplateLoader
33
 
34
  from lynxkite.core import ops
35
  import json
 
56
  V2 = "v2"
57
 
58
 
59
+ class RAGTemplate(BaseModel):
60
+ """
61
+ Model for RAG templates consisting of three tables: they are connected via scenario names.
62
+ One table (FAQs) contains scenario-denoted nodes to upsert into the knowledge base, the other
63
+ two tables serve as the configuration for the scenario selector.
64
+ Attributes:
65
+ faq_data:
66
+ Table where each row is an FAQ question, and possibly its answer pair. Will be fed into
67
+ `FAQTemplateLoader.load_nodes_and_edges()`. For configuration of this table see the
68
+ loader's init arguments.
69
+ scenario_data:
70
+ Table where each row is a Scenario, column names are thus scenario attributes. Will be
71
+ fed into `ScenarioSelector.from_data()`.
72
+ prompt_codes:
73
+ Optional helper for the scenario table, may contain prompt code mappings to real prompt
74
+ messages. It's enough then to use the codes instead of the full messages in the
75
+ scenarios table. Will be fed into `ScenarioSelector.from_data()`.
76
+ """
77
+
78
+ model_config = ConfigDict(arbitrary_types_allowed=True)
79
+
80
+ faq_data: pd.DataFrame
81
+ scenario_data: pd.DataFrame
82
+ prompt_codes: dict[str, str] = {}
83
+
84
+ @classmethod
85
+ def from_excel_path(
86
+ cls,
87
+ path: str,
88
+ faq_data_sheet_name: str,
89
+ scenario_data_sheet_name: str,
90
+ prompt_codes_sheet_name: str | None = None,
91
+ ) -> "RAGTemplate":
92
+ """Spawn a from an Excel file containing the two needed (plus one optional) sheets."""
93
+
94
+ def transform_codes(prompt_codes: pd.DataFrame) -> dict[str, str]:
95
+ """Check and transform prompt codes table into a code dictionary."""
96
+ if (len_columns := len(prompt_codes.columns)) != 2:
97
+ raise ValueError(
98
+ f"Prompt codes should contain exactly 2 columns, {len_columns} found."
99
+ )
100
+ return prompt_codes.set_index(prompt_codes.columns[0])[
101
+ prompt_codes.columns[1]
102
+ ].to_dict()
103
+
104
+ return cls(
105
+ faq_data=pd.read_excel(path, sheet_name=faq_data_sheet_name),
106
+ scenario_data=pd.read_excel(path, sheet_name=scenario_data_sheet_name),
107
+ prompt_codes=transform_codes(pd.read_excel(path, sheet_name=prompt_codes_sheet_name))
108
+ if prompt_codes_sheet_name
109
+ else {},
110
+ )
111
+
112
+
113
  @op("Cloud-sourced File Listing")
114
  def cloud_file_loader(
115
  *,
 
454
  return {"rag_graph": rag_graph}
455
 
456
 
457
+ @op("LynxScribe FAQ to RAG")
458
+ @mem.cache
459
+ async def ls_faq_to_rag(
460
+ *,
461
+ faq_excel_path: str = "uploads/organon_demo/organon_en_copy.xlsx",
462
+ vdb_provider_name: str = "faiss",
463
+ vdb_num_dimensions: int = 3072,
464
+ vdb_collection_name: str = "lynx",
465
+ text_embedder_interface: str = "openai",
466
+ text_embedder_model_name_or_path: str = "text-embedding-3-large",
467
+ scenario_cluster_distance_pct: int = 30,
468
+ ):
469
+ """
470
+ Loading a text-based RAG graph from saved files (getting pandas readable links).
471
+ """
472
+
473
+ # getting the text embedder instance
474
+ llm_params = {"name": text_embedder_interface}
475
+ llm = get_llm_engine(**llm_params)
476
+ text_embedder = TextEmbedder(llm=llm, model=text_embedder_model_name_or_path)
477
+
478
+ # getting the vector store
479
+ if vdb_provider_name == "chromadb":
480
+ vector_store = get_vector_store(name=vdb_provider_name, collection_name=vdb_collection_name)
481
+ elif vdb_provider_name == "faiss":
482
+ vector_store = get_vector_store(name=vdb_provider_name, num_dimensions=vdb_num_dimensions)
483
+ else:
484
+ raise ValueError(f"Vector store name '{vdb_provider_name}' is not supported.")
485
+
486
+ # building up the RAG graph
487
+ rag_graph = RAGGraph(
488
+ PandasKnowledgeBaseGraph(vector_store=vector_store, text_embedder=text_embedder)
489
+ )
490
+
491
+ # loading the knowledge base from the FAQ file
492
+ rag_template = RAGTemplate.from_excel_path(
493
+ path=faq_excel_path,
494
+ faq_data_sheet_name="scenario_examples",
495
+ scenario_data_sheet_name="scenario_scripts",
496
+ prompt_codes_sheet_name="prompt_dictionary",
497
+ )
498
+
499
+ faq_loader_params = {
500
+ "id_column": "scenario_example_ID",
501
+ "timestamp_column": "last_modified_timestamp",
502
+ "validity_column": "valid_flg",
503
+ "question_type_contents_id": ["faq_question", "faq_question", "q_{id}"],
504
+ "answer_type_contents_id": ["faq_answer", "{faq_question}\n\n{faq_answer}", "a_{id}"],
505
+ "question_to_answer_edge_type_weight": ["qna", 1.0],
506
+ }
507
+
508
+ nodes, edges = FAQTemplateLoader(**faq_loader_params).load_nodes_and_edges(
509
+ rag_template.faq_data
510
+ )
511
+
512
+ await rag_graph.kg_base.upsert_nodes(*nodes)
513
+ rag_graph.kg_base.upsert_edges(edges)
514
+
515
+ # Generating scenario clusters
516
+ question_ids = [_id for _id in nodes[0] if _id.startswith("q_")]
517
+ stored_embeddings = rag_graph.kg_base.vector_store.get(
518
+ question_ids, include=["embeddings", "metadatas"]
519
+ )
520
+ embedding_vals = pd.Series([_emb.value for _emb in stored_embeddings], index=question_ids)
521
+ labels = pd.Series(
522
+ [_emb.metadata["scenario_name"] for _emb in stored_embeddings], index=question_ids
523
+ )
524
+ temp_cls = FclusterBasedClustering(distance_percentile=scenario_cluster_distance_pct)
525
+ temp_cls.fit(embedding_vals, labels)
526
+ df_tempclusters = temp_cls.get_cluster_centers()
527
+
528
+ # Adding the scenario clusters to the RAG Graph
529
+ df_tempclusters["template_id"] = "t_" + df_tempclusters.index.astype(str)
530
+ df_tempclusters["embedding"] = df_tempclusters.apply(
531
+ lambda row: Embedding(
532
+ id=row["template_id"],
533
+ value=row["cluster_center"],
534
+ metadata={"scenario_name": row["control_label"], "type": "intent_cluster"},
535
+ ),
536
+ axis=1,
537
+ )
538
+ embedding_list = df_tempclusters["embedding"].tolist()
539
+ rag_graph.kg_base.vector_store.upsert(embedding_list)
540
+
541
+ return {"rag_graph": rag_graph}
542
+
543
+
544
  @output_on_top
545
  @op("LynxScribe RAG Graph Chatbot Builder")
546
+ # @mem.cache
547
  def ls_rag_chatbot_builder(
548
  rag_graph,
549
  *,
550
  scenario_file: str = "uploads/lynx_chatbot_scenario_selector.yaml",
551
  node_types: str = "intent_cluster",
552
+ scenario_meta_name: str = "",
553
  ):
554
  """
555
  Builds up a RAG Graph-based chatbot (basically the loaded RAG graph +
 
567
  # rag_graph = rag_graph[0]["rag_graph"] TODO: check why is it bad
568
  rag_graph = rag_graph["rag_graph"]
569
 
570
+ parameters = {
571
+ "scenarios": [Scenario(**scenario) for scenario in scenarios],
572
+ "node_types": node_types,
573
+ }
574
+ if len(scenario_meta_name) > 0:
575
+ parameters["get_scenario_name"] = lambda node: node.metadata[scenario_meta_name]
576
+
577
  # loading the scenarios
578
+ scenario_selector = ScenarioSelector(**parameters)
 
 
 
579
 
580
  # TODO: later we should unify this "knowledge base" object across the functions
581
  # this could be always an input of a RAG Chatbot, but also for other apps.
 
703
  messages=[{"role": "user", "content": message["text"]}],
704
  )
705
  response = await chat_api.answer(request, stream=False)
706
+ if len(response.choices) == 0:
707
+ answer = "The following FAQ items are similar to the question:\n"
708
+ for item in response.sources:
709
+ answer += f"------------------------------------------------------ \n{item.body}\n\n"
710
+ else:
711
+ answer = response.choices[0].message.content
712
  if show_details:
713
  return {"answer": answer, **response.__dict__}
714
  else: