File size: 104,078 Bytes
95422b8
8a7f07f
5e4843b
95422b8
8a7f07f
95422b8
 
 
 
 
 
 
 
 
 
7b950b0
c275715
38f15b1
7b950b0
95422b8
5e4843b
c915e07
 
 
36fcb1c
 
b233ee2
f189340
 
 
57bb7fa
de2bf69
44ed508
 
 
ec7d7e5
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
56a067e
00ca437
 
5e4843b
 
 
 
 
7f45669
 
 
5e4843b
 
dcb2475
5e4843b
de2bf69
6f9cdd1
677ceb2
6f9cdd1
677ceb2
6f9cdd1
 
 
 
 
 
d613c1c
 
6f9cdd1
5052b34
95422b8
8a7f07f
95422b8
 
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18fdbe8
5e4843b
5660872
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
5660872
5e4843b
 
5660872
 
5e4843b
5660872
 
5e4843b
5660872
5e4843b
5660872
5e4843b
 
5660872
7b950b0
5660872
5e4843b
5660872
 
5e4843b
5660872
5e4843b
5660872
5e4843b
 
 
5660872
5e4843b
5660872
 
 
 
1debbb8
5660872
1debbb8
5660872
 
 
 
 
 
 
ecb75f4
5660872
5e4843b
5660872
5e4843b
5660872
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
 
 
 
 
 
a2b6da3
 
 
c980fe2
6fedd5b
459f5f2
6fedd5b
5660872
7b950b0
6fedd5b
8fee3d9
 
 
 
 
7b950b0
 
 
 
6fedd5b
7b950b0
8fee3d9
459f5f2
 
 
 
 
 
 
7b950b0
459f5f2
6fedd5b
 
459f5f2
 
 
 
5660872
459f5f2
 
 
8fee3d9
459f5f2
 
 
 
 
 
 
 
 
 
 
 
 
 
94dd13c
17b7002
d0a4ae9
17b7002
d3bbe3a
f37d7d2
352f7d2
f37d7d2
352f7d2
d0a4ae9
fe20127
352f7d2
9605b62
d3bbe3a
 
9605b62
8901c1a
d3bbe3a
 
 
 
d924165
d3bbe3a
 
 
 
6c780a8
95422b8
8a7f07f
 
95422b8
 
 
 
 
7522fcc
fef6f3e
c915e07
 
 
 
 
 
 
 
 
b554423
f09b0ee
433b9a4
 
 
 
28a20b9
 
 
 
 
5e4843b
 
 
 
c915e07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
4658ddf
 
8394a1b
0e1060d
479b51c
 
4658ddf
 
 
 
 
53f5338
4658ddf
 
6f8f77a
bc66a28
8394a1b
 
 
4658ddf
 
 
8394a1b
 
 
 
bc66a28
4658ddf
dbb8125
7d95fad
70bad2d
17dce32
 
188b570
70bad2d
 
 
 
 
 
 
 
 
 
 
 
 
24398ed
17dce32
 
 
 
70bad2d
 
 
 
 
 
 
 
 
 
 
 
 
b77d423
17dce32
70bad2d
 
17dce32
 
70bad2d
 
 
188b570
70bad2d
19a21e9
5e4843b
19a21e9
13954ce
11ed729
 
 
d3d9923
dff3f00
d3d9923
17dce32
59ed08b
19ed182
 
 
5e4843b
19ed182
 
 
5e4843b
19ed182
 
5e4843b
19ed182
 
 
 
f4d7288
19ed182
5e4843b
4dfc13c
19ed182
5e4843b
 
4dfc13c
19ed182
 
 
5e4843b
19ed182
f62cc88
5aacebd
af85942
59ed08b
 
 
e91decc
 
 
82c756d
 
 
7b950b0
5e4843b
60c587a
 
 
 
df8a628
5e4843b
 
6c780a8
 
5e4843b
 
 
60c587a
 
 
 
 
 
 
 
 
6650cef
 
5e4843b
 
 
aa9031c
6650cef
 
 
60c587a
 
 
 
 
 
 
 
 
6650cef
 
 
 
 
 
5e4843b
60c587a
 
 
 
5e4843b
60c587a
e3b79f7
60c587a
e3b79f7
60c587a
 
 
 
 
5e4843b
e978e51
8901c1a
f37d7d2
17b7002
d0a4ae9
17b7002
5e4843b
352f7d2
d0a4ae9
 
 
352f7d2
 
d0a4ae9
352f7d2
9605b62
5e4843b
5133070
352f7d2
 
d3bbe3a
 
 
5e4843b
deb7c94
5e4843b
 
 
 
 
 
 
 
 
 
7b950b0
 
006ee8c
7b950b0
 
006ee8c
7b950b0
 
3ddad27
 
 
481459b
 
 
 
 
3ddad27
481459b
 
 
3ddad27
481459b
3ddad27
db5c113
 
 
 
 
3ddad27
5e4843b
 
 
38dc633
56a067e
3ddad27
5e4843b
 
3ddad27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
 
3ddad27
ead518d
56a067e
 
 
511cef9
11b405b
6644b90
2b1dc8c
ba9ebc9
6644b90
511cef9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
de23c8e
 
 
9ef8b14
de23c8e
 
9ef8b14
de23c8e
 
511cef9
 
9ef8b14
 
de23c8e
9ef8b14
de23c8e
 
9ef8b14
de23c8e
 
11b405b
511cef9
 
11b405b
de23c8e
 
9ef8b14
de23c8e
 
9ef8b14
de23c8e
 
511cef9
 
 
de23c8e
 
 
9ef8b14
de23c8e
 
9ef8b14
de23c8e
 
 
 
 
511cef9
 
 
de23c8e
 
 
9ef8b14
de23c8e
 
9ef8b14
de23c8e
 
9ef8b14
511cef9
 
de23c8e
11b405b
de23c8e
 
9ef8b14
de23c8e
 
9ef8b14
de23c8e
 
 
11b405b
 
 
511cef9
 
 
d83d9ca
2b1dc8c
ba9ebc9
91178d1
11b405b
 
d83d9ca
1cfe85d
b692720
48baeaf
d83d9ca
 
af82d33
d83d9ca
 
 
 
 
f6eff22
d83d9ca
af82d33
 
f6eff22
f0011ff
310d230
aa69562
 
 
 
d83d9ca
 
f0011ff
eea7cee
931a4c2
37a103c
 
 
931a4c2
37a103c
 
931a4c2
f0011ff
7b950b0
 
 
 
 
 
 
 
 
aa69562
b1b7005
7b950b0
b1b7005
 
eea7cee
b1b7005
f0011ff
cb10830
5660872
 
 
 
 
 
 
 
 
f0011ff
5660872
f0011ff
5660872
 
 
7b950b0
5660872
 
 
 
33ac1e6
5660872
 
 
 
931a4c2
5660872
 
7b950b0
5660872
 
 
 
 
 
 
 
7b950b0
5660872
 
33ac1e6
5660872
 
 
 
7b950b0
5660872
 
 
 
 
 
931a4c2
5660872
 
 
 
c117d44
47a2dcd
e447a05
 
ad645f9
a823727
7d228d9
ae199f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35d7d6f
ae199f6
 
 
 
 
 
7d228d9
83f70cc
9bf1fa0
7528adb
9bf1fa0
 
e447a05
9bf1fa0
0e87e75
9bf1fa0
9605b62
0d31d3e
9bf1fa0
 
 
 
9605b62
9bf1fa0
9605b62
 
9bf1fa0
 
 
 
 
 
 
 
 
 
 
 
 
 
aaf6915
7668a54
 
8901c1a
677ceb2
9bf1fa0
aaf6915
9605b62
 
ee7dd71
f37d7d2
 
0e87e75
5a2965f
31b0a08
db5c113
 
 
 
 
 
 
 
 
 
 
cd1207d
cbf2cd7
db5c113
cd1207d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b1a5a5
cd1207d
 
 
 
 
3b1a5a5
cd1207d
 
 
 
 
 
 
 
 
 
 
 
3b1a5a5
cd1207d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b1a5a5
 
 
 
 
 
 
 
70ad800
df8a628
db5c113
 
 
ee1283d
ac0e33e
 
 
 
25c3fbe
5e4843b
5d5de11
 
db5c113
4dfc13c
 
 
5e4843b
 
 
 
 
 
 
 
 
82c756d
5e4843b
 
4dfc13c
7f45669
 
 
 
 
 
 
 
 
 
 
 
4dfc13c
7f45669
 
 
 
 
 
c275715
 
7f45669
 
c275715
7f45669
 
 
 
c275715
7f45669
 
c275715
7f45669
 
 
 
 
 
4dfc13c
7f45669
 
4dfc13c
 
 
5660872
9f32ae4
5660872
9f32ae4
4dfc13c
459f5f2
8064f1a
5660872
8064f1a
 
 
5660872
 
 
 
 
 
 
 
 
 
 
 
 
 
459f5f2
8064f1a
 
9f32ae4
5660872
 
459f5f2
e401282
 
b17a3f5
82c756d
 
 
 
 
e401282
 
 
 
7f14fd0
9f32ae4
 
5660872
8064f1a
4dfc13c
 
6fedd5b
 
4dfc13c
 
 
 
 
 
 
 
 
 
 
38f15b1
82c756d
 
38f15b1
 
 
7f45669
fda97b6
92c205a
 
 
7f45669
92c205a
c332dc6
92c205a
7f45669
 
 
92c205a
7f45669
 
81f21fe
7f45669
 
4dfc13c
 
50d7047
 
055b331
 
 
 
 
50d7047
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cc65d99
 
 
 
 
 
 
 
 
 
 
14d32fb
 
 
cc65d99
 
 
 
 
 
587b59a
cc65d99
 
 
 
 
 
 
 
 
 
 
055b331
 
 
 
 
 
50d7047
055b331
 
 
 
 
 
50d7047
0975101
9051fb5
c275715
9051fb5
 
 
 
649a317
9051fb5
 
 
 
 
 
 
 
 
 
 
cc65d99
 
3a50fc1
 
 
 
 
cc65d99
3a50fc1
 
 
 
cc65d99
 
 
 
6e7ad92
c579ec4
cc65d99
c579ec4
ef6fd56
c579ec4
 
 
 
 
 
649a317
a344d15
 
 
6e7ad92
a344d15
cc65d99
 
 
 
50d7047
5b338c6
6e7ad92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cc65d99
b13e442
 
 
cc65d99
 
c275715
b13e442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82c756d
cc65d99
6e7ad92
82c756d
b13e442
 
 
6e7ad92
b13e442
 
 
 
 
 
0a9c8aa
649a317
a9f2bbc
cc65d99
 
 
 
 
 
c275715
 
 
 
0aacbd4
cc65d99
 
5e4843b
95422b8
 
 
 
 
 
 
 
7b950b0
 
50d7047
c275715
7b950b0
 
 
 
 
c275715
50d7047
95422b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0188f7c
95422b8
b554423
c1ecd7d
b554423
 
3f89215
 
 
 
 
 
 
c915e07
3f89215
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4256e65
3f89215
 
 
 
 
 
 
 
 
 
 
79bdd61
89cd4f0
3f89215
 
 
 
 
 
 
 
 
 
 
c915e07
3f89215
 
 
89cd4f0
3f89215
 
 
be1faed
3f89215
 
 
be1faed
c915e07
3f89215
 
053c8b7
3f89215
 
d7b3c8f
3f89215
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6fcf6f6
a981823
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c915e07
cd2bd56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
cd2bd56
5e4843b
 
39d0e4b
12d02f3
5e4843b
 
 
 
 
 
 
 
 
 
60c587a
 
 
 
5e4843b
60c587a
 
 
 
 
 
 
 
 
5e4843b
60c587a
2694382
5e4843b
2b4daf3
 
 
5e4843b
6e3eb7c
7b950b0
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
7b950b0
2b4daf3
 
 
 
 
f6fbb60
5e4843b
7b950b0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709b3b8
2b4daf3
709b3b8
60c587a
709b3b8
2b4daf3
5e4843b
2b4daf3
5e4843b
2b4daf3
 
 
 
 
 
709b3b8
deb7c94
5e4843b
 
 
deb7c94
 
5e4843b
 
 
60c587a
5e4843b
 
 
 
 
 
5fd0b22
 
709b3b8
5fd0b22
6303851
 
 
 
709b3b8
2b4daf3
bada308
 
 
 
 
2b4daf3
 
bada308
 
 
 
2b4daf3
 
bada308
 
 
 
 
2b4daf3
 
bada308
 
 
 
2b4daf3
 
bada308
 
 
 
2b4daf3
 
bada308
 
 
 
 
2b4daf3
709b3b8
 
5fd0b22
 
709b3b8
5fd0b22
709b3b8
 
5fd0b22
 
 
2b4daf3
5fd0b22
 
