File size: 63,447 Bytes
95422b8
8a7f07f
5e4843b
95422b8
8a7f07f
95422b8
 
 
 
 
 
 
 
 
 
 
5e4843b
c915e07
 
 
36fcb1c
 
b233ee2
57bb7fa
de2bf69
44ed508
 
 
ec7d7e5
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dcb2475
5e4843b
 
de2bf69
5052b34
95422b8
8a7f07f
95422b8
 
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18fdbe8
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1debbb8
 
 
 
 
ecb75f4
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c915e07
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c915e07
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
5e4843b
 
 
 
 
 
 
 
4dfc13c
5e4843b
 
 
 
 
 
4dfc13c
5e4843b
 
 
 
 
 
4dfc13c
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60c587a
 
 
 
 
 
5e4843b
 
 
 
 
60c587a
 
 
 
 
 
 
 
 
6650cef
 
5e4843b
 
 
aa9031c
6650cef
 
 
60c587a
 
 
 
 
 
 
 
 
6650cef
 
 
 
 
 
5e4843b
60c587a
 
 
 
5e4843b
60c587a
e3b79f7
60c587a
e3b79f7
60c587a
 
 
 
 
5e4843b
e978e51
6650cef
5e4843b
60c587a
 
 
5e4843b
 
60c587a
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
60c587a
 
5e4843b
 
60c587a
 
5e4843b
60c587a
5e4843b
60c587a
 
 
 
5e4843b
60c587a
5e4843b
60c587a
5e4843b
60c587a
 
 
 
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
4dfc13c
5e4843b
 
 
 
 
 
 
4dfc13c
 
 
 
 
 
 
 
5e4843b
4dfc13c
 
5e4843b
4dfc13c
 
5e4843b
4dfc13c
 
5e4843b
4dfc13c
 
5e4843b
4dfc13c
 
5e4843b
4dfc13c
 
5e4843b
 
 
4dfc13c
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60c587a
5e4843b
60c587a
 
 
4dfc13c
 
50f03c8
4dfc13c
 
 
 
5e4843b
 
 
 
 
4dfc13c
 
 
5e4843b
 
 
 
 
 
 
 
 
 
 
 
4dfc13c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c579ec4
5e4843b
6e7ad92
649a317
 
 
 
 
 
 
 
6e7ad92
649a317
4f9bd77
649a317
 
0a9c8aa
6e7ad92
5e4843b
6e7ad92
649a317
 
 
c579ec4
5e4843b
b1d2201
649a317
 
 
 
 
 
 
 
5e4843b
b1d2201
6e7ad92
9e4d975
6e7ad92
c579ec4
6e7ad92
 
 
c579ec4
6e7ad92
5e4843b
c579ec4
 
 
649a317
db113dd
 
6e7ad92
649a317
b1d2201
649a317
0b449a5
6e7ad92
beea03a
 
 
a344d15
 
 
beea03a
0a9c8aa
5e4843b
649a317
5e4843b
c579ec4
0b449a5
649a317
c579ec4
649a317
c579ec4
649a317
df08000
649a317
df08000
c579ec4
 
6e7ad92
 
 
 
 
649a317
 
5e4843b
649a317
 
 
 
 
 
 
 
 
 
c579ec4
 
649a317
 
 
6e7ad92
649a317
6e7ad92
649a317
6e7ad92
649a317
 
 
 
 
c579ec4
 
6e7ad92
 
 
 
649a317
6e7ad92
 
 
 
c579ec4
 
 
 
 
 
 
 
 
 
649a317
a344d15
 
 
6e7ad92
a344d15
 
6e7ad92
5e4843b
6e7ad92
 
5b338c6
6e7ad92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
b13e442
 
 
5e4843b
b13e442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6e7ad92
5e4843b
6e7ad92
 
b13e442
 
 
6e7ad92
b13e442
 
 
 
 
 
0a9c8aa
649a317
a9f2bbc
9e4d975
5e4843b
649a317
 
 
5e4843b
649a317
6e7ad92
 
c579ec4
 
0e33655
0b449a5
5e4843b
763fd16
95422b8
 
 
 
 
 
 
 
5e4843b
95422b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0188f7c
7522fcc
 
fef6f3e
95422b8
 
 
 
0188f7c
95422b8
b554423
c1ecd7d
b554423
 
