Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -751,524 +751,500 @@ def rename_kb_file(old_name: str, new_name: str) -> Tuple[str, str]:
|
|
| 751 |
return f"β Could not rename: {e}", list_kb_files_html()
|
| 752 |
|
| 753 |
|
| 754 |
-
# ββ CSS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 755 |
|
| 756 |
-
STYLE_HTML = """<style>
|
| 757 |
-
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
| 758 |
|
| 759 |
-
|
| 760 |
-
/* Palette */
|
| 761 |
-
--sage:#6b8f71; --sage-l:#eaf2eb; --sage-d:#4f6e55; --sage-xl:#f2f8f3;
|
| 762 |
-
--sand:#f5f0e8; --cream:#fdfaf5; --stone:#e4ddd3; --stone2:#d0c8bd;
|
| 763 |
-
--ink:#2d2d2d; --ink2:#4a4540; --muted:#7a7167; --muted2:#a09890;
|
| 764 |
-
--rose:#c0717a; --rose-l:#f8eded;
|
| 765 |
-
/* Spacing & shape */
|
| 766 |
-
--r:13px; --r-sm:8px; --r-xs:5px;
|
| 767 |
-
/* Shadows */
|
| 768 |
-
--sh-sm: 0 1px 3px rgba(0,0,0,.07);
|
| 769 |
-
--sh: 0 2px 10px rgba(0,0,0,.08);
|
| 770 |
-
--sh-md: 0 4px 20px rgba(0,0,0,.10);
|
| 771 |
-
--sh-lg: 0 8px 32px rgba(0,0,0,.13);
|
| 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 |
display: flex; align-items: center; justify-content: center;
|
| 799 |
-
font-size:
|
| 800 |
-
box-shadow: 0
|
| 801 |
}
|
| 802 |
-
.
|
| 803 |
-
|
| 804 |
-
color: var(--ink); letter-spacing: -.01em;
|
| 805 |
}
|
| 806 |
-
.
|
| 807 |
-
|
| 808 |
-
.app-hdr-badge {
|
| 809 |
margin-left: auto;
|
| 810 |
-
|
| 811 |
-
color: var(--
|
| 812 |
-
|
| 813 |
-
|
| 814 |
}
|
| 815 |
|
| 816 |
-
/* ββ 3-
|
| 817 |
-
.
|
| 818 |
-
display: grid;
|
| 819 |
-
grid-template-columns:
|
| 820 |
-
height: calc(100vh -
|
| 821 |
-
overflow: hidden;
|
|
|
|
| 822 |
}
|
| 823 |
-
@media(max-width:
|
| 824 |
-
.
|
| 825 |
-
.left-
|
| 826 |
}
|
| 827 |
|
| 828 |
-
/* ββ Left
|
| 829 |
-
.left-
|
| 830 |
-
border-right: 1px solid var(--
|
|
|
|
| 831 |
display: flex; flex-direction: column; overflow: hidden;
|
| 832 |
}
|
| 833 |
-
.
|
| 834 |
-
padding:
|
| 835 |
-
font-size:
|
| 836 |
-
text-transform: uppercase; color: var(--muted2);
|
| 837 |
-
border-bottom: 1px solid var(--
|
| 838 |
display: flex; align-items: center; gap: 6px;
|
| 839 |
}
|
| 840 |
-
.
|
| 841 |
content: "";
|
| 842 |
-
|
| 843 |
-
background: var(--sage); border-radius: 50%;
|
| 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 |
-
.suggestion-pill:hover::before { transform: translateX(3px); }
|
| 874 |
-
@keyframes pillFadeIn {
|
| 875 |
-
from { opacity: 0; transform: translateY(6px); }
|
| 876 |
-
to { opacity: 1; transform: translateY(0); }
|
| 877 |
}
|
| 878 |
|
| 879 |
-
/* ββ Centre
|
| 880 |
-
.
|
| 881 |
-
display: flex; flex-direction: column
|
| 882 |
-
background: var(--
|
| 883 |
}
|
| 884 |
|
| 885 |
-
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 886 |
[data-testid="chatbot"] > .label-wrap,
|
| 887 |
-
[data-testid="chatbot"] > div > .label-wrap,
|
| 888 |
[data-testid="chatbot"] label,
|
| 889 |
-
|
| 890 |
-
.
|
| 891 |
-
.gr-chatbot-container .label-wrap,
|
| 892 |
-
.chatbot > .panel > .label,
|
| 893 |
-
div[class*="label"] > span:only-child,
|
| 894 |
-
.block > .label-wrap { display: none !important; }
|
| 895 |
-
.gr-chatbot, [data-testid="chatbot"] {
|
| 896 |
-
flex: 1 !important; height: 100% !important;
|
| 897 |
-
border: none !important; border-radius: 0 !important; background: transparent !important;
|
| 898 |
-
}
|
| 899 |
-
footer { display: none !important; }
|
| 900 |
|
| 901 |
-
/* ββ
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
from { opacity: 0; transform: translateY(8px); }
|
| 905 |
to { opacity: 1; transform: translateY(0); }
|
| 906 |
}
|
|
|
|
|
|
|
| 907 |
.message.user > div {
|
| 908 |
-
background:
|
| 909 |
color: #fff !important;
|
| 910 |
-
border-radius: var(--r) var(--r)
|
| 911 |
-
padding:
|
| 912 |
-
|
| 913 |
-
|
|
|
|
| 914 |
}
|
| 915 |
.message.bot > div {
|
| 916 |
-
background: var(--
|
| 917 |
-
border
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
| 921 |
-
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
content: "π€";
|
| 925 |
-
display: block; font-size: .85rem; margin-bottom: 4px;
|
| 926 |
-
opacity: .7;
|
| 927 |
}
|
| 928 |
|
| 929 |
-
/* ββ Input + toolbar
|
| 930 |
.chat-input-container {
|
| 931 |
-
background: var(--
|
| 932 |
-
border-top: 1px solid var(--
|
| 933 |
-
padding:
|
| 934 |
-
flex-shrink: 0;
|
| 935 |
}
|
| 936 |
-
/*
|
| 937 |
.chat-input-container > .wrap,
|
| 938 |
.chat-input-container > div:first-child {
|
| 939 |
-
border: 1.5px solid var(--
|
| 940 |
-
border-radius: var(--r)
|
| 941 |
-
|
| 942 |
-
|
|
|
|
| 943 |
}
|
| 944 |
.chat-input-container > .wrap:focus-within,
|
| 945 |
.chat-input-container > div:first-child:focus-within {
|
| 946 |
-
border-color: var(--sage) !important;
|
| 947 |
-
box-shadow: 0 0 0 3px rgba(
|
| 948 |
}
|
| 949 |
.chat-input-container textarea {
|
| 950 |
-
background: var(--
|
| 951 |
-
border
|
| 952 |
-
|
| 953 |
-
|
|
|
|
| 954 |
line-height: 1.55 !important;
|
| 955 |
}
|
| 956 |
.chat-input-container textarea:focus { outline: none !important; box-shadow: none !important; }
|
| 957 |
-
.chat-input-container textarea::placeholder { color: var(--muted2) !important; }
|
| 958 |
-
|
| 959 |
-
|
| 960 |
-
|
| 961 |
-
|
| 962 |
-
|
| 963 |
-
|
| 964 |
-
|
| 965 |
-
|
|
|
|
|
|
|
|
|
|
| 966 |
}
|
| 967 |
.chat-input-container button[aria-label="Send"]:hover {
|
| 968 |
-
|
| 969 |
-
|
| 970 |
-
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
|
| 977 |
-
|
| 978 |
-
|
| 979 |
-
|
| 980 |
-
|
| 981 |
-
|
| 982 |
-
|
| 983 |
-
|
| 984 |
-
|
| 985 |
-
|
| 986 |
-
|
| 987 |
-
|
| 988 |
-
.tb-
|
| 989 |
-
|
| 990 |
-
|
| 991 |
-
|
| 992 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 993 |
font-family: "Inter", sans-serif;
|
| 994 |
}
|
| 995 |
-
.tb-
|
| 996 |
|
| 997 |
-
/* ββ Right
|
| 998 |
-
.right-
|
| 999 |
-
border-left: 1px solid var(--
|
|
|
|
| 1000 |
display: flex; flex-direction: column; overflow: hidden;
|
| 1001 |
}
|
| 1002 |
-
.
|
| 1003 |
-
padding:
|
| 1004 |
-
|
|
|
|
| 1005 |
}
|
| 1006 |
-
.
|
| 1007 |
-
font-size:
|
| 1008 |
-
text-transform: uppercase; color: var(--muted2);
|
| 1009 |
display: flex; align-items: center; gap: 6px;
|
| 1010 |
}
|
| 1011 |
-
.
|
| 1012 |
content: "";
|
| 1013 |
-
|
| 1014 |
-
background: var(--sage); border-radius: 50%;
|
| 1015 |
}
|
| 1016 |
-
|
| 1017 |
-
|
| 1018 |
-
background: var(--sage-
|
| 1019 |
-
|
| 1020 |
-
border: 1px solid var(--sage-l);
|
| 1021 |
}
|
| 1022 |
-
|
| 1023 |
/* + Add file */
|
| 1024 |
-
.add-
|
| 1025 |
-
.add-
|
| 1026 |
-
|
| 1027 |
-
|
| 1028 |
-
|
| 1029 |
-
|
| 1030 |
-
|
| 1031 |
-
|
| 1032 |
-
|
| 1033 |
-
|
| 1034 |
-
|
| 1035 |
-
box-shadow: 0
|
| 1036 |
-
|
| 1037 |
-
|
| 1038 |
-
|
| 1039 |
-
|
| 1040 |
-
|
| 1041 |
-
|
| 1042 |
-
|
| 1043 |
-
|
| 1044 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1045 |
}
|
| 1046 |
-
@keyframes tooltipIn {
|
| 1047 |
-
from { opacity: 0; transform: translateY(-3px); }
|
| 1048 |
-
to { opacity: 1; transform: translateY(0); }
|
| 1049 |
-
}
|
| 1050 |
-
.add-file-tooltip::before {
|
| 1051 |
-
content: ""; position: absolute; top: -5px; right: 14px;
|
| 1052 |
-
border-left: 5px solid transparent; border-right: 5px solid transparent;
|
| 1053 |
-
border-bottom: 5px solid var(--ink);
|
| 1054 |
-
}
|
| 1055 |
-
.add-file-tooltip strong { display: block; margin-bottom: 4px; font-size: .76rem; }
|
| 1056 |
-
.add-file-tooltip .tt-row { display: flex; align-items: center; gap: 6px; opacity: .88; }
|
| 1057 |
-
.add-file-tooltip .tt-row::before { content: "β’"; color: var(--sage-l); }
|
| 1058 |
-
.add-file-btn-wrap:hover .add-file-tooltip { display: block; }
|
| 1059 |
-
|
| 1060 |
-
.right-col-body { overflow-y: auto; padding: 6px 8px 16px; flex: 1; }
|
| 1061 |
|
| 1062 |
/* File rows */
|
| 1063 |
-
.
|
| 1064 |
-
display: flex; align-items: center; gap:
|
| 1065 |
-
padding: 7px
|
| 1066 |
-
transition: background .
|
| 1067 |
-
}
|
| 1068 |
-
.
|
| 1069 |
-
.
|
| 1070 |
-
.
|
| 1071 |
-
flex: 1; font-size:
|
| 1072 |
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
| 1073 |
}
|
| 1074 |
-
.
|
| 1075 |
-
|
| 1076 |
-
|
| 1077 |
-
|
| 1078 |
-
|
| 1079 |
-
|
| 1080 |
-
padding: 3px 5px; border-radius: 4px; color: var(--muted);
|
| 1081 |
-
transition: background .12s, color .12s; line-height: 1;
|
| 1082 |
}
|
| 1083 |
-
.
|
| 1084 |
-
.
|
| 1085 |
|
| 1086 |
-
/* Rename
|
| 1087 |
-
.
|
| 1088 |
-
|
| 1089 |
-
|
| 1090 |
-
.
|
| 1091 |
-
|
| 1092 |
-
|
| 1093 |
-
padding: 4px 8px; font-size: .75rem; background: var(--sand);
|
| 1094 |
-
color: var(--ink); outline: none; font-family: inherit;
|
| 1095 |
}
|
| 1096 |
-
.
|
| 1097 |
-
background: var(--sage); color: #fff; border: none;
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
}
|
| 1101 |
-
.
|
| 1102 |
-
|
| 1103 |
-
|
| 1104 |
-
|
| 1105 |
}
|
| 1106 |
|
| 1107 |
-
/* ββ
|
| 1108 |
-
.kb-toast {
|
| 1109 |
-
position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%) translateY(6px);
|
| 1110 |
-
background: var(--ink); color: #fff; border-radius: var(--r-sm);
|
| 1111 |
-
padding: 9px 20px; font-size: .79rem; z-index: 9999;
|
| 1112 |
-
opacity: 0; pointer-events: none;
|
| 1113 |
-
transition: opacity .22s, transform .22s;
|
| 1114 |
-
white-space: nowrap; box-shadow: var(--sh-md);
|
| 1115 |
-
display: flex; align-items: center; gap: 8px;
|
| 1116 |
-
}
|
| 1117 |
-
.kb-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
|
| 1118 |
-
|
| 1119 |
-
/* ββ Source chip ββββββββββββββββββββββββββββββββββββββββββ */
|
| 1120 |
.src-row {
|
| 1121 |
display: flex; align-items: center; flex-wrap: wrap; gap: 5px;
|
| 1122 |
margin-top: 10px; padding-top: 9px;
|
| 1123 |
-
border-top: 1px solid var(--
|
| 1124 |
}
|
| 1125 |
-
.src-
|
| 1126 |
-
font-size: .
|
| 1127 |
-
text-transform: uppercase; color: var(--muted2);
|
| 1128 |
-
margin-right: 2px; flex-shrink: 0;
|
| 1129 |
}
|
| 1130 |
.src-chip {
|
| 1131 |
display: inline-flex; align-items: center; gap: 4px;
|
| 1132 |
-
background: var(--sage-
|
| 1133 |
border-radius: 999px; padding: 2px 10px 2px 7px;
|
| 1134 |
-
|
| 1135 |
-
|
| 1136 |
}
|
| 1137 |
-
.src-chip:hover { background: var(--sage-
|
| 1138 |
@keyframes chipIn {
|
| 1139 |
-
from { opacity:
|
| 1140 |
-
to { opacity:
|
| 1141 |
}
|
| 1142 |
-
.src-chip-icon { font-size: .
|
| 1143 |
.src-chip-name {
|
| 1144 |
-
font-size:
|
| 1145 |
-
|
| 1146 |
-
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
| 1147 |
}
|
| 1148 |
|
| 1149 |
-
/* ββ
|
| 1150 |
-
|
| 1151 |
-
:
|
| 1152 |
-
:
|
| 1153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1154 |
|
| 1155 |
-
/* ββ
|
| 1156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1157 |
</style>
|
| 1158 |
|
| 1159 |
<script>
|
| 1160 |
-
/* ββ
|
| 1161 |
-
function kbAction(action,
|
| 1162 |
if (action === 'delete') {
|
| 1163 |
-
if (!confirm('Delete ' +
|
| 1164 |
-
|
| 1165 |
-
setTimeout(function(){
|
| 1166 |
} else if (action === 'replace') {
|
| 1167 |
document.getElementById('kb-file-attach').click();
|
| 1168 |
-
// Store target for replacement note
|
| 1169 |
-
window._kbReplaceTarget = filename;
|
| 1170 |
} else if (action === 'rename') {
|
| 1171 |
-
var
|
| 1172 |
-
var
|
| 1173 |
-
if (
|
| 1174 |
-
if (
|
| 1175 |
}
|
| 1176 |
}
|
| 1177 |
-
function kbCancelRename(
|
| 1178 |
-
var
|
| 1179 |
-
var
|
| 1180 |
-
if (
|
| 1181 |
-
if (
|
| 1182 |
-
}
|
| 1183 |
-
function kbSaveRename(
|
| 1184 |
-
var
|
| 1185 |
-
var
|
| 1186 |
-
if (!
|
| 1187 |
-
|
| 1188 |
-
|
| 1189 |
-
setTimeout(function(){
|
| 1190 |
-
}
|
| 1191 |
-
function
|
| 1192 |
-
var el = document.querySelector('#' +
|
| 1193 |
if (!el) return;
|
| 1194 |
-
el.value =
|
| 1195 |
-
el.dispatchEvent(new Event(
|
| 1196 |
-
el.dispatchEvent(new Event('change', { bubbles: true }));
|
| 1197 |
}
|
| 1198 |
-
function
|
| 1199 |
-
var
|
| 1200 |
-
if (
|
| 1201 |
}
|
| 1202 |
function showToast(msg) {
|
| 1203 |
-
var t = document.getElementById('
|
| 1204 |
if (!t) return;
|
| 1205 |
t.textContent = msg; t.classList.add('show');
|
| 1206 |
-
setTimeout(function(){ t.classList.remove('show'); },
|
| 1207 |
}
|
| 1208 |
-
/* ββ
|
| 1209 |
-
|
| 1210 |
-
function tryInject() {
|
| 1211 |
-
var chatCol = document.querySelector('.centre-col-inner');
|
| 1212 |
-
if (!chatCol) { setTimeout(tryInject, 400); return; }
|
| 1213 |
-
var body = document.querySelector('.app-body');
|
| 1214 |
-
if (body) return; // already done
|
| 1215 |
-
|
| 1216 |
-
/* Wrap everything in a 3-col grid */
|
| 1217 |
-
var wrapper = document.createElement('div');
|
| 1218 |
-
wrapper.className = 'app-body';
|
| 1219 |
-
|
| 1220 |
-
var left = document.getElementById('left-col-mount');
|
| 1221 |
-
var right = document.getElementById('right-col-mount');
|
| 1222 |
-
var chat = chatCol.parentElement;
|
| 1223 |
-
|
| 1224 |
-
if (left && right && chat) {
|
| 1225 |
-
chat.parentElement.insertBefore(wrapper, chat);
|
| 1226 |
-
wrapper.appendChild(left);
|
| 1227 |
-
wrapper.appendChild(chat);
|
| 1228 |
-
wrapper.appendChild(right);
|
| 1229 |
-
}
|
| 1230 |
-
}
|
| 1231 |
-
if (document.readyState === 'loading') {
|
| 1232 |
-
document.addEventListener('DOMContentLoaded', function(){ setTimeout(tryInject, 600); });
|
| 1233 |
-
} else {
|
| 1234 |
-
setTimeout(tryInject, 600);
|
| 1235 |
-
}
|
| 1236 |
-
})();
|
| 1237 |
-
/* Kill "Chatbot" label β JS fallback for Svelte-hashed classnames */
|
| 1238 |
-
function killChatbotLabel() {
|
| 1239 |
-
/* Find all elements whose visible text is exactly "Chatbot" and hide them */
|
| 1240 |
document.querySelectorAll('label, span, div').forEach(function(el) {
|
| 1241 |
-
if (el.children.length
|
| 1242 |
el.style.display = 'none';
|
| 1243 |
-
var
|
| 1244 |
-
if (
|
| 1245 |
}
|
| 1246 |
});
|
| 1247 |
}
|
| 1248 |
-
|
| 1249 |
-
|
| 1250 |
-
|
| 1251 |
-
} else {
|
| 1252 |
-
setTimeout(killChatbotLabel, 600);
|
| 1253 |
-
}
|
| 1254 |
-
var _kbLabelObserver = new MutationObserver(function(){ killChatbotLabel(); });
|
| 1255 |
-
_kbLabelObserver.observe(document.body, { childList: true, subtree: true });
|
| 1256 |
|
| 1257 |
-
/*
|
| 1258 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1259 |
var t = document.querySelector('.chat-input-container textarea');
|
| 1260 |
if (!t) return;
|
| 1261 |
var s = t.selectionStart, e = t.selectionEnd, v = t.value;
|
| 1262 |
if (s === e) return;
|
| 1263 |
-
t.value = v.slice(0,s)
|
| 1264 |
-
t.selectionStart = s; t.selectionEnd = e
|
| 1265 |
t.dispatchEvent(new Event('input',{bubbles:true}));
|
| 1266 |
}
|
| 1267 |
function tbBullet() {
|
| 1268 |
var t = document.querySelector('.chat-input-container textarea');
|
| 1269 |
if (!t) return;
|
| 1270 |
-
var
|
| 1271 |
-
|
| 1272 |
t.dispatchEvent(new Event('input',{bubbles:true}));
|
| 1273 |
}
|
| 1274 |
function tbPaste() {
|
|
@@ -1276,35 +1252,55 @@ function tbPaste() {
|
|
| 1276 |
if (!t) return;
|
| 1277 |
navigator.clipboard.readText().then(function(s){
|
| 1278 |
var i = t.selectionStart;
|
| 1279 |
-
t.value = t.value.slice(0,i)
|
| 1280 |
-
t.selectionStart = t.selectionEnd = i
|
| 1281 |
t.dispatchEvent(new Event('input',{bubbles:true}));
|
| 1282 |
}).catch(function(){ t.focus(); });
|
| 1283 |
}
|
| 1284 |
-
</script>
|
|
|
|
| 1285 |
|
| 1286 |
TOOLBAR_HTML = """
|
| 1287 |
-
<div class="tb
|
| 1288 |
-
<button class="tb-
|
| 1289 |
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
|
|
|
|
| 1290 |
</button>
|
| 1291 |
-
<button class="tb-
|
| 1292 |
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
|
|
|
|
|
|
|
| 1293 |
</button>
|
| 1294 |
-
<div class="tb-
|
| 1295 |
-
<button class="tb-
|
| 1296 |
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
|
|
|
|
|
|
|
| 1297 |
</button>
|
| 1298 |
-
<button class="tb-
|
| 1299 |
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
|
|
|
|
| 1300 |
</button>
|
| 1301 |
-
<button class="tb-
|
| 1302 |
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1303 |
</button>
|
| 1304 |
-
<button class="tb-
|
| 1305 |
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
|
|
|
|
| 1306 |
</button>
|
| 1307 |
-
</div>
|
|
|
|
|
|
|
|
|
|
| 1308 |
|
| 1309 |
examples = [
|
| 1310 |
q["query"] for q in CONFIG.get("quick_actions", []) if "query" in q
|
|
@@ -1314,72 +1310,67 @@ examples = [
|
|
| 1314 |
"Why is self-service important for customer support?",
|
| 1315 |
]
|
| 1316 |
|
|
|
|
|
|
|
| 1317 |
with gr.Blocks(title=CONFIG["client"]["name"]) as demo:
|
| 1318 |
|
| 1319 |
gr.HTML(STYLE_HTML)
|
| 1320 |
-
gr.HTML('<div id="
|
| 1321 |
|
| 1322 |
-
#
|
| 1323 |
gr.HTML(f"""
|
| 1324 |
-
<div class="
|
| 1325 |
-
<div class="
|
| 1326 |
<div>
|
| 1327 |
-
<
|
| 1328 |
-
<
|
| 1329 |
</div>
|
| 1330 |
-
<span class="
|
| 1331 |
</div>""")
|
| 1332 |
|
| 1333 |
-
|
| 1334 |
-
|
| 1335 |
-
|
| 1336 |
-
|
| 1337 |
-
|
| 1338 |
-
|
| 1339 |
-
|
| 1340 |
-
|
| 1341 |
-
|
| 1342 |
-
|
| 1343 |
-
|
| 1344 |
-
|
| 1345 |
-
for q in examples
|
| 1346 |
-
) + "</div>")
|
| 1347 |
-
|
| 1348 |
-
# ββ CENTRE: chat βββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1349 |
-
with gr.Column(scale=3, elem_classes="centre-col"):
|
| 1350 |
-
gr.ChatInterface(
|
| 1351 |
-
fn=chat_respond,
|
| 1352 |
-
cache_examples=False,
|
| 1353 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1354 |
gr.HTML(TOOLBAR_HTML)
|
| 1355 |
|
| 1356 |
-
# ββ
|
| 1357 |
-
with gr.Column(scale=1, elem_classes="right-
|
| 1358 |
gr.HTML("""
|
| 1359 |
-
<div class="
|
| 1360 |
-
<span class="
|
| 1361 |
-
<div class="add-
|
| 1362 |
-
<button class="add-file-
|
| 1363 |
-
onclick="document.getElementById('kb-file-attach').click()">
|
| 1364 |
+ Add file
|
| 1365 |
</button>
|
| 1366 |
-
<div class="add-
|
| 1367 |
<strong>Add to knowledge base</strong>
|
| 1368 |
-
<
|
| 1369 |
-
<
|
| 1370 |
-
<
|
| 1371 |
-
<
|
| 1372 |
</div>
|
| 1373 |
</div>
|
| 1374 |
</div>""")
|
| 1375 |
|
| 1376 |
-
kb_file_list
|
| 1377 |
-
|
| 1378 |
-
# Hidden upload status
|
| 1379 |
upload_status = gr.Markdown(visible=False)
|
| 1380 |
|
| 1381 |
-
#
|
| 1382 |
-
# These are invisible β actions are triggered by JS above
|
| 1383 |
with gr.Row(visible=False):
|
| 1384 |
toolbar_upload = gr.File(
|
| 1385 |
label="", file_count="multiple",
|
|
@@ -1387,17 +1378,15 @@ with gr.Blocks(title=CONFIG["client"]["name"]) as demo:
|
|
| 1387 |
elem_id="kb-file-attach",
|
| 1388 |
)
|
| 1389 |
toolbar_status = gr.Markdown()
|
| 1390 |
-
|
| 1391 |
-
|
| 1392 |
-
|
| 1393 |
-
delete_status= gr.Markdown()
|
| 1394 |
-
|
| 1395 |
old_name_input = gr.Textbox(elem_id="kb-hidden-old-name", show_label=False)
|
| 1396 |
new_name_input = gr.Textbox(elem_id="kb-hidden-new-name", show_label=False)
|
| 1397 |
rename_btn = gr.Button("ren", elem_id="kb-rename-trigger")
|
| 1398 |
rename_status = gr.Markdown()
|
| 1399 |
|
| 1400 |
-
#
|
| 1401 |
def handle_upload(files):
|
| 1402 |
status, _ = upload_kb_files(files)
|
| 1403 |
return status, list_kb_files_html()
|
|
@@ -1410,9 +1399,9 @@ with gr.Blocks(title=CONFIG["client"]["name"]) as demo:
|
|
| 1410 |
status, _ = rename_kb_file(old, new)
|
| 1411 |
return status, list_kb_files_html()
|
| 1412 |
|
| 1413 |
-
toolbar_upload.change(handle_upload, inputs=[toolbar_upload],
|
| 1414 |
-
delete_btn.click( handle_delete, inputs=[delete_input],
|
| 1415 |
-
rename_btn.click( handle_rename, inputs=[old_name_input, new_name_input],
|
| 1416 |
|
| 1417 |
|
| 1418 |
# -----------------------------
|
|
|
|
| 751 |
return f"β Could not rename: {e}", list_kb_files_html()
|
| 752 |
|
| 753 |
|
|
|
|
| 754 |
|
|
|
|
|
|
|
| 755 |
|
| 756 |
+
# ββ CSS + JS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 757 |
|
| 758 |
+
STYLE_HTML = """
|
| 759 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 760 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
| 761 |
+
<style>
|
| 762 |
+
/* βββ Reset & tokens βββββββββββββββββββββββββββββββββββββββββ */
|
| 763 |
+
:root {
|
| 764 |
+
--c-bg: #F6F1E9;
|
| 765 |
+
--c-surface: #FDFAF5;
|
| 766 |
+
--c-border: #E2D9CE;
|
| 767 |
+
--c-border2: #C9BFB3;
|
| 768 |
+
--c-ink: #1E1C1A;
|
| 769 |
+
--c-ink2: #4A4540;
|
| 770 |
+
--c-muted: #7A7167;
|
| 771 |
+
--c-muted2: #A09890;
|
| 772 |
+
--c-sage: #5C7E62;
|
| 773 |
+
--c-sage-h: #4A6550;
|
| 774 |
+
--c-sage-bg: #EAF2EB;
|
| 775 |
+
--c-sage-bg2: #D4E8D6;
|
| 776 |
+
--c-rose: #B5626A;
|
| 777 |
+
--c-rose-bg: #F8EDEE;
|
| 778 |
+
--r: 10px;
|
| 779 |
+
--r2: 7px;
|
| 780 |
+
--r3: 5px;
|
| 781 |
+
}
|
| 782 |
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
| 783 |
+
html, body, .gradio-container {
|
| 784 |
+
height: 100% !important;
|
| 785 |
+
background: var(--c-bg) !important;
|
| 786 |
+
font-family: "Inter", ui-sans-serif, system-ui, sans-serif !important;
|
| 787 |
+
font-size: 14px !important;
|
| 788 |
+
color: var(--c-ink) !important;
|
| 789 |
+
-webkit-font-smoothing: antialiased !important;
|
| 790 |
+
}
|
| 791 |
+
.gradio-container { max-width: 100% !important; padding: 0 !important; overflow: hidden !important; }
|
| 792 |
+
footer, .footer { display: none !important; }
|
| 793 |
+
|
| 794 |
+
/* βββ Header ββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 795 |
+
.h-bar {
|
| 796 |
+
height: 52px;
|
| 797 |
+
background: var(--c-surface);
|
| 798 |
+
border-bottom: 1px solid var(--c-border);
|
| 799 |
+
display: flex;
|
| 800 |
+
align-items: center;
|
| 801 |
+
padding: 0 20px;
|
| 802 |
+
gap: 11px;
|
| 803 |
+
position: sticky;
|
| 804 |
+
top: 0;
|
| 805 |
+
z-index: 50;
|
| 806 |
+
}
|
| 807 |
+
.h-logo {
|
| 808 |
+
width: 32px; height: 32px;
|
| 809 |
+
background: var(--c-sage);
|
| 810 |
+
border-radius: 8px;
|
| 811 |
display: flex; align-items: center; justify-content: center;
|
| 812 |
+
font-size: 15px; flex-shrink: 0;
|
| 813 |
+
box-shadow: 0 1px 4px rgba(92,126,98,.4);
|
| 814 |
}
|
| 815 |
+
.h-name {
|
| 816 |
+
font-size: 14px; font-weight: 600;
|
| 817 |
+
color: var(--c-ink); letter-spacing: -.01em;
|
| 818 |
}
|
| 819 |
+
.h-sub { font-size: 11.5px; color: var(--c-muted); margin-top: 1px; }
|
| 820 |
+
.h-badge {
|
|
|
|
| 821 |
margin-left: auto;
|
| 822 |
+
font-size: 10.5px; font-weight: 500; letter-spacing: .02em;
|
| 823 |
+
color: var(--c-sage); background: var(--c-sage-bg);
|
| 824 |
+
border: 1px solid var(--c-sage-bg2);
|
| 825 |
+
border-radius: 999px; padding: 3px 10px;
|
| 826 |
}
|
| 827 |
|
| 828 |
+
/* βββ 3-col layout ββββββββββββββββββββββββββββββββββββββββββββ */
|
| 829 |
+
.body-grid {
|
| 830 |
+
display: grid !important;
|
| 831 |
+
grid-template-columns: 196px 1fr 218px !important;
|
| 832 |
+
height: calc(100vh - 52px) !important;
|
| 833 |
+
overflow: hidden !important;
|
| 834 |
+
gap: 0 !important;
|
| 835 |
}
|
| 836 |
+
@media (max-width: 860px) {
|
| 837 |
+
.body-grid { grid-template-columns: 1fr !important; height: auto !important; overflow: visible !important; }
|
| 838 |
+
.left-panel, .right-panel { display: none !important; }
|
| 839 |
}
|
| 840 |
|
| 841 |
+
/* βββ Left panel: suggestions βββββββββββββββββββββββββββββββββ */
|
| 842 |
+
.left-panel {
|
| 843 |
+
border-right: 1px solid var(--c-border);
|
| 844 |
+
background: var(--c-surface);
|
| 845 |
display: flex; flex-direction: column; overflow: hidden;
|
| 846 |
}
|
| 847 |
+
.lp-head {
|
| 848 |
+
padding: 14px 14px 10px;
|
| 849 |
+
font-size: 10px; font-weight: 600; letter-spacing: .08em;
|
| 850 |
+
text-transform: uppercase; color: var(--c-muted2);
|
| 851 |
+
border-bottom: 1px solid var(--c-border);
|
| 852 |
display: flex; align-items: center; gap: 6px;
|
| 853 |
}
|
| 854 |
+
.lp-head::before {
|
| 855 |
content: "";
|
| 856 |
+
width: 5px; height: 5px;
|
| 857 |
+
background: var(--c-sage); border-radius: 50%; flex-shrink: 0;
|
| 858 |
+
}
|
| 859 |
+
.lp-body { overflow-y: auto; padding: 10px 10px 16px; flex: 1; }
|
| 860 |
+
.s-pill {
|
| 861 |
+
width: 100%; display: flex; align-items: flex-start; gap: 8px;
|
| 862 |
+
text-align: left; background: var(--c-surface);
|
| 863 |
+
border: 1px solid var(--c-border); border-radius: var(--r);
|
| 864 |
+
padding: 9px 11px; font-size: 12px; font-weight: 400;
|
| 865 |
+
color: var(--c-ink2); cursor: pointer; margin-bottom: 7px;
|
| 866 |
+
line-height: 1.45; transition: all .15s ease;
|
| 867 |
+
opacity: 0; animation: fadeUp .3s ease forwards;
|
| 868 |
+
}
|
| 869 |
+
.s-pill:nth-child(1) { animation-delay: .04s; }
|
| 870 |
+
.s-pill:nth-child(2) { animation-delay: .10s; }
|
| 871 |
+
.s-pill:nth-child(3) { animation-delay: .16s; }
|
| 872 |
+
.s-pill:nth-child(4) { animation-delay: .22s; }
|
| 873 |
+
.s-pill::before {
|
| 874 |
+
content: "β"; color: var(--c-sage); font-size: 13px;
|
| 875 |
+
flex-shrink: 0; margin-top: 0; line-height: 1.45;
|
| 876 |
+
transition: transform .15s ease;
|
| 877 |
+
}
|
| 878 |
+
.s-pill:hover {
|
| 879 |
+
background: var(--c-sage-bg); border-color: var(--c-sage);
|
| 880 |
+
color: var(--c-sage-h); transform: translateX(2px);
|
| 881 |
+
}
|
| 882 |
+
.s-pill:hover::before { transform: translateX(2px); }
|
| 883 |
+
@keyframes fadeUp {
|
| 884 |
+
from { opacity: 0; transform: translateY(5px); }
|
| 885 |
+
to { opacity: 1; transform: translateY(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 886 |
}
|
| 887 |
|
| 888 |
+
/* βββ Centre: chat βββββββββββββββββββββββοΏ½οΏ½οΏ½βββββββββββββββββββββ */
|
| 889 |
+
.chat-col {
|
| 890 |
+
display: flex !important; flex-direction: column !important;
|
| 891 |
+
overflow: hidden !important; background: var(--c-bg) !important;
|
| 892 |
}
|
| 893 |
|
| 894 |
+
/* Strip ALL Gradio chrome from the chatbot */
|
| 895 |
+
[data-testid="chatbot"], .gr-chatbot {
|
| 896 |
+
flex: 1 !important; border: none !important;
|
| 897 |
+
border-radius: 0 !important; background: transparent !important;
|
| 898 |
+
box-shadow: none !important;
|
| 899 |
+
}
|
| 900 |
+
/* Kill label every possible way */
|
| 901 |
+
[data-testid="chatbot"] .label-wrap,
|
| 902 |
[data-testid="chatbot"] > .label-wrap,
|
|
|
|
| 903 |
[data-testid="chatbot"] label,
|
| 904 |
+
.block > .label-wrap,
|
| 905 |
+
.label-wrap { display: none !important; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 906 |
|
| 907 |
+
/* βββ Bubbles ββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 908 |
+
@keyframes bubIn {
|
| 909 |
+
from { opacity: 0; transform: translateY(6px); }
|
|
|
|
| 910 |
to { opacity: 1; transform: translateY(0); }
|
| 911 |
}
|
| 912 |
+
.message { animation: bubIn .2s ease; }
|
| 913 |
+
|
| 914 |
.message.user > div {
|
| 915 |
+
background: var(--c-sage) !important;
|
| 916 |
color: #fff !important;
|
| 917 |
+
border-radius: var(--r) var(--r) 3px var(--r) !important;
|
| 918 |
+
padding: 9px 13px !important;
|
| 919 |
+
max-width: 72% !important;
|
| 920 |
+
font-size: 13.5px !important; line-height: 1.6 !important;
|
| 921 |
+
box-shadow: 0 2px 8px rgba(92,126,98,.28) !important;
|
| 922 |
}
|
| 923 |
.message.bot > div {
|
| 924 |
+
background: var(--c-surface) !important;
|
| 925 |
+
border: 1px solid var(--c-border) !important;
|
| 926 |
+
border-radius: var(--r) var(--r) var(--r) 3px !important;
|
| 927 |
+
padding: 11px 14px !important;
|
| 928 |
+
max-width: 80% !important;
|
| 929 |
+
font-size: 13.5px !important; line-height: 1.68 !important;
|
| 930 |
+
box-shadow: 0 1px 4px rgba(0,0,0,.07) !important;
|
| 931 |
+
color: var(--c-ink) !important;
|
|
|
|
|
|
|
|
|
|
| 932 |
}
|
| 933 |
|
| 934 |
+
/* βββ Input card (textarea + toolbar as one unit) ββββββββββββββ */
|
| 935 |
.chat-input-container {
|
| 936 |
+
background: var(--c-surface) !important;
|
| 937 |
+
border-top: 1px solid var(--c-border) !important;
|
| 938 |
+
padding: 10px 14px 10px !important;
|
| 939 |
+
flex-shrink: 0 !important;
|
| 940 |
}
|
| 941 |
+
/* The outer input row Gradio wraps */
|
| 942 |
.chat-input-container > .wrap,
|
| 943 |
.chat-input-container > div:first-child {
|
| 944 |
+
border: 1.5px solid var(--c-border) !important;
|
| 945 |
+
border-radius: var(--r) !important;
|
| 946 |
+
background: var(--c-bg) !important;
|
| 947 |
+
overflow: hidden !important;
|
| 948 |
+
transition: border-color .18s, box-shadow .18s !important;
|
| 949 |
}
|
| 950 |
.chat-input-container > .wrap:focus-within,
|
| 951 |
.chat-input-container > div:first-child:focus-within {
|
| 952 |
+
border-color: var(--c-sage) !important;
|
| 953 |
+
box-shadow: 0 0 0 3px rgba(92,126,98,.12) !important;
|
| 954 |
}
|
| 955 |
.chat-input-container textarea {
|
| 956 |
+
background: var(--c-bg) !important;
|
| 957 |
+
border: none !important; border-radius: 0 !important;
|
| 958 |
+
padding: 11px 13px !important;
|
| 959 |
+
font-size: 13.5px !important; font-family: "Inter", sans-serif !important;
|
| 960 |
+
color: var(--c-ink) !important; resize: none !important;
|
| 961 |
line-height: 1.55 !important;
|
| 962 |
}
|
| 963 |
.chat-input-container textarea:focus { outline: none !important; box-shadow: none !important; }
|
| 964 |
+
.chat-input-container textarea::placeholder { color: var(--c-muted2) !important; }
|
| 965 |
+
|
| 966 |
+
/* Send button */
|
| 967 |
+
.chat-input-container button[aria-label="Send"],
|
| 968 |
+
.chat-input-container button.send-btn {
|
| 969 |
+
background: var(--c-sage) !important; color: #fff !important;
|
| 970 |
+
border: none !important; border-radius: var(--r2) !important;
|
| 971 |
+
padding: 0 14px !important; height: 34px !important;
|
| 972 |
+
font-size: 12.5px !important; font-weight: 600 !important;
|
| 973 |
+
margin: 0 6px 6px 0 !important; align-self: flex-end !important;
|
| 974 |
+
transition: background .14s, transform .1s !important;
|
| 975 |
+
box-shadow: 0 1px 4px rgba(92,126,98,.3) !important;
|
| 976 |
}
|
| 977 |
.chat-input-container button[aria-label="Send"]:hover {
|
| 978 |
+
background: var(--c-sage-h) !important;
|
| 979 |
+
transform: translateY(-1px) !important;
|
| 980 |
+
}
|
| 981 |
+
|
| 982 |
+
/* βββ Toolbar fused below textarea βββββββββββββββββββββββββββββ */
|
| 983 |
+
.tb {
|
| 984 |
+
display: flex; align-items: center; gap: 1px;
|
| 985 |
+
padding: 4px 9px 6px;
|
| 986 |
+
background: var(--c-bg);
|
| 987 |
+
border-top: 1px solid var(--c-border);
|
| 988 |
+
border-radius: 0 0 var(--r2) var(--r2);
|
| 989 |
+
margin: 0 -1px -1px;
|
| 990 |
+
}
|
| 991 |
+
.tb-b {
|
| 992 |
+
width: 24px; height: 24px;
|
| 993 |
+
display: inline-flex; align-items: center; justify-content: center;
|
| 994 |
+
background: none; border: none; border-radius: var(--r3);
|
| 995 |
+
cursor: pointer; color: var(--c-muted);
|
| 996 |
+
transition: background .12s, color .12s; position: relative; flex-shrink: 0;
|
| 997 |
+
}
|
| 998 |
+
.tb-b svg { width: 12px; height: 12px; pointer-events: none; display: block; }
|
| 999 |
+
.tb-b:hover { background: var(--c-sage-bg); color: var(--c-sage); }
|
| 1000 |
+
.tb-div { width: 1px; height: 12px; background: var(--c-border2); margin: 0 3px; flex-shrink: 0; }
|
| 1001 |
+
.tb-b[data-tip]::after {
|
| 1002 |
+
content: attr(data-tip);
|
| 1003 |
+
position: absolute; bottom: calc(100% + 5px); left: 50%;
|
| 1004 |
+
transform: translateX(-50%);
|
| 1005 |
+
background: var(--c-ink); color: #fff;
|
| 1006 |
+
font-size: 10px; padding: 3px 7px; border-radius: 4px;
|
| 1007 |
+
white-space: nowrap; pointer-events: none;
|
| 1008 |
+
opacity: 0; transition: opacity .12s; z-index: 99;
|
| 1009 |
font-family: "Inter", sans-serif;
|
| 1010 |
}
|
| 1011 |
+
.tb-b:hover[data-tip]::after { opacity: 1; }
|
| 1012 |
|
| 1013 |
+
/* βββ Right panel: files βββββββββββββββββββββββββββββββββββββββ */
|
| 1014 |
+
.right-panel {
|
| 1015 |
+
border-left: 1px solid var(--c-border);
|
| 1016 |
+
background: var(--c-surface);
|
| 1017 |
display: flex; flex-direction: column; overflow: hidden;
|
| 1018 |
}
|
| 1019 |
+
.rp-head {
|
| 1020 |
+
padding: 13px 14px 11px;
|
| 1021 |
+
border-bottom: 1px solid var(--c-border);
|
| 1022 |
+
flex-shrink: 0; display: flex; align-items: center;
|
| 1023 |
}
|
| 1024 |
+
.rp-title {
|
| 1025 |
+
font-size: 10px; font-weight: 600; letter-spacing: .08em;
|
| 1026 |
+
text-transform: uppercase; color: var(--c-muted2);
|
| 1027 |
display: flex; align-items: center; gap: 6px;
|
| 1028 |
}
|
| 1029 |
+
.rp-title::before {
|
| 1030 |
content: "";
|
| 1031 |
+
width: 5px; height: 5px;
|
| 1032 |
+
background: var(--c-sage); border-radius: 50%;
|
| 1033 |
}
|
| 1034 |
+
.rp-count {
|
| 1035 |
+
font-size: 10px; font-weight: 600; color: var(--c-sage);
|
| 1036 |
+
background: var(--c-sage-bg); border: 1px solid var(--c-sage-bg2);
|
| 1037 |
+
border-radius: 999px; padding: 1px 7px; margin-left: 6px;
|
|
|
|
| 1038 |
}
|
|
|
|
| 1039 |
/* + Add file */
|
| 1040 |
+
.add-wrap { position: relative; margin-left: auto; }
|
| 1041 |
+
.add-btn {
|
| 1042 |
+
display: flex; align-items: center; gap: 4px;
|
| 1043 |
+
background: var(--c-sage-bg); border: 1px solid var(--c-sage-bg2);
|
| 1044 |
+
color: var(--c-sage-h); border-radius: var(--r2);
|
| 1045 |
+
padding: 5px 11px; font-size: 12px; font-weight: 600;
|
| 1046 |
+
cursor: pointer; transition: all .14s; white-space: nowrap;
|
| 1047 |
+
}
|
| 1048 |
+
.add-btn:hover {
|
| 1049 |
+
background: var(--c-sage); color: #fff;
|
| 1050 |
+
border-color: var(--c-sage);
|
| 1051 |
+
box-shadow: 0 1px 6px rgba(92,126,98,.3);
|
| 1052 |
+
}
|
| 1053 |
+
.add-tip {
|
| 1054 |
+
display: none; position: absolute; top: calc(100% + 7px); right: 0;
|
| 1055 |
+
background: var(--c-ink); color: #f5f5f0;
|
| 1056 |
+
border-radius: var(--r2); padding: 11px 13px;
|
| 1057 |
+
font-size: 11px; line-height: 1.7; min-width: 206px;
|
| 1058 |
+
box-shadow: 0 6px 24px rgba(0,0,0,.18); z-index: 60;
|
| 1059 |
+
}
|
| 1060 |
+
.add-tip strong { display: block; margin-bottom: 5px; font-size: 12px; color: #fff; }
|
| 1061 |
+
.add-tip em { display: flex; align-items: center; gap: 5px; opacity: .82; font-style: normal; }
|
| 1062 |
+
.add-tip em::before { content: "β’"; color: #9ecfa4; }
|
| 1063 |
+
.add-tip::before {
|
| 1064 |
+
content: ""; position: absolute; top: -5px; right: 13px;
|
| 1065 |
+
border: 5px solid transparent; border-top: 0;
|
| 1066 |
+
border-bottom-color: var(--c-ink);
|
| 1067 |
+
}
|
| 1068 |
+
.add-wrap:hover .add-tip { display: block; }
|
| 1069 |
+
|
| 1070 |
+
.rp-body { overflow-y: auto; padding: 4px 8px 16px; flex: 1; }
|
| 1071 |
+
.rp-count-line {
|
| 1072 |
+
font-size: 10.5px; color: var(--c-muted2); padding: 8px 6px 4px;
|
| 1073 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1074 |
|
| 1075 |
/* File rows */
|
| 1076 |
+
.f-row {
|
| 1077 |
+
display: flex; align-items: center; gap: 7px;
|
| 1078 |
+
padding: 7px 8px; border-radius: var(--r2);
|
| 1079 |
+
transition: background .12s; position: relative;
|
| 1080 |
+
}
|
| 1081 |
+
.f-row:hover { background: var(--c-bg); }
|
| 1082 |
+
.f-ico { font-size: 13px; flex-shrink: 0; opacity: .75; }
|
| 1083 |
+
.f-name {
|
| 1084 |
+
flex: 1; font-size: 12px; color: var(--c-ink2);
|
| 1085 |
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
| 1086 |
}
|
| 1087 |
+
.f-acts { display: none; gap: 1px; align-items: center; flex-shrink: 0; }
|
| 1088 |
+
.f-row:hover .f-acts { display: flex; }
|
| 1089 |
+
.f-btn {
|
| 1090 |
+
background: none; border: none; cursor: pointer;
|
| 1091 |
+
font-size: 12px; padding: 3px 4px; border-radius: 4px;
|
| 1092 |
+
color: var(--c-muted); transition: background .11s, color .11s; line-height: 1;
|
|
|
|
|
|
|
| 1093 |
}
|
| 1094 |
+
.f-btn:hover { background: var(--c-border); color: var(--c-ink); }
|
| 1095 |
+
.f-btn.del:hover { background: var(--c-rose-bg); color: var(--c-rose); }
|
| 1096 |
|
| 1097 |
+
/* Rename row */
|
| 1098 |
+
.f-rename { display: none; padding: 5px 8px; gap: 5px; align-items: center; }
|
| 1099 |
+
.f-rename.on { display: flex; }
|
| 1100 |
+
.f-rename input {
|
| 1101 |
+
flex: 1; border: 1.5px solid var(--c-sage); border-radius: var(--r3);
|
| 1102 |
+
padding: 4px 8px; font-size: 11px; background: var(--c-bg);
|
| 1103 |
+
color: var(--c-ink); outline: none; font-family: "Inter", sans-serif;
|
|
|
|
|
|
|
| 1104 |
}
|
| 1105 |
+
.f-rename .save {
|
| 1106 |
+
background: var(--c-sage); color: #fff; border: none;
|
| 1107 |
+
border-radius: var(--r3); padding: 4px 9px;
|
| 1108 |
+
font-size: 11px; font-weight: 600; cursor: pointer;
|
| 1109 |
}
|
| 1110 |
+
.f-rename .cancel {
|
| 1111 |
+
background: none; border: 1px solid var(--c-border);
|
| 1112 |
+
border-radius: var(--r3); padding: 4px 7px;
|
| 1113 |
+
font-size: 11px; color: var(--c-muted); cursor: pointer;
|
| 1114 |
}
|
| 1115 |
|
| 1116 |
+
/* βββ Source chips on bot replies ββββββββββββββββββββββββββββββ */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1117 |
.src-row {
|
| 1118 |
display: flex; align-items: center; flex-wrap: wrap; gap: 5px;
|
| 1119 |
margin-top: 10px; padding-top: 9px;
|
| 1120 |
+
border-top: 1px solid var(--c-border);
|
| 1121 |
}
|
| 1122 |
+
.src-lbl {
|
| 1123 |
+
font-size: 9.5px; font-weight: 700; letter-spacing: .08em;
|
| 1124 |
+
text-transform: uppercase; color: var(--c-muted2); flex-shrink: 0; margin-right: 1px;
|
|
|
|
| 1125 |
}
|
| 1126 |
.src-chip {
|
| 1127 |
display: inline-flex; align-items: center; gap: 4px;
|
| 1128 |
+
background: var(--c-sage-bg); border: 1px solid var(--c-sage-bg2);
|
| 1129 |
border-radius: 999px; padding: 2px 10px 2px 7px;
|
| 1130 |
+
animation: chipIn .2s ease;
|
| 1131 |
+
transition: background .13s, border-color .13s;
|
| 1132 |
}
|
| 1133 |
+
.src-chip:hover { background: var(--c-sage-bg2); border-color: var(--c-sage); }
|
| 1134 |
@keyframes chipIn {
|
| 1135 |
+
from { opacity:0; transform: scale(.92) translateY(3px); }
|
| 1136 |
+
to { opacity:1; transform: scale(1) translateY(0); }
|
| 1137 |
}
|
| 1138 |
+
.src-chip-icon { font-size: 10.5px; }
|
| 1139 |
.src-chip-name {
|
| 1140 |
+
font-size: 11px; font-weight: 500; color: var(--c-sage-h);
|
| 1141 |
+
max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
|
|
| 1142 |
}
|
| 1143 |
|
| 1144 |
+
/* βββ Toast ββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1145 |
+
.toast {
|
| 1146 |
+
position: fixed; bottom: 20px; left: 50%;
|
| 1147 |
+
transform: translateX(-50%) translateY(8px);
|
| 1148 |
+
background: var(--c-ink); color: #fff;
|
| 1149 |
+
border-radius: var(--r2); padding: 8px 18px;
|
| 1150 |
+
font-size: 12px; z-index: 9999; opacity: 0;
|
| 1151 |
+
pointer-events: none; transition: opacity .2s, transform .2s;
|
| 1152 |
+
box-shadow: 0 4px 16px rgba(0,0,0,.2); white-space: nowrap;
|
| 1153 |
+
}
|
| 1154 |
+
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
|
| 1155 |
|
| 1156 |
+
/* βββ Scrollbars βββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 1157 |
+
* { scrollbar-width: thin; scrollbar-color: var(--c-border2) transparent; }
|
| 1158 |
+
::-webkit-scrollbar { width: 4px; }
|
| 1159 |
+
::-webkit-scrollbar-thumb { background: var(--c-border2); border-radius: 99px; }
|
| 1160 |
+
|
| 1161 |
+
/* βββ Text selection βββββββββββββββββββββββββββββββββββββββββββ */
|
| 1162 |
+
::selection { background: rgba(92,126,98,.18); }
|
| 1163 |
</style>
|
| 1164 |
|
| 1165 |
<script>
|
| 1166 |
+
/* ββ Action dispatcher ββββββββββββββββββββββββββββββ */
|
| 1167 |
+
function kbAction(action, name) {
|
| 1168 |
if (action === 'delete') {
|
| 1169 |
+
if (!confirm('Delete ' + name + '?')) return;
|
| 1170 |
+
_setGI('kb-hidden-delete', name);
|
| 1171 |
+
setTimeout(function(){ _clickGI('kb-delete-trigger'); }, 80);
|
| 1172 |
} else if (action === 'replace') {
|
| 1173 |
document.getElementById('kb-file-attach').click();
|
|
|
|
|
|
|
| 1174 |
} else if (action === 'rename') {
|
| 1175 |
+
var r = document.getElementById('row-' + name);
|
| 1176 |
+
var rr= document.getElementById('rrow-' + name);
|
| 1177 |
+
if (r) r.style.display = 'none';
|
| 1178 |
+
if (rr){ rr.classList.add('on'); rr.querySelector('input').focus(); }
|
| 1179 |
}
|
| 1180 |
}
|
| 1181 |
+
function kbCancelRename(name) {
|
| 1182 |
+
var r = document.getElementById('row-' + name);
|
| 1183 |
+
var rr= document.getElementById('rrow-' + name);
|
| 1184 |
+
if (r) r.style.display = '';
|
| 1185 |
+
if (rr) rr.classList.remove('on');
|
| 1186 |
+
}
|
| 1187 |
+
function kbSaveRename(old) {
|
| 1188 |
+
var rr = document.getElementById('rrow-' + old);
|
| 1189 |
+
var v = rr ? rr.querySelector('input').value.trim() : '';
|
| 1190 |
+
if (!v) return;
|
| 1191 |
+
_setGI('kb-hidden-old-name', old);
|
| 1192 |
+
_setGI('kb-hidden-new-name', v);
|
| 1193 |
+
setTimeout(function(){ _clickGI('kb-rename-trigger'); }, 80);
|
| 1194 |
+
}
|
| 1195 |
+
function _setGI(id, val) {
|
| 1196 |
+
var el = document.querySelector('#' + id + ' input, #' + id + ' textarea');
|
| 1197 |
if (!el) return;
|
| 1198 |
+
el.value = val;
|
| 1199 |
+
['input','change'].forEach(function(e){ el.dispatchEvent(new Event(e,{bubbles:true})); });
|
|
|
|
| 1200 |
}
|
| 1201 |
+
function _clickGI(id) {
|
| 1202 |
+
var b = document.querySelector('#' + id + ' button, #' + id);
|
| 1203 |
+
if (b) b.click();
|
| 1204 |
}
|
| 1205 |
function showToast(msg) {
|
| 1206 |
+
var t = document.getElementById('app-toast');
|
| 1207 |
if (!t) return;
|
| 1208 |
t.textContent = msg; t.classList.add('show');
|
| 1209 |
+
setTimeout(function(){ t.classList.remove('show'); }, 2600);
|
| 1210 |
}
|
| 1211 |
+
/* ββ Kill "Chatbot" label via DOM walk ββββββββββββββββ */
|
| 1212 |
+
function killLabel() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1213 |
document.querySelectorAll('label, span, div').forEach(function(el) {
|
| 1214 |
+
if (!el.children.length && el.textContent.trim() === 'Chatbot') {
|
| 1215 |
el.style.display = 'none';
|
| 1216 |
+
var w = el.closest('[class*="label"]');
|
| 1217 |
+
if (w) w.style.display = 'none';
|
| 1218 |
}
|
| 1219 |
});
|
| 1220 |
}
|
| 1221 |
+
new MutationObserver(killLabel).observe(document.documentElement, { childList:true, subtree:true });
|
| 1222 |
+
setTimeout(killLabel, 400);
|
| 1223 |
+
setTimeout(killLabel, 1200);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1224 |
|
| 1225 |
+
/* ββ Pill click β fill textarea βββββββββββββββββββββββ */
|
| 1226 |
+
function fillChat(text) {
|
| 1227 |
+
var t = document.querySelector('.chat-input-container textarea');
|
| 1228 |
+
if (!t) return;
|
| 1229 |
+
t.value = text;
|
| 1230 |
+
t.dispatchEvent(new Event('input', { bubbles: true }));
|
| 1231 |
+
t.focus();
|
| 1232 |
+
}
|
| 1233 |
+
/* ββ Toolbar helpers ββββββββββββββββββββββββββββββββββ */
|
| 1234 |
+
function tbWrap(a, b) {
|
| 1235 |
var t = document.querySelector('.chat-input-container textarea');
|
| 1236 |
if (!t) return;
|
| 1237 |
var s = t.selectionStart, e = t.selectionEnd, v = t.value;
|
| 1238 |
if (s === e) return;
|
| 1239 |
+
t.value = v.slice(0,s)+a+v.slice(s,e)+b+v.slice(e);
|
| 1240 |
+
t.selectionStart = s; t.selectionEnd = e+a.length+b.length;
|
| 1241 |
t.dispatchEvent(new Event('input',{bubbles:true}));
|
| 1242 |
}
|
| 1243 |
function tbBullet() {
|
| 1244 |
var t = document.querySelector('.chat-input-container textarea');
|
| 1245 |
if (!t) return;
|
| 1246 |
+
var ls = t.value.split('\n'), idx = t.value.slice(0,t.selectionStart).split('\n').length-1;
|
| 1247 |
+
ls[idx] = '- '+ls[idx]; t.value = ls.join('\n');
|
| 1248 |
t.dispatchEvent(new Event('input',{bubbles:true}));
|
| 1249 |
}
|
| 1250 |
function tbPaste() {
|
|
|
|
| 1252 |
if (!t) return;
|
| 1253 |
navigator.clipboard.readText().then(function(s){
|
| 1254 |
var i = t.selectionStart;
|
| 1255 |
+
t.value = t.value.slice(0,i)+s+t.value.slice(t.selectionEnd);
|
| 1256 |
+
t.selectionStart = t.selectionEnd = i+s.length;
|
| 1257 |
t.dispatchEvent(new Event('input',{bubbles:true}));
|
| 1258 |
}).catch(function(){ t.focus(); });
|
| 1259 |
}
|
| 1260 |
+
</script>
|
| 1261 |
+
"""
|
| 1262 |
|
| 1263 |
TOOLBAR_HTML = """
|
| 1264 |
+
<div class="tb">
|
| 1265 |
+
<button class="tb-b" data-tip="Attach file" onclick="document.getElementById('kb-file-attach').click()">
|
| 1266 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
| 1267 |
+
<path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"/>
|
| 1268 |
+
</svg>
|
| 1269 |
</button>
|
| 1270 |
+
<button class="tb-b" data-tip="Paste" onclick="tbPaste()">
|
| 1271 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
| 1272 |
+
<rect x="8" y="2" width="8" height="4" rx="1"/>
|
| 1273 |
+
<path d="M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2"/>
|
| 1274 |
+
</svg>
|
| 1275 |
</button>
|
| 1276 |
+
<div class="tb-div"></div>
|
| 1277 |
+
<button class="tb-b" data-tip="Bold" onclick="tbWrap('**','**')">
|
| 1278 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
|
| 1279 |
+
<path d="M6 4h8a4 4 0 010 8H6zM6 12h9a4 4 0 010 8H6z"/>
|
| 1280 |
+
</svg>
|
| 1281 |
</button>
|
| 1282 |
+
<button class="tb-b" data-tip="Italic" onclick="tbWrap('*','*')">
|
| 1283 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
| 1284 |
+
<line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/>
|
| 1285 |
+
</svg>
|
| 1286 |
</button>
|
| 1287 |
+
<button class="tb-b" data-tip="Bullet" onclick="tbBullet()">
|
| 1288 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
| 1289 |
+
<line x1="9" y1="6" x2="20" y2="6"/><line x1="9" y1="12" x2="20" y2="12"/><line x1="9" y1="18" x2="20" y2="18"/>
|
| 1290 |
+
<circle cx="4" cy="6" r="1.5" fill="currentColor" stroke="none"/>
|
| 1291 |
+
<circle cx="4" cy="12" r="1.5" fill="currentColor" stroke="none"/>
|
| 1292 |
+
<circle cx="4" cy="18" r="1.5" fill="currentColor" stroke="none"/>
|
| 1293 |
+
</svg>
|
| 1294 |
</button>
|
| 1295 |
+
<button class="tb-b" data-tip="Code" onclick="tbWrap('`','`')">
|
| 1296 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
| 1297 |
+
<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>
|
| 1298 |
+
</svg>
|
| 1299 |
</button>
|
| 1300 |
+
</div>
|
| 1301 |
+
"""
|
| 1302 |
+
|
| 1303 |
+
# ββ Examples ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1304 |
|
| 1305 |
examples = [
|
| 1306 |
q["query"] for q in CONFIG.get("quick_actions", []) if "query" in q
|
|
|
|
| 1310 |
"Why is self-service important for customer support?",
|
| 1311 |
]
|
| 1312 |
|
| 1313 |
+
# ββ Gradio layout βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1314 |
+
|
| 1315 |
with gr.Blocks(title=CONFIG["client"]["name"]) as demo:
|
| 1316 |
|
| 1317 |
gr.HTML(STYLE_HTML)
|
| 1318 |
+
gr.HTML('<div id="app-toast" class="toast"></div>')
|
| 1319 |
|
| 1320 |
+
# Header
|
| 1321 |
gr.HTML(f"""
|
| 1322 |
+
<div class="h-bar">
|
| 1323 |
+
<div class="h-logo">π€</div>
|
| 1324 |
<div>
|
| 1325 |
+
<div class="h-name">{CONFIG["client"]["name"]}</div>
|
| 1326 |
+
<div class="h-sub">Search the knowledge base and get answers in plain language</div>
|
| 1327 |
</div>
|
| 1328 |
+
<span class="h-badge">MVP Β· AI-powered</span>
|
| 1329 |
</div>""")
|
| 1330 |
|
| 1331 |
+
with gr.Row(elem_classes="body-grid"):
|
| 1332 |
+
|
| 1333 |
+
# ββ Left: suggestions ββββββββββββββββββββββββββββββββββββββββββ
|
| 1334 |
+
with gr.Column(scale=1, elem_classes="left-panel"):
|
| 1335 |
+
pills_html = (
|
| 1336 |
+
'<div class="lp-head">Try asking</div>'
|
| 1337 |
+
'<div class="lp-body">'
|
| 1338 |
+
+ "".join(
|
| 1339 |
+
f'<button class="s-pill" onclick="fillChat({repr(q)})">{q}</button>'
|
| 1340 |
+
for q in examples
|
| 1341 |
+
)
|
| 1342 |
+
+ "</div>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1343 |
)
|
| 1344 |
+
gr.HTML(pills_html)
|
| 1345 |
+
|
| 1346 |
+
# ββ Centre: chat βββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1347 |
+
with gr.Column(scale=3, elem_classes="chat-col"):
|
| 1348 |
+
gr.ChatInterface(fn=chat_respond, cache_examples=False)
|
| 1349 |
gr.HTML(TOOLBAR_HTML)
|
| 1350 |
|
| 1351 |
+
# ββ Right: file list βββββββββββββββββββββββββββββββββββββββββββ
|
| 1352 |
+
with gr.Column(scale=1, elem_classes="right-panel"):
|
| 1353 |
gr.HTML("""
|
| 1354 |
+
<div class="rp-head">
|
| 1355 |
+
<span class="rp-title">Knowledge Base</span>
|
| 1356 |
+
<div class="add-wrap">
|
| 1357 |
+
<button class="add-btn" onclick="document.getElementById('kb-file-attach').click()">
|
|
|
|
| 1358 |
+ Add file
|
| 1359 |
</button>
|
| 1360 |
+
<div class="add-tip">
|
| 1361 |
<strong>Add to knowledge base</strong>
|
| 1362 |
+
<em>Formats: .txt .md .pdf .docx</em>
|
| 1363 |
+
<em>Max 10 MB per file</em>
|
| 1364 |
+
<em>Multiple files at once</em>
|
| 1365 |
+
<em>Index rebuilds automatically</em>
|
| 1366 |
</div>
|
| 1367 |
</div>
|
| 1368 |
</div>""")
|
| 1369 |
|
| 1370 |
+
kb_file_list = gr.HTML(value=list_kb_files_html)
|
|
|
|
|
|
|
| 1371 |
upload_status = gr.Markdown(visible=False)
|
| 1372 |
|
| 1373 |
+
# Hidden Gradio widgets ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 1374 |
with gr.Row(visible=False):
|
| 1375 |
toolbar_upload = gr.File(
|
| 1376 |
label="", file_count="multiple",
|
|
|
|
| 1378 |
elem_id="kb-file-attach",
|
| 1379 |
)
|
| 1380 |
toolbar_status = gr.Markdown()
|
| 1381 |
+
delete_input = gr.Textbox(elem_id="kb-hidden-delete", show_label=False)
|
| 1382 |
+
delete_btn = gr.Button("del", elem_id="kb-delete-trigger")
|
| 1383 |
+
delete_status = gr.Markdown()
|
|
|
|
|
|
|
| 1384 |
old_name_input = gr.Textbox(elem_id="kb-hidden-old-name", show_label=False)
|
| 1385 |
new_name_input = gr.Textbox(elem_id="kb-hidden-new-name", show_label=False)
|
| 1386 |
rename_btn = gr.Button("ren", elem_id="kb-rename-trigger")
|
| 1387 |
rename_status = gr.Markdown()
|
| 1388 |
|
| 1389 |
+
# Event wiring βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 1390 |
def handle_upload(files):
|
| 1391 |
status, _ = upload_kb_files(files)
|
| 1392 |
return status, list_kb_files_html()
|
|
|
|
| 1399 |
status, _ = rename_kb_file(old, new)
|
| 1400 |
return status, list_kb_files_html()
|
| 1401 |
|
| 1402 |
+
toolbar_upload.change(handle_upload, inputs=[toolbar_upload], outputs=[toolbar_status, kb_file_list])
|
| 1403 |
+
delete_btn.click( handle_delete, inputs=[delete_input], outputs=[delete_status, kb_file_list])
|
| 1404 |
+
rename_btn.click( handle_rename, inputs=[old_name_input, new_name_input], outputs=[rename_status, kb_file_list])
|
| 1405 |
|
| 1406 |
|
| 1407 |
# -----------------------------
|