2b4daf3
 
 
 
5fd0b22
 
 
 
 
709b3b8
74b4fef
6303851
4fc0f64
b7db4d3
6303851
11be43c
74b4fef
6303851
7b950b0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a9447e6
7b950b0
 
 
 
 
 
 
74b4fef
5e4843b
d43e572
 
 
 
 
 
 
 
894aa78
f6fbb60
 
 
e162bf4
677ceb2
352f7d2
677ceb2
059d224
e162bf4
 
352f7d2
 
 
 
 
 
 
 
 
 
 
 
 
53a8010
352f7d2
 
 
e162bf4
 
e1ef835
894aa78
85cba4d
894aa78
d31b02a
 
b8068bd
f041efd
83bfe1d
5e4843b
83bfe1d
dbd2afe
5e4843b
cd0af1c
894aa78
ae119d4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef81583
83bfe1d
a69a435
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8bc8ce4
 
 
 
 
a69a435
 
 
 
8bc8ce4
602c701
8bc8ce4
a69a435
 
 
 
f640c7d
a69a435
f640c7d
8bc8ce4
f640c7d
 
 
4fc0f64
 
6e3eb7c
a69a435
 
 
 
 
 
1492f8f
8bc8ce4
a69a435
 
 
d93473d
 
a881122
 
 
b7db4d3
8bc8ce4
 
 
a881122
a69a435
8bc8ce4
a69a435
8bc8ce4
a69a435
 
8bc8ce4
 
a69a435
 
 
8bc8ce4
a69a435
8bc8ce4
a69a435
 
 
8bc8ce4
a69a435
 
 
 
c275715
 
92c205a
 
 
 
 
 
 
 
 
 
 
 
 
 
587b59a
92c205a
 
587b59a
92c205a
 
fda97b6
92c205a
06bc3f3
ac29500
82c756d
c275715
70a7076
eea3f6d
92c205a
 
e2dcd75
 
 
 
 
 
 
 
9bd776a
e2dcd75
 
 
 
 
92c205a
e2dcd75
 
c275715
 
 
 
a69a435
 
c275715
a69a435
 
 
92c205a
 
a69a435
92c205a
 
b0f61b4
b3661b9
92c205a
ac5c6a0
a69a435
d93473d
92c205a
d93473d
1492f8f
a69a435
 
 
83bfe1d
92c205a
b0f61b4
a69a435
602c701
a69a435
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
import logging
import os
import streamlit as st 
from dotenv import load_dotenv
import openai
from langchain_openai import ChatOpenAI
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import tool, AgentExecutor
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser
from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages
from langchain_core.messages import AIMessage, HumanMessage
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
from langchain.text_splitter import RecursiveCharacterTextSplitter
from urllib.parse import quote, urlparse
import redis

import serpapi
import requests 
import streamlit.components.v1 as components
import smtplib
from email.mime.multipart import MIMEMultipart
from datetime import datetime
import pandas as pd
import re
from io import BytesIO
import base64

import random
from bs4 import BeautifulSoup
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from markdownify import markdownify
import chargebee
import pyrebase
import streamlit.components.v1 as components
import time
import warnings
from streamlit.components.v1 import html
from langchain.docstore.document import Document  
import firebase_admin
import uuid
import json
import io
from firebase_admin import credentials, firestore
import base64
from pdfminer.high_level import extract_text  # Import for PDF text extraction
from PIL import Image
from PyPDF2 import PdfReader
import docx

st.set_page_config(layout="wide")
import logging
import asyncio
import re 
from langchain_community.tools import TavilySearchResults


# Set up logging to suppress Streamlit warnings about experimental functions
logging.getLogger('streamlit').setLevel(logging.ERROR)
INITIAL_MESSAGE_LIMIT = 100


if "wix_user_id" not in st.session_state:
    st.session_state["wix_user_id"] = str(uuid.uuid4())  # Assign unique user ID for the session
if "email" not in st.session_state:
    st.session_state["email"] = f"user_{uuid.uuid4()}@example.com"
if "message_limit" not in st.session_state:
    st.session_state["message_limit"] = 1000
if "used_messages" not in st.session_state:
    st.session_state["used_messages"] = 0
if "chat_history" not in st.session_state:
    st.session_state["chat_history"] = []
if "documents" not in st.session_state:
    st.session_state["documents"] = {}

# Initialize logging and load environment variables
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
load_dotenv()

chargebee.configure(site="mextconsulting", api_key="live_dBLXn8yG5dFcuIgU5Szebj2KfTcdt4hjpf")

# Firebase Configuration
firebase_config = {
    "apiKey": "AIzaSyAWiaqrduoG7fzmJxBVnVg9nCC4EoEnwfY",
    "authDomain": "trustai-3e7a2.firebaseapp.com",
    "databaseURL": "https://trustai-3e7a2-default-rtdb.firebaseio.com",
    "projectId": "trustai-3e7a2",
    "storageBucket": "trustai-3e7a2.appspot.com",
    "messagingSenderId": "964339831031",
    "appId": "1:964339831031:web:66d21ceea68ab03f1043f2",
   "measurementId": "G-ZMLZQZMHK2"
}
# Initialize Firebase
firebase = pyrebase.initialize_app(firebase_config)
db = firebase.database()
storage = firebase.storage()

backend_url = "https://backend-web-05122eab4e09.herokuapp.com"


def convert_file_to_txt(file):
    """
    Convert different file types to plain text.
    """
    if file.type == "application/pdf":
        return convert_pdf_to_txt(file)
    elif file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
        return convert_docx_to_txt(file)
    elif file.type == "text/plain":
        return convert_txt_to_txt(file)
    elif file.type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
        return convert_excel_to_txt(file)
    elif file.type == "text/csv":
        return convert_csv_to_txt(file)
    else:
        st.sidebar.warning(f"Unsupported file type: {file.type}")
        return None

def convert_pdf_to_txt(file):
    """
    Convert a PDF file to plain text.
    """
    try:
        text = extract_text(file)  # Use PyPDF2 or pdfplumber for better accuracy if needed
        return text.strip()
    except Exception as e:
        st.sidebar.error(f"Error converting PDF to TXT: {e}")
        return None

def convert_docx_to_txt(file):
    """
    Extract text from a .docx file.
    """
    try:
        doc = docx.Document(file)
        text = "\n".join([paragraph.text for paragraph in doc.paragraphs])
        return text.strip()
    except Exception as e:
        st.sidebar.error(f"Error converting DOCX to TXT: {e}")
        return None

def convert_txt_to_txt(file):
    """
    Handle plain text file as is.
    """
    try:
        text = file.read().decode("utf-8")
        return text.strip()
    except Exception as e:
        st.sidebar.error(f"Error reading TXT file: {e}")
        return None

def convert_excel_to_txt(file):
    """
    Convert an Excel file to plain text.
    """
    try:
        df = pd.read_excel(file)
        text = df.to_string(index=False)
        return text.strip()
    except Exception as e:
        st.sidebar.error(f"Error converting Excel to TXT: {e}")
        return None

def convert_csv_to_txt(file):
    """
    Convert a CSV file to plain text.
    """
    try:
        df = pd.read_csv(file)
        text = df.to_string(index=False)
        return text.strip()
    except Exception as e:
        st.sidebar.error(f"Error converting CSV to TXT: {e}")
        return None









    

def merge_markdown_contents(contents):
    """
    Merge multiple Markdown contents into a single Markdown string.
    """
    merged_content = "\n\n---\n\n".join(contents)
    return 


def upload_to_firebase(user_id, file):
    """
    Upload document to Firebase, extract content, and add it to the knowledge base.
    """
    content = convert_file_to_txt(file)  # Ensure this function extracts content correctly
    if not content:
        return None, "Failed to extract content from the file."
    
    existing_files = st.session_state.get("documents", {})
    for doc_id, doc_data in existing_files.items():
        if doc_data["name"] == file.name and doc_data["content"] == content:
            return None, f"File '{file.name}' already exists."

    doc_id = str(uuid.uuid4())
    document_data = {"content": content, "name": file.name}

    # Save document to Firebase
    db.child("users").child(user_id).child("KnowledgeBase").child(doc_id).set(document_data)
    fetch_documents() 
    # Add content to the knowledge base
    if "knowledge_base" not in st.session_state:
        st.session_state["knowledge_base"] = []
    st.session_state["knowledge_base"].append({"doc_id": doc_id, "content": content})

    # Index the document content for semantic search
    index_document_content(content, doc_id)

    st.sidebar.success(f"Document '{file.name}' uploaded successfully and added to the knowledge base!")
    return content, None

def index_document_content(doc_content, doc_id):
    """
    Indexes the document content by splitting it into chunks and creating embeddings.
    """
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=500)
    texts = text_splitter.split_text(doc_content)

    # Create embeddings for each chunk
    embeddings = OpenAIEmbeddings(model="text-embedding-ada-002", api_key=openai_api_key)
    doc_metadata = [{"doc_id": doc_id, "chunk_id": i} for i in range(len(texts))]
    vector_store = FAISS.from_texts(texts, embeddings, metadatas=doc_metadata)

    # Save the vector store in session state
    if "vector_store" not in st.session_state:
        st.session_state["vector_store"] = {}
    st.session_state["vector_store"][doc_id] = vector_store







def fetch_trustbuilders(user_id):
    """
    Retrieve TrustBuilders from Firebase for a specific user.
    """
    try:
        trustbuilders = db.child("users").child(user_id).child("TrustBuilders").get().val()
        
        if trustbuilders:
            # Extract content from TrustBuilders
            return [tb["content"] for tb in trustbuilders.values()]
        else:
            st.warning("No TrustBuilders found in Firebase.")
            return []
    except Exception as e:
        st.error(f"Error fetching TrustBuilders: {e}")
        return []

def delete_trustbuilder(user_id, trustbuilder_id):
    try:
        db.child("users").child(user_id).child("TrustBuilder").child(trustbuilder_id).remove()
        st.success("TrustBuilder deleted successfully.")
        st.rerun()
    except Exception as e:
        st.error(f"Error deleting TrustBuilder: {e}")

        

# Define and validate API keys
openai_api_key = os.getenv("OPENAI_API_KEY")
serper_api_key = os.getenv("SERPER_API_KEY")

if not openai_api_key or not serper_api_key:
    logger.error("API keys are not set properly.")
    raise ValueError("API keys for OpenAI and SERPER must be set in the .env file.")

openai.api_key = openai_api_key


st.markdown("""
    <style>
    .custom-image img {
        width: 100px;  /* Set the width to make the image smaller */
        height: auto;  /* Keep the aspect ratio */
    }
    </style>
    """, unsafe_allow_html=True)
if "chat_started" not in st.session_state:
    st.session_state["chat_started"] = False
if 'previous_trust_tip' not in st.session_state:
    st.session_state.previous_trust_tip = None
if 'previous_suggestion' not in st.session_state:
    st.session_state.previous_suggestion = None

if 'used_trust_tips' not in st.session_state:
    st.session_state.used_trust_tips = set()
if 'used_suggestions' not in st.session_state:
    st.session_state.used_suggestions = set()


# Suppress Streamlit deprecation and warning messages

def copy_to_clipboard(text):
    """Creates a button to copy text to clipboard."""
    escaped_text = text.replace('\n', '\\n').replace('"', '\\"')
    copy_icon_html = f"""
    <style>
    .copy-container {{
        position: relative;
        margin-top: 10px;
        padding-bottom: 30px; /* Space for the button */
        font-size: 0; /* Hide extra space */
    }}
    .copy-button {{
        background: none;
        border: none;
        color: #808080; /* Grey color */
        cursor: pointer;
        font-size: 18px; /* Adjust icon size */
        position: absolute;
        bottom: 0;
        right: 0;
    }}
    .copy-button:hover {{
        color: #606060; /* Darker grey on hover */
    }}
    .copy-message {{
        font-size: 12px;
        color: #4CAF50;
        margin-left: 10px;
        display: none;
    }}
    </style>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <div class="copy-container">
        <button class="copy-button" onclick="copyToClipboard()">
            <i class="fas fa-copy"></i>
        </button>
        <span class="copy-message" id="copy_message">Copied!</span>
    </div>
    
    <script>
    function copyToClipboard() {{
        var textArea = document.createElement("textarea");
        textArea.value = "{escaped_text}";
        document.body.appendChild(textArea);
        textArea.select();
        document.execCommand("copy");
        document.body.removeChild(textArea);
        
        var copyMessage = document.getElementById("copy_message");
        copyMessage.style.display = "inline";
        setTimeout(function() {{
            copyMessage.style.display = "none";
        }}, 2000);
    }}
    </script>
    """
    components.html(copy_icon_html, height=60)
 