3f89215
 
 
 
 
 
 
c915e07
3f89215
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4256e65
3f89215
 
 
 
 
 
 
 
 
 
 
79bdd61
89cd4f0
3f89215
 
 
 
 
 
 
 
 
 
 
c915e07
3f89215
 
 
89cd4f0
3f89215
 
 
3ef25d2
3f89215
 
 
3ef25d2
c915e07
3f89215
 
053c8b7
3f89215
 
d7b3c8f
3f89215
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6fcf6f6
a981823
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c915e07
cd2bd56
 
 
 
 
 
 
 
5e4843b
cd2bd56
 
 
 
 
 
 
 
 
5e4843b
cd2bd56
 
 
5e4843b
cd2bd56
 
 
5e4843b
cd2bd56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e4843b
cd2bd56
5e4843b
 
39d0e4b
12d02f3
5e4843b
 
 
 
 
 
 
 
 
 
60c587a
 
 
 
5e4843b
60c587a
 
 
 
 
 
 
 
 
5e4843b
60c587a
2694382
64b019d
5e4843b
 
 
 
 
 
64b019d
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60c587a
 
 
 
 
5e4843b
 
 
 
 
60c587a
 
 
 
 
5e4843b
 
60c587a
 
5e4843b
 
 
60c587a
 
 
5e4843b
60c587a
5e4843b
60c587a
 
5e4843b
60c587a
 
 
 
 
 
 
5e4843b
 
 
60c587a
5e4843b
 
 
 
 
 
60c587a
 
 
5e4843b
 
 
 
 
894aa78
5e4843b
4296a78
059d224
bdcbb9c
4296a78
 
 
 
 
bdcbb9c
059d224
bdcbb9c
 
 
 
059d224
bdcbb9c
 
 
 
059d224
bdcbb9c
 
059d224
 
bdcbb9c
e1ef835
894aa78
 
 
 
 
 
 
 
 
 
 
5e4843b
f041efd
 
894aa78
5e4843b
 
 
 
 
 
 
 
cd0af1c
894aa78
 
5e4843b
 
 
 
 
 
 
894aa78
5e4843b
 
 
 
 
 
 
 
 
 
 
60c587a
5e4843b
60c587a
 
 
5e4843b
894aa78
5e4843b
 
 
 
 
 
 
 
 
 
0b449a5
894aa78
5e4843b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894aa78
5e4843b
 
 
894aa78
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
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
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
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

st.set_page_config(layout="wide")
import logging
import asyncio
import re 
# Set up logging to suppress Streamlit warnings about experimental functions
logging.getLogger('streamlit').setLevel(logging.ERROR)
INITIAL_MESSAGE_LIMIT = 100



# 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_pdf_to_md(file):
    """
    Convert a PDF file to Markdown.
    """
    try:
        text = extract_text(file)
        return f"# PDF Document\n\n{text}"
    except Exception as e:
        logger.error(f"Error converting PDF to MD: {e}")
        return ""

def convert_docx_to_md(file):
    """
    Convert a Word (DOCX) file to Markdown.
    """
    try:
        doc = Document(file)
        full_text = '\n'.join([para.text for para in doc.paragraphs])
        return f"# Word Document\n\n{full_text}"
    except Exception as e:
        logger.error(f"Error converting DOCX to MD: {e}")
        return ""

def convert_txt_to_md(file):
    """
    Convert a TXT file to Markdown.
    """
    try:
        text = file.read().decode("utf-8")
        return f"# Text Document\n\n{text}"
    except Exception as e:
        logger.error(f"Error converting TXT to MD: {e}")
        return ""
def display_save_confirmation(type_saved):
    """
    Display a confirmation message when content is saved.
    """
    st.info(f"Content successfully saved as **{type_saved}**!")

def convert_file_to_md(file):
    """
    Detect file type and convert to Markdown accordingly.
    """
    if file.type == "application/pdf":
        return convert_pdf_to_md(file)
    elif file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
        return convert_docx_to_md(file)
    elif file.type == "text/plain":
        return convert_txt_to_md(file)
    else:
        st.sidebar.warning(f"Unsupported file type: {file.type}")
        return ""

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

def upload_to_firebase(user_id, merged_md_content):
    """
    Upload the merged Markdown content to Firebase Storage.
    Returns the public URL of the uploaded file.
    """
    try:
        file_path = f"knowledge_bases/{user_id}/knowledge_base.md"
        # Upload the content as bytes
        storage.child(file_path).put(io.BytesIO(merged_md_content.encode('utf-8')), content_type="text/markdown")
        # Get the download URL
        public_url = storage.child(file_path).get_url(None)
        return public_url
    except Exception as e:
        logger.error(f"Error uploading to Firebase Storage: {e}")
        st.sidebar.error(f"Error uploading files: {e}")
        return None

