Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -89,14 +89,17 @@ def clean_source_name(book_name: str) -> str:
|
|
| 89 |
return name or "Professor Handouts"
|
| 90 |
|
| 91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
def prioritize_professor_handouts(records):
|
| 93 |
-
"""
|
| 94 |
-
Professor Handouts are always shown and used first.
|
| 95 |
-
Other textbooks are used only as supporting material.
|
| 96 |
-
"""
|
| 97 |
return sorted(
|
| 98 |
records,
|
| 99 |
-
key=lambda r:
|
|
|
|
|
|
|
|
|
|
| 100 |
)
|
| 101 |
|
| 102 |
|
|
@@ -107,21 +110,10 @@ def is_general_chat(text: str) -> bool:
|
|
| 107 |
t = text.lower().strip()
|
| 108 |
|
| 109 |
general_phrases = [
|
| 110 |
-
"hi",
|
| 111 |
-
"
|
| 112 |
-
"
|
| 113 |
-
"
|
| 114 |
-
"good morning",
|
| 115 |
-
"good afternoon",
|
| 116 |
-
"good evening",
|
| 117 |
-
"thanks",
|
| 118 |
-
"thank you",
|
| 119 |
-
"gracias",
|
| 120 |
-
"ok",
|
| 121 |
-
"okay",
|
| 122 |
-
"who are you",
|
| 123 |
-
"what can you do",
|
| 124 |
-
"help"
|
| 125 |
]
|
| 126 |
|
| 127 |
return t in general_phrases
|
|
@@ -158,9 +150,9 @@ def general_chat_reply(text: str, language_mode: str) -> str:
|
|
| 158 |
|
| 159 |
|
| 160 |
# =====================================================
|
| 161 |
-
# RETRIEVAL WITH
|
| 162 |
# =====================================================
|
| 163 |
-
def search_hybrid(query: str, shortlist_k: int =
|
| 164 |
ensure_loaded()
|
| 165 |
|
| 166 |
q_tokens = tokenize(query)
|
|
@@ -172,18 +164,28 @@ def search_hybrid(query: str, shortlist_k: int = 20, final_k: int = 4):
|
|
| 172 |
qvec = EMBED_MODEL.encode([query], normalize_embeddings=True).astype("float32")[0]
|
| 173 |
dense_scores = shortlist_emb @ qvec
|
| 174 |
|
| 175 |
-
rerank = np.argsort(dense_scores)[::-1][:final_k]
|
| 176 |
-
final_idx = shortlist_idx[rerank]
|
| 177 |
-
final_scores = dense_scores[rerank]
|
| 178 |
-
|
| 179 |
results = []
|
| 180 |
|
| 181 |
-
for idx, score in zip(
|
| 182 |
record = CHUNKS[int(idx)].copy()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
record["similarity_score"] = float(score)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
results.append(record)
|
| 185 |
|
| 186 |
-
|
|
|
|
|
|
|
| 187 |
|
| 188 |
|
| 189 |
def build_context(records):
|
|
@@ -197,10 +199,11 @@ def build_context(records):
|
|
| 197 |
blocks.append(
|
| 198 |
f"""[Source {i}]
|
| 199 |
Book: {clean_book}
|
| 200 |
-
Source priority: {
|
| 201 |
Section: {r.get('section_title','')}
|
| 202 |
Pages: {r.get('page_start','')}-{r.get('page_end','')}
|
| 203 |
Similarity Score: {r.get('similarity_score', 0):.3f}
|
|
|
|
| 204 |
Text:
|
| 205 |
{r.get('text','')}"""
|
| 206 |
)
|
|
@@ -232,7 +235,7 @@ def make_sources(records):
|
|
| 232 |
section = r.get("section_title", "Course Material")
|
| 233 |
page_start = r.get("page_start", "")
|
| 234 |
page_end = r.get("page_end", "")
|
| 235 |
-
score = r.get("similarity_score", 0)
|
| 236 |
|
| 237 |
if page_start and page_end and page_start != page_end:
|
| 238 |
page_text = f"pages {page_start}-{page_end}"
|
|
@@ -241,13 +244,10 @@ def make_sources(records):
|
|
| 241 |
else:
|
| 242 |
page_text = "page not specified"
|
| 243 |
|
| 244 |
-
|
| 245 |
-
source_type = "Primary source"
|
| 246 |
-
else:
|
| 247 |
-
source_type = "Supporting textbook"
|
| 248 |
|
| 249 |
lines.append(
|
| 250 |
-
f"• {clean_book} ({source_type}) | {section} | {page_text} |
|
| 251 |
)
|
| 252 |
|
| 253 |
return "\n".join(lines)
|
|
@@ -275,36 +275,49 @@ def compute_confidence(records, answer: str):
|
|
| 275 |
"score": 0.0,
|
| 276 |
}
|
| 277 |
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
if not scores:
|
| 281 |
return {
|
| 282 |
"level": "red",
|
| 283 |
"label": "Not found",
|
| 284 |
"score": 0.0,
|
| 285 |
}
|
| 286 |
|
|
|
|
|
|
|
|
|
|
| 287 |
top_score = max(scores)
|
| 288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
|
| 290 |
-
if top_score >= 0.
|
| 291 |
return {
|
| 292 |
"level": "green",
|
| 293 |
"label": "High confidence",
|
| 294 |
-
"score":
|
| 295 |
}
|
| 296 |
|
| 297 |
-
if top_score >= 0.
|
| 298 |
return {
|
| 299 |
"level": "orange",
|
| 300 |
"label": "Medium confidence",
|
| 301 |
-
"score":
|
| 302 |
}
|
| 303 |
|
| 304 |
return {
|
| 305 |
"level": "red",
|
| 306 |
"label": "Low confidence",
|
| 307 |
-
"score":
|
| 308 |
}
|
| 309 |
|
| 310 |
|
|
@@ -739,9 +752,7 @@ def respond(user_msg, history, mode, language_mode, quiz_count_mode, show_source
|
|
| 739 |
try:
|
| 740 |
history = history + [{"role": "user", "content": text}]
|
| 741 |
|
| 742 |
-
# ---------------------------------------------
|
| 743 |
# General greeting / normal conversation
|
| 744 |
-
# ---------------------------------------------
|
| 745 |
if is_general_chat(text):
|
| 746 |
reply = general_chat_reply(text, language_mode)
|
| 747 |
|
|
@@ -770,9 +781,7 @@ def respond(user_msg, history, mode, language_mode, quiz_count_mode, show_source
|
|
| 770 |
|
| 771 |
return "", history, render_chat(history), quiz_state, render_dashboard()
|
| 772 |
|
| 773 |
-
# ---------------------------------------------
|
| 774 |
# Quiz evaluation mode
|
| 775 |
-
# ---------------------------------------------
|
| 776 |
if quiz_state.get("active", False):
|
| 777 |
evaluation = oai_json(
|
| 778 |
build_quiz_eval_prompt(
|
|
@@ -837,16 +846,11 @@ def respond(user_msg, history, mode, language_mode, quiz_count_mode, show_source
|
|
| 837 |
|
| 838 |
return "", history, render_chat(history), quiz_state, render_dashboard()
|
| 839 |
|
| 840 |
-
# ---------------------------------------------
|
| 841 |
# Retrieval
|
| 842 |
-
|
| 843 |
-
records = search_hybrid(text, shortlist_k=20, final_k=4)
|
| 844 |
-
records = prioritize_professor_handouts(records)
|
| 845 |
context = build_context(records)
|
| 846 |
|
| 847 |
-
# ---------------------------------------------
|
| 848 |
# Quiz generation
|
| 849 |
-
# ---------------------------------------------
|
| 850 |
if mode == "Quiz Me":
|
| 851 |
n_questions = choose_quiz_count(text, quiz_count_mode)
|
| 852 |
|
|
@@ -899,9 +903,7 @@ def respond(user_msg, history, mode, language_mode, quiz_count_mode, show_source
|
|
| 899 |
|
| 900 |
return "", history, render_chat(history), quiz_state, render_dashboard()
|
| 901 |
|
| 902 |
-
# ---------------------------------------------
|
| 903 |
# Normal answer
|
| 904 |
-
# ---------------------------------------------
|
| 905 |
answer = oai_text(
|
| 906 |
build_tutor_prompt(
|
| 907 |
mode,
|
|
@@ -972,18 +974,12 @@ def clear_all():
|
|
| 972 |
CSS = """
|
| 973 |
:root{
|
| 974 |
--page-bg: #d9d9dd;
|
| 975 |
-
--
|
| 976 |
-
--
|
| 977 |
-
--
|
| 978 |
-
--
|
| 979 |
-
--
|
| 980 |
-
--accent: #f4eb4b;
|
| 981 |
-
--accent-soft: #f5ef9a;
|
| 982 |
-
--user-bubble: #ffffff;
|
| 983 |
-
--bot-bubble: #f5efad;
|
| 984 |
--text-dark: #241336;
|
| 985 |
-
--text-dark-strong: #170c25;
|
| 986 |
-
--text-light: #ffffff;
|
| 987 |
--shadow: rgba(30,20,50,0.18);
|
| 988 |
}
|
| 989 |
|
|
@@ -1037,13 +1033,15 @@ footer{
|
|
| 1037 |
border-left: 5px solid #c7a008;
|
| 1038 |
}
|
| 1039 |
|
|
|
|
| 1040 |
.bc-phone{
|
| 1041 |
position: relative;
|
| 1042 |
-
background:
|
| 1043 |
border-radius: 30px;
|
| 1044 |
padding: 92px 14px 14px 14px;
|
| 1045 |
-
box-shadow: 0 16px 34px
|
| 1046 |
min-height: 620px;
|
|
|
|
| 1047 |
}
|
| 1048 |
|
| 1049 |
.bc-logo-holder{
|
|
@@ -1054,7 +1052,7 @@ footer{
|
|
| 1054 |
width: 104px;
|
| 1055 |
height: 104px;
|
| 1056 |
border-radius: 999px;
|
| 1057 |
-
background:
|
| 1058 |
display: flex;
|
| 1059 |
align-items: center;
|
| 1060 |
justify-content: center;
|
|
@@ -1078,17 +1076,17 @@ footer{
|
|
| 1078 |
text-align:center;
|
| 1079 |
font-size: 13px;
|
| 1080 |
font-weight: 900;
|
| 1081 |
-
color:
|
| 1082 |
-
background: rgba(255,255,255,0.
|
| 1083 |
line-height: 1.05;
|
| 1084 |
}
|
| 1085 |
|
| 1086 |
.bc-chat-shell{
|
| 1087 |
-
background:
|
| 1088 |
border-radius: 20px;
|
| 1089 |
padding: 16px;
|
| 1090 |
min-height: 460px;
|
| 1091 |
-
box-shadow: inset 0
|
| 1092 |
}
|
| 1093 |
|
| 1094 |
.bc-chat-wrap{
|
|
@@ -1105,7 +1103,7 @@ footer{
|
|
| 1105 |
}
|
| 1106 |
|
| 1107 |
.bc-chat-wrap::-webkit-scrollbar-thumb{
|
| 1108 |
-
background:
|
| 1109 |
border-radius: 999px;
|
| 1110 |
}
|
| 1111 |
|
|
@@ -1134,19 +1132,21 @@ footer{
|
|
| 1134 |
}
|
| 1135 |
|
| 1136 |
.bc-user-bubble{
|
| 1137 |
-
background:
|
| 1138 |
-
color:
|
|
|
|
| 1139 |
border-bottom-left-radius: 8px;
|
| 1140 |
}
|
| 1141 |
|
| 1142 |
.bc-bot-bubble{
|
| 1143 |
-
background:
|
| 1144 |
-
color:
|
|
|
|
| 1145 |
border-bottom-right-radius: 8px;
|
| 1146 |
}
|
| 1147 |
|
| 1148 |
.bc-bubble strong{
|
| 1149 |
-
color:
|
| 1150 |
}
|
| 1151 |
|
| 1152 |
.bc-confidence{
|
|
@@ -1155,10 +1155,11 @@ footer{
|
|
| 1155 |
gap:8px;
|
| 1156 |
margin-bottom:10px;
|
| 1157 |
padding:7px 10px;
|
| 1158 |
-
background:rgba(255,255,255,0.
|
| 1159 |
border-radius:999px;
|
| 1160 |
font-size:13px;
|
| 1161 |
color:#111827;
|
|
|
|
| 1162 |
}
|
| 1163 |
|
| 1164 |
.bc-dot{
|
|
@@ -1177,16 +1178,17 @@ footer{
|
|
| 1177 |
}
|
| 1178 |
|
| 1179 |
.bc-empty-text{
|
| 1180 |
-
color:
|
| 1181 |
text-align:center;
|
| 1182 |
opacity: 0.96;
|
| 1183 |
font-size: 16px;
|
| 1184 |
line-height: 1.6;
|
|
|
|
| 1185 |
}
|
| 1186 |
|
| 1187 |
.bc-input-bar{
|
| 1188 |
margin-top: 12px;
|
| 1189 |
-
background:
|
| 1190 |
border-radius: 999px;
|
| 1191 |
padding: 8px 10px;
|
| 1192 |
display:flex;
|
|
@@ -1199,22 +1201,22 @@ footer{
|
|
| 1199 |
width: 38px;
|
| 1200 |
height: 38px;
|
| 1201 |
border-radius: 999px;
|
| 1202 |
-
background:
|
| 1203 |
display:flex;
|
| 1204 |
align-items:center;
|
| 1205 |
justify-content:center;
|
| 1206 |
font-size: 30px;
|
| 1207 |
font-weight: 900;
|
| 1208 |
-
color:
|
| 1209 |
user-select:none;
|
| 1210 |
}
|
| 1211 |
|
| 1212 |
#bc_msg textarea{
|
| 1213 |
-
background:
|
| 1214 |
-
border:
|
| 1215 |
box-shadow: none !important;
|
| 1216 |
border-radius: 999px !important;
|
| 1217 |
-
color:
|
| 1218 |
padding: 11px 14px !important;
|
| 1219 |
min-height: 42px !important;
|
| 1220 |
}
|
|
@@ -1228,15 +1230,15 @@ footer{
|
|
| 1228 |
height: 42px !important;
|
| 1229 |
border-radius: 999px !important;
|
| 1230 |
border: none !important;
|
| 1231 |
-
background:
|
| 1232 |
-
color:
|
| 1233 |
font-size: 20px !important;
|
| 1234 |
font-weight: 900 !important;
|
| 1235 |
box-shadow: none !important;
|
| 1236 |
}
|
| 1237 |
|
| 1238 |
#bc_send button:hover{
|
| 1239 |
-
background:
|
| 1240 |
}
|
| 1241 |
|
| 1242 |
#bc_clear button, #bc_refresh button, #bc_clear_analytics button{
|
|
|
|
| 89 |
return name or "Professor Handouts"
|
| 90 |
|
| 91 |
|
| 92 |
+
def source_priority_label(book_name: str) -> str:
|
| 93 |
+
return "Primary source" if clean_source_name(book_name) == "Professor Handouts" else "Supporting textbook"
|
| 94 |
+
|
| 95 |
+
|
| 96 |
def prioritize_professor_handouts(records):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
return sorted(
|
| 98 |
records,
|
| 99 |
+
key=lambda r: (
|
| 100 |
+
0 if clean_source_name(r.get("book", "")) == "Professor Handouts" else 1,
|
| 101 |
+
-float(r.get("final_score", r.get("similarity_score", 0)))
|
| 102 |
+
)
|
| 103 |
)
|
| 104 |
|
| 105 |
|
|
|
|
| 110 |
t = text.lower().strip()
|
| 111 |
|
| 112 |
general_phrases = [
|
| 113 |
+
"hi", "hello", "hola", "hey",
|
| 114 |
+
"good morning", "good afternoon", "good evening",
|
| 115 |
+
"thanks", "thank you", "gracias",
|
| 116 |
+
"ok", "okay", "who are you", "what can you do", "help"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
]
|
| 118 |
|
| 119 |
return t in general_phrases
|
|
|
|
| 150 |
|
| 151 |
|
| 152 |
# =====================================================
|
| 153 |
+
# RETRIEVAL WITH PROFESSOR HANDOUT BOOST
|
| 154 |
# =====================================================
|
| 155 |
+
def search_hybrid(query: str, shortlist_k: int = 30, final_k: int = 5):
|
| 156 |
ensure_loaded()
|
| 157 |
|
| 158 |
q_tokens = tokenize(query)
|
|
|
|
| 164 |
qvec = EMBED_MODEL.encode([query], normalize_embeddings=True).astype("float32")[0]
|
| 165 |
dense_scores = shortlist_emb @ qvec
|
| 166 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
results = []
|
| 168 |
|
| 169 |
+
for idx, score in zip(shortlist_idx, dense_scores):
|
| 170 |
record = CHUNKS[int(idx)].copy()
|
| 171 |
+
clean_book = clean_source_name(record.get("book", ""))
|
| 172 |
+
|
| 173 |
+
priority_boost = 0.15 if clean_book == "Professor Handouts" else 0.0
|
| 174 |
+
final_score = float(score) + priority_boost
|
| 175 |
+
|
| 176 |
record["similarity_score"] = float(score)
|
| 177 |
+
record["final_score"] = final_score
|
| 178 |
+
record["source_priority"] = (
|
| 179 |
+
"Professor Handouts"
|
| 180 |
+
if clean_book == "Professor Handouts"
|
| 181 |
+
else "Supporting textbook"
|
| 182 |
+
)
|
| 183 |
+
|
| 184 |
results.append(record)
|
| 185 |
|
| 186 |
+
results = sorted(results, key=lambda r: r["final_score"], reverse=True)
|
| 187 |
+
|
| 188 |
+
return prioritize_professor_handouts(results[:final_k])
|
| 189 |
|
| 190 |
|
| 191 |
def build_context(records):
|
|
|
|
| 199 |
blocks.append(
|
| 200 |
f"""[Source {i}]
|
| 201 |
Book: {clean_book}
|
| 202 |
+
Source priority: {source_priority_label(clean_book)}
|
| 203 |
Section: {r.get('section_title','')}
|
| 204 |
Pages: {r.get('page_start','')}-{r.get('page_end','')}
|
| 205 |
Similarity Score: {r.get('similarity_score', 0):.3f}
|
| 206 |
+
Final Score: {r.get('final_score', r.get('similarity_score', 0)):.3f}
|
| 207 |
Text:
|
| 208 |
{r.get('text','')}"""
|
| 209 |
)
|
|
|
|
| 235 |
section = r.get("section_title", "Course Material")
|
| 236 |
page_start = r.get("page_start", "")
|
| 237 |
page_end = r.get("page_end", "")
|
| 238 |
+
score = r.get("final_score", r.get("similarity_score", 0))
|
| 239 |
|
| 240 |
if page_start and page_end and page_start != page_end:
|
| 241 |
page_text = f"pages {page_start}-{page_end}"
|
|
|
|
| 244 |
else:
|
| 245 |
page_text = "page not specified"
|
| 246 |
|
| 247 |
+
source_type = source_priority_label(clean_book)
|
|
|
|
|
|
|
|
|
|
| 248 |
|
| 249 |
lines.append(
|
| 250 |
+
f"• {clean_book} ({source_type}) | {section} | {page_text} | relevance: {score:.2f}"
|
| 251 |
)
|
| 252 |
|
| 253 |
return "\n".join(lines)
|
|
|
|
| 275 |
"score": 0.0,
|
| 276 |
}
|
| 277 |
|
| 278 |
+
if not records:
|
|
|
|
|
|
|
| 279 |
return {
|
| 280 |
"level": "red",
|
| 281 |
"label": "Not found",
|
| 282 |
"score": 0.0,
|
| 283 |
}
|
| 284 |
|
| 285 |
+
scores = [float(r.get("final_score", r.get("similarity_score", 0))) for r in records]
|
| 286 |
+
raw_scores = [float(r.get("similarity_score", 0)) for r in records]
|
| 287 |
+
|
| 288 |
top_score = max(scores)
|
| 289 |
+
top_raw = max(raw_scores)
|
| 290 |
+
|
| 291 |
+
professor_found = any(
|
| 292 |
+
clean_source_name(r.get("book", "")) == "Professor Handouts"
|
| 293 |
+
for r in records[:3]
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
if professor_found and top_score >= 0.48:
|
| 297 |
+
return {
|
| 298 |
+
"level": "green",
|
| 299 |
+
"label": "High confidence",
|
| 300 |
+
"score": top_raw,
|
| 301 |
+
}
|
| 302 |
|
| 303 |
+
if top_score >= 0.52:
|
| 304 |
return {
|
| 305 |
"level": "green",
|
| 306 |
"label": "High confidence",
|
| 307 |
+
"score": top_raw,
|
| 308 |
}
|
| 309 |
|
| 310 |
+
if top_score >= 0.35:
|
| 311 |
return {
|
| 312 |
"level": "orange",
|
| 313 |
"label": "Medium confidence",
|
| 314 |
+
"score": top_raw,
|
| 315 |
}
|
| 316 |
|
| 317 |
return {
|
| 318 |
"level": "red",
|
| 319 |
"label": "Low confidence",
|
| 320 |
+
"score": top_raw,
|
| 321 |
}
|
| 322 |
|
| 323 |
|
|
|
|
| 752 |
try:
|
| 753 |
history = history + [{"role": "user", "content": text}]
|
| 754 |
|
|
|
|
| 755 |
# General greeting / normal conversation
|
|
|
|
| 756 |
if is_general_chat(text):
|
| 757 |
reply = general_chat_reply(text, language_mode)
|
| 758 |
|
|
|
|
| 781 |
|
| 782 |
return "", history, render_chat(history), quiz_state, render_dashboard()
|
| 783 |
|
|
|
|
| 784 |
# Quiz evaluation mode
|
|
|
|
| 785 |
if quiz_state.get("active", False):
|
| 786 |
evaluation = oai_json(
|
| 787 |
build_quiz_eval_prompt(
|
|
|
|
| 846 |
|
| 847 |
return "", history, render_chat(history), quiz_state, render_dashboard()
|
| 848 |
|
|
|
|
| 849 |
# Retrieval
|
| 850 |
+
records = search_hybrid(text, shortlist_k=30, final_k=5)
|
|
|
|
|
|
|
| 851 |
context = build_context(records)
|
| 852 |
|
|
|
|
| 853 |
# Quiz generation
|
|
|
|
| 854 |
if mode == "Quiz Me":
|
| 855 |
n_questions = choose_quiz_count(text, quiz_count_mode)
|
| 856 |
|
|
|
|
| 903 |
|
| 904 |
return "", history, render_chat(history), quiz_state, render_dashboard()
|
| 905 |
|
|
|
|
| 906 |
# Normal answer
|
|
|
|
| 907 |
answer = oai_text(
|
| 908 |
build_tutor_prompt(
|
| 909 |
mode,
|
|
|
|
| 974 |
CSS = """
|
| 975 |
:root{
|
| 976 |
--page-bg: #d9d9dd;
|
| 977 |
+
--uva-purple: #5a2d77;
|
| 978 |
+
--uva-purple-light: #7b3f98;
|
| 979 |
+
--uva-gold: #c7a008;
|
| 980 |
+
--uva-gold-light: #fff8cc;
|
| 981 |
+
--uva-soft-purple: #efe7f6;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 982 |
--text-dark: #241336;
|
|
|
|
|
|
|
| 983 |
--shadow: rgba(30,20,50,0.18);
|
| 984 |
}
|
| 985 |
|
|
|
|
| 1033 |
border-left: 5px solid #c7a008;
|
| 1034 |
}
|
| 1035 |
|
| 1036 |
+
/* CHAT WINDOW - same family as analytics dashboard */
|
| 1037 |
.bc-phone{
|
| 1038 |
position: relative;
|
| 1039 |
+
background: #ffffff;
|
| 1040 |
border-radius: 30px;
|
| 1041 |
padding: 92px 14px 14px 14px;
|
| 1042 |
+
box-shadow: 0 16px 34px rgba(0,0,0,0.22);
|
| 1043 |
min-height: 620px;
|
| 1044 |
+
border-top: 8px solid #5a2d77;
|
| 1045 |
}
|
| 1046 |
|
| 1047 |
.bc-logo-holder{
|
|
|
|
| 1052 |
width: 104px;
|
| 1053 |
height: 104px;
|
| 1054 |
border-radius: 999px;
|
| 1055 |
+
background: #c7a008;
|
| 1056 |
display: flex;
|
| 1057 |
align-items: center;
|
| 1058 |
justify-content: center;
|
|
|
|
| 1076 |
text-align:center;
|
| 1077 |
font-size: 13px;
|
| 1078 |
font-weight: 900;
|
| 1079 |
+
color: #241336;
|
| 1080 |
+
background: rgba(255,255,255,0.55);
|
| 1081 |
line-height: 1.05;
|
| 1082 |
}
|
| 1083 |
|
| 1084 |
.bc-chat-shell{
|
| 1085 |
+
background: #ffffff;
|
| 1086 |
border-radius: 20px;
|
| 1087 |
padding: 16px;
|
| 1088 |
min-height: 460px;
|
| 1089 |
+
box-shadow: inset 0 0 0 2px #e5d8ef;
|
| 1090 |
}
|
| 1091 |
|
| 1092 |
.bc-chat-wrap{
|
|
|
|
| 1103 |
}
|
| 1104 |
|
| 1105 |
.bc-chat-wrap::-webkit-scrollbar-thumb{
|
| 1106 |
+
background: #c7a008;
|
| 1107 |
border-radius: 999px;
|
| 1108 |
}
|
| 1109 |
|
|
|
|
| 1132 |
}
|
| 1133 |
|
| 1134 |
.bc-user-bubble{
|
| 1135 |
+
background: #efe7f6;
|
| 1136 |
+
color: #241336 !important;
|
| 1137 |
+
border: 2px solid #d8c6e8;
|
| 1138 |
border-bottom-left-radius: 8px;
|
| 1139 |
}
|
| 1140 |
|
| 1141 |
.bc-bot-bubble{
|
| 1142 |
+
background: #fff8cc;
|
| 1143 |
+
color: #241336 !important;
|
| 1144 |
+
border: 2px solid #c7a008;
|
| 1145 |
border-bottom-right-radius: 8px;
|
| 1146 |
}
|
| 1147 |
|
| 1148 |
.bc-bubble strong{
|
| 1149 |
+
color: #241336 !important;
|
| 1150 |
}
|
| 1151 |
|
| 1152 |
.bc-confidence{
|
|
|
|
| 1155 |
gap:8px;
|
| 1156 |
margin-bottom:10px;
|
| 1157 |
padding:7px 10px;
|
| 1158 |
+
background:rgba(255,255,255,0.75);
|
| 1159 |
border-radius:999px;
|
| 1160 |
font-size:13px;
|
| 1161 |
color:#111827;
|
| 1162 |
+
border:1px solid #e5d8ef;
|
| 1163 |
}
|
| 1164 |
|
| 1165 |
.bc-dot{
|
|
|
|
| 1178 |
}
|
| 1179 |
|
| 1180 |
.bc-empty-text{
|
| 1181 |
+
color: #5a2d77;
|
| 1182 |
text-align:center;
|
| 1183 |
opacity: 0.96;
|
| 1184 |
font-size: 16px;
|
| 1185 |
line-height: 1.6;
|
| 1186 |
+
font-weight:600;
|
| 1187 |
}
|
| 1188 |
|
| 1189 |
.bc-input-bar{
|
| 1190 |
margin-top: 12px;
|
| 1191 |
+
background: #5a2d77;
|
| 1192 |
border-radius: 999px;
|
| 1193 |
padding: 8px 10px;
|
| 1194 |
display:flex;
|
|
|
|
| 1201 |
width: 38px;
|
| 1202 |
height: 38px;
|
| 1203 |
border-radius: 999px;
|
| 1204 |
+
background: #c7a008;
|
| 1205 |
display:flex;
|
| 1206 |
align-items:center;
|
| 1207 |
justify-content:center;
|
| 1208 |
font-size: 30px;
|
| 1209 |
font-weight: 900;
|
| 1210 |
+
color: #ffffff;
|
| 1211 |
user-select:none;
|
| 1212 |
}
|
| 1213 |
|
| 1214 |
#bc_msg textarea{
|
| 1215 |
+
background: #ffffff !important;
|
| 1216 |
+
border: 2px solid #c7a008 !important;
|
| 1217 |
box-shadow: none !important;
|
| 1218 |
border-radius: 999px !important;
|
| 1219 |
+
color: #241336 !important;
|
| 1220 |
padding: 11px 14px !important;
|
| 1221 |
min-height: 42px !important;
|
| 1222 |
}
|
|
|
|
| 1230 |
height: 42px !important;
|
| 1231 |
border-radius: 999px !important;
|
| 1232 |
border: none !important;
|
| 1233 |
+
background: #c7a008 !important;
|
| 1234 |
+
color: #ffffff !important;
|
| 1235 |
font-size: 20px !important;
|
| 1236 |
font-weight: 900 !important;
|
| 1237 |
box-shadow: none !important;
|
| 1238 |
}
|
| 1239 |
|
| 1240 |
#bc_send button:hover{
|
| 1241 |
+
background: #9f8006 !important;
|
| 1242 |
}
|
| 1243 |
|
| 1244 |
#bc_clear button, #bc_refresh button, #bc_clear_analytics button{
|