def send_feedback_via_email(name, email, feedback):
    """Sends an email with feedback details."""
    smtp_server = 'smtp.office365.com'  
    smtp_port = 465  # Typically 587 for TLS, 465 for SSL
    smtp_user = os.getenv("EMAIL_ADDRESS") 
    smtp_password = os.getenv("Password")   

    msg = MIMEMultipart()
    msg['From'] = smtp_user
    msg['To'] = "wajahat698@gmail.com"
    msg['Subject'] = 'Feedback Received'
    
    body = f"Feedback received from {name}:\n\n{feedback}"
    msg.attach(MIMEText(body, 'plain'))

    try:
        with smtplib.SMTP(smtp_server, smtp_port, timeout=10) as server:
            server.set_debuglevel(1)  # Enable debug output for troubleshooting
            server.starttls()  
            server.login(smtp_user, smtp_password)
            server.sendmail(smtp_user, email, msg.as_string())
            st.success("Feedback sent via email successfully!")
    except smtplib.SMTPConnectError:
        st.error("Failed to connect to the SMTP server. Check server settings and network connectivity.")
    except smtplib.SMTPAuthenticationError:
        st.error("Authentication failed. Check email and password.")
    except Exception as e:
        st.error(f"Error sending email: {e}")



def clean_text(text):
    text = text.replace('\\n', '\n')

    # Remove all HTML tags, including nested structures
    text = re.sub(r'<[^>]*>', '', text)
    # Remove any remaining < or > characters
    text = text.replace('<', '').replace('>', '')
    text = re.sub(r'<[^>]+>', '', text)
    text = re.sub(r'(\d+)\s*(B|M|T|billion|million|trillion)', lambda m: f"{m.group(1)} {m.group(2)}", text)    
    text = re.sub(r'(\d)\s*([a-zA-Z])', r'\1 \2', text)  # Fix numbers next to letters
    text = re.sub(r'(\d+)\s+([a-zA-Z])', r'\1 \2', text)  # Fix broken numbers and words
    text = re.sub(r'<span class="(mathnormal|mord)">.*?</span>', '', text, flags=re.DOTALL)

    # Split the text into paragraphs
    paragraphs = text.split('\n\n')
    
    cleaned_paragraphs = []
    for paragraph in paragraphs:
        lines = paragraph.split('\n')
        cleaned_lines = []
        for line in lines:
            # Preserve bold formatting for headings
            if line.strip().startswith('**') and line.strip().endswith('**'):
                cleaned_line = line.strip()
            else:
                # Remove asterisks, special characters, and fix merged text
                cleaned_line = re.sub(r'\*|\−|\∗', '', line)
                cleaned_line = re.sub(r'([a-z])([A-Z])', r'\1 \2', cleaned_line)
            
            # Handle bullet points
            if cleaned_line.strip().startswith('-'):
                cleaned_line = '\n' + cleaned_line.strip()
            
            # Remove extra spaces
          
            cleaned_lines.append(cleaned_line)
        
        # Join the lines within each paragraph
        cleaned_paragraph = '\n'.join(cleaned_lines)
        cleaned_paragraphs.append(cleaned_paragraph)
    
    # Join the paragraphs back together
    cleaned_text = '\n\n'.join(para for para in cleaned_paragraphs if para)
    return cleaned_text
    

 
  

def get_trust_tip_and_suggestion():
    trust_tip = random.choice(trust_tips)
    suggestion = random.choice(suggestions)
    return trust_tip, suggestion




from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.schema import Document

def load_main_data_source():
    """
    Load the main data source, split it into chunks, and return Document objects.
    """
    try:
        # Load the main data source
        with open("./data_source/time_to_rethink_trust_book.md", "r", encoding="utf-8") as f:
            main_content = f.read()

        # Use a more robust text splitter
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=2000,  # Adjust the chunk size based on your LLM's token limit
            chunk_overlap=500,  # Add overlap to improve context continuity
        )
        main_texts = text_splitter.split_text(main_content)

        # Create Document objects for the split texts
        main_documents = [Document(page_content=text) for text in main_texts]
        return main_documents

    except FileNotFoundError:
        st.error("The file './data_source/time_to_rethink_trust_book.md' was not found.")
        return []

    except Exception as e:
        st.error(f"An unexpected error occurred while loading ")





def refresh_faiss_index():
    combined_sources = load_main_data_source()
    if combined_sources:
        embeddings = OpenAIEmbeddings()
        db_faiss = FAISS.from_documents(combined_sources, embeddings)
        st.session_state["faiss_db"] = db_faiss


def update_message_counter():
    remaining_messages = st.session_state["message_limit"] - st.session_state["used_messages"]
    message_counter_placeholder = st.sidebar.empty()

    message_counter_placeholder.markdown(f" Message left : unlimited \n\n Unlimited chats for a limited time")




def store_brand_tonality(user_id, message):
    try:
        tonality_id = str(uuid.uuid4())
        # Save to Firebase
        db.child("users").child(user_id).child("BrandTonality").child(tonality_id).set({"message": message})

        # Update `st.session_state` for immediate sidebar display
        if "BrandTonality" not in st.session_state:
            st.session_state["BrandTonality"] = {}
        st.session_state["BrandTonality"][tonality_id] = {"message": message}

        # Confirmation
        display_save_confirmation("Brand Tonality")

    except Exception as e:
        st.error(f"Error saving Brand Tonality: {e}")


def store_trustbuilder(user_id, message):
    try:
        trustbuilder_id = str(uuid.uuid4())
        # Save to Firebase
        db.child("users").child(user_id).child("TrustBuilder").child(trustbuilder_id).set({"message": message})

        # Update `st.session_state` for immediate sidebar display
        if "TrustBuilder" not in st.session_state:
            st.session_state["TrustBuilder"] = {}
        st.session_state["TrustBuilder"][trustbuilder_id] = {"message": message}

        # Confirmation
        display_save_confirmation("TrustBuilder")

    except Exception as e:
        st.error(f"Error saving TrustBuilder: {e}")


def load_user_content(user_id):
    """
    Load all content for a user from Firebase, ensuring each user has a single root
    containing TrustBuilder, BrandTonality, and other data fields like email, message limits, etc.
    """
    try:
        user_data = db.child("users").child(user_id).get().val()
        if user_data:
            # Update session state with all user data
            st.session_state.update(user_data)
            
            # Load TrustBuilder and BrandTonality into session state for display
            st.session_state["TrustBuilder"] = user_data.get("TrustBuilder", {})
            st.session_state["BrandTonality"] = user_data.get("BrandTonality", {})
            
    except Exception as e:
         st.info("not loaded ")

def save_content(user_id, content):
    """
    Save a TrustBuilder as plain text under the user's TrustBuilders node in Firebase.
    """
    try:
        # Prepare the TrustBuilder data
        trustbuilder_data = {
            "content": content
        }
        
        # Push to TrustBuilders node under the user's ID
        db.child("users").child(user_id).child("TrustBuilders").push(trustbuilder_data)
        
        st.success("TrustBuilder saved successfully!")
    except Exception as e:
        st.error(f"Error saving TrustBuilder: {e}")

        
def ai_allocate_trust_bucket(trust_builder_text):
    # Implement your AI allocation logic here
    return "Stability"

        

def download_link(content, filename):
    """
    Create a download link for content.
    """
    b64 = base64.b64encode(content.encode()).decode()
    return f'<a href="data:text/plain;base64,{b64}" download="{filename}">Download</a>'




def fetch_documents():
    try:
        docs = db.child("users").child(st.session_state["wix_user_id"]).child("KnowledgeBase").get().val()
        st.session_state["documents"] = docs if docs else {}
    except Exception as e:
        st.sidebar.error(f"Error fetching documents: {e}")
        st.session_state["documents"] = {}



# Function to delete a document from Firebase
def delete_document(user_id, doc_id):
    """
    Deletes a document from Firebase.
    """
    try:
        db.child("users").child(user_id).child("KnowledgeBase").child(doc_id).remove()
        st.success("Document deleted successfully!")
        st.rerun()  # Refresh the list after deletion
    except Exception as e:
        st.error(f"Error deleting document: {e}")