# 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



def load_main_data_source():
    try:
        with open("./data_source/time_to_rethink_trust_book.md", "r") as f:
            main_content = f.read()
        
        # Split main content into chunks
        text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
        main_texts = text_splitter.split_text(main_content)

        # Create Document objects for the main data source
        main_documents = [Document(page_content=text) for text in main_texts]
        return main_documents
    except Exception as e:
        st.error(f"Error loading main data source: {e}")
        return []

def combine_data_sources():
    main_data_source = load_main_data_source()
    user_data_source = load_user_data_source(st.session_state["wix_user_id"])
    
    trustbuilders = [Document(page_content=tb["message"]) for tb in st.session_state.get("trustbuilders", {}).values()]
    brand_tonalities = [Document(page_content=bt["message"]) for bt in st.session_state.get("brand_tonality", {}).values()]
    
    return main_data_source + user_data_source + trustbuilders + brand_tonalities


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

def load_user_data_source(user_id):
    """
    Load user-uploaded data source from Firebase.
    """
    try:
        file_path = f"knowledge_bases/{user_id}/knowledge_base.md"
        storage_url = storage.child(file_path).get_url(None)
        response = requests.get(storage_url)

        if response.status_code == 200:
            user_content = response.text
            st.session_state["user_data_source"] = user_content
            return [Document(page_content=user_content)]
        else:
            return []
    except Exception as e:
        st.error(f"Error loading user data source: {e}")
        return []

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"**Messages Left**: {remaining_messages} / {st.session_state['message_limit']}")



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, content_type):
    """
    Save TrustBuilder or Brand Tonality to Firebase and update session state, with a clean confirmation.
    """
    try:
        entry_id = str(uuid.uuid4())
        firebase_key = "TrustBuilder" if content_type.lower() == "trustbuilder" else "BrandTonality"

        # Save to Firebase
        db.child("users").child(user_id).child(firebase_key).child(entry_id).set({"message": content})

        # Update `st.session_state` for immediate display in sidebar and chatbot
        if firebase_key not in st.session_state:
            st.session_state[firebase_key] = {}
        st.session_state[firebase_key][entry_id] = {"message": content}

        # Display save confirmation without showing any ID or debug information
        display_save_confirmation(content_type.capitalize())

    except Exception as e:
        st.error(f"Could not save {content_type}. Please try again. Error: {e}")

        
