Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- .gitattributes +44 -44
- .gitignore +4 -0
- app.py +502 -381
- requirements.txt +15 -15
.gitattributes
CHANGED
|
@@ -1,44 +1,44 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
-
faiss_index_unmad_magz/index.faiss filter=lfs diff=lfs merge=lfs -text
|
| 37 |
-
images/354043071_653375850167696_1862718270923061923_n-removebg-preview.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
-
images/unmad_pic.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
-
images/c1.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
-
lance_unmad_db/unmad_documents.lance/data/1ed6346a-63e5-488b-8266-93cb400a38fa.lance filter=lfs diff=lfs merge=lfs -text
|
| 41 |
-
lance_unmad_db/unmad_documents.lance/data/fb6df230-9aa6-455d-b5a8-eb3fe5acda98.lance filter=lfs diff=lfs merge=lfs -text
|
| 42 |
-
lance_unmad_db/unmad_documents.lance/data/78e3ec7c-8251-40e9-b828-8f3610f16dc6.lance filter=lfs diff=lfs merge=lfs -text
|
| 43 |
-
lance_unmad_db/unmad_documents.lance/data/974f34e7-a8d6-4bb7-b0f6-53cd0f4a684b.lance filter=lfs diff=lfs merge=lfs -text
|
| 44 |
-
lance_unmad_db/unmad_documents.lance/data/ad577893-15ee-4592-bc76-65bbd21939d4.lance filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
faiss_index_unmad_magz/index.faiss filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
images/354043071_653375850167696_1862718270923061923_n-removebg-preview.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
images/unmad_pic.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
images/c1.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
lance_unmad_db/unmad_documents.lance/data/1ed6346a-63e5-488b-8266-93cb400a38fa.lance filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
lance_unmad_db/unmad_documents.lance/data/fb6df230-9aa6-455d-b5a8-eb3fe5acda98.lance filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
lance_unmad_db/unmad_documents.lance/data/78e3ec7c-8251-40e9-b828-8f3610f16dc6.lance filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
lance_unmad_db/unmad_documents.lance/data/974f34e7-a8d6-4bb7-b0f6-53cd0f4a684b.lance filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
lance_unmad_db/unmad_documents.lance/data/ad577893-15ee-4592-bc76-65bbd21939d4.lance filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
chat_logs/
|
app.py
CHANGED
|
@@ -1,382 +1,503 @@
|
|
| 1 |
-
import os
|
| 2 |
-
import re
|
| 3 |
-
import
|
| 4 |
-
import
|
| 5 |
-
|
| 6 |
-
import
|
| 7 |
-
import
|
| 8 |
-
import
|
| 9 |
-
import
|
| 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 |
-
if
|
| 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 |
demo.launch(ssr_mode=False)
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import re
|
| 3 |
+
import csv
|
| 4 |
+
import json
|
| 5 |
+
import uuid
|
| 6 |
+
import time
|
| 7 |
+
import threading
|
| 8 |
+
import warnings
|
| 9 |
+
from typing import List, Dict, Any, Optional
|
| 10 |
+
import lancedb
|
| 11 |
+
import gradio as gr
|
| 12 |
+
import numpy as np
|
| 13 |
+
import pandas as pd
|
| 14 |
+
from datetime import datetime, timezone
|
| 15 |
+
from dotenv import load_dotenv
|
| 16 |
+
from openai import OpenAI
|
| 17 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
| 18 |
+
from huggingface_hub import HfApi, CommitScheduler
|
| 19 |
+
|
| 20 |
+
# Load environment variables
|
| 21 |
+
load_dotenv()
|
| 22 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY_Project")
|
| 23 |
+
if not OPENAI_API_KEY:
|
| 24 |
+
raise ValueError("Missing OPENAI_API_KEY. Please set it in your environment variables.")
|
| 25 |
+
|
| 26 |
+
# Suppress warnings
|
| 27 |
+
warnings.filterwarnings("ignore")
|
| 28 |
+
|
| 29 |
+
# ---------------------------------------------------------------------------
|
| 30 |
+
# Chat-history persistence to a (private) Hugging Face Dataset repo
|
| 31 |
+
# ---------------------------------------------------------------------------
|
| 32 |
+
# Required Space secrets (set in Space -> Settings -> Variables and secrets):
|
| 33 |
+
# HF_TOKEN -> a HF access token with WRITE permission
|
| 34 |
+
# HF_DATASET_REPO -> e.g. "Rezuwan/usb-unmad-chatlogs"
|
| 35 |
+
#
|
| 36 |
+
# The CommitScheduler watches a local folder and pushes its contents to the
|
| 37 |
+
# dataset repo every `every` minutes. We write two files:
|
| 38 |
+
# - chat_history.csv (machine readable, append-only)
|
| 39 |
+
# - chat_history.txt (human readable transcript, append-only)
|
| 40 |
+
# ---------------------------------------------------------------------------
|
| 41 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 42 |
+
HF_DATASET_REPO = os.getenv("HF_DATASET_REPO")
|
| 43 |
+
|
| 44 |
+
LOG_DIR = "chat_logs"
|
| 45 |
+
os.makedirs(LOG_DIR, exist_ok=True)
|
| 46 |
+
CSV_PATH = os.path.join(LOG_DIR, "chat_history.csv")
|
| 47 |
+
TXT_PATH = os.path.join(LOG_DIR, "chat_history.txt")
|
| 48 |
+
|
| 49 |
+
# Create the CSV with a header on first run
|
| 50 |
+
if not os.path.exists(CSV_PATH):
|
| 51 |
+
with open(CSV_PATH, "w", encoding="utf-8", newline="") as f:
|
| 52 |
+
writer = csv.writer(f)
|
| 53 |
+
writer.writerow([
|
| 54 |
+
"timestamp_utc",
|
| 55 |
+
"session_id",
|
| 56 |
+
"turn",
|
| 57 |
+
"user_message",
|
| 58 |
+
"bot_response",
|
| 59 |
+
])
|
| 60 |
+
|
| 61 |
+
_log_lock = threading.Lock()
|
| 62 |
+
_scheduler = None
|
| 63 |
+
|
| 64 |
+
if HF_TOKEN and HF_DATASET_REPO:
|
| 65 |
+
try:
|
| 66 |
+
# Make sure the dataset repo exists (private by default)
|
| 67 |
+
HfApi(token=HF_TOKEN).create_repo(
|
| 68 |
+
repo_id=HF_DATASET_REPO,
|
| 69 |
+
repo_type="dataset",
|
| 70 |
+
private=True,
|
| 71 |
+
exist_ok=True,
|
| 72 |
+
)
|
| 73 |
+
# Push the contents of LOG_DIR every 5 minutes
|
| 74 |
+
_scheduler = CommitScheduler(
|
| 75 |
+
repo_id=HF_DATASET_REPO,
|
| 76 |
+
repo_type="dataset",
|
| 77 |
+
folder_path=LOG_DIR,
|
| 78 |
+
path_in_repo=".",
|
| 79 |
+
every=5, # minutes
|
| 80 |
+
token=HF_TOKEN,
|
| 81 |
+
squash_history=False,
|
| 82 |
+
)
|
| 83 |
+
print(f"[chat-log] Persisting chat history to dataset: {HF_DATASET_REPO}")
|
| 84 |
+
except Exception as e:
|
| 85 |
+
print(f"[chat-log] Failed to set up HF dataset logging: {e}")
|
| 86 |
+
_scheduler = None
|
| 87 |
+
else:
|
| 88 |
+
print("[chat-log] HF_TOKEN or HF_DATASET_REPO not set \u2014 chat history will only be saved locally inside the Space container (non-persistent).")
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def log_chat_turn(session_id: str, turn: int, user_message: str, bot_response: str) -> None:
|
| 92 |
+
"""Append a single chat turn to both the CSV and TXT log files.
|
| 93 |
+
|
| 94 |
+
Thread-safe. The CommitScheduler will push the files to the HF dataset
|
| 95 |
+
repo on its own schedule.
|
| 96 |
+
"""
|
| 97 |
+
ts = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
|
| 98 |
+
try:
|
| 99 |
+
with _log_lock:
|
| 100 |
+
# CSV row
|
| 101 |
+
with open(CSV_PATH, "a", encoding="utf-8", newline="") as f:
|
| 102 |
+
writer = csv.writer(f)
|
| 103 |
+
writer.writerow([ts, session_id, turn, user_message, bot_response])
|
| 104 |
+
# Human-readable transcript
|
| 105 |
+
with open(TXT_PATH, "a", encoding="utf-8") as f:
|
| 106 |
+
f.write(f"[{ts}] session={session_id} turn={turn}\n")
|
| 107 |
+
f.write(f"USER: {user_message}\n")
|
| 108 |
+
f.write(f"BOT : {bot_response}\n")
|
| 109 |
+
f.write("-" * 80 + "\n")
|
| 110 |
+
except Exception as e:
|
| 111 |
+
print(f"[chat-log] Failed to write chat log: {e}")
|
| 112 |
+
|
| 113 |
+
class LanceDBRAG:
|
| 114 |
+
def __init__(self,
|
| 115 |
+
db_path: str = "lance_unmad_db",
|
| 116 |
+
table_name: str = "unmad_documents"):
|
| 117 |
+
"""Initialize LanceDB RAG System"""
|
| 118 |
+
self.db_path = db_path
|
| 119 |
+
self.table_name = table_name
|
| 120 |
+
|
| 121 |
+
# Initialize OpenAI client
|
| 122 |
+
self.client = OpenAI(api_key=OPENAI_API_KEY)
|
| 123 |
+
|
| 124 |
+
# Connect to LanceDB
|
| 125 |
+
try:
|
| 126 |
+
self.db = lancedb.connect(self.db_path)
|
| 127 |
+
self.table = self.db.open_table(self.table_name)
|
| 128 |
+
print(f"Connected to LanceDB: {self.db_path}/{self.table_name}")
|
| 129 |
+
except Exception as e:
|
| 130 |
+
raise ConnectionError(f"Failed to connect to LanceDB: {e}")
|
| 131 |
+
|
| 132 |
+
def get_embedding(self, text: str) -> List[float]:
|
| 133 |
+
"""Get OpenAI embedding for query text"""
|
| 134 |
+
try:
|
| 135 |
+
response = self.client.embeddings.create(
|
| 136 |
+
model="text-embedding-3-small",
|
| 137 |
+
input=text
|
| 138 |
+
)
|
| 139 |
+
return response.data[0].embedding
|
| 140 |
+
except Exception as e:
|
| 141 |
+
print(f"Error getting embedding: {e}")
|
| 142 |
+
return None
|
| 143 |
+
|
| 144 |
+
def search_similar_content(self, query: str, limit: int = 10) -> pd.DataFrame:
|
| 145 |
+
"""Search for similar content in the database"""
|
| 146 |
+
print(f"Searching: '{query}'")
|
| 147 |
+
|
| 148 |
+
# Get query embedding
|
| 149 |
+
query_embedding = self.get_embedding(query)
|
| 150 |
+
if not query_embedding:
|
| 151 |
+
return pd.DataFrame()
|
| 152 |
+
|
| 153 |
+
# Perform vector search
|
| 154 |
+
try:
|
| 155 |
+
search_query = self.table.search(query_embedding).limit(limit)
|
| 156 |
+
results = search_query.to_pandas()
|
| 157 |
+
|
| 158 |
+
if not results.empty:
|
| 159 |
+
print(f"Found {len(results)} relevant results")
|
| 160 |
+
else:
|
| 161 |
+
print("No results found")
|
| 162 |
+
|
| 163 |
+
return results
|
| 164 |
+
|
| 165 |
+
except Exception as e:
|
| 166 |
+
print(f"Search error: {e}")
|
| 167 |
+
return pd.DataFrame()
|
| 168 |
+
|
| 169 |
+
# Initialize global RAG instance
|
| 170 |
+
rag_system = LanceDBRAG()
|
| 171 |
+
|
| 172 |
+
def maximal_marginal_relevance_search(query, rag_instance, k=10, lambda_param=0.6, top_k=3):
|
| 173 |
+
"""
|
| 174 |
+
Implement Maximal Marginal Relevance (MMR) for diverse document retrieval using LanceDB.
|
| 175 |
+
|
| 176 |
+
Args:
|
| 177 |
+
query: Search query string
|
| 178 |
+
rag_instance: LanceDB RAG instance
|
| 179 |
+
k: Number of candidate documents to consider
|
| 180 |
+
lambda_param: Trade-off between relevance and diversity (0-1)
|
| 181 |
+
top_k: Number of final documents to return
|
| 182 |
+
|
| 183 |
+
Returns:
|
| 184 |
+
List of selected documents with MMR ranking
|
| 185 |
+
"""
|
| 186 |
+
# Get initial candidate documents using LanceDB search
|
| 187 |
+
search_results = rag_instance.search_similar_content(query, limit=k)
|
| 188 |
+
|
| 189 |
+
if search_results.empty:
|
| 190 |
+
return []
|
| 191 |
+
|
| 192 |
+
# Convert to document-like objects for compatibility
|
| 193 |
+
docs = []
|
| 194 |
+
for _, row in search_results.iterrows():
|
| 195 |
+
doc_obj = {
|
| 196 |
+
'page_content': row['text'],
|
| 197 |
+
'metadata': {
|
| 198 |
+
'source': row.get('magazine_name', 'Unknown Source'),
|
| 199 |
+
'page': row.get('page_number', 'Unknown Page'),
|
| 200 |
+
'chunk': row.get('chunk_id', 0)
|
| 201 |
+
},
|
| 202 |
+
'score': row['_distance']
|
| 203 |
+
}
|
| 204 |
+
docs.append(doc_obj)
|
| 205 |
+
|
| 206 |
+
# Apply MMR selection if we have enough documents
|
| 207 |
+
if len(docs) <= top_k:
|
| 208 |
+
return docs[:top_k]
|
| 209 |
+
|
| 210 |
+
# MMR Selection Algorithm
|
| 211 |
+
selected_docs = []
|
| 212 |
+
remaining_indices = list(range(len(docs)))
|
| 213 |
+
|
| 214 |
+
for _ in range(min(top_k, len(docs))):
|
| 215 |
+
if not remaining_indices:
|
| 216 |
+
break
|
| 217 |
+
|
| 218 |
+
mmr_scores = []
|
| 219 |
+
|
| 220 |
+
for i in remaining_indices:
|
| 221 |
+
# Calculate relevance score (inverse of distance)
|
| 222 |
+
relevance = 1 / (1 + docs[i]['score'])
|
| 223 |
+
|
| 224 |
+
# Calculate diversity score (max similarity to already selected docs)
|
| 225 |
+
if selected_docs:
|
| 226 |
+
max_similarity = 0
|
| 227 |
+
for selected_doc in selected_docs:
|
| 228 |
+
# Simple text-based similarity for diversity
|
| 229 |
+
text1 = docs[i]['page_content']
|
| 230 |
+
text2 = selected_doc['page_content']
|
| 231 |
+
|
| 232 |
+
# Calculate simple Jaccard similarity
|
| 233 |
+
words1 = set(text1.split())
|
| 234 |
+
words2 = set(text2.split())
|
| 235 |
+
if words1 and words2:
|
| 236 |
+
similarity = len(words1.intersection(words2)) / len(words1.union(words2))
|
| 237 |
+
max_similarity = max(max_similarity, similarity)
|
| 238 |
+
|
| 239 |
+
diversity = max_similarity
|
| 240 |
+
else:
|
| 241 |
+
diversity = 0
|
| 242 |
+
|
| 243 |
+
# Calculate MMR score
|
| 244 |
+
mmr_score = lambda_param * relevance - (1 - lambda_param) * diversity
|
| 245 |
+
mmr_scores.append((mmr_score, i))
|
| 246 |
+
|
| 247 |
+
# Select document with highest MMR score
|
| 248 |
+
if mmr_scores:
|
| 249 |
+
best_score, best_idx = max(mmr_scores, key=lambda x: x[0])
|
| 250 |
+
selected_docs.append(docs[best_idx])
|
| 251 |
+
remaining_indices.remove(best_idx)
|
| 252 |
+
|
| 253 |
+
return selected_docs
|
| 254 |
+
|
| 255 |
+
def clean_bangla_content(text):
|
| 256 |
+
"""
|
| 257 |
+
Clean the retrieved content to remove English watermarks, scan text, and tags.
|
| 258 |
+
Keeps the Bengali text intact instead of deleting the whole line.
|
| 259 |
+
"""
|
| 260 |
+
if not text:
|
| 261 |
+
return ""
|
| 262 |
+
|
| 263 |
+
# 1. First, strip out the specific tags entirely using NO backslashes
|
| 264 |
+
text = re.sub("[[]source: *[0-9]+[]]", "", text, flags=re.IGNORECASE)
|
| 265 |
+
|
| 266 |
+
# Common English watermarks and scan text to remove
|
| 267 |
+
english_patterns = [
|
| 268 |
+
r'scanned by \w+',
|
| 269 |
+
r'found in \w+',
|
| 270 |
+
r'www\.\w+\.\w+',
|
| 271 |
+
r'http[s]?://[^\s]+',
|
| 272 |
+
r'\.pdf',
|
| 273 |
+
r'\.com',
|
| 274 |
+
r'\.org',
|
| 275 |
+
r'\.net',
|
| 276 |
+
r'banglapdf',
|
| 277 |
+
r'sadaqpdf',
|
| 278 |
+
r'pdf scanner',
|
| 279 |
+
r'scan by',
|
| 280 |
+
r'converted by',
|
| 281 |
+
r'page \d+',
|
| 282 |
+
r'source:',
|
| 283 |
+
r'reference:',
|
| 284 |
+
r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+', # emails
|
| 285 |
+
]
|
| 286 |
+
|
| 287 |
+
lines = text.split('\n')
|
| 288 |
+
cleaned_lines = []
|
| 289 |
+
|
| 290 |
+
for line in lines:
|
| 291 |
+
# 2. Replace matched English watermark patterns with an empty string
|
| 292 |
+
for pattern in english_patterns:
|
| 293 |
+
line = re.sub(pattern, '', line, flags=re.IGNORECASE)
|
| 294 |
+
|
| 295 |
+
line = line.strip()
|
| 296 |
+
if not line:
|
| 297 |
+
continue
|
| 298 |
+
|
| 299 |
+
# 3. Check if there's actual Bengali content left
|
| 300 |
+
bengali_chars = len(re.findall(r'[\u0980-\u09FF]', line))
|
| 301 |
+
|
| 302 |
+
# Only keep the line if it has Bengali characters
|
| 303 |
+
if bengali_chars > 0:
|
| 304 |
+
cleaned_lines.append(line)
|
| 305 |
+
|
| 306 |
+
return '\n'.join(cleaned_lines)
|
| 307 |
+
|
| 308 |
+
# Enhanced Satirical QA function with MMR and content cleaning
|
| 309 |
+
def custom_unmad_satirical_bot(message, history, top_k=3, lambda_param=0.6, session_id="anonymous"):
|
| 310 |
+
"""
|
| 311 |
+
Enhanced satirical bot using MMR for diverse and relevant content retrieval.
|
| 312 |
+
|
| 313 |
+
Args:
|
| 314 |
+
message: User query
|
| 315 |
+
history: Chat history
|
| 316 |
+
top_k: Number of documents to retrieve
|
| 317 |
+
lambda_param: MMR trade-off (higher favors exact relevance over diversity)
|
| 318 |
+
"""
|
| 319 |
+
# Use MMR search with LanceDB
|
| 320 |
+
docs = maximal_marginal_relevance_search(
|
| 321 |
+
query=message,
|
| 322 |
+
rag_instance=rag_system,
|
| 323 |
+
k=15, # Consider more candidates for better diversity
|
| 324 |
+
lambda_param=lambda_param,
|
| 325 |
+
top_k=top_k
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
# Extract context from MMR-selected documents
|
| 329 |
+
if docs:
|
| 330 |
+
# Clean each document's content before joining
|
| 331 |
+
cleaned_contexts = []
|
| 332 |
+
for doc in docs:
|
| 333 |
+
cleaned_content = clean_bangla_content(doc['page_content'])
|
| 334 |
+
if cleaned_content.strip(): # Only add if there's meaningful Bengali content
|
| 335 |
+
cleaned_contexts.append(cleaned_content)
|
| 336 |
+
|
| 337 |
+
if cleaned_contexts:
|
| 338 |
+
top_contexts = "\n\n---\n\n".join(cleaned_contexts)
|
| 339 |
+
else:
|
| 340 |
+
top_contexts = "No relevant information were found"
|
| 341 |
+
|
| 342 |
+
# Add metadata about source diversity (optional)
|
| 343 |
+
source_info = []
|
| 344 |
+
for i, doc in enumerate(docs, 1):
|
| 345 |
+
source = doc['metadata'].get('source', 'Unknown source')
|
| 346 |
+
page = doc['metadata'].get('page', 'Unknown page')
|
| 347 |
+
# Clean source info too
|
| 348 |
+
if not re.search(r'[a-zA-Z]', str(source)): # Only if source doesn't contain English
|
| 349 |
+
source_info.append(f"[{i}] {source} - {page}")
|
| 350 |
+
|
| 351 |
+
source_context = "Source: " + " | ".join(source_info[:3]) if source_info else ""
|
| 352 |
+
else:
|
| 353 |
+
top_contexts = "No relevant information were found"
|
| 354 |
+
source_context = ""
|
| 355 |
+
|
| 356 |
+
# Prepare system prompt
|
| 357 |
+
system_prompt = """
|
| 358 |
+
তুমি বাংলাদেশের জনপ্রিয় স্যাটায়ার ম্যাগাজিন 'উন্মাদ'-এর একজন অত্যন্ত বুদ্ধিদীপ্ত, রসিক এবং কিছুটা 'তেড়া' (cynical) স্বভাবের লেখক। তোমার কাজ হলো ব্যবহারকারীর প্রশ্নের এমন উত্তর দেওয়া, যা পড়ে মনে হবে ঢাকার কোনো টং দোকানে বসে আড্ডা দেওয়ার সময় কেউ চরম স্যাটায়ার করছে। উত্তরগুলো হতে হবে লোকাল, চটপটে, এবং স্মার্ট।
|
| 359 |
+
|
| 360 |
+
**এই নির্দেশনাগুলো কঠোরভাবে মেনে চলবে - কোন ব্যতিক্রম নেই:**
|
| 361 |
+
|
| 362 |
+
১। **লোকাল ও খাঁটি দেশি রসিকতা:** ভিনগ্রহ, পিরামিড, বা রূপকথার মতো আজগুবি বা ভিনদেশি উদাহরণ একদম টানবে না। খাঁটি বাংলাদেশি মেটাফোর ব্যবহার করবে (যেমন: টংয়ের চা, ঢাকার জ্যাম, লোডশেডিং, কারওয়ান বাজারের কাদা, লোকাল বাসের হেলপার, ইত্যাদি)। কথাবার্তা হবে একদম ন্যাচারাল, যেন মুখোমুখি বসে আড্ডা দিচ্ছ।
|
| 363 |
+
২। **প্রসঙ্গের ওপর সর্বোচ্চ জোর:** আমি তোমাকে যে 'প্রসঙ্গ' (Context) দেব, তোমার উত্তরের মূল ভিত্তি হবে সেটাই। প্রসঙ্গের বাইরের কোনো মনগড়া গল্প বানাবে না, বরং প্রসঙ্গের তথ্যগুলোকে বাঁকাভাবে উপস্থাপন করে খোঁচা দেবে।
|
| 364 |
+
৩। **অচেনা নাম নিয়ে দেশি স্টাইলে কটাক্ষ:** ব্যবহারকারী যদি এমন কোনো নাম বা বিষয় নিয়ে প্রশ্ন করে যা তোমার 'প্রসঙ্গে' নেই (যেমন ইশরাকের সাথে সাথে 'নগর ড্যাডি'), তাহলে এমনভাবে খোঁচা দেবে যেন সে গুলিস্তানের মোড়ে দাঁড়িয়ে গাঁজাখুরি গল্প করছে। (যেমন বলতে পারো: "নগর ড্যাডি ইশরাক আবার কে ভাই? গুলিস্তানের নতুন কোনো চাঁদাবাজ নাকি? নাকি চাঁদা চাইতে গিয়ে নিজেই চাঁদা হয়ে গেছে?")
|
| 365 |
+
৪। **খোঁচা দেওয়ার ধরন:** প্রসঙ্গের তথ্য ব্যবহার করে চরম স্যাটায়ার করবে। (যেমন: পিনাকী বা ইলিয়াসের কথা এলে বলবে তারা ফ্রান্স বা আমেরিকায় বসে 'ল্যাপটপ বিপ্লব' করছে; প্রথম আলোর কথা এলে বলবে আগুনে পোড়া ফার্নিচার দিয়ে আর্ট গ্যালারি বানানোর কথা)।
|
| 366 |
+
৫। কোন ইমোজি (EMOJI), ইংরেজি শব্দ, ইংরেজি অক্ষর, ইংরেজি সংখ্যা বা স্ক্যান ওয়াটারমার্ক ব্যবহার করবে না। সম্পূর্ণ বাংলায় স্মার্ট, রসবোধ সম্পন্ন এবং 'উন্মাদ' স্টাইলে তীক্ষ্ণ উত্তর লেখো।
|
| 367 |
+
"""
|
| 368 |
+
|
| 369 |
+
user_prompt = f"""
|
| 370 |
+
প্রসঙ্গ (বিভিন্ন উৎস থেকে সংগৃহীত):
|
| 371 |
+
{top_contexts}
|
| 372 |
+
|
| 373 |
+
প্রশ্ন: {message}
|
| 374 |
+
|
| 375 |
+
নির্দেশনা: উপরের প্রসঙ্গ থেকে শুধুমাত্র বাংলা ভাষার বিষয়বস্তু ব্যবহার করে উন্মাদ ম্যাগাজিনের দেশি স্টাইলে উত্তর দাও। কোন ইমোজি বা ইংরেজি শব্দ দেবে না। উত্তরের ভাষা হবে চটপটে, ব্যঙ্গাত্মক এবং খাঁটি বাংলাদেশি।
|
| 376 |
+
|
| 377 |
+
"""
|
| 378 |
+
|
| 379 |
+
# Generate response using OpenAI
|
| 380 |
+
try:
|
| 381 |
+
response = rag_system.client.chat.completions.create(
|
| 382 |
+
model="gpt-4o",
|
| 383 |
+
messages=[
|
| 384 |
+
{"role": "system", "content": system_prompt},
|
| 385 |
+
{"role": "user", "content": user_prompt}
|
| 386 |
+
],
|
| 387 |
+
temperature=0.7,
|
| 388 |
+
max_tokens=700
|
| 389 |
+
)
|
| 390 |
+
|
| 391 |
+
ai_response = response.choices[0].message.content
|
| 392 |
+
history.append((message, ai_response))
|
| 393 |
+
# Persist this turn (best-effort, never breaks the chat)
|
| 394 |
+
try:
|
| 395 |
+
log_chat_turn(
|
| 396 |
+
session_id=session_id,
|
| 397 |
+
turn=len(history),
|
| 398 |
+
user_message=message,
|
| 399 |
+
bot_response=ai_response,
|
| 400 |
+
)
|
| 401 |
+
except Exception as log_err:
|
| 402 |
+
print(f"[chat-log] log_chat_turn failed: {log_err}")
|
| 403 |
+
return "", history
|
| 404 |
+
|
| 405 |
+
except Exception as e:
|
| 406 |
+
error_response = f"উত্তর তৈরিতে সমস্যা হয়েছে। আবার চেষ্টা করুন।"
|
| 407 |
+
history.append((message, error_response))
|
| 408 |
+
try:
|
| 409 |
+
log_chat_turn(
|
| 410 |
+
session_id=session_id,
|
| 411 |
+
turn=len(history),
|
| 412 |
+
user_message=message,
|
| 413 |
+
bot_response=f"[ERROR] {error_response} ({e})",
|
| 414 |
+
)
|
| 415 |
+
except Exception:
|
| 416 |
+
pass
|
| 417 |
+
return "", history
|
| 418 |
+
|
| 419 |
+
# Enhanced Gradio UI with Polished Layout and Fixed State Management
|
| 420 |
+
with gr.Blocks(theme=gr.themes.Soft(), css=".gradio-container {padding-top: 40px;}") as demo:
|
| 421 |
+
|
| 422 |
+
with gr.Column(elem_classes="text-center"):
|
| 423 |
+
gr.Markdown("# USB: Unmad Satirical Bot")
|
| 424 |
+
gr.Markdown("### *A Satirical Bot that impersonates the satirical character UNMAD*")
|
| 425 |
+
|
| 426 |
+
try:
|
| 427 |
+
# Upgraded Image block for a full-width banner look
|
| 428 |
+
gr.Image(
|
| 429 |
+
"images/c1.png",
|
| 430 |
+
height=250, # Adjust this number to make the banner taller or shorter
|
| 431 |
+
show_label=False,
|
| 432 |
+
container=False, # Removes the bulky white background box
|
| 433 |
+
interactive=False, # Makes it a static image (removes upload/edit hover buttons)
|
| 434 |
+
show_download_button=False, # Hides the download icon
|
| 435 |
+
show_fullscreen_button=False # Hides the fullscreen icon
|
| 436 |
+
)
|
| 437 |
+
except:
|
| 438 |
+
gr.Markdown("*[UNMAD Logo]*")
|
| 439 |
+
|
| 440 |
+
# Upgraded Chatbot component with avatars and better height
|
| 441 |
+
chatbot = gr.Chatbot(
|
| 442 |
+
height=500,
|
| 443 |
+
type="tuples",
|
| 444 |
+
avatar_images=(None, "images/c1.png"), # Left: User (Default), Right: Unmad (Your logo)
|
| 445 |
+
show_label=False
|
| 446 |
+
)
|
| 447 |
+
|
| 448 |
+
with gr.Row():
|
| 449 |
+
msg = gr.Textbox(
|
| 450 |
+
placeholder="কি চলে আপনার মনে? বলেন শুনি...",
|
| 451 |
+
scale=8,
|
| 452 |
+
show_label=False,
|
| 453 |
+
container=False # Removes the bulky box around the input
|
| 454 |
+
)
|
| 455 |
+
send = gr.Button("Send (↲)", variant="primary", scale=1)
|
| 456 |
+
|
| 457 |
+
clear = gr.Button("Clear Chat", variant="secondary")
|
| 458 |
+
|
| 459 |
+
# State to keep track of the conversation
|
| 460 |
+
state = gr.State([])
|
| 461 |
+
# Per-browser-session anonymous ID (generated once when the page loads).
|
| 462 |
+
# This lets you group all turns of one participant in the saved logs
|
| 463 |
+
# without collecting any personal info.
|
| 464 |
+
session_id_state = gr.State()
|
| 465 |
+
|
| 466 |
+
def _init_session():
|
| 467 |
+
return f"sess-{uuid.uuid4().hex[:12]}"
|
| 468 |
+
|
| 469 |
+
demo.load(_init_session, inputs=None, outputs=session_id_state)
|
| 470 |
+
|
| 471 |
+
def chat_with_fixed_mmr(message, history, session_id):
|
| 472 |
+
if not message.strip():
|
| 473 |
+
return "", history, history
|
| 474 |
+
if not session_id:
|
| 475 |
+
session_id = f"sess-{uuid.uuid4().hex[:12]}"
|
| 476 |
+
|
| 477 |
+
# Call your core function with increased top_k and higher lambda_param for strict relevance
|
| 478 |
+
_, updated_history = custom_unmad_satirical_bot(
|
| 479 |
+
message, history, top_k=4, lambda_param=0.85, session_id=session_id
|
| 480 |
+
)
|
| 481 |
+
|
| 482 |
+
# Return: 1. Empty Textbox, 2. Visual Chatbot update, 3. Internal State update
|
| 483 |
+
return "", updated_history, updated_history
|
| 484 |
+
|
| 485 |
+
# Event Listeners with Loading States
|
| 486 |
+
# Disable the input box while generating to prevent spam
|
| 487 |
+
msg.submit(
|
| 488 |
+
chat_with_fixed_mmr,
|
| 489 |
+
inputs=[msg, state, session_id_state],
|
| 490 |
+
outputs=[msg, chatbot, state]
|
| 491 |
+
)
|
| 492 |
+
|
| 493 |
+
send.click(
|
| 494 |
+
chat_with_fixed_mmr,
|
| 495 |
+
inputs=[msg, state, session_id_state],
|
| 496 |
+
outputs=[msg, chatbot, state]
|
| 497 |
+
)
|
| 498 |
+
|
| 499 |
+
# Properly clear both the visual chatbot and the internal state
|
| 500 |
+
clear.click(lambda: ([], []), None, [chatbot, state], queue=False)
|
| 501 |
+
|
| 502 |
+
if __name__ == "__main__":
|
| 503 |
demo.launch(ssr_mode=False)
|
requirements.txt
CHANGED
|
@@ -1,16 +1,16 @@
|
|
| 1 |
-
gradio==5.49.1
|
| 2 |
-
gradio-client==1.13.3
|
| 3 |
-
pydantic>=2.11,<2.12
|
| 4 |
-
huggingface-hub>=0.33.5
|
| 5 |
-
langchain==0.3.25
|
| 6 |
-
langchain-community==0.3.24
|
| 7 |
-
langchain-core==0.3.60
|
| 8 |
-
langchain-openai==0.3.17
|
| 9 |
-
openai==1.79.0
|
| 10 |
-
faiss-cpu==1.11.0
|
| 11 |
-
lancedb>=0.3.0
|
| 12 |
-
pandas>=1.5.0
|
| 13 |
-
tqdm>=4.64.0
|
| 14 |
-
python-dotenv>=1.0.0
|
| 15 |
-
numpy>=1.21.0
|
| 16 |
scikit-learn>=1.0.0
|
|
|
|
| 1 |
+
gradio==5.49.1
|
| 2 |
+
gradio-client==1.13.3
|
| 3 |
+
pydantic>=2.11,<2.12
|
| 4 |
+
huggingface-hub>=0.33.5
|
| 5 |
+
langchain==0.3.25
|
| 6 |
+
langchain-community==0.3.24
|
| 7 |
+
langchain-core==0.3.60
|
| 8 |
+
langchain-openai==0.3.17
|
| 9 |
+
openai==1.79.0
|
| 10 |
+
faiss-cpu==1.11.0
|
| 11 |
+
lancedb>=0.3.0
|
| 12 |
+
pandas>=1.5.0
|
| 13 |
+
tqdm>=4.64.0
|
| 14 |
+
python-dotenv>=1.0.0
|
| 15 |
+
numpy>=1.21.0
|
| 16 |
scikit-learn>=1.0.0
|