def side():
    with st.sidebar:

        with st.sidebar.expander("**TrustLogic®**", expanded=False):
                st.image("Trust Logic_Wheel_RGB_Standard.png")
            
                st.markdown(
                    """
                    **TrustLogic®** is a proven, scientific method for building trust, showing how our minds process trust.  
                    Remember:
            
                    You can’t trust in general – only for specific reasons.
            
                    Our mind organizes these reasons into six types of trust:  
                    **Stability**, **Development**, **Relationship**, **Benefit**, **Vision**, and **Competence**.  
                    Together, they form your **trust score**. Every bit more trust counts and can be nudged up in each interaction.
            
                    Think of these as the **Six Buckets of Trust®** – the fuller each bucket, the greater the trust.
            
                    To build trust, understand what makes you more trustworthy in each **Trust Bucket®** and convey these **Trust Builders®** – because what I don’t know about you, I can’t trust.
            
                    **Stability + Development + Relationship + Benefit + Vision + Competence Trust = Your Trust.**
                    """
                )
                st.markdown("For detailed descriptions, visit [Academy](https://www.trustifier.ai/account/academy)")

            
        st.image("Trust Logic_Wheel_RGB_Standard.png")
        
        st.sidebar.markdown('<hr style="border: 2px solid rgb(255, 153, 0); width: 80%; margin: 20px auto;">', unsafe_allow_html=True)
                
        with st.sidebar.expander("**Trust Buckets® and Trust Builders®**", expanded=False):
                        
                        st.image("s (3).png")  # Adjust width as needed

                        
                        st.markdown(
                            "Our minds assess trust through Six Buckets of Trust® and determine their importance and order in a given situation. We then evaluate why we can or can’t trust someone in these Buckets. Trustifier.ai®, trained on 20 years of TrustLogic® application, helps you identify reasons why your audience can trust you in each Bucket and create trust-optimised solutions. It’s copy AI with substance."
                        )
                        st.markdown(
                            """
                            <style>
                                .stability { color: rgb(7, 55, 99); font-size: 24px; font-weight: bold; }
                                .development { color: rgb(241, 194, 50); font-size: 24px; font-weight: bold; }
                                .relationship { color: rgb(204, 0, 0); font-size: 24px; font-weight: bold; }
                                .benefit { color: rgb(56, 118, 29); font-size: 24px; font-weight: bold; }
                                .vision { color: rgb(255, 153, 0); font-size: 24px; font-weight: bold; }
                                .competence { color: rgb(111, 168, 220); font-size: 24px; font-weight: bold; }
                            </style>
                
                            <h3 class="stability">Stability Trust:</h3>
                            <p>Why can I trust you to have built a strong and stable foundation?</p>
                            <h5>Examples</h5>
                            <ul>
                                <li>
                                    Volkswagen Auto Lease Trust 2023-A's note issuance is an ABS transaction backed by prime automobile lease receivables. This ensures financial reliability for investors.
                                </li>
                                <li>
                                    The Group aims to reduce the life-cycle carbon emissions of its vehicles by <strong>30%</strong> compared to 2018, promoting environmental responsibility for customers.
                                </li>
                            </ul>
                            <h3 class="development">Development Trust:</h3>
                            <p>Why can I trust you to develop well in the future?</p>
                            <h5>Examples</h5>
                             <ul>
                                <li>
                                    In 2023, Volkswagen announced a <strong>€1 billion</strong> investment in a new development and procurement center for electric vehicles in Hefei, China, enhancing the company's commitment to e-mobility. This supports technological advancement for eco-conscious consumers.
                                </li>
                                <li>
                                    Volkswagen Group of America launched its first autonomous vehicle test program in Austin, Texas, in July 2023, spearheaded by a dedicated team of engineers. This supports innovation for tech enthusiasts.
                                </li>
                            </ul>
                            
                            <h3 class="relationship">Relationship Trust:</h3>
                            <p>What appealing relationship qualities can I trust you for?</p>
                            <h5>Examples</h5>
                            <ul>
                                <li>
                                    In March 2023, Volkswagen joined forces with <strong>20 universities</strong> worldwide to advance automotive research, impacting over <strong>5,000 students</strong>. This promotes educational partnerships for academic institutions.
                                </li>
                                <li>
                                    Dr. Herbert Diess, CEO of Volkswagen, led initiatives in 2023 to engage <strong>3,000 employees</strong> in community volunteering projects, enhancing corporate social responsibility. This supports community engagement for employees.
                                </li>
                            </ul>
                
                            <h3 class="benefit">Benefit Trust:</h3>
                            <p>What benefits can I trust you for?</p>
                            <h5>Examples</h5>
                            <ul>
                                <li>
                                    Volkswagen's commitment to becoming a <strong>net-carbon-neutral</strong> company by 2050 includes using recycled materials to reduce primary raw material needs, supporting sustainability. This promotes environmental responsibility for future generations.
                                </li>
                                <li>
                                    The company has reduced water consumption by <strong>24%</strong>, waste by <strong>75%</strong>, and VOC emissions by <strong>68%</strong> per vehicle as of 2023, highlighting its dedication to minimizing environmental impact. This supports eco-friendly manufacturing for industry stakeholders.
                                </li>
                            </ul>
                            
                            
                                                        
                
                            <h3 class="vision">Vision Trust:</h3>
                            <p>What Vision and Values can I trust you for?</p>
                            <h5>Examples</h5>
                            <ul>
                                <li>
                                    The company has committed to investing <strong>€180 billion</strong> between 2023 and 2027 in areas like battery technology, digitalization, and e-mobility, driving forward its vision of sustainable transport. This supports technological advancement for stakeholders.
                                </li>
                                <li>
                                    Volkswagen's <strong>"NEW AUTO"</strong> strategy, unveiled in 2023, aims to transform the company into a leading provider of sustainable and software-driven mobility solutions by 2030. This supports future mobility innovation for the automotive industry.
                                </li>
                            </ul>
    
                            <h3 class="competence">Competence Trust:</h3>
                            <p>What competencies can I trust you for?</p>
                            <h5>Examples</h5>
                            
                            <ul>
                                <li>
                                    Volkswagen's manufacturing plants in Wolfsburg, Germany, are known for their advanced automation and production techniques, producing over <strong>800,000 vehicles annually</strong>. This supports manufacturing excellence for industry professionals.
                                </li>
                                <li>
                                    Volkswagen's design team, led by <strong>Klaus Bischoff</strong>, has received accolades for innovative vehicle designs, enhancing aesthetic appeal and functionality. For instance, the Volkswagen Touareg received the top gold award in the "Passenger Vehicles" category at the German Design Awards. This supports creativity for automotive designers.
                                </li>
                            </ul>
                                                      
                            
                            
                            
                            """, unsafe_allow_html=True
                        )
                        st.markdown("For detailed descriptions, visit [Academy](https://www.trustifier.ai/account/academy)")

        st.image("s (3).png")  # Adjust width as needed


                
        st.sidebar.markdown('<hr style="border: 2px solid rgb(255, 153, 0); width: 80%; margin: 20px auto;">', unsafe_allow_html=True)

        st.header("TrustVault®")
        st.markdown("In the TrustVault you can save your preferred trust equity Trust Builders®, great outputs, brand and segment info for easy use.")
        st.sidebar.markdown("""
            <style>
            .scrollable-container {
                max-height: 200px;
                overflow-y: auto;
                border: 1px solid gray;
                padding: 10px;
                border-radius: 5px;
                background-color: #f9f9f9;
                margin-bottom: 10px;
            }
            .button-container {
                display: flex;
                justify-content: space-between;
                gap: 10px;
            }
            .stTextArea [data-baseweb="textarea"] {
                    resize: none; /* Disable resizing */
                    overflow: hidden; /* Hide scrollbars */
                }
            </style>
        """, unsafe_allow_html=True)
            
        # Fetch documents from Firebase
        
        if "documents" not in st.session_state:
            try:
                docs = db.child("users").child(st.session_state["wix_user_id"]).child("KnowledgeBase").get().val()
                st.session_state["documents"] = docs if docs else {}
            except Exception as e:
                st.sidebar.error(f"Error fetching documents: {e}")
                st.session_state["documents"] = {}
        
        def update_saved_docs_content():
            return "\n\n---\n\n".join(
                [
                    f"**{doc_data.get('name', f'Document {doc_id[:8]}')}**\n{doc_data.get('content', 'No content available')}"
                    for doc_id, doc_data in st.session_state["documents"].items()
                ]
            ) if st.session_state["documents"] else "Save documents like your brand tonality, key phrases, or segments here and they will show here."
        saved_docs_content = update_saved_docs_content()

        st.text_area(
            label="",
            value=saved_docs_content,
            height=150,
            key="saved_documents_text_area",
            disabled=True
        )
        
        # File uploader
        uploaded_files = st.file_uploader(
            "",
            type=["pdf", "docx", "txt"],
            accept_multiple_files=True,
            key="file_uploader"
        )        
        
        if uploaded_files:
            for uploaded_file in uploaded_files:
                try:
                    upload_to_firebase(st.session_state["wix_user_id"], uploaded_file)
                except Exception as e:
                    st.sidebar.error(f"Error processing file '{uploaded_file.name}': {e}")
        
        
        # Display and delete functionality for documents
        if st.session_state.get("documents"):
            doc_ids = list(st.session_state["documents"].keys())
            doc_options = ["None (use only main knowledge base)"] + doc_ids
            selected_options = st.multiselect(
                "",
                options=doc_options,
                default="None (use only main knowledge base)",
                format_func=lambda x: st.session_state["documents"][x].get("name", f"Document {x}") if x != "None (use only main knowledge base)" else x,
                key="select_docs"
            )
            selected_doc_ids = [doc_id for doc_id in selected_options if doc_id != "None (use only main knowledge base)"]
            st.session_state['selected_doc_ids'] = selected_doc_ids

            if selected_doc_ids:
                selected_doc_names = [st.session_state['documents'][doc_id]['name'] for doc_id in selected_doc_ids]
                st.info(f"Selected Documents: {', '.join(selected_doc_names)}")
            else:
                st.sidebar.info("Using only the main knowledge base.")
        else:
          
            selected_doc_ids = []
        
        # Button to delete the selected documents
        if selected_doc_ids:
            if st.button("Delete ", key="delete_button"):
                try:
                    for doc_id in selected_doc_ids:
                        # Remove the document from Firebase
                        db.child("users").child(st.session_state["wix_user_id"]).child("KnowledgeBase").child(doc_id).remove()
        
                        # Remove from session state
                        st.session_state["vector_store"].pop(doc_id, None)
                        st.session_state["documents"].pop(doc_id, None)
        
                    st.success("Selected documents deleted successfully!")
                    st.rerun()
                except Exception as e:
                    st.error(f"Error deleting documents: {e}")


        
        st.sidebar.markdown("</div>", unsafe_allow_html=True)
        trust_buckets = ["Any","Stability", "Development", "Relationship", "Benefit", "Vision", "Competence"]

      
        


        st.markdown("""
            <style>
            .info-icon {
                display: inline-block;
                margin-left: 8px;
                color: #007BFF;
                cursor: pointer;
                position: relative;
            }
            .tooltip {
                visibility: hidden;
                width: 250px;
                background-color: #555;
                color: #fff;
                text-align: center;
                border-radius: 5px;
                padding: 5px;
                position: absolute;
                z-index: 1;
                bottom: 125%; /* Position above the icon */
                left: 50%;
                margin-left: -125px; /* Center the tooltip */
                opacity: 0;
                transition: opacity 0.3s;
            }
            .info-icon:hover .tooltip {
                visibility: visible;
                opacity: 1;
            }
            </style>
        """, unsafe_allow_html=True)
        
        # Add the header with the info icon and hover effect
        st.markdown("""
            <div style="display: flex; align-items: center;">
                <h3>Show My TrustBuilders®</h3>
                <div class="info-icon">

                    <span class="tooltip">You can ask AI to find your TrustBuilders® also by prompting "show my saved trustbuilders".</span>
                </div>
            </div>
        """, unsafe_allow_html=True)

        
        search_query = st.text_input("Search by keyword", key="search_query")
        st.write("or")
        search_query1 = st.text_input("Search by Brand/Product/Person", key="search_query1")
        
        # Dropdown for selecting a trust bucket
        selected_bucket = st.selectbox("Select Trust Bucket", trust_buckets, key="selected_bucket")
        
        # Button to show results
        if st.button("Show TrustBuilders", key="show_trustbuilders"):
            # Fetch trustbuilders
            trustbuilders = fetch_trustbuilders(st.session_state.get("wix_user_id"))
          
            # Initialize variable for a match
            matching_trustbuilders = []
        
            # Filter trustbuilders based on the criteria
            for tb in trustbuilders:
                # Split bucket and text
                bucket, text = tb.split(": ", 1) if ": " in tb else ("", tb)
        
                # Check if bucket matches or "Any" is selected
                bucket_matches = selected_bucket == "Any" or bucket == selected_bucket
        
                # Match keyword or brand/product/person search
                keyword_match = search_query.lower() in text.lower() if search_query else False
                additional_match = search_query1.lower() in text.lower() if search_query1 else False
        
                # Append if all conditions are met
                if bucket_matches and (keyword_match or additional_match):
                    matching_trustbuilders.append(tb)
        
            # Display the first matching trustbuilder
            if matching_trustbuilders:
                st.write("### Result:")
                # Join the matching trustbuilders into a bullet list
                escaped_trustbuilders = [tb.replace('$', '\\$') for tb in matching_trustbuilders]
                st.markdown("\n".join([f"- {tb}" for tb in escaped_trustbuilders]))
            else:
                st.write("No TrustBuilders found matching the criteria.")


            
                # UI for saving TrustBuilders
        st.subheader("Save TrustBuilders®")
        brand_save = st.text_input("Brand/Product/Person", key="brand_input_save")
        trust_builder_text = st.text_area("Type/paste Trust Builder®", key="trust_builder_text")
        trust_buckets = ["Stability", "Development", "Relationship", "Benefit", "Vision", "Competence"]
        selected_save_bucket = st.selectbox("Allocate to®", trust_buckets, key="save_bucket")
        
        col1, col2 = st.columns([1, 1])  # Adjust column widths as needed
        with col1:

            if st.button("Allocate", key="save_trustbuilder"):
                        if trust_builder_text.strip() and selected_save_bucket:
                            content_to_save = f"{selected_save_bucket}: Brand: {brand_save.strip()} | {trust_builder_text.strip()}"
                            save_content(st.session_state.get("wix_user_id"), content_to_save)
                        else:
                            st.warning("Please fill all fields")
    
        with col2:
            
            tooltip_css = """
                <style>
                    /* Tooltip container styling */
                    .tooltip-container {
                        position: relative; 
                        display: inline-block; 
                        vertical-align: top; 
                        width: 100%;
                        margin-top: -15px; /* Aligns with st.button */
                    }
        
                    /* Tooltip text styling */
                    .tooltip-container .tooltiptext {
                        visibility: hidden;
                        width: 300px; /* Fixed width for better readability */
                        max-width: 90%; /* Ensure tooltip fits within sidebar */
                        background-color: #f9f9f9;
                        color: #333;
                        text-align: left;
                        border-radius: 8px;
                        padding: 10px;
                        box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
                        position: absolute;
                        z-index: 1000; /* Ensure tooltip is above other elements */
                        top: calc(100% + 10px); /* Position tooltip below the button with spacing */
                        left: 50%; /* Center horizontally */
                        transform: translateX(-50%);
                        opacity: 0;
                        transition: opacity 0.3s ease-in-out;
                    }
        
                    /* Show tooltip on hover */
                    .tooltip-container:hover .tooltiptext {
                        visibility: visible;
                        opacity: 1;
                    }
        
                    /* Button styling */
                    .tooltip-container button {
                        background-color: rgb(82, 129, 134);
                        color: white;
                        border: none;
                        padding: 8px 16px;
                        font-size: 14px;
                        border-radius: 5px;
                        cursor: pointer;
                        box-shadow: 0px 4px 8px rgba(0,0,0,0.2);
                        font-family: Arial, sans-serif;
                    }
        
                    /* Hover effect for button */
                    .tooltip-container button:hover {
                        background-color: rgb(70, 115, 119);
                    }
                </style>
            """
        
            # Inject CSS
            st.markdown(tooltip_css, unsafe_allow_html=True)
        
            # Tooltip Button
            st.markdown("""
                <div class="tooltip-container">
                    <button>LetAI Allocate</button>
                    <span class="tooltiptext">
                        <b>Here’s how you can save your TrustBuilder®:</b><br><br>
                        1. Type your TrustBuilder® in the chat.<br>
                        2. If unsure of the TrustBucket®, ask the AI:<br>
                           <i>"Hey, which TrustBucket does this TrustBuilder® belong to?"</i><br><br>
                        3. Save it using the following format:<br>
                           <code>Save this as a TrustBuilder. [BucketName]. [TrustBuilder Text]</code><br><br>
                        Example:<br>
                           <code>Save this as a TrustBuilder. Stability. We focus on keeping and nurturing our team.</code>
                    </span>
                </div>
            """, unsafe_allow_html=True)
        
        
        
        




side()
update_message_counter()
if st.session_state.get("wix_user_id") and "faiss_db" not in st.session_state:
    refresh_faiss_index()










 

# Define search functions
def search_knowledge_base(query):
    """
    Searches the FAISS index using the provided query.
    Returns the most relevant documents based on the query.
    """
    if "faiss_db" not in st.session_state:
        st.error("FAISS database is not initialized.")
        return []

    # Retrieve the top 5 most relevant documents
    retrieved_docs = st.session_state["faiss_db"].similarity_search(query, k=3)
    return retrieved_docs