def display_saved_trustbuilders():
    
    # Display TrustBuilders with delete buttons
    st.sidebar.subheader("Saved TrustBuilders")
    trustbuilders = st.session_state.get("TrustBuilder", {})
    for trustbuilder_id, trustbuilder_data in trustbuilders.items():
        message = trustbuilder_data.get("message", "No message available")
        st.sidebar.markdown(f"- {message[:50]}...")
        if st.sidebar.button("Delete", key=f"del_tb_{trustbuilder_id}"):
            delete_entry("TrustBuilder", trustbuilder_id, "TrustBuilder")

    # Display Brand Tonality entries with delete buttons
    st.sidebar.subheader("Saved Brand Tonality")
    brand_tonality = st.session_state.get("BrandTonality", {})
    for tonality_id, tonality_data in brand_tonality.items():
        message = tonality_data.get("message", "No message available")
        st.sidebar.markdown(f"- {message[:50]}...")
        if st.sidebar.button("Delete", key=f"del_bt_{tonality_id}"):
            delete_entry("BrandTonality", tonality_id, "BrandTonality")


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 side():
    with st.sidebar:
        st.image("Trust Logic_Wheel_RGB_Standard.png")
        st.header("Let's create something great.")

        with st.sidebar.expander("Explore", expanded=False):
                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>
        
                    <h3 class="development">Development Trust:</h3>
                    <p>Why can I trust you to develop well in the future?</p>
        
                    <h3 class="relationship">Relationship Trust:</h3>
                    <p>What appealing relationship qualities can I trust you for?</p>
        
                    <h3 class="benefit">Benefit Trust:</h3>
                    <p>What benefits can I trust you for?</p>
        
                    <h3 class="vision">Vision Trust:</h3>
                    <p>What Vision and Values can I trust you for?</p>
        
                    <h3 class="competence">Competence Trust:</h3>
                    <p>What competencies can I trust you for?</p>
                    """, unsafe_allow_html=True
                )
                st.markdown("For detailed descriptions, visit [Academy](https://www.trustifier.ai/account/academy)")

        st.header("Upload Data source")
        
        with st.form(key="upload_form"):
            uploaded_files = st.file_uploader("Upload PDF, DOCX, or TXT files", type=["pdf", "docx", "txt"], accept_multiple_files=True)
            submit_button = st.form_submit_button("Upload")
            
            if submit_button and uploaded_files:
                md_contents = [convert_file_to_md(file) for file in uploaded_files if convert_file_to_md(file)]
                if md_contents:
                    merged_md = merge_markdown_contents(md_contents)
                    upload_url = upload_to_firebase(st.session_state["wix_user_id"], merged_md)
                    if upload_url:
                        st.success("Files uploaded and processed successfully!")
                        st.markdown(f"[View your uploaded knowledge base here]({upload_url})", unsafe_allow_html=True)
                        refresh_faiss_index()
        # Save Custom Content section
        st.header("Save Custom Content")
        custom_content = st.text_area("Enter content to save")
        if st.button("Save as Brand Tonality"):
            save_content(st.session_state["wix_user_id"], custom_content, "brandtonality")
        if st.button("Save as TrustBuilder"):
            save_content(st.session_state["wix_user_id"], custom_content, "trustbuilder")





side()
# Load knowledge base


# Initialize embeddings and FAISS index only when wix_user_id is set

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=5)
    return retrieved_docs

def google_search(query):
    try:
        search_client = serpapi.Client(api_key=serper_api_key)
        results = search_client.search({"engine": "google", "q": query})
        snippets = [result["snippet"] for result in results.get("organic_results", [])]
        return snippets
    except Exception as e:
        logger.error(f"Error in Google search: {e}")
        return ["Error occurred during Google search"]
        


# RAG response function
def rag_response(query):
    try:
        # Directly search for the exact term in the knowledge base
        retrieved_docs = search_knowledge_base(query)
        context = "\n".join(doc.page_content for doc in retrieved_docs)
        
        # Prepare the prompt with the retrieved context
        prompt = f"Context:\n{context}\n\nQuestion: {query}\nAnswer:"
        llm = ChatOpenAI(model="gpt-4o", temperature=0.5, api_key=openai_api_key)
        response = llm.invoke(prompt)
        
        # Replace terms in the final output as per your restrictions
        response_content = response.content
        
        return response_content
    except Exception as e:
        logger.error(f"Error generating RAG response: {e}")
        return "Error occurred during RAG response generation"

# Define tools
@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)

tools = [knowledge_base_tool, google_search_tool]

prompt_message = f"""
**You are an expert copywriter specializing in creating highly creative marketing content in a natural tone that integrates Trust Builders into various content formats for any organization. Your goal is to produce compelling, factual, and well-structured material that is concise and based on the knowledgebase, adhering to the following guidelines. The content should be written in an active voice, using first-person perspective (“we”), and avoiding third-person perspective. Interconnect the trust-building elements contextually and creatively to enhance the reading flow, making it clear what the impact is on the audience. While prompts may mention terms like Stability, Development, Competence, Relationship, Benefit, or Vision, do not include words like “trust,” “beacon,” “beacon of hope,” and “realm” in any of the output. The word “trust” can be used in phrases like “Development trust builders,” but not elsewhere in the copy.**

### 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** (e.g., "Dr. Sarah Chen, Global Health Director").
   - **At least 2 complete program names with years** (e.g., "Operation Healthy Future 2024-2025").
   - **Minimum 3 specific locations** with city/country (e.g., "Nairobi, Kenya").
   - **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 REQUIREMENTS*
1. **Each source link must**:
   - Be **working and clickable**.
   - Be **no older than 2 years** unless historically significant.
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".
- ❌ "team of experts" → ✅ "157 certified professionals led by Dr. Sarah Chen".

###ERROR CHECKING
Before submitting, verify and fix:
**When query is to find trust builders never mention heuristic and creative techniques**
1.**Avoid flowery, exaggerated, or overly emotional language**.
2. Eliminate typical AI jargon such as "cutting-edge," ,"beacon of hope,"realm","leading," or other repetitive phrases. 
3. **No approximations** (e.g., "about", "around", "approximately").
4. **No ranges** (e.g., "10-20 million")—use **exact figures**.
5. **No missing specific details** from the mandatory checklist.
6. **No prohibited terms included in the copy.**.
7. ** DONOT INCLUDE heuristic and  creative techniques in Trustbuilder queries**