def google_search(query):
    """
    Performs a Google search using the SerpApi service and retrieves search result snippets.
    This function uses the SerpApi client to perform a Google search based on the provided query.
    It extracts and returns the snippets from the organic search results.
    Args:
        query (str): The search query to be used for the Google search.
    Returns:
        list: A list of snippets from the organic search results. If an error occurs, returns a list with an error message.
    Raises:
        requests.exceptions.HTTPError: If an HTTP error occurs during the search, it is logged and an error message is returned.
        Exception: For any other general errors, they are logged and an error message is returned.
    """
    try:
        # Set up connection to google.serper.dev API
        conn = http.client.HTTPSConnection("google.serper.dev")
        payload = json.dumps({"q": query})
        headers = {
            "X-API-KEY": "07b4113c2730711b568623b13f7c88078bab9c78",
            "Content-Type": "application/json",
        }

        # Send POST request to the API
        conn.request("POST", "/search", payload, headers)

        # Get response and decode the data
        res = conn.getresponse()
        data = res.read()
        results = json.loads(data.decode("utf-8"))

        # Extract snippets from organic search results
        snippets = [result["snippet"] for result in results.get("organic", [])]

        # Return the list of snippets
        return snippets
    except http.client.HTTPException as http_err:
        # Log HTTP errors and return a specific error message
        print(f"HTTP error occurred: {http_err}")
        return ["HTTP error occurred during Google search"]
    except Exception as e:
        # Log any other general errors and return a generic error message
        print(f"General Error: {e}")
        return ["Error occurred during Google search"]


def rag_response(query, selected_doc_ids=None):
    """
    Handle queries by searching both the main knowledge base and the selected documents.
    """
    try:
        results = []

        # Search FAISS database (main knowledge base)
        if "faiss_db" in st.session_state:
            retrieved_docs = search_knowledge_base(query)
            results.extend(retrieved_docs)

        # If selected_doc_ids is None, try to get it from session state
        if selected_doc_ids is None:
            selected_doc_ids = st.session_state.get('selected_doc_ids', [])

        # Search vector stores of the selected documents
        if selected_doc_ids:
            for doc_id in selected_doc_ids:
                vector_store = st.session_state.get("vector_store", {}).get(doc_id)
                if vector_store:
                    vector_store_results = vector_store.similarity_search(query, k=5)
                    results.extend(vector_store_results)
                else:
                    st.warning(f"Vector store for document '{st.session_state['documents'][doc_id]['name']}' not found.")

        # Combine results into a single context
        context = "\n".join([doc.page_content for doc in results])

        if not context.strip():
            return "No relevant information found in the knowledge bases."
        # Generate AI response with the retrieved context
        prompt = f"""
        Context:
        {context}
        You are an expert assistant tasked with providing precise and accurate answers based only on the provided context.
        1. Use only the provided context to generate your answer.
        2. Match headings and content exactly as they appear in the knowledge base. Do not add, modify, or generalize content.
       
        3. Maintain clarity, conciseness, and accuracy.
        Question:
        {query}
        Answer:
        """
        llm = ChatOpenAI(model="gpt-4", temperature=0.2, api_key=openai_api_key)
        response = llm.invoke(prompt)


        return response.content.strip()
    except Exception as e:
        logger.error(f"Error generating RAG response: {e}")
        return "An error occurred during the RAG response generation process."


@tool
def knowledge_base_tool(query: str):
    """Query the knowledge base and retrieve a response."""
    return rag_response(query)

@tool
def google_search_tool(query: str):
    """Perform a Google search using the SERPER API."""
    return google_search(query)







tavily_tool = TavilySearchResults(
    max_results=12,
    search_depth="advanced",
    topic="news",
    days=1,
    include_answer=True,
    include_raw_content=True,
    # include_domains=[...],
    exclude_domains=['example.com'],
    # name="...",            # overwrite default tool name
    # description="...",     # overwrite default tool description
    # args_schema=...,       # overwrite default args_schema: BaseModel
)# Compile all tool functions into a list
tools = [
    knowledge_base_tool,  # Tool for querying the knowledge base and retrieving responses
    tavily_tool,
    # google_search_tool,  # Tool for performing a Google search and retrieving search result snippets
]

prompt_message = f"""
**You are an expert multilingual copywriter specializing in creating highly fluid, compelling, and interconnected marketing copy that seamlessly integrates Trust Builders into various content formats for any organization. Your goal is to craft concise, engaging material  based on the knowledgebase, adhering to the following guidelines:**

- Write in **active voice** using **first-person perspective (“we”)**, avoiding third-person.
- Ensure **seamless flow** with logical transitions between paragraphs, maintaining relevance and consistency.
- Contextually integrate trust-building elements creatively. Avoid using **Stability, Development, Competence, Relationship, Benefit, Vision**, and the terms **“trust,” “beacon,” “beacon of hope,” “realm”**, except in specific phrases like **“Development trust builders.”**
- Focus on clarity, avoiding jargon or repetition while emphasizing impact on the audience.


### Key Requirements
**Adhere to Uploaded Document's Style**:
   - Match the uploaded document's tone, structure, and style exactly.
   - Use the same level of language complexity and formality.
   - If the uploaded document includes headings, subheadings, or specific formatting, replicate them. If none exist, avoid including headings.

### MANDATORY Elements
- **Avoid Prohibited Terms**:
  - Do **not** mention "trust," "trust buckets," or any category names like "Development," "Stability," "Competence," "Relationship," "Vision" in the copy.
  - Use these terms for searching and headings but **not in the content or any copy**.
- **Consistency**: Maintain a uniform format across all content types.

- **Formatting**: Ensure formatting is clean and professional, with **no HTML tags**.
- **List of TrustBuilders Used**:
     - Include relevant TrustBuilders® in every response.
     - Provide embedded, clickable source links for each TrustBuilder®.
- **Heuristics and Creative Techniques**:
     - Always include heuristics and creative techniques at the end of the response.
     - Use the following format under separate headings:
       - **Heuristics**: List relevant examples (e.g., social proof, authority, commitment).
       - **Creative Techniques**: List relevant marketing techniques (e.g., storytelling, visual metaphors).


### MANDATORY VERIFICATION CHECKLIST:
Before submitting **any content**, ensure that each piece includes:
1. **Specific Details**:
   - **At least 3 specific dollar amounts** with exact figures (e.g., "$127.5 million").
   - **Minimum 2 full dates** with day/month/year (e.g., "March 15, 2023").
   - **At least 3 specific quantities** of people/items (e.g., "12,457 beneficiaries").
   - **Minimum 2 full names with titles** 
   - **At least 2 complete program names with years** (e.g., "Operation Healthy Future 2024-2025").
   - **At least 1 specific award**with year and organization (e.g., "2023 UN Global Health Excellence Award"). 
   - **Minimum 2 measurable outcomes with percentages** (e.g., "47% reduction in malnutrition").
2. **Audience Relevance**:
   - **Each point must be followed by**:
     - "This [specific benefit] for [specific audience]"
     - **Example**: "This reduces wait times by 47% for patients seeking emergency care."
3. *Give [sources] next to each trust building point and heuristics and creative techniques with every copy application*.    


*SOURCE LINK*
1. **Each source link must**:
    -Be Latest, factual and verifiable not page not found links  please.

2. Refer knowledge base for description, guiding principles, question to consider and examples for relevant trustbucket then *google search* and then give relevant trustbuilders.

##SPECIFICITY ENFORCEMENT
Replace vague phrases with specific details:
- ❌ "many" → ✅ exact number.
- ❌ "millions" → ✅ "$127.5 million".
- ❌ "recently" → ✅ "March 15, 2023".
- ❌ "global presence" → ✅ "offices in 127 cities across 45 countries".
- ❌ "industry leader" → ✅ "ranked #1 in customer satisfaction by J.D. Power in 2023".
- ❌ "significant impact" → ✅ "47% reduction in processing time".


### CONTENT TYPES AND FORMATS

#### 1. Report/Article/writeup/blog
- **Introduction**: Start with "Here is a draft of your [Annual Report/Article/writeup]. Feel free to suggest further refinements."
- **Structure**:
  - **Headlines **: WRITE ONE CREATIVE ACTIVE LANGUAGE HEADLINE THAT SUMMARISES THE POINTS.Headline should be like this in active language *without mentioning prohibited terms**.
  - **Content**:
    -  **Donot give any source link in contents**
    - **Perspective**: Write as if you are part of the organization (using "we"), emphasizing togetherness and collective effort.
    - **Integration**: Interweave various trust-builder  fluidly, focusing on specifics like names, numbers (dollar amounts and years), programs, strategies, places, awards, and actions, **without mentioning prohibited terms**.
    - **Avoid Flowery Language**: Ensure content is clear and factual.
    - Use an **active, engaging, and direct tone**. Eg:"World Vision partners with [organizations] to drive progress."
     
#### 2. Social Media Posts
- **Introduction Line**: Start with "Here is a draft of your social media post. Feel free to suggest further refinements."
- **Content**:
  - Ensure the post is **concise, impactful**, and designed to engage the audience.
  - **Avoid prohibited terms or flowery language**.
  - **Include specific names, numbers, programs, strategies, places, awards, and actions** to enhance credibility.
  - Focus on **clear messaging**.
- **Additional Requirements**:
  - Do **not** mention prohibited terms in hashtags or post copy.
  - Ensure **source links are not included** in the post text.
- **Sub-Headings (After Summary) **:
  1. **List of TrustBuilders Used**: Provide relevant trust-building elements  with embedded source links.
  2. **Heuristics and Creative Techniques**:
     - List them in footnote-style tiny small heading.
     - Select and name only **3-5 relevant heuristics** with tight bullet points.
     - Name only the relevant marketing creative techniques, with no additional details.
- **Word Count**: Follow any specified word count.
 - **Important Notes**:
  - **Strictly search and provide accurate source links always**.
  
#### 3. Sales Conversations or Ad Copy
- **Introduction Line**: Start with "Here is a draft of your [Sales Conversation/Ad Copy]. Feel free to suggest further refinements."
- **Content**:
  - Include **persuasive elements** with integrated trust-building elements, interconnecting them fluidly **without mentioning prohibited terms**.
  - **Avoid flowery language** and focus on factual, specific information such as names, numbers, and actions.
    - **Sub-Headings(After Summary)  **:
      1. **List of TrustBuilders Used**:Provide relevant trust-building elements   with embedded source links .
      2. **Heuristics and Creative Techniques**:
         - List them in footnote-style tiny small heading.
         - Select and name only **3-5 relevant heuristics** with tight bullet points.
         - Name only the relevant marketing creative techniques, with no additional details.
- **Important Notes**:
  - Strictly search and provide accurate source links always.
  
#### 4. Emails, Newsletter, Direct Marketing Letters**
- **Introduction Line**: Start with "Here is a draft of your [Email/Newsletter/Letter,Blog]. Feel free to suggest further refinements."
- **Structure**:
  - **Headlines**: WRITE ONE CREATIVE ACTIVE LANGUAGE HEADLINE THAT SUMMARISES THE POINTS YOU MAKE.Headline should be like this in activae language eg.we empower instead **without mentioning prohibited terms**.
  - **Content**:
    -  Use **headings** with all content paragraphs to structure the article.** Donot give any source link in contents**
    - **Perspective**: Write as if you are part of the organization (using "we"), emphasizing togetherness and collective effort.
    - **Integration**: Interweave various trust-builder  fluidly, focusing on specifics like names, numbers (dollar amounts and years), programs, strategies, places, awards, and actions, **without mentioning prohibited terms**.
    - **Avoid Flowery Language**: Ensure content is clear and factual.
    - Use an **active, engaging, and direct tone**. Eg:"World Vision partners with [organizations] to drive progress."
- **Sub-Headings(After Summary) **:
  1. **List of TrustBuilders Used**: Provide relevant trust-building elements  followed  with embedded source links.
  2. **Heuristics and Creative Techniques**:
     -List them in a footnote-style small heading.
     -Use the following structure:
        -Heuristics: examples (e.g., social proof, authority, commitment).
        -Creative Techniques: examples (list only relevant marketing techniques without additional details).
     -Limit to 3-5 items in each category.
Note: When including heuristics and creative techniques, use the structure “Heuristics: examples” and “Creative Techniques: examples” with no extra details.
- **Word Count**: Follow any specified word count for the main body. Do not count sub-heading sections in the word count limit.

### 5.Trust-Based Queries:**
 -Be over specific with numbers,names,dollars, programs ,awards and action. 
- When a query seeks a specific number of trust builders (e.g., "5 trust builders"), the AI should:
         - Randomly pick the requested number of trust buckets from the six available: Development Trust, Competence Trust, Stability Trust, Relationship Trust, Benefit Trust, and Vision Trust.
         - For each selected bucket, find 15  TrustBuilders® points be over specific with numbers,names,dollars, programs ,awards and action. 
         - Categorize these points into Organization, People, and Offers/Services (with 5 points for each category).
         - **Each point must be followed by**:
         - "This [specific benefit] for [specific audience]"
         - **Example**: "This reduces wait times by 47% for patients seeking emergency care."
       -For each selected bucket, find 15 TrustBuilders® points.
       
       -**Categorization:** Categorize these points into three sections with **specific details**:
        - **[Category Name]**
          - **Organization** (5 points)
          - **People** (5 points)
          - **Offers/Services** (5 points)
        - **[Next Category Name]**
          - **Organization** (5 points)
          - **People** (5 points)
          - **Offers/Services** (5 points)
      - **Important Specificity:** Always include **names**, **numbers** (e.g., $ amounts and years), **programs**, **strategies**, **places**, **awards**, and **actions** by searching on google to add credibility and depth to the content. Ensure that trust-building points are detailed and specific.

- **For Specific Categories:**
  - When a query asks for a specific category (e.g., "Development trust builders"), find 15 trust-building points that are specific with relevant names, numbers like $ amounts and years, programs, strategies, places, awards, and actions specifically for that category.
  - Categorize these points into Organization, People, and Offers/Services (with 5 points for each category).

- **Format:**
  - **Introduction Line:** Start with "Here are TrustBuilders® for [Selected Categories] at [Organization Name]. Let me know if you want to refine the results or find more."
  - **Categories:**
    - **Organization:**
      - [Trust-Building Point 1] - [Source](#)
      - [Trust-Building Point 2] - [Source](#)
      - [Trust-Building Point 3] - [Source](#)
      - [Trust-Building Point 4] - [Source](#)
      - [Trust-Building Point 5] - [Source](#)
    - **People:**
      - [Trust-Building Point 6] - [Source](#)
      - [Trust-Building Point 7] - [Source](#)
      - [Trust-Building Point 8] - [Source](#)
      - [Trust-Building Point 9] - [Source](#)
      - [Trust-Building Point 10] - [Source](#)
    - **Offers/Services:**
      - [Trust-Building Point 11] - [Source](#)
      - [Trust-Building Point 12] - [Source](#)
      - [Trust-Building Point 13] - [Source](#)
      - [Trust-Building Point 14] - [Source](#)
      - [Trust-Building Point 15] - [Source](#)
  - Ensure each selected category contains 15 trust-building points, categorized as specified.
  - Provide bullet points under each section with relevant accurate source link.

**Important Notes:**
  - Strictly search and provide accurate source links always.
  - **No Subheadings or Labels:** Under each main category, list the trust-building points directly as bullet points or numbered lists **without any additional subheadings, labels, descriptors, phrases, or words before the points**.
  - **Avoid Flowery Language:** Do not use any flowery or exaggerated language.
  - **Do Not Include:**
    - Heuristics and Creative Techniques** in Trust-Based Queries.
    - Subheadings or mini-titles before each point.
    - Labels or descriptors like "Strategic Partnerships:", "Global Reach:", etc.
    - Colons, dashes, or any formatting that separates a label from the point.
  - **Do Include:**
    - The full sentence of the trust-building point starting directly after the bullet, with specific details.
  - **Do Not Include the Prohibited Terms:** Do not mention the prohibited terms anywhere, **even when asked**.
-*Donot provide list of trustbuilders used and heuristics here. That is for copy applications not here.
- **Example of Correct Format**:
  **Organization**
     - In **20XX**, World Vision invested **$150 million** in sustainable agriculture programs across **35 countries**, impacting over **2 million** farmers.This improves food security for vulnerable communities.- [Source](#)

### 6. LinkedIn Profile
- If requested, generate a LinkedIn profile in a professional manner.
- **Avoid prohibited terms** and **flowery language**.

### General Queries
- Do not use the knowledge base for non-trust content.
- Always clarify the audience impact and ensure all information is based on verified sources.
-Refer knowledgebase when asked about trustifier or TrustLogic.

"MOST IMPORTANT RULE. IN EVERY PARAGRAPH Strengthen the connections between sections to ensure smoother flow and SHOULD  BE DEEPLY INTERCONNECTED WITH EACH OTHER TO CREATE A SEAMLESS FLOW, MAKING THE CONTENT READ LIKE A SINGLE CONTENT RATHER THAN DISJOINTED PARAGRAPHS OR INDEPENDENT BLOG SECTIONS. EACH SECTION MUST LOGICALLY TRANSITION INTO THE NEXT, ENSURING THAT THE TOPIC REMAINS CONSISTENT AND RELEVANT THROUGHOUT. BY MAINTAINING A COHESIVE STRUCTURE, THE ARTICLE WILL ENGAGE READERS MORE EFFECTIVELY, HOLDING THEIR ATTENTION AND CONVEYING THE INTENDED MESSAGE WITH CLARITY AND IMPACT."

"""
prompt_template = ChatPromptTemplate.from_messages([
    ("system", prompt_message),
    MessagesPlaceholder(variable_name="chat_history"),
    ("user", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

# Create Langchain Agent
llm = ChatOpenAI(
    model="gpt-4o",
    temperature=0.8,  # Balanced creativity and adherence
    max_tokens=3000,  # Ensure sufficient output length
    top_p=0.85,  # Focused outputs
    frequency_penalty=0.1,  # Minimize repetition
    presence_penalty=0.7  # Moderate novelty to maintain adherence
)



llm_with_tools = llm.bind_tools(tools)

# Define the agent pipeline
agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),
        "chat_history": lambda x: x["chat_history"],
    }
    | prompt_template
    | llm_with_tools
    | OpenAIToolsAgentOutputParser()
)

# Instantiate an AgentExecutor
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# Streamlit app

# Display chat history
for message in st.session_state.chat_history:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# Chat input
if not st.session_state.get("chat_started", False):


    st.markdown("""
    <script>
    document.addEventListener('DOMContentLoaded', (event) => {
        const svgs = document.querySelectorAll('svg');
        svgs.forEach(svg => {
            if (svg.getAttribute('xmlns') === 'http://www.w3.org/2000/svg' && svg.getAttribute('width') === '18' && svg.getAttribute('height') === '18') {
                svg.style.display = 'none';
            }
        });
    });
    </script>
    <style>
    /* Hide all <a> elements inside elements with block-container and st-emotion-cache-1eo1tir ea3mdgi5 classes */
    .block-container.st-emotion-cache-1eo1tir.ea3mdgi5 a {
        display: none !important;
    }
    /* Ensure links in the sidebar are visible and underlined */
    .stSidebar a {
        display: inline !important;
        text-decoration: underline !important;
        color: inherit !important;
    }
    /* Additional styles */
    .section-container {
        display: flex;
        justify-content: center;
        align-items: stretch;
        flex-wrap: wrap;
        gap: 4px;
    }
    
    .section {
        flex: 1;
        min-width: 150px;
        max-width: 90px;
        min-height: 150px;
        border: 1px solid #afafaf;
        border-radius: 10px;
        padding: 5px;
        background-color: transparent;
        margin: 3px;
        text-align: center;
        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        box-sizing: border-box;
        font-size: 12px;
        transition: background-color 0.3s ease;
    }
    .section h2 {
        color: #afafaf;
        font-size: 14px;
        margin-bottom: 8px;
        border-bottom: 1px solid #afafaf;
        padding-bottom: 4px;
        text-align: center; /* Center headings */
    }
    .section p {
        color: #afafaf;
        font-size: 11px;
        margin: 5px 0;
        line-height: 1.4;
    }
    @media (max-width: 100px) {
        .section {
            min-width: 90%;
            max-width: 90%;
        }
    }
    </style>
    
    <h1 style="text-align: center; background: #528186; -webkit-background-clip: text; color: transparent;">How can I help you today?</h1>
    <div class="section-container">
        <div class="section">
            <h2>Find</h2>
            <p>Discover all your great TrustBuilders®. <br> Example: Find Development Trust Builders® for World vision
        </div>
        <div class="section">
            <h2>Create</h2>
            <p>Generate trust-optimised solutions : <br>Example: Find World vision development TrustBuilders®. Then use them to write a 200-word annual report article. Enthusiastic tone.</p>
        </div>
        <div class="section">
            <h2>Trust-optimise</h2>
            <p>Paste your LinkedIn profile, EDM or blog and ask Trustifier.ai® to improve it using specific Trust Buckets® and add your specific TrustBuilders® as examples.</p>
        </div>
    </div>
    <div style="height: 50px;"></div> <!-- Adds a gap of 50px after the section containers -->
    """, unsafe_allow_html=True)
    
hide_specific_warning = """
<script>
document.addEventListener('DOMContentLoaded', function() {
    const alerts = window.parent.document.querySelectorAll('div[data-testid="stAlert"]');
    alerts.forEach(function(alert) {
        if (alert.innerText.includes('Please replace st.experimental_get_query_params with st.query_params')) {
            alert.style.display = 'none';          // Hide the warning
            alert.style.visibility = 'hidden';     // Make it invisible
            alert.style.height = '0px';            // Set height to zero to remove space
            alert.style.margin = '0px';            // Set margin to zero
            alert.style.padding = '0px';           // Set padding to zero
        }
    });
});
</script>
"""


# Embed the JavaScript in your Streamlit app
components.html(hide_specific_warning, height=0, scrolling=False)

query_params = st.experimental_get_query_params()
wix_user_id = query_params.get('wix_user_id', [None])[0]
email = query_params.get('email', [None])[0]

# Session state to track user login and message usage
if "wix_user_id" not in st.session_state:
    st.session_state["wix_user_id"] = wix_user_id
if "email" not in st.session_state:
    st.session_state["email"] = email
if "message_limit" not in st.session_state:
    st.session_state["message_limit"] = 0
if "used_messages" not in st.session_state:
    st.session_state["used_messages"] = 0


def receive_wix_message():
    components.html(
        """
        <script>
        window.addEventListener('message', function(event) {
            const data = event.data;
            if (data.wixUserId && data.email) {
                window.parent.postMessage({
                    'wix_user_id': data.wixUserId,
                    'email': data.email
                }, "*");
                // Send message back to Streamlit
                window.parent.postMessage({
                    wix_user_id: data.wixUserId,
                    email: data.email
                }, "*");
            }
        });
        </script>
        """,
        height=0
    )

# Calling  this function to initialize listening for Wix messages
receive_wix_message()

trust_tips = [
    "What I don’t know I can’t trust you for. Make sure you know all your great TrustBuilders® and use them over time.",
    "The more specific, the more trustworthy each TrustBuilder® is.",
    "For TrustBuilders®, think about each Trust Bucket® and in each one organization, product, and key individuals.",
    "You are infinitely trustworthy. Organization, products, and your people. In each Trust Bucket® and past, present, and future.",
    "Some TrustBuilders® are enduring (we have over 3 million clients), others changing (we are ranked No. 1 for 8 years/9 years), and yet others short-lived (we will present at XYZ conference next month).",
    "Not all Trust Buckets® are equally important all the time. Think about which ones are most important right now and how to fill them (with TrustAnalyser® you know).",
    "In social media, structure posts over time to focus on different Trust Buckets® and themes within them.",
    "Try focusing your idea on specific Trust Buckets® or a mix of them.",
    "Within each Trust Bucket®, ask for examples across different themes like employee programs, IT, R&D.",
    "To create more and different trust, ask trustifier.ai to combine seemingly unconnected aspects like 'I played in bands all my youth. What does this add to my competence as a lawyer?'",
    "With every little bit more trust, your opportunity doubles. It's about using trustifier.ai to help you nudge trust up ever so slightly in everything you do.",
    "Being honest is not enough. You can be honest with one aspect and destroy trust and build a lot of trust with another. Define what that is.",
    "The more I trust you, the more likely I am to recommend you. And that's much easier with specifics.",
    "What others don’t say they are not trusted for - but you can claim that trust.",
    "Building more trust is a service to your audience. It's so valuable to us, as humans, that we reflect that value right away in our behaviors.",
    "In your audience journey, you can use TrustAnalyser® to know precisely which Trust Buckets® and TrustBuilders® are most effective at each stage of the journey.",
    "Try structuring a document. Like % use of each Trust Bucket® and different orders in the document.",
    "In longer documents like proposals, think about the chapter structure and which Trust Buckets® and TrustBuilders® you want to focus on when.",
    "Building Trust doesn’t take a long time. Trust is built and destroyed every second, with every word, action, and impression. That's why it's so important to build more trust all the time.",
    "There is no prize for the second most trusted. To get the most business, support, and recognition, you have to be the most trusted.",
    "With most clients, we know they don’t know 90% of their available TrustBuilders®. Knowing them increases internal trust - and that can be carried to the outside.",
    "Our client data always shows that, after price, trust is the key decision factor (and price is a part of benefit and relationship trust).",
    "Our client data shows that customer value increases 9x times from Trust Neutral to High Trust. A good reason for internal discussions.",
    "Our client's data shows that high trust customers are consistently far more valuable than just trusting ones.",
    "Trust determines up to 85% of your NPS. No wonder, because the more I trust you, the more likely I am to recommend you.",
    "Trust determines up to 75% of your loyalty. Think about it yourself. It's intuitive.",
    "Trust determines up to 87% of your reputation. Effectively, they are one and the same.",
    "Trust determines up to 85% of your employee engagement. But what is it that they want to trust you for?",
    "Don't just ask 'what your audience needs to trust for'. That just keeps you at low, hygiene trust levels. Ask what they 'would love to trust for'. That's what gets you to High Trust."
]