### CRITICAL MANDATORY INSTRUCTIONS
- **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.
- **Tone**:
  - Use an **active voice , engaging, and direct tone**.
- **Accuracy**: Ensure all dollar amounts, facts, figures, and details are accurate and up-to-date.
- Only provide **verified and clickable source links fron google** in the "List of TrustBuilders." 
- **Formatting**: Ensure formatting is clean and professional, with **no HTML tags**.
With every copy application involving always include this:
- **List of TrustBuilders Used**: Provide relevant trustbuilders  used with embedded source links always.
-**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 techniques without additional details).
     -Limit to 3-5 items in each category.
    Note: When including heuristics and creative techniques, use the  single line structure “Heuristics: examples” and “Creative Techniques: examples” with no extra details.
- If the query is about trust builders , do not include heuristics or creative techniques,List of TrustBuilders Used.

### CONTENT TYPES AND FORMATS

#### 1. Report/Article/writeup  
- **Introduction**: Start with "Here is a draft of your [Annual Report/Article/writeup]. Feel free to suggest further refinements."
- **Structure**:
  - **Headlines**: Create a compelling headline that reflects the content, **without mentioning prohibited terms**.
  - **Content**:
    -  Use **headings** with all content paragraphs to structure the article.**without source links**.
    - **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**:Strictly Provide relevant trust-building points followed  with -[Source link](#).
      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**: Strictly follow any specified word count for the main content. Do not include sub-heading sections in the word count limit.
- **Important Notes**:
  - **Strictly search and provide accurate source links always**.

#### 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,Blog, 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**: Create a compelling headline that reflects the content, **without mentioning prohibited terms**.
  - **Content**:
    -  Use **headings** with all content paragraphs to structure the article.**without source links**.
    - **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 **2023**, 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
- Donot use knowledge base for non-trust content.Give quick output according to above given guidance.
- **Audience Impact**: Always clarify what the information means to  the audience.
- Refer knowledgebase when asked about trustifier or TrustLogic.
- Search always in Knowledgebase first and then move to google.


"""

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.6)
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

# Initialize chat history
if 'chat_history' not in st.session_state:
    st.session_state.chat_history = []

# 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 Food for the Hungry
        </div>
        <div class="section">
            <h2>Create</h2>
            <p>Generate trust-optimised solutions : <br>Example: Find Food for the Hungry 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}")





# Function to handle queries about saved TrustBuilders or Brand Tonality
def handle_memory_queries(prompt):
    prompt = prompt.lower().strip()
    
    # Save as TrustBuilder, removing the phrase from the content
    if "save this as trustbuilder" in prompt:
        content_to_save = prompt.replace("save this as trustbuilder", "").strip()
        if content_to_save:  # Only save if there's actual content
            store_trustbuilder(st.session_state["wix_user_id"], content_to_save)
            return "TrustBuilder saved successfully!"
        else:
            return "Please provide content to save as TrustBuilder."

    # Save as Brand Tonality, removing the phrase from the content
    elif "save this as brand tonality" in prompt:
        content_to_save = prompt.replace("save this as brand tonality", "").strip()
        if content_to_save:  # Only save if there's actual content
            store_brand_tonality(st.session_state["wix_user_id"], content_to_save)
            return "Brand Tonality saved successfully!"
        else:
            return "Please provide content to save as Brand Tonality."

    # Retrieve saved TrustBuilders
    elif "show my saved trustbuilders" in prompt or "find my saved trustbuilders" in prompt:
        trustbuilders = st.session_state.get("TrustBuilder", {})
        if trustbuilders:
            # Return only the content messages without any IDs or extra details
            response = "\n".join([f"- {entry['message']}" for entry in trustbuilders.values()])
            return f"Here are your saved TrustBuilders:\n{response}"
        else:
            return "You haven't saved any TrustBuilders yet."

    # Retrieve saved Brand Tonality
    elif "show my saved brand tonality" in prompt or "find my saved brand tonality" in prompt:
        brand_tonality = st.session_state.get("BrandTonality", {})
        if brand_tonality:
            # Return only the content messages without any IDs or extra details
            response = "\n".join([f"- {entry['message']}" for entry in brand_tonality.values()])
            return f"Here are your saved Brand Tonality entries:\n{response}"
        else:
            return "You haven't saved any Brand Tonality entries yet."

    return None # If no recognized command, proceed with general handling


def delete_entry(category, entry_id, session_key):
    """
    Deletes an entry from Firebase and updates the session state to reflect the deletion.
    """
    try:
        # Get user ID from session state
        user_id = st.session_state["wix_user_id"]
        
        # Remove the entry from Firebase
        db.child("users").child(user_id).child(category).child(entry_id).remove()

        # Remove from session state and refresh sidebar display
        if session_key in st.session_state and entry_id in st.session_state[session_key]:
            del st.session_state[session_key][entry_id]

        # Refresh the app to immediately reflect the change in the sidebar
        st.rerun()
    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_or_tonality(user_id, content, type_name):
    save_content(user_id, content, type_name)
    display_saved_trustbuilders()


                        
# Function to update the message counter in a static location



def initialize_wix_only_user(wix_user_id, email):
    try:
        # Send a POST request to initialize Wix-only user
        response = requests.post(f"{backend_url}/wix_user_login_no_chargebee", json={
            "email": email,
            "wixUserId": wix_user_id
        })
        
        # Check for a successful response
        if response.status_code == 200:
            data = response.json()
            user_data = data.get("user_data", {})
            st.session_state["message_limit"] = user_data.get("message_limit", 100)
            st.session_state["used_messages"] = user_data.get("used_messages", 0)
        else:
            # Log and display error if status code is not 200
            st.error(f"Failed to initialize Wix-only user. Status Code: {response.status_code}")
            st.error(f"Response: {response.text}")

    except Exception as e:
        # Log exception details
        st.error(f"Error initializing user data for Wix-only login: {str(e)}")
        st.session_state["message_limit"] = 100
        st.session_state["used_messages"] = 0

   

# Update message usage in Firebase after each interaction
def update_message_usage(wix_user_id):
    response = requests.post(f"{backend_url}/update-message-usage/{wix_user_id}")
    if response.status_code == 200:
        st.session_state["used_messages"] += 1
        update_message_counter()
    else:
        st.error("Error updating message usage.")

# Main interface
if st.session_state.get("wix_user_id") and st.session_state.get("email"):
    initialize_wix_only_user(st.session_state["wix_user_id"], st.session_state["email"])

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

    user_name = extract_name(st.session_state["email"])
    welcome_placeholder = st.empty()
    welcome_placeholder.info(f"**Hello, {user_name}!**")
    time.sleep(3)
    welcome_placeholder.empty()



    # Input field for chatbot interaction
    prompt = st.chat_input("")
    global combined_text
    if st.session_state["used_messages"] < st.session_state["message_limit"]:
        if prompt:
            st.session_state.chat_started = True
            st.session_state.chat_history.append({"role": "user", "content": prompt})

            # Handle save commands based on the user prompt
            memory_response = handle_memory_queries(prompt)
            if memory_response:
                with st.chat_message("assistant"):
                    st.markdown(memory_response)
            else:
                save_as_trustbuilder = re.search(r"\b(save|add|store)\s*(this)?\s*(as)?\s*(trust\s*builder|trustbuilder)\b", prompt, re.IGNORECASE)
                save_as_tonality = re.search(r"\b(save|add|store)\s*(this)?\s*(as)?\s*(brand\s*tonality|tonality)\b", prompt, re.IGNORECASE)

                if save_as_trustbuilder or save_as_tonality:
                    user_id = st.session_state["wix_user_id"]
                    if save_as_trustbuilder:
                        handle_save_trustbuilder_or_tonality(user_id, prompt, "trustbuilder")
                    elif save_as_tonality:
                        handle_save_trustbuilder_or_tonality(user_id, prompt, "brandtonality")

                   
                else:
                    # Generate a response with AI for general queries
                    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 = ""
                    try:
                        output = agent_executor.invoke({
                            "input": f"{prompt} Be in natural tone,doesn’t use flowery language and typical ai words .Sources should be accurate search on google for that.Avoid AI jargons.Give headings with each paragraph in content of article,blogs,writeup and newsletter keeping mentioned format.",
                            "chat_history": st.session_state.chat_history
                        })
                        full_response = output["output"]
                        cleaned_text = clean_text(full_response)
                        trust_tip, suggestion = get_trust_tip_and_suggestion()
                        combined_text = f"{cleaned_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, unsafe_allow_html=True)

                        update_message_usage(st.session_state["wix_user_id"])

                    except Exception as e:
                        logger.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": cleaned_text})
                    copy_to_clipboard(cleaned_text)
    else:
        st.warning("You have reached your message limit. Please upgrade your plan to continue.")
else:
    st.warning("Please log in to access the chatbot features.")