suggestions = [
    "Try digging deeper into a specific TrustBuilder®.",
    "Ask just for organization, product, or a person's TrustBuilders® for a specific Trust Bucket®.",
    "Some TrustBuilders® can fill more than one Trust Bucket®. We call these PowerBuilders. TrustAnalyser® reveals them for you.",
    "Building trust is storytelling. trustifier.ai connects Trust Buckets® and TrustBuilders® for you. But you can push it more to connect specific Trust Buckets® and TrustBuilders®.",
    "Describe your audience and ask trustifier.ai to choose the most relevant Trust Buckets®, TrustBuilders®, and tonality (TrustAnalyser® can do this precisely for you).",
    "Ask trustifier.ai to find TrustBuilders® for yourself. Then correct and add a few for your focus Trust Buckets® - and generate a profile or CV.",
    "LinkedIn Profiles are at their most powerful if they are regularly updated and focused on your objectives. Rewrite it every 2-3 months using different Trust Buckets®.",
    "Share more of your TrustBuilders® with others and get them to help you build your trust.",
    "Build a trust strategy. Ask trustifier.ai to find all your TrustBuilders® in the Trust Buckets® and then create a trust-building program for a specific person/audience over 8 weeks focusing on different Trust Buckets® that build on one another over time. Then refine and develop by channel ideas.",
    "Brief your own TrustBuilders® and ask trustifier.ai to tell you which Trust Buckets® they're likely to fill (some can fill more than one).",
    "Have some fun. Ask trustifier.ai to write a 200-word speech to investors using all Trust Buckets®, but leading and ending with Development Trust. Use [BRAND], product, and personal CEO [NAME] TrustBuilders®.",
    "Ask why TrustLogic® can be trusted in each Trust Bucket®.",
    "Ask what's behind TrustLogic®."
]

def add_dot_typing_animation():
    st.markdown(
        """
        <style>
        .dots-container {
            display: flex;
            align-items: center;
        }
        .dot {
            height: 10px;
            width: 10px;
            margin: 0 5px;
            background-color: #bbb;
            border-radius: 50%;
            display: inline-block;
            animation: dot-blink 1.5s infinite ease-in-out;
        }
        .dot:nth-child(2) {
            animation-delay: 0.2s;
        }
        .dot:nth-child(3) {
            animation-delay: 0.4s;
        }
        @keyframes dot-blink {
            0% {
                opacity: 0.3;
            }
            20% {
                opacity: 1;
            }
            100% {
                opacity: 0.3;
            }
        }
        </style>
        """,
        unsafe_allow_html=True,
    )

# Function to display the assistant typing dots
def display_typing_indicator():
    dot_typing_html = """
    <div class="dots-container">
        <span class="dot"></span>
        <span class="dot"></span>
        <span class="dot"></span>
    </div>
    """
 
    st.markdown(dot_typing_html, unsafe_allow_html=True)
def display_save_confirmation(type_saved):
    st.info(f"Content successfully saved as **{type_saved}**!")


def extract_name(email):
    return email.split('@')[0].capitalize()

if "trustbuilders" not in st.session_state:
    st.session_state["trustbuilders"] = {}
if "brand_tonality" not in st.session_state:
    st.session_state["brand_tonality"] = {}

# Load saved entries upon user login
def retrieve_user_data(user_id):
    """
    Load all content for a user from Firebase, ensuring each user has a single root
    containing TrustBuilder, BrandTonality, and other data fields like email, message limits, etc.
    """
    try:
        user_data = db.child("users").child(user_id).get().val()
        if user_data:
            # Update session state with all user data
            st.session_state.update(user_data)
            
            # Load TrustBuilder and BrandTonality into session state for display
            st.session_state["TrustBuilder"] = user_data.get("TrustBuilder", {})
            st.session_state["BrandTonality"] = user_data.get("BrandTonality", {})
            
    except Exception as e:
        st.error(f"Error loading saved content: {e}")

def handle_memory_queries(prompt):
    """
    Main function to handle user commands and allocate Trust Buckets.
    """
    prompt = prompt.lower().strip()

    valid_buckets = ["Stability", "Development", "Relationship", "Benefit", "Vision", "Competence"]

    # Case 1: Save this as [bucket] trust builder: [content]
    match_save_this_specific = re.search(r"\bsave\s+(this\s+)?as\s+(\w+)\s+trust\s+builders?\s*:\s*(.+)", prompt, re.IGNORECASE)
    if match_save_this_specific:
        specified_bucket = match_save_this_specific.group(2).capitalize()
        content_to_save = match_save_this_specific.group(3).strip()

        if specified_bucket in valid_buckets:
            if content_to_save:
                assistant_response = handle_save_trustbuilder(content_to_save, specified_bucket)
            else:
                assistant_response = "No content provided. Please include content after 'save this as [bucket] trust builder:'."
        else:
            assistant_response = f"Invalid Trust Bucket '{specified_bucket}'. Valid buckets are: {', '.join(valid_buckets)}."

        # Save response to chat history and display it
        st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
        with st.chat_message("assistant"):
            st.markdown(assistant_response)
        return None

    # Case 2: Save this under [bucket]: [content]
    match_save_under_specific = re.search(r"\bsave\s+(this\s+)?under\s+(\w+)\s*:\s*(.+)", prompt, re.IGNORECASE)
    if match_save_under_specific:
        specified_bucket = match_save_under_specific.group(2).capitalize()
        content_to_save = match_save_under_specific.group(3).strip()

        if specified_bucket in valid_buckets:
            if content_to_save:
                assistant_response = handle_save_trustbuilder(content_to_save, specified_bucket)
            else:
                assistant_response = "No content provided. Please include content after 'save this under [bucket]:'."
        else:
            assistant_response = f"Invalid Trust Bucket '{specified_bucket}'. Valid buckets are: {', '.join(valid_buckets)}."

        # Save response to chat history and display it
        st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
        with st.chat_message("assistant"):
            st.markdown(assistant_response)
        return None

    # Case 3: Save and allocate: [content] (automatic allocation)
    match_save_allocate_auto = re.search(r"\bsave\s+(this\s+)?and\s+allocate\s*:\s*(.+)", prompt, re.IGNORECASE)
    if match_save_allocate_auto:
        content_to_save = match_save_allocate_auto.group(2).strip()
        if content_to_save:
            assistant_response = handle_save_trustbuilder(content_to_save)  # Automatically allocate bucket
        else:
            assistant_response = "No content provided. Please include content after 'save and allocate:'."

        # Save response to chat history and display it
        st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
        with st.chat_message("assistant"):
            st.markdown(assistant_response)
        return 

    # Show saved TrustBuilders
    elif "find my saved trustbuilders" in prompt or "show my saved trustbuilders" in prompt:
        trustbuilders = fetch_trustbuilders(st.session_state.get("wix_user_id", "default_user"))
        if trustbuilders:
            saved_content = "\n".join([f"- {entry['message']}" for entry in trustbuilders.values()])
            assistant_response = f"Here are your saved TrustBuilders:\n{saved_content}"
        else:
            assistant_response = "You haven't saved any TrustBuilders yet."

        # Save response to chat history and display it
        st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
        with st.chat_message("assistant"):
            st.markdown(assistant_response)
        return None

    return None
def delete_entry(category, entry_id):
    try:
        user_id = st.session_state["wix_user_id"]
        db.child("users").child(user_id).child(category).child(entry_id).remove()
        st.session_state[category].pop(entry_id, None)
        st.success(f"{category} entry deleted successfully!")
    except Exception as e:
        st.error(f"Error deleting entry: {e}")

        
# Function to download TrustBuilder as a .md file
def download_trustbuilder_as_md(content, trustbuilder_id):
    b64_content = base64.b64encode(content.encode()).decode()
    download_link = f'<a href="data:text/markdown;base64,{b64_content}" download="TrustBuilder_{trustbuilder_id}.md">Download</a>'
    st.sidebar.markdown(download_link, unsafe_allow_html=True)

def handle_save_trustbuilder(content, specified_bucket=None):
    """
    Handles saving TrustBuilders by detecting or automatically allocating the Trust Bucket.
    """
    # Avoid reprocessing the same content
    if "last_processed_content" in st.session_state and st.session_state["last_processed_content"] == content:
        return None  # Exit if the content was already processed

    trust_buckets = {
        "Stability": [
            "track record", "longevity", "size", "stability", "experience", "established", "heritage",
            "continuity", "reliable", "secure", "trustworthy", "dependable", "durable", "assurance",
            "foundation", "longstanding", "rooted", "strong", "solid", "proven", "milestones",
            "geographic footprint", "history", "recognizable", "retention", "consistent", "employees",
            "families", "recognition", "awards"
        ],
        "Development": [
            "innovation", "investment", "future-focused", "cutting-edge", "leadership", "growth",
            "ambition", "strategy", "adaptation", "forward-thinking", "evolve", "progress",
            "pilot programs", "technology", "training", "pioneering", "future-proof", "patents",
            "pipeline", "biotechnology", "adapt", "change", "radical", "sustainable"
        ],
        "Relationship": [
            "collaboration", "support", "empathy", "engagement", "customer-focused", "community",
            "partnership", "bond", "interaction", "sensitivity", "diversity", "social responsibility",
            "inclusive", "well-being", "investment", "communication", "feedback", "employee benefits",
            "customer councils", "loyalty", "wellness", "stakeholder", "inclusive initiatives",
            "social awareness", "active engagement", "connected"
        ],
        "Benefit": [
            "value", "benefit", "growth", "success", "advantage", "efficiency", "satisfaction",
            "reward", "functional value", "emotional value", "unique", "output", "results", "superior",
            "return", "proposition", "cost savings", "improvements", "enjoyment", "peace of mind",
            "confidence", "methodologies", "results", "growth strategy", "improvement", "continuous"
        ],
        "Vision": [
            "goal", "mission", "aspire", "dream", "visionary", "great", "future", "ideal", "ambition",
            "long-term", "objective", "focus", "drive", "purpose", "values", "integrity",
            "philanthropy", "social impact", "ethical", "society", "inspire", "sustainability",
            "impact", "initiatives", "greater good", "common good", "compelling", "volunteering"
        ],
        "Competence": [
            "expertise", "skills", "innovation", "excellence", "knowledge", "capability",
            "proficiency", "technical", "problem-solving", "methodologies", "effectiveness",
            "specialization", "certifications", "creativity", "collaboration", "leadership",
            "capabilities", "accreditations", "teamwork", "publications", "training", "patents",
            "high-profile", "results-oriented", "proven ability", "credentials", "creative excellence"
        ]
    }

    bucket = specified_bucket

    # Automatically allocate bucket if not provided
    if not bucket:
        for tb, keywords in trust_buckets.items():
            if any(keyword in content.lower() for keyword in keywords):
                bucket = tb
                break

    # If no bucket can be allocated, prompt the user
    if not bucket:
        st.session_state["missing_trustbucket_content"] = content
        return (
            "No Trust Bucket could be allocated automatically. "
            "Please indicate the Trust Bucket (e.g., Stability, Development, Relationship, Benefit, Vision, Competence)."
        )

    # Save TrustBuilder with detected/provided bucket
    brand = st.session_state.get("brand_input_save", "Unknown")
    content_to_save = f"{bucket}: Brand: {brand.strip()} | {content.strip()}"
    save_content(st.session_state["wix_user_id"], content_to_save)

    # Update last processed content
    st.session_state["last_processed_content"] = content
 # Confirm saving to the user
    return f"TrustBuilder allocated to **{bucket}** and saved successfully!"




                        
def load_user_memory(user_id):
    """
    Load saved TrustBuilders and uploaded documents from Firebase into session state.
    """
    try:
        # Load TrustBuilders
        trustbuilders = db.child("users").child(user_id).child("TrustBuilders").get().val()
        st.session_state["trustbuilders"] = trustbuilders if trustbuilders else []

        # Load Uploaded Documents from 'KnowledgeBase'
        documents = db.child("users").child(user_id).child("KnowledgeBase").get().val()
        st.session_state["documents"] = documents if documents else {}

        # Reconstruct vector stores for each document
        st.session_state["vector_store"] = {}
        for doc_id, doc_data in st.session_state["documents"].items():
            content = doc_data.get("content", "")
            if content:
                index_document_content(content, doc_id)

    except Exception as e:
        st.error(f"Error loading user memory: {e}")
        st.session_state["trustbuilders"] = []
        st.session_state["documents"] = {}
        st.session_state["vector_store"] = {}



if "missing_trustbucket_content" not in st.session_state:
    st.session_state["missing_trustbucket_content"] = None

if "handled" not in st.session_state:
    st.session_state["handled"] = False



if "email" not in st.session_state:
    st.session_state["email"] = f"demo_user_{st.session_state['wix_user_id']}@example.com"
if "user_name" not in st.session_state:
    st.session_state["user_name"] = "Demo"
if "message_limit" not in st.session_state:
    st.session_state["message_limit"] = 1000
if "used_messages" not in st.session_state:
    st.session_state["used_messages"] = 0

if "missing_trustbucket_content" not in st.session_state:
    st.session_state["missing_trustbucket_content"] = None

def initialize_user_session():
    """
    Initialize user session and ensure user data exists in Firebase.
    """
    try:
        user_id = st.session_state["wix_user_id"]
        email = st.session_state["email"]

        # Check if user already exists in Firebase
        user_data = db.child("users").child(user_id).get().val()
        
        if not user_data:
            # Create user data in Firebase if it doesn't exist
            user_data = {
                "user_name": user_id,
                "email": email,
                "message_limit": 1000,
                "used_messages": 0
            }
            db.child("users").child(user_id).set(user_data)
        
        
        # Update session state with user data
        st.session_state.update(user_data)
    except Exception as e:
        st.error(f"Error initializing user session: {e}")
   





initialize_user_session()

retrieve_user_data(st.session_state["wix_user_id"])  # Fetch and display saved data for the user

user_name = extract_name(st.session_state["email"])





def clean_and_format_markdown(raw_text):
    """
    Dynamically cleans and formats Markdown text to ensure URLs are properly encoded 
    and handles issues with line breaks or improperly formatted Markdown.
    """
    # Regular expression to find Markdown links [text](url)
    pattern = r'\[([^\]]+)\]\(([^)]+)\)'

    def encode_url(match):
        text = match.group(1)
        url = match.group(2).strip()  # Remove leading/trailing spaces
        encoded_url = quote(url, safe=':/')  # Encode the URL while keeping : and /
        return f"[{text}]({encoded_url})"

    # Fix Markdown links dynamically
    formatted_text = re.sub(pattern, encode_url, raw_text)

    # Replace single newlines with spaces to avoid breaking Markdown rendering

    return formatted_text


prompt = st.chat_input("")
global combined_text
def handle_prompt(prompt):
    if st.session_state["used_messages"] < st.session_state["message_limit"]:
        if prompt:
            st.session_state.chat_started = True

            # Prevent duplicate messages in chat history
            if not any(msg["content"] == prompt for msg in st.session_state["chat_history"]):
                st.session_state.chat_history.append({"role": "user", "content": prompt})

            # Introduce a flag to track if a specific flow is handled
            st.session_state["handled"] = False

            # Handle missing Trust Bucket if needed
            if st.session_state.get("missing_trustbucket_content") and not st.session_state["handled"]:
                bucket = prompt.strip().capitalize()
                valid_buckets = ["Stability", "Development", "Relationship", "Benefit", "Vision", "Competence"]

                if bucket in valid_buckets:
                    content_to_save = st.session_state.pop("missing_trustbucket_content")
                    response = handle_save_trustbuilder(content_to_save, bucket)
                    if response:
                        st.session_state.chat_history.append({"role": "assistant", "content": response})
                        with st.chat_message("assistant"):
                            st.markdown(response)
                else:
                    with st.chat_message("assistant"):
                        st.markdown("Invalid Trust Bucket. Please choose from Stability, Development, Relationship, Benefit, Vision, or Competence.")
                st.session_state["handled"] = True
                return  # Exit to prevent further processing

            # Handle fetching saved TrustBuilders
            if ("find my saved trustbuilders" in prompt.lower() or "show my saved trustbuilders" in prompt.lower()) and not st.session_state["handled"]:
                trustbuilders = fetch_trustbuilders(st.session_state.get("wix_user_id", "default_user"))
                if trustbuilders:
                    saved_content = "\n".join([f"- {entry}" for entry in trustbuilders])
                    assistant_response = f"Here are your saved TrustBuilders:\n{saved_content}"
                else:
                    assistant_response = "You haven't saved any TrustBuilders yet."

                st.session_state.chat_history.append({"role": "assistant", "content": assistant_response})
                with st.chat_message("assistant"):
                    st.markdown(assistant_response)
                st.session_state["handled"] = True
                return  # Exit to prevent further processing

            # Handle save TrustBuilder command
            if not st.session_state["handled"]:
                save_match = re.search(r"\b(save|add|keep|store)\s+(this)?\s*(as)?\s*(\w+\s*trustbuilder|trustbuilder)\s*:?(.+)?", prompt, re.IGNORECASE)
                if save_match:
                    content_to_save = save_match.group(5).strip() if save_match.group(5) else None
                    specified_bucket = None

                    # Check for explicit bucket mention
                    bucket_match = re.search(r"\b(stability|development|relationship|benefit|vision|competence)\b", prompt, re.IGNORECASE)
                    if bucket_match:
                        specified_bucket = bucket_match.group(1).capitalize()

                    if content_to_save:
                        response = handle_save_trustbuilder(content_to_save, specified_bucket)
                        if response:
                            st.session_state.chat_history.append({"role": "assistant", "content": response})

                    else:
                        with st.chat_message("assistant"):
                            st.markdown("Please provide the content to save as a TrustBuilder.")

                    st.session_state["handled"] = True
                    return  # Exit to prevent further processing

            # Handle other memory queries
            if not st.session_state["handled"]:
                memory_response = handle_memory_queries(prompt)
                if memory_response:
                    st.session_state.chat_history.append({"role": "assistant", "content": memory_response})
                    with st.chat_message("assistant"):
                        st.markdown(memory_response)
                    st.session_state["handled"] = True
                    return  # Exit to prevent further processing

            # If no specific handling, generate a general AI response
            if not st.session_state["handled"]:
                with st.chat_message("user"):
                    st.markdown(prompt)

                response_placeholder = st.empty()
                with response_placeholder:
                    with st.chat_message("assistant"):
                        add_dot_typing_animation()
                        display_typing_indicator()  
                cleaned_text = ""
                base_instructions="""
                        Avoid Flowery language and ai words.Always include alof of  data of numbers,names,dollars, programs ,awards and action when finding trustbuilders from internet.*
               
                        1. **Adhere to Uploaded Document's Style**:
                           - When asked uploaded files or document means knowledgebase.
                           - Use the uploaded document as a primary guide for writing style, tone, and structure. Just directly give response.
                           - Match formatting such as headings, subheadings, and paragraph styles. If the uploaded document lacks headings, Strictly do not include them in the response.
                        
                        2. **Prioritize Knowledge Base and Internet Sources**:
                           - Use uploaded documents or knowledge base files as the primary source.
                           - Perform a Google search to retrieve valid and correct internet links for references, ensuring only accurate and verified source links are used.
                        
                        3. **Avoid Flowery Language and AI Jargon**:
                           - Use clear, professional language without exaggerated or vague expressions. Avoid jargon like "beacon," "realm," "exemplifies," etc.
                        
                        4. **Ensure Accuracy**:
                           - Provide only verifiable and accurate information. Do not include placeholders, fabricated URLs, or vague references.
                        
                        - Give output in proper formatting.
                        - Response in same  language in which asked. 
                        -Use google to provide accurate  sources links containing the trustbuilder text information.
                        """


                
                # Check if user request includes blog, article, or newsletter
                if any(keyword in prompt.lower() for keyword in ["blog", "write","article","annual report","report", "newsletter","website introduction"]):
                   appended_instructions = (
                            "Craft a flawless, engaging, and fluid compelling copy using *non-flowery language* that reads as though written by a professional copywriter having 25 years of experience. "
                            "Do not use AI jargon, vague phrases, or  formal language.Donot mention trustbucket names in the headings and content. Follow these enhanced guidelines to ensure a polished, publication-ready copy with a 10/10 quality: "
                            "1. **Interconnected Structure**: Ensure all sections and ideas flow seamlessly with logical transitions between paragraphs. Build a cohesive narrative where every part supports the overall theme, reinforcing the message at every step. "                            
                            "3. **Seamless Integration of TrustBuilders®**: Naturally incorporate TrustBuilders® into the narrative without isolating or explicitly listing them in the main body. Instead, weave them fluidly into sentences to build credibility and trust while maintaining the content’s readability and engagement. "
                            "4. **Human Tone**: Write in a relatable, conversational tone that engages the reader and feels natural. Avoid repetitive phrasing, overly technical explanations, or mechanical structures. Use active voice consistently, ensuring the tone is both approachable and professional."
                            "5. **Audience-Centric Engagement**: Tailor the content to meet the audience's needs, goals, and challenges. Create emotional connections by using relatable examples, vivid imagery, and direct appeals. Emphasize actionable insights and practical relevance to ensure the audience feels seen and understood."
                            "6. **Enhanced Audience Engagement**: Use storytelling techniques and mix the trustbuilders into a content. Begin with a compelling hook, maintain momentum through transitions, and conclude with a strong call-to-action that inspires the reader to act or reflect. "
                            "7. **Purpose-Driven Impact**: Clearly define and achieve the content’s purpose—whether to inform, persuade, or inspire action. Ensure every paragraph serves the overall objective while reinforcing the key message. "
                            "8. **Polished Presentation**: Ensure the final output is refined, professional, and suitable for publication. The copy should demonstrate mastery of language and content design, leaving no room for ambiguity or errors. "
                            "dont give source link in content"
                             "1. ##List of TrustBuilders Used: Provide trustbuilders used followed by *Source links always*"
                             " 2. ##Heuristics and Creative Techniques :"
                             "   -List them in a footnote-style small heading."
                              "    Use the following structure:"
                              "      -Heuristics: Mention names only like examples (e.g., social proof, authority, commitment)."
                              "    -Creative Techniques: Mention names onlyexamples (list only relevant marketing techniques without additional details)."
                             "The final output must not include AI jargons. *With every paragraph give a creative headline that summarises the content give sub-headlines with each paragraph like example headline: Drive,empower use similar  words but  no driving, empowering etc *. Avoid mentioning trustbucket names."
                             "MOST IMPORTANT RULE. IN EVERY PARAGRAPH Strengthen the connections between sections to ensure smoother flow and SHOULD  BE DEEPLY INTERCONNECTED WITH EACH OTHER TO CREATE A SEAMLESS FLOW, MAKING THE CONTENT READ LIKE A SINGLE CONTENT RATHER THAN DISJOINTED PARAGRAPHS OR INDEPENDENT BLOG SECTIONS. EACH SECTION MUST LOGICALLY TRANSITION INTO THE NEXT, ENSURING THAT THE TOPIC REMAINS CONSISTENT AND RELEVANT THROUGHOUT. BY MAINTAINING A COHESIVE STRUCTURE, THE ARTICLE WILL ENGAGE READERS MORE EFFECTIVELY, HOLDING THEIR ATTENTION AND CONVEYING THE INTENDED MESSAGE WITH CLARITY AND IMPACT."
                    )
                else:
                    appended_instructions = ""
                final_prompt = f"{prompt} {base_instructions} {appended_instructions}"
                      
                try:
                    output = agent_executor.invoke({
                        "input": final_prompt,
                        "chat_history": st.session_state.chat_history
                    })
                    full_response = output["output"]
                    import html
                    escaped_text = full_response.replace("$", "\$")

                    #cleaned_text = clean_text(full_response)
                    #formatted_text = clean_and_format_markdown(cleaned_text)

                    trust_tip, suggestion = get_trust_tip_and_suggestion()
                    combined_text = f"{escaped_text}\n\n---\n\n**Trust Tip**: {trust_tip}\n\n**Suggestion**: {suggestion}"

                    with response_placeholder:
                        with st.chat_message("assistant"):
                            st.markdown(combined_text)


                except Exception as e:
                    logging.error(f"Error generating response: {e}")
                    st.error("An error occurred while generating the response. Please try again.")

                st.session_state.chat_history.append({"role": "assistant", "content": escaped_text})
                copy_to_clipboard(combined_text)
                st.session_state["handled"] = True  # Mark as handled

# Call the function to handle the prompt
handle_prompt(prompt)